feat: add Linux OAuth adapters
Add a bounded libcurl transport with verified TLS, no redirects or retries, sanitized failures, binary-safe requests, and resolved-address enforcement for cleartext loopback traffic. Add shell-free xdg-open launching and a one-shot IPv4 loopback callback receiver with strict HTTP/query parsing, deadlines, fixed callback path, and RAII cleanup. Token parsing, Secret Service, and Graph remain follow-up phases.
This commit is contained in:
@@ -183,10 +183,40 @@ consent policy remains authoritative and may require administrator approval or
|
||||
block consent. A desktop binary distributed as open source is not a confidential
|
||||
client and must not embed or depend on a client secret.
|
||||
|
||||
This boundary does not yet contain a concrete HTTP transport, system-browser or
|
||||
loopback-listener adapter, token JSON parsing, a Secret Service backend, Graph
|
||||
requests, or usable account setup. Those concrete desktop, HTTP, and secret
|
||||
storage adapters are the next slice. Read-only Microsoft Graph calendar
|
||||
The generic boundary deliberately contains no concrete networking or desktop
|
||||
code. The Linux adapters below supply the transport, browser launch, and
|
||||
loopback listener. Token JSON parsing, Secret Service storage, Graph requests,
|
||||
and usable account setup remain later slices. Read-only Microsoft Graph calendar
|
||||
discovery and delta synchronization follows; delta links remain opaque and are
|
||||
persisted only through the calendar/window transaction described above. Remote
|
||||
writes and conflict resolution come later.
|
||||
|
||||
### Concrete Linux adapters
|
||||
|
||||
The concrete adapter phase provides a libcurl transport that keeps certificate
|
||||
and host verification enabled, bounds response bodies and
|
||||
connection/operation timeouts, and disables automatic redirects. It implements
|
||||
one request attempt only: neither the adapter nor the generic transport retries.
|
||||
Cleartext HTTP is accepted solely for explicit loopback tests; provider traffic
|
||||
uses HTTPS.
|
||||
|
||||
The browser adapter launches `xdg-open` directly without a shell, so an
|
||||
authorization URL is never interpreted as shell syntax. The callback receiver
|
||||
binds IPv4 `127.0.0.1` on a dynamically assigned port, advertises that port with
|
||||
the `localhost` host and fixed `/nocal/oauth/callback` path, and handles one
|
||||
bounded callback before closing. Bounded header/input sizes and a deadline keep
|
||||
a local peer from holding the authorization process indefinitely.
|
||||
|
||||
The Entra registration must configure Nocal as a Mobile and desktop public
|
||||
client with `http://localhost/nocal/oauth/callback`. Microsoft ignores the port
|
||||
when matching a `localhost` redirect, which permits the runtime-selected port.
|
||||
Using an HTTP redirect with the literal `127.0.0.1` host instead requires editing
|
||||
the application manifest, and IPv6 loopback redirect addresses are currently
|
||||
unsupported. The advertised `localhost` URL therefore remains distinct from the
|
||||
IPv4-only listener binding.
|
||||
|
||||
Concrete token JSON parsing, Secret Service storage, Graph requests, account UI,
|
||||
and usable account setup are still absent. libsecret's synchronous calls may
|
||||
block; the next adapter isolates them behind an off-render-thread boundary
|
||||
rather than calling them from the TUI loop. Read-only Graph discovery and delta
|
||||
follow token parsing and secret persistence.
|
||||
|
||||
@@ -141,13 +141,25 @@ desktop binary.
|
||||
|
||||
The provider-neutral HTTP seam accepts an injected transport and can therefore
|
||||
be exercised with deterministic fakes. It intentionally owns no generic retry
|
||||
policy; provider operations must decide whether a retry is safe. This phase does
|
||||
not make Office 365 usable yet. It includes no concrete HTTP transport, real
|
||||
browser/loopback adapter, token JSON parser, Secret Service backend, Graph call,
|
||||
or usable account setup. The next product slice supplies concrete desktop,
|
||||
network, and secret-storage adapters, followed by read-only Graph calendar
|
||||
discovery and delta synchronization. Remote writes remain gated on the
|
||||
durability and conflict paths being exercised end to end.
|
||||
policy; provider operations must decide whether a retry is safe. The concrete
|
||||
Linux adapter uses libcurl while preserving
|
||||
TLS certificate and host verification, bounds responses and timeouts, and
|
||||
follows neither redirects nor retries automatically. Cleartext HTTP exists only
|
||||
for loopback tests. Browser opening invokes `xdg-open` without a shell.
|
||||
|
||||
The receiver listens only on `127.0.0.1`, chooses a dynamic port, advertises a
|
||||
`localhost` URL with the fixed `/nocal/oauth/callback` path, and processes one
|
||||
bounded callback. The Microsoft registration is a Mobile and desktop public
|
||||
client with `http://localhost/nocal/oauth/callback`. Microsoft ignores the port
|
||||
when matching localhost redirects. Literal HTTP `127.0.0.1` registration needs
|
||||
a manifest edit, and IPv6 loopback redirects are currently unsupported.
|
||||
|
||||
These adapters still do not make Office 365 usable. They include no token JSON
|
||||
parser, Secret Service backend, Graph call, or account UI. libsecret exposes
|
||||
synchronous operations that may block, so the next phase isolates its adapter
|
||||
off the render thread. Token parsing and secure persistence come before
|
||||
read-only Graph calendar discovery and delta synchronization. Remote writes
|
||||
remain gated on the durability and conflict paths being exercised end to end.
|
||||
|
||||
## Local file interchange
|
||||
|
||||
|
||||
@@ -46,9 +46,21 @@ Completed HTTP/OAuth boundary:
|
||||
block user consent
|
||||
- No client secret in the open-source desktop binary
|
||||
|
||||
Completed concrete Linux adapters:
|
||||
|
||||
- libcurl transport with verified TLS, bounded responses/timeouts, no automatic
|
||||
redirects/retries, and cleartext HTTP only for loopback tests
|
||||
- Shell-free `xdg-open` launcher and one-shot `127.0.0.1` callback receiver
|
||||
advertising `http://localhost:<dynamic-port>/nocal/oauth/callback`
|
||||
- Mobile/Desktop public-client registration at
|
||||
`http://localhost/nocal/oauth/callback`; Microsoft ignores localhost ports,
|
||||
while literal HTTP `127.0.0.1` needs a manifest edit and IPv6 loopback is not
|
||||
supported
|
||||
|
||||
Next provider-boundary slices:
|
||||
|
||||
- Concrete HTTP, browser/loopback, token JSON, and Secret Service adapters
|
||||
- Token JSON parsing and a Secret Service adapter isolated off the render thread
|
||||
because synchronous libsecret calls may block
|
||||
- OAuth secrets in Secret Service, never SQLite
|
||||
- Generic `SyncProvider` contract and observable sync status
|
||||
|
||||
@@ -65,12 +77,11 @@ Next provider-boundary slices:
|
||||
ETag-aware remote writes after the conflict boundary is proven
|
||||
- Account/calendar management UI and per-calendar ANSI identity
|
||||
|
||||
The cache and generic HTTP/OAuth boundaries are prerequisites, not usable
|
||||
Microsoft 365 integration. The boundary phase has no concrete HTTP transport,
|
||||
real browser/loopback adapter, token parser, Secret Service backend, Graph call,
|
||||
or account setup. The immediate sequence is concrete desktop, HTTP, and Secret
|
||||
Service adapters, then read-only Microsoft Graph discovery and delta
|
||||
synchronization.
|
||||
The cache, generic HTTP/OAuth boundary, and concrete Linux adapters are
|
||||
prerequisites, not usable Microsoft 365 integration. There is still no token
|
||||
parser, Secret Service backend, Graph call, or account UI. The immediate sequence is token parsing plus an
|
||||
off-render-thread Secret Service adapter, then read-only Microsoft Graph
|
||||
discovery and delta synchronization.
|
||||
|
||||
## 1.0 — distribution quality
|
||||
|
||||
|
||||
Reference in New Issue
Block a user