Implements a service-worker-side session timer that locks the vault after a configurable period of inactivity (default 15 min). Supports two modes: 'inactivity' (timer-based) and 'every_time' (no timer). Config persists via chrome.storage.local and is exposed through get_session_config / update_session_config popup messages. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
161 lines
5.7 KiB
TypeScript
161 lines
5.7 KiB
TypeScript
import type {
|
|
Item, ItemId, Manifest, ManifestEntry, VaultConfig, SetupState,
|
|
DeviceSettings, GeneratorRequest, VaultSettings, AttachmentRef, Device,
|
|
FieldHistoryView,
|
|
} from './types';
|
|
|
|
// --- Session timeout config ---
|
|
|
|
export type SessionTimeoutConfig =
|
|
| { mode: 'inactivity'; minutes: number }
|
|
| { mode: 'every_time' };
|
|
|
|
// --- Messages a popup (or setup page) may send ---
|
|
|
|
export type PopupMessage =
|
|
| { type: 'is_unlocked' }
|
|
| { type: 'unlock'; passphrase: string }
|
|
| { type: 'lock' }
|
|
| { type: 'list_items'; group?: string }
|
|
| { type: 'get_item'; id: ItemId }
|
|
| { type: 'add_item'; item: Item }
|
|
| { type: 'update_item'; id: ItemId; item: Item }
|
|
| { type: 'delete_item'; id: ItemId } // soft-delete
|
|
| { type: 'get_totp'; id: ItemId }
|
|
| { type: 'sync' }
|
|
| { type: 'get_setup_state' }
|
|
| { type: 'save_setup'; config: VaultConfig; imageBase64: string }
|
|
| { type: 'rate_passphrase'; passphrase: string }
|
|
| { type: 'generate_password'; request: GeneratorRequest }
|
|
| { type: 'generate_passphrase'; request: GeneratorRequest }
|
|
| { type: 'fill_credentials'; id: ItemId; capturedTabId: number; capturedUrl: string }
|
|
| { type: 'ack_autofill_origin'; hostname: string }
|
|
| { type: 'get_settings' }
|
|
| { type: 'update_settings'; settings: Partial<DeviceSettings> }
|
|
| { type: 'get_vault_settings' }
|
|
| { type: 'update_vault_settings'; settings: VaultSettings }
|
|
| { type: 'get_blacklist' }
|
|
| { type: 'remove_blacklist'; hostname: string }
|
|
| { type: 'upload_attachment'; itemId: string; filename: string; mimeType: string; bytes: ArrayBuffer }
|
|
| { type: 'download_attachment'; itemId: string; attachmentId: string }
|
|
| { type: 'list_devices' }
|
|
| { type: 'add_device'; name: string; public_key: string }
|
|
| { type: 'revoke_device'; name: string }
|
|
| { type: 'list_trashed' }
|
|
| { type: 'restore_item'; id: ItemId }
|
|
| { type: 'purge_item'; id: ItemId }
|
|
| { type: 'purge_all_trash' }
|
|
| { type: 'get_field_history'; id: ItemId }
|
|
| { type: 'get_session_config' }
|
|
| { type: 'update_session_config'; config: SessionTimeoutConfig };
|
|
|
|
// --- Messages a content script may send ---
|
|
|
|
// Note deliberate absence of a `url` field — the SW derives origin from sender.tab.url.
|
|
|
|
export type ContentMessage =
|
|
| { type: 'get_autofill_candidates' }
|
|
| { type: 'get_credentials'; id: ItemId }
|
|
| { type: 'check_credential'; username: string; password: string }
|
|
| { type: 'blacklist_site' }
|
|
| { type: 'capture_save_login'; username: string; password: string };
|
|
|
|
// --- Union for chrome.runtime.sendMessage call sites ---
|
|
|
|
export type Request = PopupMessage | ContentMessage;
|
|
|
|
// --- Response ---
|
|
|
|
export type Response =
|
|
| { ok: true; data?: unknown }
|
|
| { ok: false; error: string };
|
|
|
|
// --- Typed response helpers ---
|
|
|
|
export interface IsUnlockedResponse extends Extract<Response, { ok: true }> {
|
|
data: { unlocked: boolean };
|
|
}
|
|
|
|
export interface ListItemsResponse extends Extract<Response, { ok: true }> {
|
|
data: { items: Array<[ItemId, ManifestEntry]> };
|
|
}
|
|
|
|
export interface GetItemResponse extends Extract<Response, { ok: true }> {
|
|
data: { item: Item };
|
|
}
|
|
|
|
export interface TotpResponse extends Extract<Response, { ok: true }> {
|
|
data: { code: string; expires_at: number };
|
|
}
|
|
|
|
export interface AutofillCandidatesResponse extends Extract<Response, { ok: true }> {
|
|
data: { candidates: Array<[ItemId, ManifestEntry]> };
|
|
}
|
|
|
|
export interface CredentialsResponse extends Extract<Response, { ok: true }> {
|
|
data:
|
|
| { requires_ack: true; hostname: string }
|
|
| { username: string; password: string };
|
|
}
|
|
|
|
export interface SetupStateResponse extends Extract<Response, { ok: true }> {
|
|
data: SetupState;
|
|
}
|
|
|
|
export interface GeneratePasswordResponse extends Extract<Response, { ok: true }> {
|
|
data: { password: string };
|
|
}
|
|
|
|
export interface RatePassphraseResponse extends Extract<Response, { ok: true }> {
|
|
data: { score: number; guesses_log10: number };
|
|
}
|
|
|
|
export interface VaultSettingsResponse extends Extract<Response, { ok: true }> {
|
|
data: { settings: VaultSettings };
|
|
}
|
|
|
|
export interface UploadAttachmentResponse extends Extract<Response, { ok: true }> {
|
|
data: { attachment: AttachmentRef };
|
|
}
|
|
|
|
export interface DownloadAttachmentResponse extends Extract<Response, { ok: true }> {
|
|
data: { bytes: ArrayBuffer; filename: string; mimeType: string };
|
|
}
|
|
|
|
export interface ListDevicesResponse extends Extract<Response, { ok: true }> {
|
|
data: { devices: Device[] };
|
|
}
|
|
|
|
export interface ListTrashedResponse extends Extract<Response, { ok: true }> {
|
|
data: { items: Array<[ItemId, ManifestEntry]> };
|
|
}
|
|
|
|
export interface PurgeAllTrashResponse extends Extract<Response, { ok: true }> {
|
|
data: { itemCount: number; orphanCount: number };
|
|
}
|
|
|
|
export interface FieldHistoryResponse extends Extract<Response, { ok: true }> {
|
|
data: { history: FieldHistoryView[] };
|
|
}
|
|
|
|
// --- Capability sets (consumed by the router) ---
|
|
|
|
export const POPUP_ONLY_TYPES: ReadonlySet<PopupMessage['type']> = new Set([
|
|
'is_unlocked', 'unlock', 'lock', 'list_items', 'get_item', 'add_item',
|
|
'update_item', 'delete_item', 'get_totp', 'sync', 'get_setup_state',
|
|
'save_setup', 'rate_passphrase', 'generate_password', 'generate_passphrase',
|
|
'fill_credentials',
|
|
'ack_autofill_origin', 'get_settings', 'update_settings',
|
|
'get_vault_settings', 'update_vault_settings', 'get_blacklist',
|
|
'remove_blacklist', 'upload_attachment', 'download_attachment',
|
|
'list_devices', 'add_device', 'revoke_device',
|
|
'list_trashed', 'restore_item', 'purge_item', 'purge_all_trash',
|
|
'get_field_history',
|
|
'get_session_config', 'update_session_config',
|
|
] as PopupMessage['type'][]);
|
|
|
|
export const CONTENT_CALLABLE_TYPES: ReadonlySet<ContentMessage['type']> = new Set([
|
|
'get_autofill_candidates', 'get_credentials', 'check_credential', 'blacklist_site',
|
|
'capture_save_login',
|
|
] as ContentMessage['type'][]);
|