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:
@@ -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}` };
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user