Skip to content
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@

All notable changes to cmux are documented here.

## [Unreleased]

### Fixed
- Open Settings > Account sign-in in the user's default browser, complete through the cmux auth callback, and guard malformed native auth handoffs ([#3617](https://github.com/manaflow-ai/cmux/issues/3617))

Comment thread
coderabbitai[bot] marked this conversation as resolved.
## [0.64.10] - 2026-05-23

### Added
Expand Down
13 changes: 0 additions & 13 deletions Resources/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -53,19 +53,6 @@
<string>A program running within cmux would like to use AppleScript.</string>
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
<key>CFBundleURLName</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER).web</string>
<key>LSHandlerRank</key>
<string>Default</string>
<key>CFBundleURLSchemes</key>
<array>
<string>http</string>
<string>https</string>
</array>
</dict>
<dict>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
Expand Down
29 changes: 29 additions & 0 deletions Resources/Localizable.xcstrings
Original file line number Diff line number Diff line change
Expand Up @@ -120943,6 +120943,35 @@
}
}
},
"settings.account.error.signInTimedOut": {
"extractionState": "manual",
"localizations": {
"en": {
"stringUnit": {
"state": "translated",
"value": "Sign in timed out. Try again."
}
},
"ja": {
"stringUnit": {
"state": "translated",
"value": "サインインがタイムアウトしました。もう一度お試しください。"
}
},
"uk": {
"stringUnit": {
"state": "translated",
"value": "Час очікування входу минув. Спробуйте ще раз."
}
},
"ko": {
"stringUnit": {
"state": "translated",
"value": "로그인 시간이 초과되었습니다. 다시 시도하세요."
}
}
}
},
"remote.state.connected.vmNoProxy": {
"extractionState": "manual",
"localizations": {
Comment on lines 120943 to 121073
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Missing translations for 16 of 20 supported locales

The new settings.account.error.signInTimedOut string is only translated into en, ja, uk, and ko. The catalog already supports ar, bs, da, de, es, fr, it, km, nb, pl, pt-BR, ru, th, tr, zh-Hans, and zh-Hant — users on any of those locales will see the raw English fallback "Sign in timed out. Try again." when the timeout fires. The settings.account.error.missingRefreshToken and settings.account.error.invalidCallback strings added in companion PRs each carry all 20 translations; this one is the odd one out.

Rule Used: Flag production user-facing text that is not fully... (source)

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Expand Down
17 changes: 16 additions & 1 deletion Sources/Auth/AuthCallbackRouter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import Foundation
struct CMUXAuthCallbackPayload: Equatable, Sendable {
let refreshToken: String
let accessToken: String
let state: String?
}

enum AuthCallbackRouter {
Expand All @@ -29,10 +30,19 @@ enum AuthCallbackRouter {

return CMUXAuthCallbackPayload(
refreshToken: refreshToken,
accessToken: accessToken
accessToken: accessToken,
state: callbackState(in: components)
)
}

static func callbackState(from url: URL) -> String? {
guard isAuthCallbackURL(url),
let components = URLComponents(url: url, resolvingAgainstBaseURL: false) else {
return nil
}
return callbackState(in: components)
}

private static func isAllowedScheme(_ scheme: String?) -> Bool {
guard let normalized = scheme?.lowercased() else { return false }
if normalized == "cmux" || normalized == "cmux-nightly" || normalized == "cmux-dev" {
Expand Down Expand Up @@ -63,6 +73,11 @@ enum AuthCallbackRouter {
.value
}

private static func callbackState(in components: URLComponents) -> String? {
queryValue(named: "state", in: components)?
.trimmingCharacters(in: .whitespacesAndNewlines)
}

private static func decodeAccessToken(from accessCookie: String) -> String? {
guard accessCookie.hasPrefix("[") else {
return accessCookie
Expand Down
17 changes: 15 additions & 2 deletions Sources/Auth/AuthEnvironment.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,20 @@ enum AuthEnvironment {
}

static var callbackURL: URL {
URL(string: "\(callbackScheme)://auth-callback")!
authCallbackURL()
}

static func authCallbackURL(state: String? = nil) -> URL {
var components = URLComponents()
components.scheme = callbackScheme
components.host = "auth-callback"
if let state,
!state.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
components.queryItems = [
URLQueryItem(name: "state", value: state),
]
}
return components.url!
}

static var websiteOrigin: URL {
Expand Down Expand Up @@ -191,7 +204,7 @@ enum AuthEnvironment {
)
}

static func signInURL() -> URL {
static func signInURL(callbackURL: URL = AuthEnvironment.callbackURL) -> URL {
// Build the after-sign-in callback URL that includes the native app return scheme.
// The after-sign-in handler extracts tokens from the Stack Auth session
// and redirects to the native app via the cmux:// callback scheme.
Expand Down
Loading
Loading