SHA256
Обновить UI и документы личных сообщений
This commit is contained in:
@@ -36,22 +36,20 @@ function pairingSessionKindLabel(sessionType) {
|
||||
return Number(sessionType || 0) === SESSION_TYPE_WALLET ? 'Wallet session' : 'Client session';
|
||||
}
|
||||
|
||||
function buildTransferKeys(savedKeys, { withExtras = false }) {
|
||||
function buildTransferKeys(savedKeys, selection = {}) {
|
||||
const keys = {
|
||||
clientKey: String(savedKeys?.clientKey || savedKeys?.clientKey || '').trim(),
|
||||
clientKey: String(savedKeys?.clientKey || '').trim(),
|
||||
blockchainKey: '',
|
||||
rootKey: '',
|
||||
};
|
||||
if (!keys.clientKey) {
|
||||
throw new Error('На этом устройстве нет сохранённого client key для передачи.');
|
||||
}
|
||||
if (withExtras) {
|
||||
if (state.deviceConnect.blockchain && savedKeys?.blockchainKey) {
|
||||
keys.blockchainKey = String(savedKeys.blockchainKey || '').trim();
|
||||
}
|
||||
if (state.deviceConnect.root && savedKeys?.rootKey) {
|
||||
keys.rootKey = String(savedKeys.rootKey || '').trim();
|
||||
}
|
||||
if (selection.blockchain && savedKeys?.blockchainKey) {
|
||||
keys.blockchainKey = String(savedKeys.blockchainKey || '').trim();
|
||||
}
|
||||
if (selection.root && savedKeys?.rootKey) {
|
||||
keys.rootKey = String(savedKeys.rootKey || '').trim();
|
||||
}
|
||||
return keys;
|
||||
}
|
||||
@@ -73,10 +71,9 @@ function requestCardHtml(request) {
|
||||
<span class="meta-muted">Истекает: ${expiresText}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row" style="flex-wrap:wrap;">
|
||||
<button class="ghost-btn" type="button" data-action="approve-device">${sessionOnly ? 'Подключить wallet-session' : 'Подключить без доп. ключей'}</button>
|
||||
${sessionOnly ? '' : '<button class="primary-btn" type="button" data-action="approve-full">Подключить и передать ключи</button>'}
|
||||
<button class="text-btn" type="button" data-action="reject">Отклонить</button>
|
||||
<div class="row pairing-request-actions" style="flex-wrap:wrap;">
|
||||
<button class="primary-btn pairing-approve-btn" type="button" data-action="approve-device">Подключить</button>
|
||||
<button class="text-btn pairing-reject-btn" type="button" data-action="reject">Отклонить</button>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
@@ -179,6 +176,7 @@ export function render({ navigate }) {
|
||||
let settingsBusy = false;
|
||||
let pairingPasswordConfigured = false;
|
||||
let dialogMode = '';
|
||||
let pendingTransferRequest = null;
|
||||
|
||||
screen.append(
|
||||
renderHeader({
|
||||
@@ -187,6 +185,38 @@ export function render({ navigate }) {
|
||||
}),
|
||||
);
|
||||
|
||||
const transferDialog = document.createElement('div');
|
||||
transferDialog.className = 'pairing-transfer-dialog';
|
||||
transferDialog.hidden = true;
|
||||
transferDialog.innerHTML = `
|
||||
<div class="pairing-transfer-dialog__backdrop" data-transfer-action="cancel"></div>
|
||||
<section class="card stack pairing-transfer-dialog__card" role="dialog" aria-modal="true" aria-labelledby="pairing-transfer-title">
|
||||
<div class="stack" style="gap:5px;">
|
||||
<h2 class="login-panel-title" id="pairing-transfer-title">Подключить и передать ключи</h2>
|
||||
<p class="meta-muted">Client key передаётся всегда. Дополнительные ключи можно передать только если они есть на этом устройстве.</p>
|
||||
</div>
|
||||
<div class="pairing-transfer-key-list">
|
||||
<label class="pairing-transfer-key is-required">
|
||||
<input type="checkbox" checked disabled />
|
||||
<span><strong>Client key</strong><small>Обязателен для клиентского устройства</small></span>
|
||||
</label>
|
||||
<label class="pairing-transfer-key" data-transfer-key="root">
|
||||
<input type="checkbox" id="pairing-transfer-root" checked />
|
||||
<span><strong>Root key</strong><small>Передать на новое устройство</small></span>
|
||||
</label>
|
||||
<label class="pairing-transfer-key" data-transfer-key="blockchain">
|
||||
<input type="checkbox" id="pairing-transfer-blockchain" checked />
|
||||
<span><strong>Blockchain key</strong><small>Передать на новое устройство</small></span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="row pairing-transfer-dialog__actions">
|
||||
<button class="ghost-btn" type="button" data-transfer-action="cancel">Отмена</button>
|
||||
<button class="primary-btn pairing-approve-btn" type="button" data-transfer-action="confirm">Подключить</button>
|
||||
</div>
|
||||
</section>
|
||||
`;
|
||||
screen.append(transferDialog);
|
||||
|
||||
const settingsCard = document.createElement('div');
|
||||
settingsCard.className = 'card stack';
|
||||
const passwordIcons = makePasswordToggleIcons();
|
||||
@@ -432,11 +462,11 @@ export function render({ navigate }) {
|
||||
const loadSavedKeys = async () => {
|
||||
savedKeys = await loadEncryptedUserSecrets(state.session.login, state.session.storagePwdInMemory);
|
||||
const available = [];
|
||||
if (savedKeys?.clientKey || savedKeys?.clientKey) available.push('client');
|
||||
if (savedKeys?.blockchainKey && state.deviceConnect.blockchain) available.push('blockchain');
|
||||
if (savedKeys?.rootKey && state.deviceConnect.root) available.push('root');
|
||||
keySummaryEl.textContent = available.length
|
||||
? `При расширенном подключении будут переданы: ${available.join(', ')}.`
|
||||
if (savedKeys?.clientKey) available.push('client');
|
||||
if (savedKeys?.blockchainKey) available.push('blockchain');
|
||||
if (savedKeys?.rootKey) available.push('root');
|
||||
keySummaryEl.textContent = available.length > 1
|
||||
? `Доступны для подключения: ${available.join(', ')}.`
|
||||
: 'На этом устройстве доступен только client key.';
|
||||
};
|
||||
|
||||
@@ -460,10 +490,10 @@ export function render({ navigate }) {
|
||||
refreshBtn.disabled = flag;
|
||||
};
|
||||
|
||||
const approveRequest = async (request, mode) => {
|
||||
const withExtras = mode === 'with-extras';
|
||||
const approveRequest = async (request, selection = {}) => {
|
||||
const withExtras = !!selection.root || !!selection.blockchain;
|
||||
let payload;
|
||||
if (!withExtras && Number(request?.requesterSessionType || 0) === SESSION_TYPE_WALLET) {
|
||||
if (Number(request?.requesterSessionType || 0) === SESSION_TYPE_WALLET) {
|
||||
const delegatedSession = await authService.createDelegatedSessionWithClientKey({
|
||||
login: state.session.login,
|
||||
clientPrivPkcs8: String(savedKeys?.clientKey || savedKeys?.clientKey || '').trim(),
|
||||
@@ -477,7 +507,7 @@ export function render({ navigate }) {
|
||||
session: delegatedSession,
|
||||
});
|
||||
} else {
|
||||
const keys = buildTransferKeys(savedKeys, { withExtras });
|
||||
const keys = buildTransferKeys(savedKeys, selection);
|
||||
payload = buildSecretsPayload({
|
||||
login: state.session.login,
|
||||
keys,
|
||||
@@ -486,7 +516,7 @@ export function render({ navigate }) {
|
||||
}
|
||||
const encryptedPayload = await encryptPairingPayloadForRequester(request?.requesterSessionKey, payload);
|
||||
await runPairingOpWithSessionRestore(() => authService.approveTrustedDeviceLogin(request?.pairingId, encryptedPayload));
|
||||
const sessionOnly = !withExtras && Number(request?.requesterSessionType || 0) === SESSION_TYPE_WALLET;
|
||||
const sessionOnly = Number(request?.requesterSessionType || 0) === SESSION_TYPE_WALLET;
|
||||
showToast(
|
||||
withExtras
|
||||
? 'Ключи переданы на новое устройство'
|
||||
@@ -505,6 +535,53 @@ export function render({ navigate }) {
|
||||
await reloadRequests({ silent: true });
|
||||
};
|
||||
|
||||
const closeTransferDialog = () => {
|
||||
pendingTransferRequest = null;
|
||||
transferDialog.hidden = true;
|
||||
};
|
||||
|
||||
const openTransferDialog = (request) => {
|
||||
pendingTransferRequest = request;
|
||||
const rootRow = transferDialog.querySelector('[data-transfer-key="root"]');
|
||||
const blockchainRow = transferDialog.querySelector('[data-transfer-key="blockchain"]');
|
||||
const rootInput = transferDialog.querySelector('#pairing-transfer-root');
|
||||
const blockchainInput = transferDialog.querySelector('#pairing-transfer-blockchain');
|
||||
const hasRoot = !!String(savedKeys?.rootKey || '').trim();
|
||||
const hasBlockchain = !!String(savedKeys?.blockchainKey || '').trim();
|
||||
rootRow.hidden = !hasRoot;
|
||||
blockchainRow.hidden = !hasBlockchain;
|
||||
rootInput.checked = hasRoot;
|
||||
blockchainInput.checked = hasBlockchain;
|
||||
transferDialog.hidden = false;
|
||||
};
|
||||
|
||||
transferDialog.addEventListener('click', async (event) => {
|
||||
const target = event.target instanceof Element ? event.target.closest('[data-transfer-action]') : null;
|
||||
const action = String(target?.dataset?.transferAction || '');
|
||||
if (!action) return;
|
||||
if (action === 'cancel') {
|
||||
closeTransferDialog();
|
||||
return;
|
||||
}
|
||||
if (action !== 'confirm' || !pendingTransferRequest) return;
|
||||
const request = pendingTransferRequest;
|
||||
const confirmBtn = transferDialog.querySelector('[data-transfer-action="confirm"]');
|
||||
confirmBtn.disabled = true;
|
||||
try {
|
||||
await approveRequest(request, {
|
||||
root: !!transferDialog.querySelector('#pairing-transfer-root')?.checked,
|
||||
blockchain: !!transferDialog.querySelector('#pairing-transfer-blockchain')?.checked,
|
||||
});
|
||||
closeTransferDialog();
|
||||
} catch (error) {
|
||||
const message = toUserMessage(error, 'Не удалось подключить устройство.');
|
||||
setAuthError(message);
|
||||
setStatus(status, message, 'error');
|
||||
} finally {
|
||||
confirmBtn.disabled = false;
|
||||
}
|
||||
});
|
||||
|
||||
passwordDialog.addEventListener('click', (event) => {
|
||||
const target = event.target;
|
||||
if (!(target instanceof HTMLElement)) return;
|
||||
@@ -609,9 +686,14 @@ export function render({ navigate }) {
|
||||
buttons.forEach((btn) => { btn.disabled = true; });
|
||||
try {
|
||||
if (action === 'approve-device') {
|
||||
await approveRequest(request, 'device-only');
|
||||
} else if (action === 'approve-full') {
|
||||
await approveRequest(request, 'with-extras');
|
||||
const isWallet = Number(request?.requesterSessionType || 0) === SESSION_TYPE_WALLET;
|
||||
const hasExtras = !!String(savedKeys?.rootKey || '').trim() || !!String(savedKeys?.blockchainKey || '').trim();
|
||||
if (!isWallet && hasExtras) {
|
||||
openTransferDialog(request);
|
||||
buttons.forEach((btn) => { btn.disabled = false; });
|
||||
return;
|
||||
}
|
||||
await approveRequest(request, {});
|
||||
} else if (action === 'reject') {
|
||||
await runPairingOpWithSessionRestore(() => authService.rejectTrustedDeviceLogin(pairingId, 'rejected_by_user'));
|
||||
showToast('Заявка отклонена', { kind: 'error' });
|
||||
|
||||
Reference in New Issue
Block a user