chore: rename project from idfoto to relicario
Sweeping rename across crates, CLI binary, WASM bindings, extension, docs,
and vault metadata paths. Git remote updated to relicario.git.
- crates/idfoto-{core,cli,wasm} -> crates/relicario-{core,cli,wasm}
- IdfotoError -> RelicarioError
- IDFOTO_IMAGE env var -> RELICARIO_IMAGE
- ~/.config/idfoto -> ~/.config/relicario
- .idfoto/ vault metadata dir -> .relicario/ (breaking; pre-release)
- Binary name idfoto -> relicario
- Extension wasm module idfoto_wasm -> relicario_wasm
- Storage key idfotoSettings -> relicarioSettings
- All doc filenames and content references updated
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -4,7 +4,7 @@
|
||||
/// credentials in the vault. Supports bar and toast prompt styles.
|
||||
|
||||
import type { Request, Response } from '../shared/messages';
|
||||
import type { IdfotoSettings } from '../shared/types';
|
||||
import type { RelicarioSettings } from '../shared/types';
|
||||
|
||||
// --- State ---
|
||||
|
||||
@@ -89,8 +89,8 @@ async function onFormSubmit(pwField: HTMLInputElement): Promise<void> {
|
||||
|
||||
// Fetch settings for prompt style
|
||||
const settingsResp = await sendMessage({ type: 'get_settings' });
|
||||
const settings: IdfotoSettings = settingsResp.ok
|
||||
? (settingsResp.data as { settings: IdfotoSettings }).settings
|
||||
const settings: RelicarioSettings = settingsResp.ok
|
||||
? (settingsResp.data as { settings: RelicarioSettings }).settings
|
||||
: { captureEnabled: true, captureStyle: 'bar' };
|
||||
|
||||
showPrompt(settings.captureStyle, data.action, url, username, password, data.entryId);
|
||||
@@ -99,7 +99,7 @@ async function onFormSubmit(pwField: HTMLInputElement): Promise<void> {
|
||||
// --- Prompt UI ---
|
||||
|
||||
function removeExistingPrompt(): void {
|
||||
const existing = document.getElementById('idfoto-capture-prompt');
|
||||
const existing = document.getElementById('relicario-capture-prompt');
|
||||
if (existing) existing.remove();
|
||||
}
|
||||
|
||||
@@ -121,7 +121,7 @@ function showPrompt(
|
||||
}
|
||||
|
||||
const container = document.createElement('div');
|
||||
container.id = 'idfoto-capture-prompt';
|
||||
container.id = 'relicario-capture-prompt';
|
||||
|
||||
// Common styles
|
||||
const baseStyles = [
|
||||
@@ -173,17 +173,17 @@ function showPrompt(
|
||||
<span style="flex:1; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;">
|
||||
${actionLabel} login for <strong style="color:#58a6ff">${escapeForHtml(hostname)}</strong>${escapeForHtml(displayUser)}?
|
||||
</span>
|
||||
<button id="idfoto-save-btn" style="
|
||||
<button id="relicario-save-btn" style="
|
||||
background:#1f6feb; color:#fff; border:none; padding:5px 14px;
|
||||
border-radius:3px; cursor:pointer; font-family:inherit; font-size:12px;
|
||||
white-space:nowrap;
|
||||
">${actionLabel}</button>
|
||||
<button id="idfoto-never-btn" style="
|
||||
<button id="relicario-never-btn" style="
|
||||
background:transparent; color:#8b949e; border:1px solid #30363d;
|
||||
padding:5px 10px; border-radius:3px; cursor:pointer;
|
||||
font-family:inherit; font-size:12px; white-space:nowrap;
|
||||
">Never</button>
|
||||
<button id="idfoto-close-btn" style="
|
||||
<button id="relicario-close-btn" style="
|
||||
background:transparent; color:#8b949e; border:none;
|
||||
cursor:pointer; font-size:16px; padding:2px 6px;
|
||||
font-family:inherit; line-height:1;
|
||||
@@ -212,7 +212,7 @@ function showPrompt(
|
||||
};
|
||||
|
||||
// Save button
|
||||
container.querySelector('#idfoto-save-btn')?.addEventListener('click', async () => {
|
||||
container.querySelector('#relicario-save-btn')?.addEventListener('click', async () => {
|
||||
clearAutoDismiss();
|
||||
|
||||
const now = new Date().toISOString();
|
||||
@@ -246,22 +246,22 @@ function showPrompt(
|
||||
// Show confirmation
|
||||
const span = container.querySelector('span');
|
||||
if (span) span.textContent = '\u2713 Saved';
|
||||
const saveBtn = container.querySelector('#idfoto-save-btn') as HTMLElement | null;
|
||||
const neverBtn = container.querySelector('#idfoto-never-btn') as HTMLElement | null;
|
||||
const saveBtn = container.querySelector('#relicario-save-btn') as HTMLElement | null;
|
||||
const neverBtn = container.querySelector('#relicario-never-btn') as HTMLElement | null;
|
||||
if (saveBtn) saveBtn.style.display = 'none';
|
||||
if (neverBtn) neverBtn.style.display = 'none';
|
||||
setTimeout(() => removeExistingPrompt(), 1500);
|
||||
});
|
||||
|
||||
// Never button
|
||||
container.querySelector('#idfoto-never-btn')?.addEventListener('click', async () => {
|
||||
container.querySelector('#relicario-never-btn')?.addEventListener('click', async () => {
|
||||
clearAutoDismiss();
|
||||
await sendMessage({ type: 'blacklist_site', hostname });
|
||||
removeExistingPrompt();
|
||||
});
|
||||
|
||||
// Close button
|
||||
container.querySelector('#idfoto-close-btn')?.addEventListener('click', () => {
|
||||
container.querySelector('#relicario-close-btn')?.addEventListener('click', () => {
|
||||
clearAutoDismiss();
|
||||
removeExistingPrompt();
|
||||
});
|
||||
|
||||
@@ -21,7 +21,7 @@ export function injectFieldIcons(
|
||||
const icon = document.createElement('div');
|
||||
icon.textContent = 'id';
|
||||
icon.setAttribute('role', 'button');
|
||||
icon.setAttribute('aria-label', 'idfoto autofill');
|
||||
icon.setAttribute('aria-label', 'relicario autofill');
|
||||
|
||||
Object.assign(icon.style, {
|
||||
position: 'absolute',
|
||||
@@ -98,10 +98,10 @@ function showPicker(
|
||||
candidates: Array<[string, ManifestEntry]>,
|
||||
): void {
|
||||
// Remove any existing picker.
|
||||
document.querySelectorAll('.idfoto-picker').forEach(el => el.remove());
|
||||
document.querySelectorAll('.relicario-picker').forEach(el => el.remove());
|
||||
|
||||
const picker = document.createElement('div');
|
||||
picker.className = 'idfoto-picker';
|
||||
picker.className = 'relicario-picker';
|
||||
Object.assign(picker.style, {
|
||||
position: 'absolute',
|
||||
right: '0',
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/// Settings view — capture toggle, prompt style, and blacklist management.
|
||||
|
||||
import { sendMessage, navigate, escapeHtml } from '../popup';
|
||||
import type { IdfotoSettings } from '../../shared/types';
|
||||
import type { RelicarioSettings } from '../../shared/types';
|
||||
|
||||
export async function renderSettings(app: HTMLElement): Promise<void> {
|
||||
app.innerHTML = '<div class="pad" style="text-align:center; padding-top:20px;"><span class="spinner"></span></div>';
|
||||
@@ -12,8 +12,8 @@ export async function renderSettings(app: HTMLElement): Promise<void> {
|
||||
sendMessage({ type: 'get_blacklist' }),
|
||||
]);
|
||||
|
||||
const settings: IdfotoSettings = settingsResp.ok
|
||||
? (settingsResp.data as { settings: IdfotoSettings }).settings
|
||||
const settings: RelicarioSettings = settingsResp.ok
|
||||
? (settingsResp.data as { settings: RelicarioSettings }).settings
|
||||
: { captureEnabled: false, captureStyle: 'bar' };
|
||||
|
||||
const blacklist: string[] = blacklistResp.ok
|
||||
@@ -24,7 +24,7 @@ export async function renderSettings(app: HTMLElement): Promise<void> {
|
||||
? blacklist.map((h) => `
|
||||
<div style="display:flex; align-items:center; justify-content:space-between; padding:4px 0; border-bottom:1px solid #21262d;">
|
||||
<span style="font-size:12px; overflow:hidden; text-overflow:ellipsis;">${escapeHtml(h)}</span>
|
||||
<button class="idfoto-remove-bl" data-hostname="${escapeHtml(h)}" style="
|
||||
<button class="relicario-remove-bl" data-hostname="${escapeHtml(h)}" style="
|
||||
background:transparent; color:#f85149; border:none; cursor:pointer;
|
||||
font-size:11px; padding:2px 6px;
|
||||
">remove</button>
|
||||
@@ -86,7 +86,7 @@ export async function renderSettings(app: HTMLElement): Promise<void> {
|
||||
});
|
||||
|
||||
// Blacklist remove buttons
|
||||
document.querySelectorAll('.idfoto-remove-bl').forEach((btn) => {
|
||||
document.querySelectorAll('.relicario-remove-bl').forEach((btn) => {
|
||||
btn.addEventListener('click', async () => {
|
||||
const hostname = (btn as HTMLElement).dataset.hostname;
|
||||
if (hostname) {
|
||||
|
||||
@@ -9,8 +9,8 @@ import { escapeHtml } from '../popup';
|
||||
export function renderSetupWizard(app: HTMLElement): void {
|
||||
app.innerHTML = `
|
||||
<div class="pad" style="padding-top:24px;text-align:center;">
|
||||
<img class="brand-logo" src="icons/idfoto-logo.svg" alt="">
|
||||
<div class="brand" style="font-size:16px;margin-bottom:4px;">idfoto</div>
|
||||
<img class="brand-logo" src="icons/relicario-logo.svg" alt="">
|
||||
<div class="brand" style="font-size:16px;margin-bottom:4px;">relicario</div>
|
||||
<p class="secondary" style="margin-bottom:20px;">two-factor vault</p>
|
||||
|
||||
<p class="muted" style="margin-bottom:16px;font-size:11px;line-height:1.6;">
|
||||
|
||||
@@ -8,8 +8,8 @@ export function renderUnlock(app: HTMLElement): void {
|
||||
|
||||
app.innerHTML = `
|
||||
<div class="pad" style="text-align:center; padding-top:40px;">
|
||||
<img class="brand-logo" src="icons/idfoto-logo.svg" alt="">
|
||||
<div class="brand">idfoto</div>
|
||||
<img class="brand-logo" src="icons/relicario-logo.svg" alt="">
|
||||
<div class="brand">relicario</div>
|
||||
<p class="muted" style="margin:8px 0 24px;">two-factor vault</p>
|
||||
<div class="form-group">
|
||||
<input
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=360">
|
||||
<link rel="stylesheet" href="styles.css">
|
||||
<title>idfoto</title>
|
||||
<title>relicario</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* idfoto extension — terminal dark theme */
|
||||
/* relicario extension — terminal dark theme */
|
||||
|
||||
* {
|
||||
margin: 0;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/// Background script entry point for the idfoto browser extension.
|
||||
/// Background script entry point for the relicario browser extension.
|
||||
///
|
||||
/// In Chrome this runs as a service worker (MV3). In Firefox this runs
|
||||
/// as a persistent background script. WASM loading adapts automatically.
|
||||
@@ -7,7 +7,7 @@
|
||||
/// and routes all messages from the popup and content scripts.
|
||||
|
||||
import type { Request, Response } from '../shared/messages';
|
||||
import type { Manifest, VaultConfig, SetupState, IdfotoSettings } from '../shared/types';
|
||||
import type { Manifest, VaultConfig, SetupState, RelicarioSettings } from '../shared/types';
|
||||
import { DEFAULT_SETTINGS } from '../shared/types';
|
||||
import type { GitHost } from './git-host';
|
||||
import { createGitHost } from './git-host';
|
||||
@@ -30,9 +30,9 @@ const totpSecretCache: Map<string, string> = new Map();
|
||||
// We detect the environment at runtime and use the appropriate loading strategy.
|
||||
|
||||
// @ts-ignore TS2307 — resolved by webpack alias / copy
|
||||
import initDefault, { initSync } from '../../wasm/idfoto_wasm.js';
|
||||
import initDefault, { initSync } from '../../wasm/relicario_wasm.js';
|
||||
// @ts-ignore TS2307
|
||||
import * as wasmBindings from '../../wasm/idfoto_wasm.js';
|
||||
import * as wasmBindings from '../../wasm/relicario_wasm.js';
|
||||
|
||||
type WasmModule = typeof wasmBindings;
|
||||
let wasm: WasmModule | null = null;
|
||||
@@ -47,12 +47,12 @@ async function initWasm(): Promise<WasmModule> {
|
||||
|
||||
if (isServiceWorker) {
|
||||
// Chrome: fetch WASM binary and instantiate synchronously
|
||||
const wasmResponse = await fetch(chrome.runtime.getURL('idfoto_wasm_bg.wasm'));
|
||||
const wasmResponse = await fetch(chrome.runtime.getURL('relicario_wasm_bg.wasm'));
|
||||
const wasmBytes = await wasmResponse.arrayBuffer();
|
||||
initSync({ module: new WebAssembly.Module(wasmBytes) });
|
||||
} else {
|
||||
// Firefox: background script — async init works
|
||||
const wasmUrl = chrome.runtime.getURL('idfoto_wasm_bg.wasm');
|
||||
const wasmUrl = chrome.runtime.getURL('relicario_wasm_bg.wasm');
|
||||
await initDefault(wasmUrl);
|
||||
}
|
||||
|
||||
@@ -86,13 +86,13 @@ 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 loadSettings(): Promise<RelicarioSettings> {
|
||||
const result = await chrome.storage.local.get('relicarioSettings');
|
||||
return (result.relicarioSettings as RelicarioSettings) ?? { ...DEFAULT_SETTINGS };
|
||||
}
|
||||
|
||||
async function saveSettings(settings: IdfotoSettings): Promise<void> {
|
||||
await chrome.storage.local.set({ idfotoSettings: settings });
|
||||
async function saveSettings(settings: RelicarioSettings): Promise<void> {
|
||||
await chrome.storage.local.set({ relicarioSettings: settings });
|
||||
}
|
||||
|
||||
async function loadBlacklist(): Promise<string[]> {
|
||||
|
||||
@@ -30,8 +30,8 @@ export interface VaultMeta {
|
||||
|
||||
/// Read the vault salt and KDF params from the git repo.
|
||||
export async function fetchVaultMeta(git: GitHost): Promise<VaultMeta> {
|
||||
const saltBytes = await git.readFile('.idfoto/salt');
|
||||
const paramsRaw = await git.readFile('.idfoto/params.json');
|
||||
const saltBytes = await git.readFile('.relicario/salt');
|
||||
const paramsRaw = await git.readFile('.relicario/params.json');
|
||||
const paramsJson = new TextDecoder().decode(paramsRaw);
|
||||
return { salt: saltBytes, paramsJson };
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/// Vault initialization wizard — 4-step flow for creating new idfoto vaults.
|
||||
/// Vault initialization wizard — 4-step flow for creating new relicario vaults.
|
||||
///
|
||||
/// Step 1: Choose host type (Gitea / GitHub)
|
||||
/// Step 2: Configure connection (URL, repo, token) + test
|
||||
@@ -11,16 +11,16 @@ import type { VaultConfig } from '../shared/types';
|
||||
|
||||
// --- WASM module (loaded dynamically) ---
|
||||
|
||||
type WasmModule = typeof import('idfoto-wasm');
|
||||
type WasmModule = typeof import('relicario-wasm');
|
||||
let wasm: WasmModule | null = null;
|
||||
|
||||
async function loadWasm(): Promise<WasmModule> {
|
||||
if (wasm) return wasm;
|
||||
const mod = await import(
|
||||
// @ts-ignore TS2307 — resolved at runtime, not by TS/webpack
|
||||
/* webpackIgnore: true */ '../idfoto_wasm.js'
|
||||
/* webpackIgnore: true */ '../relicario_wasm.js'
|
||||
) as WasmModule & { default: (input?: string | URL) => Promise<void> };
|
||||
await mod.default('../idfoto_wasm_bg.wasm');
|
||||
await mod.default('../relicario_wasm_bg.wasm');
|
||||
wasm = mod;
|
||||
return mod;
|
||||
}
|
||||
@@ -109,8 +109,8 @@ function render(): void {
|
||||
|
||||
app.innerHTML = `
|
||||
<div class="pad" style="padding-top:12px;">
|
||||
<img class="brand-logo" src="icons/idfoto-logo.svg" alt="" style="margin-bottom:12px;">
|
||||
<div class="brand" style="margin-bottom:4px;">idfoto vault setup</div>
|
||||
<img class="brand-logo" src="icons/relicario-logo.svg" alt="" style="margin-bottom:12px;">
|
||||
<div class="brand" style="margin-bottom:4px;">relicario vault setup</div>
|
||||
${progressHtml}
|
||||
${state.error ? `<div class="error">${escapeHtml(state.error)}</div>` : ''}
|
||||
${stepHtml}
|
||||
@@ -412,14 +412,14 @@ function attachStep3(): void {
|
||||
const host = createGitHost(state.hostType, hostUrl, state.repoPath, state.apiToken);
|
||||
|
||||
await host.writeFile(
|
||||
'.idfoto/salt',
|
||||
'.relicario/salt',
|
||||
salt,
|
||||
'init: vault salt',
|
||||
);
|
||||
|
||||
const paramsBytes = new TextEncoder().encode(paramsJson);
|
||||
await host.writeFile(
|
||||
'.idfoto/params.json',
|
||||
'.relicario/params.json',
|
||||
paramsBytes,
|
||||
'init: KDF parameters',
|
||||
);
|
||||
@@ -427,7 +427,7 @@ function attachStep3(): void {
|
||||
const devicesJson = '{"devices":[]}';
|
||||
const devicesBytes = new TextEncoder().encode(devicesJson);
|
||||
await host.writeFile(
|
||||
'.idfoto/devices.json',
|
||||
'.relicario/devices.json',
|
||||
devicesBytes,
|
||||
'init: device registry',
|
||||
);
|
||||
|
||||
@@ -23,7 +23,7 @@ export type Request =
|
||||
| { type: 'check_credential'; url: string; username: string; password: string }
|
||||
| { type: 'blacklist_site'; hostname: string }
|
||||
| { type: 'get_settings' }
|
||||
| { type: 'update_settings'; settings: Partial<import('./types').IdfotoSettings> }
|
||||
| { type: 'update_settings'; settings: Partial<import('./types').RelicarioSettings> }
|
||||
| { type: 'get_blacklist' }
|
||||
| { type: 'remove_blacklist'; hostname: string };
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/// Full credential entry (matches Rust Entry struct in idfoto-core).
|
||||
/// Full credential entry (matches Rust Entry struct in relicario-core).
|
||||
export interface Entry {
|
||||
name: string;
|
||||
url?: string;
|
||||
@@ -42,12 +42,12 @@ export interface SetupState {
|
||||
}
|
||||
|
||||
/// User-configurable credential capture settings.
|
||||
export interface IdfotoSettings {
|
||||
export interface RelicarioSettings {
|
||||
captureEnabled: boolean;
|
||||
captureStyle: 'bar' | 'toast';
|
||||
}
|
||||
|
||||
export const DEFAULT_SETTINGS: IdfotoSettings = {
|
||||
export const DEFAULT_SETTINGS: RelicarioSettings = {
|
||||
captureEnabled: false,
|
||||
captureStyle: 'bar',
|
||||
};
|
||||
|
||||
4
extension/src/wasm.d.ts
vendored
4
extension/src/wasm.d.ts
vendored
@@ -1,9 +1,9 @@
|
||||
/// Type declarations for the idfoto WASM module produced by wasm-pack.
|
||||
/// Type declarations for the relicario WASM module produced by wasm-pack.
|
||||
|
||||
// Ambient module declarations for the WASM glue code.
|
||||
// The module specifier must exactly match what's used in import statements.
|
||||
|
||||
declare module 'idfoto-wasm' {
|
||||
declare module 'relicario-wasm' {
|
||||
export default function init(input?: string | URL): Promise<void>;
|
||||
export function derive_master_key(
|
||||
passphrase: string,
|
||||
|
||||
Reference in New Issue
Block a user