SHA256
UI: обновлена шапка каналов, закрыты pending-задачи и обновлены версии
This commit is contained in:
@@ -0,0 +1,140 @@
|
||||
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;
|
||||
}
|
||||
Reference in New Issue
Block a user