SHA256
Wallet plugin: офлайн wallet-session и выбор homeserver\n\nСделано:\n- wallet plugin сохраняет PDA-профиль и остаётся офлайн до действия;\n- добавлен каркас выбора ключа подписи и homeserver-устройства;\n- добавлен ручной refresh trusted devices через ListSessions;\n- на регистрации показан первый сервер SHiNE и его адрес;\n- обновлены pending notes для ручной проверки.\n\nЕщё не проверено / не доделано:\n- end-to-end ручная проверка plugin после этих правок не завершена;\n- signaling запроса подписи и ответ подписи ещё не реализованы;\n- локальный browser plugin нужно отдельно reload в Chrome/Opera.
This commit is contained in:
@@ -16,8 +16,15 @@ const els = {
|
||||
sessionLogin: document.querySelector('#session-login'),
|
||||
sessionId: document.querySelector('#session-id'),
|
||||
sessionType: document.querySelector('#session-type'),
|
||||
deviceKeyShort: document.querySelector('#device-key-short'),
|
||||
resumeBtn: document.querySelector('#resume-btn'),
|
||||
refreshDevicesBtn: document.querySelector('#refresh-devices-btn'),
|
||||
disconnectBtn: document.querySelector('#disconnect-btn'),
|
||||
signingCard: document.querySelector('#signing-card'),
|
||||
signKeySelect: document.querySelector('#sign-key-select'),
|
||||
deviceSelect: document.querySelector('#device-select'),
|
||||
homeserverList: document.querySelector('#homeserver-list'),
|
||||
prepareSignBtn: document.querySelector('#prepare-sign-btn'),
|
||||
connectionPill: document.querySelector('#connection-pill'),
|
||||
};
|
||||
|
||||
@@ -62,6 +69,34 @@ function formatRemaining(ms) {
|
||||
return `${minutes} мин ${seconds} сек`;
|
||||
}
|
||||
|
||||
function shortKey(value, size = 10) {
|
||||
const raw = String(value || '').trim();
|
||||
return raw ? `${raw.slice(0, size)}...` : '—';
|
||||
}
|
||||
|
||||
function renderHomeserverList(items = []) {
|
||||
els.homeserverList.innerHTML = '';
|
||||
if (!items.length) {
|
||||
const empty = document.createElement('p');
|
||||
empty.className = 'muted small';
|
||||
empty.textContent = 'В PDA пока нет опубликованных homeserver-сессий.';
|
||||
els.homeserverList.append(empty);
|
||||
return;
|
||||
}
|
||||
items.forEach((item) => {
|
||||
const row = document.createElement('div');
|
||||
row.className = 'summary-row device-row';
|
||||
const label = document.createElement('span');
|
||||
label.textContent = `${item.sessionName} (${shortKey(item.sessionPubKeyBase58, 8)})`;
|
||||
const badge = document.createElement('strong');
|
||||
const stateValue = String(item.onlineState || 'unknown');
|
||||
badge.textContent = stateValue;
|
||||
badge.className = `device-state device-state-${stateValue}`;
|
||||
row.append(label, badge);
|
||||
els.homeserverList.append(row);
|
||||
});
|
||||
}
|
||||
|
||||
function applyState(nextState) {
|
||||
state = nextState || state;
|
||||
const serverValue = String(state?.settings?.serverLogin || 'shineupme');
|
||||
@@ -78,18 +113,46 @@ function applyState(nextState) {
|
||||
setStatus(state?.status?.text || '', state?.status?.kind || 'info');
|
||||
|
||||
const session = state?.session;
|
||||
const walletProfile = state?.walletProfile;
|
||||
const signing = state?.signing || {};
|
||||
if (session) {
|
||||
els.sessionCard.classList.remove('hidden');
|
||||
els.sessionLogin.textContent = session.login || '—';
|
||||
els.sessionId.textContent = session.sessionId || '—';
|
||||
els.sessionType.textContent = String(session.sessionType || 50) === '50' ? 'wallet' : String(session.sessionType || '—');
|
||||
els.deviceKeyShort.textContent = shortKey(walletProfile?.publicKeys?.deviceKeyBase58 || '');
|
||||
els.signingCard.classList.remove('hidden');
|
||||
} else {
|
||||
els.sessionCard.classList.add('hidden');
|
||||
els.sessionLogin.textContent = '—';
|
||||
els.sessionId.textContent = '—';
|
||||
els.sessionType.textContent = 'wallet';
|
||||
els.deviceKeyShort.textContent = '—';
|
||||
els.signingCard.classList.add('hidden');
|
||||
}
|
||||
|
||||
const signKeyOptions = Array.isArray(walletProfile?.signingKeyOptions) ? walletProfile.signingKeyOptions : [];
|
||||
els.signKeySelect.innerHTML = '';
|
||||
signKeyOptions.forEach((item) => {
|
||||
const option = document.createElement('option');
|
||||
option.value = item.id;
|
||||
option.textContent = item.label;
|
||||
option.selected = item.id === signing.selectedKeyId;
|
||||
els.signKeySelect.append(option);
|
||||
});
|
||||
|
||||
const homeservers = Array.isArray(walletProfile?.homeserverSessions) ? walletProfile.homeserverSessions : [];
|
||||
els.deviceSelect.innerHTML = '';
|
||||
homeservers.forEach((item) => {
|
||||
const option = document.createElement('option');
|
||||
option.value = item.sessionName;
|
||||
option.textContent = `${item.sessionName} [${item.onlineState || 'unknown'}]`;
|
||||
option.selected = item.sessionName === signing.selectedDeviceName;
|
||||
els.deviceSelect.append(option);
|
||||
});
|
||||
renderHomeserverList(homeservers);
|
||||
els.prepareSignBtn.disabled = !session || !signing.selectedKeyId || !signing.selectedDeviceName;
|
||||
|
||||
const pairing = state?.pairing || {};
|
||||
if (pairing.active) {
|
||||
els.pairingCard.classList.remove('hidden');
|
||||
@@ -201,6 +264,35 @@ async function disconnectSession() {
|
||||
}
|
||||
}
|
||||
|
||||
async function refreshDevices() {
|
||||
setStatus('Обновляем trusted homeserver-устройства...', 'info');
|
||||
try {
|
||||
await sendMessage('wallet:refreshWalletDevices');
|
||||
} catch (error) {
|
||||
setStatus(error.message || 'Не удалось обновить список устройств.', 'error');
|
||||
}
|
||||
}
|
||||
|
||||
async function updateSigningSelection() {
|
||||
try {
|
||||
await sendMessage('wallet:updateSigningSelection', {
|
||||
selectedKeyId: String(els.signKeySelect.value || '').trim(),
|
||||
selectedDeviceName: String(els.deviceSelect.value || '').trim(),
|
||||
});
|
||||
} catch (error) {
|
||||
setStatus(error.message || 'Не удалось обновить выбор для подписи.', 'error');
|
||||
}
|
||||
}
|
||||
|
||||
async function prepareSignSignal() {
|
||||
setStatus('Готовим каркас запроса подписи...', 'info');
|
||||
try {
|
||||
await sendMessage('wallet:prepareSignSignal');
|
||||
} catch (error) {
|
||||
setStatus(error.message || 'Не удалось подготовить запрос подписи.', 'error');
|
||||
}
|
||||
}
|
||||
|
||||
function startUiRefreshLoop() {
|
||||
stopUiRefreshLoop();
|
||||
refreshTimer = window.setInterval(() => {
|
||||
@@ -229,7 +321,11 @@ function bindUi() {
|
||||
els.startBtn.addEventListener('click', () => { void startPairing(); });
|
||||
els.cancelBtn.addEventListener('click', () => { void cancelPairing(); });
|
||||
els.resumeBtn.addEventListener('click', () => { void resumeSession(); });
|
||||
els.refreshDevicesBtn.addEventListener('click', () => { void refreshDevices(); });
|
||||
els.disconnectBtn.addEventListener('click', () => { void disconnectSession(); });
|
||||
els.signKeySelect.addEventListener('change', () => { void updateSigningSelection(); });
|
||||
els.deviceSelect.addEventListener('change', () => { void updateSigningSelection(); });
|
||||
els.prepareSignBtn.addEventListener('click', () => { void prepareSignSignal(); });
|
||||
}
|
||||
|
||||
async function init() {
|
||||
|
||||
Reference in New Issue
Block a user