SHA256
Промежуточный коммит: состояние до нормальной Solana-first регистрации
This commit is contained in:
@@ -2,7 +2,8 @@ import { WsJsonClient } from './ws-client.js';
|
||||
import {
|
||||
base64ToBytes,
|
||||
bytesToBase64,
|
||||
deriveEd25519FromPassword,
|
||||
deriveEd25519FromMasterSecret,
|
||||
deriveMasterSecretFromPassword,
|
||||
exportEd25519PublicKeyB64,
|
||||
exportPkcs8B64,
|
||||
generateEd25519Pair,
|
||||
@@ -671,6 +672,8 @@ export class AuthService {
|
||||
this.ws = new WsJsonClient(this.serverUrl);
|
||||
this.headerHashCache = new Map();
|
||||
this.writeLocks = new Map();
|
||||
this.passwordKeyBundleCache = new Map();
|
||||
this.passwordKeyBundleInFlight = new Map();
|
||||
}
|
||||
|
||||
async reconnect(serverUrl) {
|
||||
@@ -706,13 +709,56 @@ export class AuthService {
|
||||
return payload.exists !== true;
|
||||
}
|
||||
|
||||
async derivePasswordKeyBundle(login, password) {
|
||||
async derivePasswordKeyBundle(login, password, options = {}) {
|
||||
const normalizedLogin = String(login ?? '');
|
||||
const normalizedPassword = String(password ?? '');
|
||||
const rootPair = await deriveEd25519FromPassword(normalizedPassword, 'root.key', { login: normalizedLogin });
|
||||
const blockchainPair = await deriveEd25519FromPassword(normalizedPassword, 'bch.key', { login: normalizedLogin });
|
||||
const devicePair = await deriveEd25519FromPassword(normalizedPassword, 'dev.key', { login: normalizedLogin });
|
||||
return { rootPair, blockchainPair, devicePair };
|
||||
const cacheKey = `${normalizedLogin}\n${normalizedPassword}`;
|
||||
const onProgress = typeof options?.onProgress === 'function' ? options.onProgress : null;
|
||||
const isCancelled = typeof options?.isCancelled === 'function' ? options.isCancelled : null;
|
||||
|
||||
if (this.passwordKeyBundleCache.has(cacheKey)) {
|
||||
if (onProgress) onProgress({ percent: 100, stage: 'cached', message: 'Ключи уже сгенерированы в памяти.' });
|
||||
return this.passwordKeyBundleCache.get(cacheKey);
|
||||
}
|
||||
if (this.passwordKeyBundleInFlight.has(cacheKey)) {
|
||||
return this.passwordKeyBundleInFlight.get(cacheKey);
|
||||
}
|
||||
|
||||
const task = (async () => {
|
||||
if (onProgress) onProgress({ percent: 3, stage: 'prepare', message: 'Подготовка параметров генерации...' });
|
||||
if (isCancelled && isCancelled()) throw new Error('DERIVE_CANCELLED');
|
||||
|
||||
const masterSecret = await deriveMasterSecretFromPassword(normalizedPassword, {
|
||||
login: normalizedLogin,
|
||||
onProgress: (value01) => {
|
||||
if (!onProgress) return;
|
||||
const v = Math.max(0, Math.min(1, Number(value01) || 0));
|
||||
const percent = Math.round(5 + (v * 88));
|
||||
onProgress({ percent, stage: 'secret', message: 'Генерация секрета из пароля...' });
|
||||
},
|
||||
});
|
||||
if (isCancelled && isCancelled()) throw new Error('DERIVE_CANCELLED');
|
||||
|
||||
if (onProgress) onProgress({ percent: 94, stage: 'derive', message: 'Вычисление root key...' });
|
||||
const rootPair = await deriveEd25519FromMasterSecret(masterSecret, 'root.key');
|
||||
if (isCancelled && isCancelled()) throw new Error('DERIVE_CANCELLED');
|
||||
|
||||
if (onProgress) onProgress({ percent: 96, stage: 'derive', message: 'Вычисление blockchain key...' });
|
||||
const blockchainPair = await deriveEd25519FromMasterSecret(masterSecret, 'bch.key');
|
||||
if (isCancelled && isCancelled()) throw new Error('DERIVE_CANCELLED');
|
||||
|
||||
if (onProgress) onProgress({ percent: 98, stage: 'derive', message: 'Вычисление device key...' });
|
||||
const devicePair = await deriveEd25519FromMasterSecret(masterSecret, 'dev.key');
|
||||
const result = { rootPair, blockchainPair, devicePair };
|
||||
this.passwordKeyBundleCache.set(cacheKey, result);
|
||||
if (onProgress) onProgress({ percent: 100, stage: 'done', message: 'Ключи сгенерированы.' });
|
||||
return result;
|
||||
})().finally(() => {
|
||||
this.passwordKeyBundleInFlight.delete(cacheKey);
|
||||
});
|
||||
|
||||
this.passwordKeyBundleInFlight.set(cacheKey, task);
|
||||
return task;
|
||||
}
|
||||
|
||||
async createAuthSession(login, keyBundle) {
|
||||
@@ -784,6 +830,24 @@ export class AuthService {
|
||||
return { ...session, keyBundle };
|
||||
}
|
||||
|
||||
async registerUserWithKeyBundle(login, keyBundle) {
|
||||
const cleanLogin = (login || '').trim();
|
||||
if (!cleanLogin) throw new Error('Введите логин');
|
||||
|
||||
const addResp = await this.ws.request('AddUser', {
|
||||
login: cleanLogin,
|
||||
blockchainName: `${cleanLogin}-${BCH_SUFFIX}`,
|
||||
solanaKey: keyBundle.devicePair.publicKeyB64,
|
||||
blockchainKey: keyBundle.blockchainPair.publicKeyB64,
|
||||
deviceKey: keyBundle.devicePair.publicKeyB64,
|
||||
bchLimit: 1000000,
|
||||
});
|
||||
if (addResp.status !== 200) throw opError('AddUser', addResp);
|
||||
|
||||
const session = await this.createAuthSession(cleanLogin, keyBundle);
|
||||
return { ...session, keyBundle };
|
||||
}
|
||||
|
||||
async createSessionForExistingUser(login, password) {
|
||||
const cleanLogin = (login || '').trim();
|
||||
if (!cleanLogin) throw new Error('Введите логин');
|
||||
|
||||
Reference in New Issue
Block a user