Миграция PDA на client.key

This commit is contained in:
AidarKC
2026-06-22 21:57:09 +04:00
parent ba348dafb3
commit 5c92b6a734
133 changed files with 941 additions and 30531 deletions
+48 -39
View File
@@ -809,22 +809,27 @@ export class AuthService {
});
if (isCancelled && isCancelled()) throw new Error('DERIVE_CANCELLED');
if (onProgress) onProgress({ percent: 94, stage: 'derive', message: 'Вычисление root key...' });
if (onProgress) onProgress({ percent: 93, stage: 'derive', message: 'Вычисление recovery key...' });
const recoveryPair = await deriveEd25519FromMasterSecret(masterSecret, 'recovery.key');
if (isCancelled && isCancelled()) throw new Error('DERIVE_CANCELLED');
if (onProgress) onProgress({ percent: 95, 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 (onProgress) onProgress({ percent: 97, stage: 'derive', message: 'Вычисление blockchain key...' });
const blockchainPair = await deriveEd25519FromMasterSecret(masterSecret, 'blockchain.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 = {
masterSecretB64: bytesToBase64(masterSecret),
rootPair,
blockchainPair,
devicePair,
};
if (onProgress) onProgress({ percent: 99, stage: 'derive', message: 'Вычисление client key...' });
const clientPair = await deriveEd25519FromMasterSecret(masterSecret, 'client.key');
const result = {
masterSecretB64: bytesToBase64(masterSecret),
recoveryPair,
rootPair,
blockchainPair,
clientPair,
};
this.passwordKeyBundleCache.set(cacheKey, result);
if (onProgress) onProgress({ percent: 100, stage: 'done', message: 'Ключи сгенерированы.' });
return result;
@@ -839,6 +844,8 @@ export class AuthService {
async createAuthSession(login, keyBundle) {
const cleanLogin = (login || '').trim();
if (!cleanLogin) throw new Error('Введите логин');
const clientPair = keyBundle?.clientPair;
if (!clientPair) throw new Error('createAuthSession: не передан clientPair');
const sessionPair = await generateEd25519Pair();
const sessionKeyPub = await exportEd25519PublicKeyB64(sessionPair.publicKey);
@@ -853,7 +860,7 @@ export class AuthService {
const timeMs = Date.now();
const preimage = `AUTH_CREATE_SESSION:${cleanLogin}:${sessionKey}:${storagePwd}:${timeMs}:${authNonce}`;
const signatureB64 = await signBase64(keyBundle.devicePair.privateKey, preimage);
const signatureB64 = await signBase64(clientPair.privateKey, preimage);
const createResp = await this.ws.request('CreateAuthSession', {
login: cleanLogin,
@@ -861,7 +868,7 @@ export class AuthService {
sessionKey,
timeMs,
authNonce,
deviceKey: keyBundle.devicePair.publicKeyB64,
clientKey: clientPair.publicKeyB64,
signatureB64,
sessionType: SESSION_TYPE_CLIENT,
clientPlatform: makeClientPlatform(),
@@ -892,13 +899,14 @@ export class AuthService {
if (!isFree) throw new Error('Этот логин уже занят');
const keyBundle = await this.derivePasswordKeyBundle(cleanLogin, password);
const clientPair = keyBundle?.clientPair;
const addResp = await this.ws.request('AddUser', {
login: cleanLogin,
blockchainName: `${cleanLogin}-${BCH_SUFFIX}`,
solanaKey: keyBundle.devicePair.publicKeyB64,
solanaKey: clientPair.publicKeyB64,
blockchainKey: keyBundle.blockchainPair.publicKeyB64,
deviceKey: keyBundle.devicePair.publicKeyB64,
clientKey: clientPair.publicKeyB64,
bchLimit: 1000000,
});
if (addResp.status !== 200) throw opError('AddUser', addResp);
@@ -910,13 +918,14 @@ export class AuthService {
async registerUserWithKeyBundle(login, keyBundle) {
const cleanLogin = (login || '').trim();
if (!cleanLogin) throw new Error('Введите логин');
const clientPair = keyBundle?.clientPair;
const addResp = await this.ws.request('AddUser', {
login: cleanLogin,
blockchainName: `${cleanLogin}-${BCH_SUFFIX}`,
solanaKey: keyBundle.devicePair.publicKeyB64,
solanaKey: clientPair.publicKeyB64,
blockchainKey: keyBundle.blockchainPair.publicKeyB64,
deviceKey: keyBundle.devicePair.publicKeyB64,
clientKey: clientPair.publicKeyB64,
bchLimit: 1000000,
});
if (addResp.status !== 200) throw opError('AddUser', addResp);
@@ -937,13 +946,13 @@ export class AuthService {
async createSessionFromImportedSecrets(login, secrets) {
const cleanLogin = (login || '').trim();
if (!cleanLogin) throw new Error('В QR-коде нет логина');
const deviceKey = String(secrets?.deviceKey || '').trim();
if (!deviceKey) throw new Error('В QR-коде нет device key для входа');
const clientKey = String(secrets?.clientKey || secrets?.clientKey || '').trim();
if (!clientKey) throw new Error('В QR-коде нет client key для входа');
const privateKey = await importPkcs8Ed25519(deviceKey);
const publicKeyB64 = await publicKeyB64FromPkcs8Ed25519(deviceKey);
const privateKey = await importPkcs8Ed25519(clientKey);
const publicKeyB64 = await publicKeyB64FromPkcs8Ed25519(clientKey);
const session = await this.createAuthSession(cleanLogin, {
devicePair: {
clientPair: {
privateKey,
publicKeyB64,
},
@@ -951,9 +960,9 @@ export class AuthService {
return session;
}
async createDelegatedSessionWithDeviceKey({
async createDelegatedSessionWithClientKey({
login,
devicePrivPkcs8,
clientPrivPkcs8,
sessionKey,
sessionType = SESSION_TYPE_WALLET,
clientPlatform = 'Delegated session',
@@ -961,13 +970,13 @@ export class AuthService {
}) {
const cleanLogin = String(login || '').trim();
const cleanSessionKey = String(sessionKey || '').trim();
const cleanDevicePriv = String(devicePrivPkcs8 || '').trim();
if (!cleanLogin) throw new Error('createDelegatedSessionWithDeviceKey: пустой login');
if (!cleanSessionKey) throw new Error('createDelegatedSessionWithDeviceKey: пустой sessionKey');
if (!cleanDevicePriv) throw new Error('createDelegatedSessionWithDeviceKey: пустой device private key');
const cleanClientPriv = String(clientPrivPkcs8 || '').trim();
if (!cleanLogin) throw new Error('createDelegatedSessionWithClientKey: пустой login');
if (!cleanSessionKey) throw new Error('createDelegatedSessionWithClientKey: пустой sessionKey');
if (!cleanClientPriv) throw new Error('createDelegatedSessionWithClientKey: пустой client private key');
const devicePrivateKey = await importPkcs8Ed25519(cleanDevicePriv);
const devicePublicKeyB64 = await publicKeyB64FromPkcs8Ed25519(cleanDevicePriv);
const clientPrivateKey = await importPkcs8Ed25519(cleanClientPriv);
const clientPublicKeyB64 = await publicKeyB64FromPkcs8Ed25519(cleanClientPriv);
const storagePwd = randomBase64(32);
const tempAuth = new AuthService(this.serverUrl);
@@ -980,7 +989,7 @@ export class AuthService {
const timeMs = Date.now();
const preimage = `AUTH_CREATE_SESSION:${cleanLogin}:${cleanSessionKey}:${storagePwd}:${timeMs}:${authNonce}`;
const signatureB64 = await signBase64(devicePrivateKey, preimage);
const signatureB64 = await signBase64(clientPrivateKey, preimage);
const createResp = await tempAuth.ws.request('CreateAuthSession', {
login: cleanLogin,
@@ -988,7 +997,7 @@ export class AuthService {
sessionKey: cleanSessionKey,
timeMs,
authNonce,
deviceKey: devicePublicKeyB64,
clientKey: clientPublicKeyB64,
signatureB64,
sessionType: Number(sessionType) || SESSION_TYPE_WALLET,
clientPlatform: String(clientPlatform || '').trim() || 'Delegated session',
@@ -1025,7 +1034,7 @@ export class AuthService {
const secrets = {
...currentSecrets,
deviceKey: keyBundle.devicePair.privatePkcs8B64,
clientKey: keyBundle.clientPair.privatePkcs8B64,
};
if (saveOptions.saveRoot) secrets.rootKey = keyBundle.rootPair.privatePkcs8B64;
if (saveOptions.saveBlockchain) secrets.blockchainKey = keyBundle.blockchainPair.privatePkcs8B64;
@@ -1898,9 +1907,9 @@ export class AuthService {
if (!storagePwd) throw new Error('Не передан storagePwd для подписи');
const secrets = await loadEncryptedUserSecrets(cleanFromLogin, storagePwd);
const devicePriv = secrets?.deviceKey;
if (!devicePriv) throw new Error('Не найден приватный deviceKey');
const privateKey = await importPkcs8Ed25519(devicePriv);
const clientPriv = secrets?.clientKey || secrets?.clientKey;
if (!clientPriv) throw new Error('Не найден приватный clientKey');
const privateKey = await importPkcs8Ed25519(clientPriv);
const toBytes = ensureAsciiBytes(cleanToLogin, 'toLogin');
const fromBytes = ensureAsciiBytes(cleanFromLogin, 'fromLogin');
@@ -1941,9 +1950,9 @@ export class AuthService {
}
const secrets = await loadEncryptedUserSecrets(cleanFromLogin, storagePwd);
const devicePriv = secrets?.deviceKey;
if (!devicePriv) throw new Error('Не найден приватный deviceKey');
const privateKey = await importPkcs8Ed25519(devicePriv);
const clientPriv = secrets?.clientKey || secrets?.clientKey;
if (!clientPriv) throw new Error('Не найден приватный clientKey');
const privateKey = await importPkcs8Ed25519(clientPriv);
const toBytes = ensureAsciiBytes(cleanToLogin, 'toLogin');
const fromBytes = ensureAsciiBytes(cleanFromLogin, 'fromLogin');