mirror of
https://github.com/netbirdio/netbird.git
synced 2026-09-24 15:49:06 +02:00
embed-multi-client-knobs
2
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
652d5f3c15 |
[client] Reuse the profile's account for iOS SSO logins (#7193)
* [client] Reuse the profile's account for iOS SSO logins Android reads the profile's stored account and passes it as the OIDC login_hint, and records it again after a successful login. iOS did neither: it called GetOAuthFlow with an empty hint, so a re-login was resolved by whatever session the browser's cookie jar held rather than by the account the profile belongs to. With a non-ephemeral browser session that is the wrong account as soon as more than one is signed in. Mirror client/android/login.go: hint from mobile.ReadProfileEmail before the flow, mobile.WriteProfileEmail after Login succeeds. Storing after Login and not before keeps a rejected token from leaving a hint that points at an account which cannot be used. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * [client] Persist the account email on tvOS and on the device flow Two paths left a profile with no account bound, so every later login went out without a login_hint — the case this change exists to remove. WriteProfileEmail went through util.WriteJsonWithRestrictedPermission, which writes a temp file and renames it over the target. The tvOS App Group sandbox blocks exactly that, which is why the config sitting next to this file is written with DirectWriteOutConfig. On tvOS the email write therefore failed and was dropped with a warning. Use DirectWriteJson: the file is rewritten whole from a single key, so the only thing atomicity buys here is surviving a crash mid-write, and a torn file reads back as "no email" and is replaced by the next login. The device authorization flow never populated TokenInfo.Email, unlike the PKCE flow, so a client driven through it — Android TV and tvOS — bound no account at all. Parse the ID token there too. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * [client] Report a failed close from DirectWriteJson The deferred close assigned its error to err, but the return value was not named, so the assignment went nowhere: a close that failed was logged and the function still returned nil. The write is only durable once the file closes cleanly, so every caller — the management config, the profile configs and the profile account email — could be told the data landed when it had not. Name the return so the assignment does what its shape always intended, and report the failure once. When the body succeeded the close error is returned and the caller logs it. When the body already failed, that error is the one that explains the failure and is what the caller gets, which leaves the deferred log as the only place the close failure can surface — at debug, per the logging rules for close errors on writes. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
f2318a8fef |
[client] iOS - Remove duplicate Login RPCs from the iOS SDK (#6931)
## Describe your changes Removes redundant `Login` RPCs from the iOS SDK bindings. ## Issue ticket number and link ## Stack <!-- branch-stack --> ### Checklist - [x] Is it a bug fix - [ ] Is a typo/documentation fix - [ ] Is a feature enhancement - [ ] It is a refactor - [ ] Created tests that fail without the change (if possible) - [ ] This change does **not** modify the public API, gRPC protocols, functionality behavior, CLI / service flags, or introduce a new feature — **OR** I have discussed it with the NetBird team beforehand (link the issue / Slack thread in the description). See [CONTRIBUTING.md](https://github.com/netbirdio/netbird/blob/main/CONTRIBUTING.md#discuss-changes-with-the-netbird-team-first). > By submitting this pull request, you confirm that you have read and agree to the terms of the [Contributor License Agreement](https://github.com/netbirdio/netbird/blob/main/CONTRIBUTOR_LICENSE_AGREEMENT.md). ## Documentation Select exactly one: - [ ] I added/updated documentation for this change - [x] Documentation is **not needed** for this change (explain why) ### Docs PR URL (required if "docs added" is checked) Paste the PR link from https://github.com/netbirdio/docs here: https://github.com/netbirdio/docs/pull/__ <!-- codesmith:footer --> --- <a href="https://app.blacksmith.sh/netbirdio/codesmith/netbird/pr/6931"><picture><source media="(prefers-color-scheme: dark)" srcset="https://pr-comments-assets.blacksmith.sh/codesmith/view-with-codesmith-dark-v2.svg"><source media="(prefers-color-scheme: light)" srcset="https://pr-comments-assets.blacksmith.sh/codesmith/view-with-codesmith-light-v2.svg"><img alt="View with [code]smith" src="https://pr-comments-assets.blacksmith.sh/codesmith/view-with-codesmith-dark-v2.svg"></picture></a> <a href="https://backend.blacksmith.sh/track/enable-autofix?expires=1787779607&installation_model_id=427504&pr_number=6931&repository=netbirdio%2Fnetbird&return_to=https%3A%2F%2Fgithub.com%2Fnetbirdio%2Fnetbird%2Fpull%2F6931&signature=ce1631be2a5ffdba58c44b4669b0d480dc9f956102cf10a0c7b5845a800cdc68"><picture><source media="(prefers-color-scheme: dark)" srcset="https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-light.svg"><img alt="Autofix with [code]smith" src="https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-dark.svg"></picture></a> <sup>Need help on this PR? Tag <code>@codesmith-bot</code> with what you need. Autofix is disabled.</sup> <!-- codesmith:autofix:disabled --> <!-- /codesmith:footer --> <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added an interactive iOS login option that starts authentication directly when needed. * Improved login flow handling, including clearer error reporting and successful-login notifications. * Login configuration is now saved automatically after successful authentication when applicable. * **Bug Fixes** * Prevented duplicate login requests during iOS startup. * Improved startup behavior and error propagation when the management service is unavailable. <!-- end of auto-generated comment: release notes by coderabbit.ai --> Removes redundant `Login` RPCs from the iOS SDK bindings. Both changed files are behind the `ios` build tag — Android, desktop and the shared core are not affected. ### Problem `auth.Auth.IsLoginRequired()` is not a cheap probe: it calls `doMgmLogin()` and classifies the resulting error, so every "is login required?" check costs a **full `Login` RPC**. There is no lighter way to ask. As a result the iOS client issued ~7 `Login` requests before the first `Sync`, where Android issues ~3, and the extra ones were indistinguishable from real logins in the management logs. Three of those came from this package: 1. `Run()` called `LoginSync()` before starting the engine, which performs `IsLoginRequired` **and** `Login` — two RPCs. This duplicated the engine's own `loginToManagement` (`client/internal/connect.go`), which runs immediately before the first `Sync` and is the authoritative login. The `Login(ctx, "", "")` inside `LoginSync` could not even establish anything: with an empty setup key and empty JWT, a registration attempt fails by construction, so it was a pure check. 2. `Auth.login()` called `IsLoginRequired()` again before opening the browser, even when the caller had already determined that login is needed. This is not only wasted traffic: - **It pushes peers toward the server-side login ban.** In `management/internals/shared/grpc/loginfilter.go`, every login with unchanged metadata increments `sessionCounter`, and exceeding `reconnLimitForBan` (30) within `reconnThreshold` (5 min) bans the peer for `baseBlockDuration` (10 min), doubling on repeat. Redundant logins carry identical metadata, so they count against exactly this budget. At 7 logins per connect the budget is exhausted after ~4 reconnects instead of ~10 — reachable on flaky mobile networks. - **Each redundant check is a potential 2-minute stall.** `IsLoginRequired` retries with backoff up to `MaxElapsedTime` (2 min) and returns `true` on failure, so an unreachable server was reported as "login required" rather than as a timeout, and the `LoginSync` pre-flight could abort engine startup on that basis. ### Changes **`client/ios/NetBirdSDK/client.go`** — `Run()` no longer performs the `LoginSync()` pre-flight. The engine's `loginToManagement` remains the single authoritative login. **`client/ios/NetBirdSDK/login.go`** — new exported `LoginInteractive`, which skips the `IsLoginRequired()` pre-flight and goes straight to the browser / device-code flow, for callers that have already established login is required. `LoginWithDeviceName` keeps the check for callers where the auth state is unknown (tvOS). Both now delegate to a shared `startLogin()`. ### Why this is safe An expired or revoked session still fails the connection, one step later and through a single path: `loginToManagement` returns `PermissionDenied` → the deferred `MarkManagementDisconnected` records it on the shared status recorder → `ClientStop` fires the listener's disconnect callback, where `IsLoginRequiredCached()` reports login-required → the client tears the tunnel down. The error is also returned out of `Run()`. Where the server is unreachable, the engine now retries with backoff and recovers on its own instead of aborting the start. Co-authored-by: Zoltan Papp <zoltan.pmail@gmail.com> |