Monorepo for wisp.place. A static site hosting service built on top of the AT Protocol. wisp.place
86
fork

Configure Feed

Select the types of activity you want to include in your feed.

be more specific about keystore error

+66 -7
+66 -7
cli/lib/auth.ts
··· 30 30 31 31 type KeyringEntryConstructor = new (service: string, account: string) => KeyringEntryLike 32 32 33 + interface KeychainProbeResult { 34 + available: boolean 35 + detail?: string 36 + moduleAvailable: boolean 37 + } 38 + 33 39 let keyringEntryConstructor: KeyringEntryConstructor | null | undefined 34 40 35 41 async function getKeyringEntryConstructor(): Promise<KeyringEntryConstructor | null> { ··· 45 51 return keyringEntryConstructor 46 52 } 47 53 48 - async function probeKeychain(): Promise<boolean> { 54 + function formatProbeError(error: unknown): string | undefined { 55 + if (error instanceof Error) { 56 + return error.message 57 + } 58 + if (typeof error === 'string') { 59 + return error 60 + } 61 + return undefined 62 + } 63 + 64 + function describeUnavailableKeychain(result: KeychainProbeResult): string { 65 + if (process.platform === 'darwin') { 66 + if (!result.moduleAvailable) { 67 + return 'macOS Keychain support is unavailable in this build.' 68 + } 69 + if (result.detail?.toLowerCase().includes('authorization')) { 70 + return 'macOS Keychain access could not be authorized.' 71 + } 72 + return result.detail ? `macOS Keychain access failed: ${result.detail}` : 'macOS Keychain access is unavailable.' 73 + } 74 + 75 + if (process.platform === 'linux') { 76 + if (!result.moduleAvailable) { 77 + return 'System keychain support is unavailable in this build.' 78 + } 79 + if (result.detail?.toLowerCase().includes('secret service')) { 80 + return 'System keychain is unavailable (no Secret Service daemon or equivalent).' 81 + } 82 + return result.detail ? `System keychain access failed: ${result.detail}` : 'System keychain is unavailable.' 83 + } 84 + 85 + if (process.platform === 'win32') { 86 + if (!result.moduleAvailable) { 87 + return 'Windows Credential Manager support is unavailable in this build.' 88 + } 89 + return result.detail 90 + ? `Windows Credential Manager access failed: ${result.detail}` 91 + : 'Windows Credential Manager is unavailable.' 92 + } 93 + 94 + if (!result.moduleAvailable) { 95 + return 'Secure OS credential storage is unavailable in this build.' 96 + } 97 + return result.detail ? `Secure OS credential storage failed: ${result.detail}` : 'Secure OS credential storage is unavailable.' 98 + } 99 + 100 + async function probeKeychain(): Promise<KeychainProbeResult> { 49 101 const KeyringEntry = await getKeyringEntryConstructor() 50 - if (!KeyringEntry) return false 102 + if (!KeyringEntry) { 103 + return { available: false, moduleAvailable: false } 104 + } 51 105 52 106 const testKey = '__wispctl_probe__' 53 107 try { 54 108 const entry = new KeyringEntry(KEYCHAIN_SERVICE, testKey) 55 109 entry.setPassword('1') 56 110 entry.deletePassword() 57 - return true 58 - } catch { 59 - return false 111 + return { available: true, moduleAvailable: true } 112 + } catch (error) { 113 + return { 114 + available: false, 115 + detail: formatProbeError(error), 116 + moduleAvailable: true, 117 + } 60 118 } 61 119 } 62 120 ··· 324 382 ): Promise<{ agent: Agent; did: string }> { 325 383 const kv = await openKv(options.dbPath || DEFAULT_DB_PATH) 326 384 327 - const useKeychain = await probeKeychain() 385 + const keychainProbe = await probeKeychain() 386 + const useKeychain = keychainProbe.available 328 387 if (!useKeychain) { 329 - log.warn('System keychain is unavailable (no Secret Service daemon or equivalent).') 388 + log.warn(describeUnavailableKeychain(keychainProbe)) 330 389 const fallback = await confirm({ 331 390 message: 332 391 'Fall back to storing session tokens unencrypted in SQLite? (On headless systems, prefer --password instead.)',