feat: add settings, blacklist, and credential check handlers

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
adlee-was-taken
2026-04-12 12:22:54 -04:00
parent 1916fa0f81
commit a56114650a

View File

@@ -4,7 +4,8 @@
/// and routes all messages from the popup and content scripts. /// and routes all messages from the popup and content scripts.
import type { Request, Response } from '../shared/messages'; import type { Request, Response } from '../shared/messages';
import type { Manifest, VaultConfig, SetupState } from '../shared/types'; import type { Manifest, VaultConfig, SetupState, IdfotoSettings } from '../shared/types';
import { DEFAULT_SETTINGS } from '../shared/types';
import type { GitHost } from './git-host'; import type { GitHost } from './git-host';
import { createGitHost } from './git-host'; import { createGitHost } from './git-host';
import { base64ToUint8Array } from './git-host'; import { base64ToUint8Array } from './git-host';
@@ -69,6 +70,26 @@ async function loadSetupState(): Promise<SetupState> {
}; };
} }
// --- Settings & blacklist helpers ---
async function loadSettings(): Promise<IdfotoSettings> {
const result = await chrome.storage.local.get('idfotoSettings');
return (result.idfotoSettings as IdfotoSettings) ?? { ...DEFAULT_SETTINGS };
}
async function saveSettings(settings: IdfotoSettings): Promise<void> {
await chrome.storage.local.set({ idfotoSettings: settings });
}
async function loadBlacklist(): Promise<string[]> {
const result = await chrome.storage.local.get('captureBlacklist');
return (result.captureBlacklist as string[]) ?? [];
}
async function saveBlacklist(list: string[]): Promise<void> {
await chrome.storage.local.set({ captureBlacklist: list });
}
function ensureGitHost(config: VaultConfig): GitHost { function ensureGitHost(config: VaultConfig): GitHost {
if (!gitHost) { if (!gitHost) {
gitHost = createGitHost(config.hostType, config.hostUrl, config.repoPath, config.apiToken); gitHost = createGitHost(config.hostType, config.hostUrl, config.repoPath, config.apiToken);
@@ -310,6 +331,96 @@ async function handleMessage(req: Request): Promise<Response> {
return { ok: true }; return { ok: true };
} }
// --- Settings & blacklist ---
case 'get_settings': {
const settings = await loadSettings();
return { ok: true, data: { settings } };
}
case 'update_settings': {
const current = await loadSettings();
const updated = { ...current, ...req.settings };
await saveSettings(updated);
return { ok: true };
}
case 'get_blacklist': {
const blacklist = await loadBlacklist();
return { ok: true, data: { blacklist } };
}
case 'remove_blacklist': {
const bl = await loadBlacklist();
await saveBlacklist(bl.filter((h) => h !== req.hostname));
return { ok: true };
}
case 'blacklist_site': {
const bl2 = await loadBlacklist();
if (!bl2.includes(req.hostname)) {
bl2.push(req.hostname);
await saveBlacklist(bl2);
}
return { ok: true };
}
// --- Credential capture ---
case 'check_credential': {
// Skip if vault locked
if (!masterKey || !gitHost || !manifest) {
return { ok: true, data: { action: 'skip' } };
}
// Skip if capture disabled
const captureSettings = await loadSettings();
if (!captureSettings.captureEnabled) {
return { ok: true, data: { action: 'skip' } };
}
// Skip if hostname blacklisted
let checkHostname: string;
try {
checkHostname = new URL(req.url).hostname;
} catch {
return { ok: true, data: { action: 'skip' } };
}
const captureBlacklist = await loadBlacklist();
if (captureBlacklist.includes(checkHostname)) {
return { ok: true, data: { action: 'skip' } };
}
// Search manifest by hostname
const candidates = vault.findByUrl(manifest, req.url);
if (candidates.length === 0) {
return { ok: true, data: { action: 'save' } };
}
// Check for matching username
for (const [entryId, entry] of candidates) {
if (entry.username === req.username) {
// Same hostname + username — compare passwords
try {
const fullEntry = await vault.fetchAndDecryptEntry(gitHost, masterKey, entryId);
if (fullEntry.password === req.password) {
return { ok: true, data: { action: 'skip' } };
} else {
return { ok: true, data: { action: 'update', entryId, entryName: entry.name } };
}
} catch {
// If we can't decrypt, skip rather than error
return { ok: true, data: { action: 'skip' } };
}
}
}
// Same hostname, different username — new account
return { ok: true, data: { action: 'save' } };
}
default: default:
return { ok: false, error: `Unknown message type: ${(req as { type: string }).type}` }; return { ok: false, error: `Unknown message type: ${(req as { type: string }).type}` };
} }