mirror of
https://github.com/stablyai/orca.git
synced 2026-10-22 08:03:37 +00:00
fix(browser): keep cookie-import warnings readable from newer hosts
The import summary is cast, not decoded, coming off the runtime RPC wire, so a newer host can publish a warning code or undecryptable reason this build has never seen. Both switches then matched nothing and returned undefined, which rendered as a blank toast.warning(undefined). #14683 replaced the absorbing default: arm with case 'unknown' to satisfy switch-exhaustiveness-check, which forbids default: on an exhaustive switch. Guard before each switch instead: narrow the wire value against the handled set and route anything else to a generic message. The handled sets are keyed by the unions themselves, so a fourth member still fails typecheck here.
This commit is contained in:
@@ -788,7 +788,9 @@
|
||||
"undecryptableAppBoundMixed": "Orca cannot decrypt {{value0}} of this browser's cookies because they use app-bound encryption; {{value1}} more could not be decrypted for another reason. You can import cookies from a file using “From File…”.",
|
||||
"undecryptableKeyring": "{{value0}} cookies could not be decrypted because the system keyring was unavailable. Unlock your login keyring (or install a Secret Service provider such as gnome-keyring) and import again.",
|
||||
"undecryptableKeyringMixed": "{{value0}} cookies could not be decrypted because the system keyring was unavailable; {{value1}} more could not be decrypted for another reason. Unlock your login keyring (or install a Secret Service provider such as gnome-keyring) and import again.",
|
||||
"undecryptableUnknown": "{{value0}} cookies could not be decrypted and were skipped. Close the source browser completely and try the import again."
|
||||
"undecryptableUnknown": "{{value0}} cookies could not be decrypted and were skipped. Close the source browser completely and try the import again.",
|
||||
"unrecognizedWarning": "The cookie import finished with a warning this version of Orca does not recognize. Update Orca to see the details, then check this profile before relying on its cookies.",
|
||||
"undecryptableUnrecognizedReason": "{{value0}} cookies could not be decrypted and were skipped for a reason this version of Orca does not recognize. Update Orca to see the details, then try the import again."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -101,6 +101,46 @@ describe('emitBrowserCookieImportToast', () => {
|
||||
expect(warningToastMock).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
// Why: the summary crosses the runtime RPC wire and is cast, not decoded, so a newer host can
|
||||
// publish a reason/code this client build has never heard of (#14683 follow-up).
|
||||
it('still warns when a newer host sends an undeclared undecryptable reason', () => {
|
||||
emitBrowserCookieImportToast(
|
||||
{
|
||||
...summary,
|
||||
warning: {
|
||||
code: 'cookies-undecryptable',
|
||||
failedCookies: 3,
|
||||
reason: 'hardware-token-required'
|
||||
} as unknown as BrowserCookieImportSummary['warning']
|
||||
},
|
||||
'Imported 0 cookies.',
|
||||
'Remote Linux'
|
||||
)
|
||||
|
||||
const message = warningToastMock.mock.calls[0]?.[0]
|
||||
expect(typeof message).toBe('string')
|
||||
expect(message).not.toBe('')
|
||||
expect(message).toContain('3')
|
||||
})
|
||||
|
||||
it('still warns when a newer host sends an undeclared warning code', () => {
|
||||
emitBrowserCookieImportToast(
|
||||
{
|
||||
...summary,
|
||||
warning: {
|
||||
code: 'profile-locked',
|
||||
failedCookies: 3
|
||||
} as unknown as BrowserCookieImportSummary['warning']
|
||||
},
|
||||
'Imported 0 cookies.',
|
||||
'Remote Linux'
|
||||
)
|
||||
|
||||
const message = warningToastMock.mock.calls[0]?.[0]
|
||||
expect(typeof message).toBe('string')
|
||||
expect(message).not.toBe('')
|
||||
})
|
||||
|
||||
it('keeps both applicable warnings when restart fallback is unavailable', () => {
|
||||
emitBrowserCookieImportToast(
|
||||
{
|
||||
|
||||
@@ -3,8 +3,39 @@ import type { BrowserCookieImportSummary } from '../../../shared/browser-workspa
|
||||
import { translate } from '@/i18n/i18n'
|
||||
|
||||
type CookieImportWarning = NonNullable<BrowserCookieImportSummary['warning']>
|
||||
type CookieImportWarningCode = CookieImportWarning['code']
|
||||
type UndecryptableReason = Extract<CookieImportWarning, { code: 'cookies-undecryptable' }>['reason']
|
||||
|
||||
// Why: the summary is cast, not decoded, on the way off the runtime RPC wire, so a newer host can
|
||||
// send a code/reason this build has never heard of. The Record keys are the union itself, so a new
|
||||
// member fails typecheck here instead of silently falling out of the switch (#14683 follow-up).
|
||||
const HANDLED_WARNING_CODES: Record<CookieImportWarningCode, true> = {
|
||||
'restart-fallback-unavailable': true,
|
||||
'cookies-undecryptable': true
|
||||
}
|
||||
|
||||
const HANDLED_UNDECRYPTABLE_REASONS: Record<UndecryptableReason, true> = {
|
||||
'app-bound-encryption': true,
|
||||
'linux-keyring-unavailable': true,
|
||||
unknown: true
|
||||
}
|
||||
|
||||
function isHandledWarningCode(code: string): code is CookieImportWarningCode {
|
||||
return Object.hasOwn(HANDLED_WARNING_CODES, code)
|
||||
}
|
||||
|
||||
function isHandledUndecryptableReason(reason: string): reason is UndecryptableReason {
|
||||
return Object.hasOwn(HANDLED_UNDECRYPTABLE_REASONS, reason)
|
||||
}
|
||||
|
||||
function formatCookieImportWarning(warning: CookieImportWarning): string {
|
||||
const code: string = warning.code
|
||||
if (!isHandledWarningCode(code)) {
|
||||
return translate(
|
||||
'auto.lib.browser.cookie.import.toast.unrecognizedWarning',
|
||||
'The cookie import finished with a warning this version of Orca does not recognize. Update Orca to see the details, then check this profile before relying on its cookies.'
|
||||
)
|
||||
}
|
||||
switch (warning.code) {
|
||||
case 'restart-fallback-unavailable':
|
||||
return warning.loadedCookies === 0
|
||||
@@ -21,7 +52,15 @@ function formatCookieImportWarning(warning: CookieImportWarning): string {
|
||||
value1: warning.loadedCookies + warning.failedCookies
|
||||
}
|
||||
)
|
||||
case 'cookies-undecryptable':
|
||||
case 'cookies-undecryptable': {
|
||||
const reason: string = warning.reason
|
||||
if (!isHandledUndecryptableReason(reason)) {
|
||||
return translate(
|
||||
'auto.lib.browser.cookie.import.toast.undecryptableUnrecognizedReason',
|
||||
'{{value0}} cookies could not be decrypted and were skipped for a reason this version of Orca does not recognize. Update Orca to see the details, then try the import again.',
|
||||
{ value0: warning.failedCookies }
|
||||
)
|
||||
}
|
||||
switch (warning.reason) {
|
||||
case 'app-bound-encryption':
|
||||
return warning.otherFailedCookies
|
||||
@@ -54,6 +93,7 @@ function formatCookieImportWarning(warning: CookieImportWarning): string {
|
||||
{ value0: warning.failedCookies }
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user