TrustedDeviceLogin API и настройки входа через устройство

Что сделано:\n- публичный API сценария входа через доверенное устройство переведён на TrustedDeviceLogin\n- добавлен GetTrustedDeviceLoginSettings\n- отсутствие записи настроек на сервере теперь трактуется как enabled=true и hasPassword=false\n- ttlSeconds убран из клиентского API, TTL заявки фиксирован на сервере: 300 секунд\n- в shine-UI добавлен отдельный экран настроек входа через устройство и статус на основном экране\n- browser wallet переведён на новые TrustedDeviceLogin операции\n- в wallet добавлен выбор rootKey/deviceKey для будущего запроса подписи\n- документация API обновлена\n\nЧто ещё не проверено вручную end-to-end:\n- полный сценарий UI/plugin после этого деплоя не прогонялся руками до конца\n- сам signaling подписи в wallet всё ещё не реализован
This commit is contained in:
AidarKC
2026-06-18 14:19:31 +04:00
parent cf2152dcfc
commit 56db6d0add
29 changed files with 689 additions and 241 deletions
+28 -22
View File
@@ -194,6 +194,7 @@ export function render({ navigate }) {
login: state.registrationDraft.login,
keyBundle,
solanaEndpoint: state.entrySettings.solanaServer,
accessServers: [state.entrySettings.shineServerLogin || 'shineupme'],
});
} catch (solanaError) {
const solanaMsg = formatSolanaErrorDetails(solanaError);
@@ -307,28 +308,33 @@ function renderSolanaDoneStage({ navigate, status, keyBundle }) {
tryLoginBtn.addEventListener('click', async () => {
if (!canTryLogin) return;
status.style.display = 'none';
tryLoginBtn.disabled = true;
tryLoginBtn.textContent = 'Вход...';
try {
await authService.reconnect(state.entrySettings.shineServer);
const result = await authService.createSessionForExistingUser(
state.registrationDraft.login,
state.registrationDraft.password,
);
state.registrationDraft.flowType = 'registration';
state.registrationDraft.sessionId = result.sessionId;
state.registrationDraft.storagePwd = result.storagePwd;
state.registrationDraft.pendingKeyBundle = keyBundle;
state.registrationDraft.pendingSessionMaterial = result.sessionMaterial;
setAuthInfo(`Регистрация завершена. Вы вошли как @${result.login}. Далее откройте вкладку «Каналы».`);
navigate('registration-keys-view');
} catch (error) {
status.className = 'status-line is-unavailable';
status.textContent = toUserMessage(error, 'Пока не удалось войти. Попробуйте ещё раз через несколько секунд.');
status.style.display = '';
tryLoginBtn.disabled = false;
tryLoginBtn.textContent = 'Попробовать войти на сервер';
}
tryLoginBtn.disabled = true;
tryLoginBtn.textContent = 'Вход...';
try {
await authService.reconnect(state.entrySettings.shineServer);
const result = await authService.createSessionForExistingUser(
state.registrationDraft.login,
state.registrationDraft.password,
);
await authService.persistSessionMaterial(
result.login,
result.sessionMaterial,
);
const resumed = await authService.resumeSession(result.login, result.sessionId);
state.registrationDraft.flowType = 'registration';
state.registrationDraft.sessionId = resumed.sessionId || result.sessionId;
state.registrationDraft.storagePwd = resumed.storagePwd || result.storagePwd;
state.registrationDraft.pendingKeyBundle = keyBundle;
state.registrationDraft.pendingSessionMaterial = result.sessionMaterial;
setAuthInfo(`Регистрация завершена. Вы вошли как @${result.login}. Далее откройте вкладку «Каналы».`);
navigate('registration-keys-view');
} catch (error) {
status.className = 'status-line is-unavailable';
status.textContent = toUserMessage(error, 'Пока не удалось войти. Попробуйте ещё раз через несколько секунд.');
status.style.display = '';
tryLoginBtn.disabled = false;
tryLoginBtn.textContent = 'Попробовать войти на сервер';
}
});
card.innerHTML = '';