mirror of
https://github.com/langgenius/dify.git
synced 2026-06-16 22:11:09 +08:00
51 lines
1.7 KiB
TypeScript
51 lines
1.7 KiB
TypeScript
import type { Registry } from '@/auth/hosts'
|
|
import type { HttpClient } from '@/http/types'
|
|
import type { TokenStore } from '@/store/token-store'
|
|
import type { IOStreams } from '@/sys/io/streams'
|
|
import { AccountSessionsClient } from '@/api/account-sessions'
|
|
import { getTokenStore } from '@/store/manager'
|
|
import { colorEnabled, colorScheme } from '@/sys/io/color'
|
|
|
|
export type LogoutOptions = {
|
|
readonly io: IOStreams
|
|
readonly reg: Registry
|
|
readonly http?: HttpClient
|
|
/** Optional override for tests; production resolves via `getTokenStore`. */
|
|
readonly store?: TokenStore
|
|
}
|
|
|
|
const REVOCABLE_PREFIXES = ['dfoa_', 'dfoe_'] as const
|
|
|
|
export async function runLogout(opts: LogoutOptions): Promise<void> {
|
|
const cs = colorScheme(colorEnabled(opts.io.isErrTTY))
|
|
const reg = opts.reg
|
|
const active = reg.requireActive()
|
|
|
|
const store = opts.store ?? getTokenStore(reg.token_storage)
|
|
let bearer = ''
|
|
try {
|
|
bearer = await store.read(active.host, active.email)
|
|
}
|
|
catch { /* keyring locked — skip remote revocation, local cleanup still runs */ }
|
|
|
|
let revokeWarning = ''
|
|
if (bearer !== '' && revokeAllowed(bearer) && opts.http !== undefined) {
|
|
try {
|
|
await new AccountSessionsClient(opts.http).revokeSelf()
|
|
}
|
|
catch (err) {
|
|
revokeWarning = `${cs.warningIcon()} server revoke failed (${(err as Error).message}); local credentials cleared anyway\n`
|
|
}
|
|
}
|
|
|
|
await reg.forget(active, store)
|
|
|
|
if (revokeWarning !== '')
|
|
opts.io.err.write(revokeWarning)
|
|
opts.io.out.write(`${cs.successIcon()} Logged out of ${active.host}\n`)
|
|
}
|
|
|
|
function revokeAllowed(bearer: string): boolean {
|
|
return REVOCABLE_PREFIXES.some(p => bearer.startsWith(p))
|
|
}
|