feat(ext/setup): unified device registration in Step 5; fixes silent dropped pubkey
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -7,6 +7,7 @@
|
||||
/// Step 5: Finish (download reference image, push config to extension or copy JSON)
|
||||
|
||||
import { createGitHost, uint8ArrayToBase64 } from '../service-worker/git-host';
|
||||
import { addDevice } from '../service-worker/devices';
|
||||
import { probeVault } from './probe';
|
||||
import type { VaultConfig } from '../shared/types';
|
||||
import type { SessionHandle } from 'relicario-wasm';
|
||||
@@ -1042,16 +1043,21 @@ function renderStep5(): string {
|
||||
repoPath: state.repoPath,
|
||||
apiToken: state.apiToken,
|
||||
};
|
||||
|
||||
const configJson = JSON.stringify(config, null, 2);
|
||||
const isAttach = state.mode === 'attach';
|
||||
|
||||
return `
|
||||
<div class="wizard-step">
|
||||
<div class="success-box">
|
||||
<h3>vault created</h3>
|
||||
<p class="secondary">Your vault has been initialized and pushed to the repository.</p>
|
||||
<h3>${isAttach ? 'device verified' : 'vault created'}</h3>
|
||||
<p class="secondary">
|
||||
${isAttach
|
||||
? 'Your passphrase and reference image decrypt the vault successfully.'
|
||||
: 'Your vault has been initialized and pushed to the repository.'}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
${isAttach ? '' : `
|
||||
<div class="form-group">
|
||||
<label class="label">reference image</label>
|
||||
<p class="muted" style="margin-bottom:8px;">
|
||||
@@ -1060,14 +1066,15 @@ function renderStep5(): string {
|
||||
</p>
|
||||
<button class="btn btn-primary" id="download-ref-btn">download reference.jpg</button>
|
||||
</div>
|
||||
`}
|
||||
|
||||
${state.extensionDetected ? `
|
||||
<div class="form-group" style="margin-top:16px;">
|
||||
<label class="label">extension configuration</label>
|
||||
<label class="label">register this device</label>
|
||||
<button class="btn btn-primary" id="push-config-btn" ${state.configPushed ? 'disabled' : ''}>
|
||||
${state.configPushed ? 'config saved to extension' : 'save config to extension'}
|
||||
${state.configPushed ? 'device registered' : (isAttach ? 'attach this device' : 'register this device')}
|
||||
</button>
|
||||
${state.configPushed ? '<span class="test-result pass" style="margin-left:8px;">saved</span>' : ''}
|
||||
${state.configPushed ? '<span class="test-result pass" style="margin-left:8px;">done</span>' : ''}
|
||||
</div>
|
||||
` : `
|
||||
<div class="form-group" style="margin-top:16px;">
|
||||
@@ -1098,7 +1105,8 @@ function attachStep5(): void {
|
||||
});
|
||||
|
||||
document.getElementById('push-config-btn')?.addEventListener('click', async () => {
|
||||
if (!state.referenceImageBytes) return;
|
||||
state.error = null;
|
||||
render();
|
||||
|
||||
const config: VaultConfig = {
|
||||
hostType: state.hostType,
|
||||
@@ -1107,39 +1115,55 @@ function attachStep5(): void {
|
||||
apiToken: state.apiToken,
|
||||
};
|
||||
|
||||
const imageBase64 = uint8ArrayToBase64(state.referenceImageBytes);
|
||||
|
||||
try {
|
||||
chrome.runtime.sendMessage(
|
||||
{ type: 'save_setup', config, imageBase64 },
|
||||
async (response: { ok: boolean; error?: string }) => {
|
||||
if (response?.ok) {
|
||||
state.configPushed = true;
|
||||
|
||||
// Generate device keypair and register
|
||||
const w = await loadWasm();
|
||||
const keypair = JSON.parse(w.generate_device_keypair()) as { public_key_hex: string; private_key_base64: string };
|
||||
const keypair = JSON.parse(w.generate_device_keypair()) as {
|
||||
public_key_hex: string; private_key_base64: string;
|
||||
};
|
||||
|
||||
// Store private key locally
|
||||
// 1) Save private key + name locally.
|
||||
await chrome.storage.local.set({
|
||||
device_name: state.deviceName,
|
||||
device_private_key: keypair.private_key_base64,
|
||||
});
|
||||
|
||||
// Register device with vault
|
||||
chrome.runtime.sendMessage({
|
||||
type: 'add_device',
|
||||
name: state.deviceName,
|
||||
public_key: keypair.public_key_hex,
|
||||
});
|
||||
} else {
|
||||
// 2) Save vault config + reference image to extension storage.
|
||||
const imageBytes = state.referenceImageBytes ?? state.referenceImageBytesAttach;
|
||||
const imageBase64 = imageBytes ? uint8ArrayToBase64(imageBytes) : '';
|
||||
const saveOk = await new Promise<boolean>((resolve) => {
|
||||
chrome.runtime.sendMessage(
|
||||
{ type: 'save_setup', config, imageBase64 },
|
||||
(response: { ok: boolean; error?: string }) => {
|
||||
if (!response?.ok) {
|
||||
state.error = response?.error ?? 'Failed to save config to extension';
|
||||
resolve(false); return;
|
||||
}
|
||||
render();
|
||||
resolve(true);
|
||||
},
|
||||
);
|
||||
});
|
||||
if (!saveOk) { render(); return; }
|
||||
|
||||
// 3) Register device on the remote (read-modify-write devices.json).
|
||||
const hostUrl = state.hostType === 'github' ? 'https://api.github.com' : state.hostUrl;
|
||||
const host = createGitHost(state.hostType, hostUrl, state.repoPath, state.apiToken);
|
||||
await addDevice(host, {
|
||||
name: state.deviceName,
|
||||
public_key: keypair.public_key_hex,
|
||||
added_at: Math.floor(Date.now() / 1000),
|
||||
});
|
||||
|
||||
// 4) Release any attach-mode WASM handle.
|
||||
if (state.verifiedHandle !== null) {
|
||||
try { w.lock(state.verifiedHandle); } catch { /* best effort */ }
|
||||
state.verifiedHandle = null;
|
||||
}
|
||||
|
||||
state.configPushed = true;
|
||||
render();
|
||||
} catch (err: unknown) {
|
||||
state.error = `Failed to communicate with extension: ${err instanceof Error ? err.message : String(err)}`;
|
||||
console.error('[relicario setup] register device failed:', err);
|
||||
state.error = `Failed to register device: ${err instanceof Error ? err.message : String(err)}`;
|
||||
render();
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user