import { renderHeader } from '../components/header.js'; import { state } from '../state.js'; import { bytesToBase64 } from '../services/crypto-utils.js'; import { extractSeed32FromPkcs8B64 } from '../services/device-key-utils.js'; export const pageMeta = { id: 'registration-draft-keys-view', title: 'Сгенерированные ключи', showAppChrome: false }; function makeSecretField({ label, value }) { const wrap = document.createElement('div'); wrap.className = 'stack'; const labelEl = document.createElement('span'); labelEl.className = 'field-label'; labelEl.textContent = label; const row = document.createElement('div'); row.className = 'inline-input-row'; const input = document.createElement('input'); input.className = 'input'; input.type = 'password'; input.readOnly = true; input.value = value; const toggleBtn = document.createElement('button'); toggleBtn.className = 'ghost-btn'; toggleBtn.type = 'button'; toggleBtn.textContent = 'Показать'; toggleBtn.addEventListener('click', () => { if (input.type === 'password') { input.type = 'text'; toggleBtn.textContent = 'Скрыть'; } else { input.type = 'password'; toggleBtn.textContent = 'Показать'; } }); row.append(input, toggleBtn); wrap.append(labelEl, row); return wrap; } function makePublicField({ label, value }) { const wrap = document.createElement('div'); wrap.className = 'stack'; const labelEl = document.createElement('span'); labelEl.className = 'field-label'; labelEl.textContent = label; const input = document.createElement('input'); input.className = 'input'; input.type = 'text'; input.readOnly = true; input.value = value; wrap.append(labelEl, input); return wrap; } export function render({ navigate }) { const screen = document.createElement('section'); screen.className = 'stack'; const keyBundle = state.registrationDraft.preGeneratedKeyBundle; const card = document.createElement('div'); card.className = 'card stack'; if (!keyBundle) { const msg = document.createElement('p'); msg.className = 'status-line is-unavailable'; msg.textContent = 'Ключи ещё не сгенерированы. Вернитесь на экран регистрации и введите логин с паролем.'; card.append(msg); } else { const warning = document.createElement('p'); warning.className = 'meta-muted'; warning.textContent = 'Никому не сообщайте приватные ключи и секрет. Они не хранятся на сервере и существуют только на вашем устройстве.'; card.append(warning); // Секрет (root key seed) let secretB64 = ''; try { const rootSeed32 = extractSeed32FromPkcs8B64(keyBundle.rootPair.privatePkcs8B64); secretB64 = bytesToBase64(rootSeed32); } catch { secretB64 = '(не удалось извлечь)'; } card.append(makeSecretField({ label: 'Секрет (root seed, 32 байта)', value: secretB64 })); // Root key const rootSep = document.createElement('p'); rootSep.className = 'field-label'; rootSep.textContent = 'Root key'; card.append(rootSep); card.append(makePublicField({ label: 'Root — публичный', value: keyBundle.rootPair.publicKeyB64 })); card.append(makeSecretField({ label: 'Root — приватный (PKCS8)', value: keyBundle.rootPair.privatePkcs8B64 })); // Blockchain key const bchSep = document.createElement('p'); bchSep.className = 'field-label'; bchSep.textContent = 'Blockchain key'; card.append(bchSep); card.append(makePublicField({ label: 'Blockchain — публичный', value: keyBundle.blockchainPair.publicKeyB64 })); card.append(makeSecretField({ label: 'Blockchain — приватный (PKCS8)', value: keyBundle.blockchainPair.privatePkcs8B64 })); // Device key const devSep = document.createElement('p'); devSep.className = 'field-label'; devSep.textContent = 'Device key (= Solana wallet)'; card.append(devSep); card.append(makePublicField({ label: 'Device — публичный', value: keyBundle.devicePair.publicKeyB64 })); card.append(makeSecretField({ label: 'Device — приватный (PKCS8)', value: keyBundle.devicePair.privatePkcs8B64 })); } const actions = document.createElement('div'); actions.className = 'auth-footer-actions'; const backButton = document.createElement('button'); backButton.className = 'ghost-btn'; backButton.type = 'button'; backButton.textContent = 'Назад'; backButton.addEventListener('click', () => navigate('registration-payment-view')); actions.append(backButton); screen.append( renderHeader({ title: 'Сгенерированные ключи', leftAction: { label: '←', onClick: () => navigate('registration-payment-view') }, }), card, actions, ); return screen; }