SHA256
ESP32 wallet RPC, browser wallet provider, and side panel
This commit is contained in:
@@ -8,6 +8,7 @@ const els = {
|
||||
passwordField: document.querySelector('#password-field'),
|
||||
passwordInput: document.querySelector('#password-input'),
|
||||
startBtn: document.querySelector('#start-btn'),
|
||||
connectCard: document.querySelector('#connect-card'),
|
||||
pairingCard: document.querySelector('#pairing-card'),
|
||||
shortCode: document.querySelector('#short-code'),
|
||||
pairingHint: document.querySelector('#pairing-hint'),
|
||||
@@ -22,11 +23,15 @@ const els = {
|
||||
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'),
|
||||
walletCard: document.querySelector('#wallet-card'),
|
||||
deviceSelect: document.querySelector('#device-select'),
|
||||
homeserverList: document.querySelector('#homeserver-list'),
|
||||
prepareSignBtn: document.querySelector('#prepare-sign-btn'),
|
||||
requestWalletBtn: document.querySelector('#request-wallet-btn'),
|
||||
walletResultCard: document.querySelector('#wallet-result-card'),
|
||||
walletType: document.querySelector('#wallet-type'),
|
||||
walletPubkey: document.querySelector('#wallet-pubkey'),
|
||||
walletVerify: document.querySelector('#wallet-verify'),
|
||||
copyWalletBtn: document.querySelector('#copy-wallet-btn'),
|
||||
connectionPill: document.querySelector('#connection-pill'),
|
||||
};
|
||||
|
||||
@@ -34,16 +39,19 @@ let state = {
|
||||
settings: {
|
||||
serverLogin: 'shineupme',
|
||||
serverHttp: 'https://shineup.me',
|
||||
serverUrl: 'wss://shineup.me/ws',
|
||||
login: '',
|
||||
},
|
||||
pairing: {
|
||||
active: false,
|
||||
pairingId: '',
|
||||
expiresAtMs: 0,
|
||||
shortCode: '',
|
||||
},
|
||||
session: null,
|
||||
connectionOnline: false,
|
||||
walletProfile: null,
|
||||
signing: {
|
||||
selectedDeviceName: '',
|
||||
},
|
||||
currentWallet: null,
|
||||
status: {
|
||||
text: '',
|
||||
kind: 'info',
|
||||
@@ -60,7 +68,7 @@ function setStatus(message, kind = 'info') {
|
||||
}
|
||||
|
||||
function setConnectedPill(connected) {
|
||||
els.connectionPill.textContent = connected ? 'online' : 'offline';
|
||||
els.connectionPill.textContent = connected ? 'подключено' : 'не подключено';
|
||||
els.connectionPill.className = connected ? 'pill pill-online' : 'pill pill-offline';
|
||||
}
|
||||
|
||||
@@ -104,76 +112,65 @@ function applyState(nextState) {
|
||||
const loginValue = String(state?.settings?.login || '');
|
||||
const resolvedServerLogin = String(state?.settings?.serverLogin || '').trim();
|
||||
const resolvedServerAddress = String(state?.settings?.serverHttp || '').trim();
|
||||
if (loginValue && resolvedServerLogin && resolvedServerAddress) {
|
||||
els.serverLoginInfo.textContent = `Сервер SHiNE: ${resolvedServerLogin}`;
|
||||
els.serverAddress.textContent = `Адрес: ${resolvedServerAddress}`;
|
||||
} else {
|
||||
els.serverLoginInfo.textContent = 'Сервер SHiNE: —';
|
||||
els.serverAddress.textContent = 'Адрес: —';
|
||||
}
|
||||
els.serverLoginInfo.textContent = resolvedServerLogin ? `Сервер SHiNE: ${resolvedServerLogin}` : 'Сервер SHiNE: —';
|
||||
els.serverAddress.textContent = resolvedServerAddress ? `Адрес: ${resolvedServerAddress}` : 'Адрес: —';
|
||||
if (document.activeElement !== els.loginInput) {
|
||||
els.loginInput.value = loginValue;
|
||||
}
|
||||
setConnectedPill(!!state?.connectionOnline);
|
||||
|
||||
setConnectedPill(!!state?.session);
|
||||
setStatus(state?.status?.text || '', state?.status?.kind || 'info');
|
||||
|
||||
const session = state?.session;
|
||||
const walletProfile = state?.walletProfile;
|
||||
const signing = state?.signing || {};
|
||||
const currentWallet = state?.currentWallet || null;
|
||||
|
||||
els.connectCard.classList.toggle('hidden', !!session);
|
||||
els.sessionCard.classList.toggle('hidden', !session);
|
||||
els.walletCard.classList.toggle('hidden', !session);
|
||||
|
||||
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.textContent = `${item.sessionName} [${item.onlineState || 'offline'}]`;
|
||||
option.selected = item.sessionName === signing.selectedDeviceName;
|
||||
els.deviceSelect.append(option);
|
||||
});
|
||||
renderHomeserverList(homeservers);
|
||||
els.prepareSignBtn.disabled = !session || !signing.selectedKeyId || !signing.selectedDeviceName;
|
||||
els.requestWalletBtn.disabled = !session || !signing.selectedDeviceName;
|
||||
|
||||
if (currentWallet?.publicKeyBase58) {
|
||||
els.walletResultCard.classList.remove('hidden');
|
||||
els.walletType.textContent = currentWallet.type || '—';
|
||||
els.walletPubkey.textContent = currentWallet.publicKeyBase58 || '—';
|
||||
els.walletVerify.textContent = currentWallet.verificationText || '—';
|
||||
} else {
|
||||
els.walletResultCard.classList.add('hidden');
|
||||
els.walletType.textContent = '—';
|
||||
els.walletPubkey.textContent = '—';
|
||||
els.walletVerify.textContent = '—';
|
||||
}
|
||||
|
||||
const pairing = state?.pairing || {};
|
||||
if (pairing.active) {
|
||||
els.pairingCard.classList.remove('hidden');
|
||||
const shortCode = String(pairing.shortCode || els.shortCode.dataset.shortCode || els.shortCode.textContent || '');
|
||||
els.shortCode.dataset.shortCode = shortCode;
|
||||
els.shortCode.textContent = formatPairingShortCode(shortCode);
|
||||
els.pairingHint.textContent = pairing.trustedSessionOnline
|
||||
? 'Покажите код на доверенном устройстве и подтвердите выпуск wallet-session.'
|
||||
: 'Сейчас нет онлайн доверенной сессии. Откройте другое устройство и подтвердите заявку.';
|
||||
els.shortCode.textContent = formatPairingShortCode(String(pairing.shortCode || ''));
|
||||
const leftMs = Number(pairing.expiresAtMs || 0) - Date.now();
|
||||
els.pairingExpire.textContent = leftMs > 0 ? `Код действителен ещё ${formatRemaining(leftMs)}.` : 'Время ожидания истекло.';
|
||||
els.startBtn.disabled = true;
|
||||
} else {
|
||||
els.pairingCard.classList.add('hidden');
|
||||
els.shortCode.textContent = formatPairingShortCode('');
|
||||
delete els.shortCode.dataset.shortCode;
|
||||
els.pairingExpire.textContent = '';
|
||||
els.startBtn.disabled = false;
|
||||
}
|
||||
@@ -241,16 +238,13 @@ async function startPairing() {
|
||||
return;
|
||||
}
|
||||
setStatus('Создаём wallet-session заявку...', 'info');
|
||||
els.startBtn.disabled = true;
|
||||
try {
|
||||
const response = await sendMessage('wallet:startPairing', {
|
||||
await sendMessage('wallet:startPairing', {
|
||||
login,
|
||||
usePassword: !!els.usePassword.checked,
|
||||
password: String(els.passwordInput.value || ''),
|
||||
});
|
||||
applyState(response.state);
|
||||
} catch (error) {
|
||||
els.startBtn.disabled = false;
|
||||
setStatus(error.message || 'Не удалось начать pairing.', 'error');
|
||||
}
|
||||
}
|
||||
@@ -289,23 +283,33 @@ async function refreshDevices() {
|
||||
}
|
||||
}
|
||||
|
||||
async function updateSigningSelection() {
|
||||
async function updateDeviceSelection() {
|
||||
try {
|
||||
await sendMessage('wallet:updateSigningSelection', {
|
||||
selectedKeyId: String(els.signKeySelect.value || '').trim(),
|
||||
selectedDeviceName: String(els.deviceSelect.value || '').trim(),
|
||||
});
|
||||
} catch (error) {
|
||||
setStatus(error.message || 'Не удалось обновить выбор для подписи.', 'error');
|
||||
setStatus(error.message || 'Не удалось обновить выбор homeserver.', 'error');
|
||||
}
|
||||
}
|
||||
|
||||
async function prepareSignSignal() {
|
||||
setStatus('Готовим каркас запроса подписи...', 'info');
|
||||
async function requestCurrentWallet() {
|
||||
setStatus('Запрашиваем текущий кошелёк с ESP32...', 'info');
|
||||
try {
|
||||
await sendMessage('wallet:prepareSignSignal');
|
||||
await sendMessage('wallet:requestCurrentWallet');
|
||||
} catch (error) {
|
||||
setStatus(error.message || 'Не удалось подготовить запрос подписи.', 'error');
|
||||
setStatus(error.message || 'Не удалось получить кошелёк с ESP32.', 'error');
|
||||
}
|
||||
}
|
||||
|
||||
async function copyWalletKey() {
|
||||
const value = String(els.walletPubkey.textContent || '').trim();
|
||||
if (!value || value === '—') return;
|
||||
try {
|
||||
await navigator.clipboard.writeText(value);
|
||||
setStatus('Публичный ключ скопирован.', 'info');
|
||||
} catch (error) {
|
||||
setStatus(error.message || 'Не удалось скопировать ключ.', 'error');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -340,9 +344,9 @@ function bindUi() {
|
||||
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(); });
|
||||
els.deviceSelect.addEventListener('change', () => { void updateDeviceSelection(); });
|
||||
els.requestWalletBtn.addEventListener('click', () => { void requestCurrentWallet(); });
|
||||
els.copyWalletBtn.addEventListener('click', () => { void copyWalletKey(); });
|
||||
}
|
||||
|
||||
async function init() {
|
||||
|
||||
Reference in New Issue
Block a user