SHA256
Wallet-session pairing и browser plugin wallet, оплаты пока не работают
This commit is contained in:
@@ -54,6 +54,7 @@ const CHANNEL_TYPE_PERSONAL = 100;
|
||||
const CHANNEL_TYPE_GROUP = 200;
|
||||
const CHANNEL_TYPE_VERSION_DEFAULT = 1;
|
||||
const SESSION_TYPE_CLIENT = 1;
|
||||
const SESSION_TYPE_WALLET = 50;
|
||||
|
||||
const CONNECTION_SUBTYPES = Object.freeze({
|
||||
// Legacy alias: friend == close_friend. Оба ключа ведут на один и тот же код 10/11.
|
||||
@@ -887,6 +888,67 @@ export class AuthService {
|
||||
return session;
|
||||
}
|
||||
|
||||
async createDelegatedSessionWithDeviceKey({
|
||||
login,
|
||||
devicePrivPkcs8,
|
||||
sessionKey,
|
||||
sessionType = SESSION_TYPE_WALLET,
|
||||
clientPlatform = 'Delegated session',
|
||||
clientInfo = 'Delegated session via pairing',
|
||||
}) {
|
||||
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 devicePrivateKey = await importPkcs8Ed25519(cleanDevicePriv);
|
||||
const devicePublicKeyB64 = await publicKeyB64FromPkcs8Ed25519(cleanDevicePriv);
|
||||
const storagePwd = randomBase64(32);
|
||||
const tempAuth = new AuthService(this.serverUrl);
|
||||
|
||||
try {
|
||||
const challengeResp = await tempAuth.ws.request('AuthChallenge', { login: cleanLogin });
|
||||
if (challengeResp.status !== 200) throw opError('AuthChallenge', challengeResp);
|
||||
|
||||
const authNonce = challengeResp?.payload?.authNonce;
|
||||
if (!authNonce) throw new Error('AuthChallenge: сервер не вернул authNonce');
|
||||
|
||||
const timeMs = Date.now();
|
||||
const preimage = `AUTH_CREATE_SESSION:${cleanLogin}:${cleanSessionKey}:${storagePwd}:${timeMs}:${authNonce}`;
|
||||
const signatureB64 = await signBase64(devicePrivateKey, preimage);
|
||||
|
||||
const createResp = await tempAuth.ws.request('CreateAuthSession', {
|
||||
login: cleanLogin,
|
||||
storagePwd,
|
||||
sessionKey: cleanSessionKey,
|
||||
timeMs,
|
||||
authNonce,
|
||||
deviceKey: devicePublicKeyB64,
|
||||
signatureB64,
|
||||
sessionType: Number(sessionType) || SESSION_TYPE_WALLET,
|
||||
clientPlatform: String(clientPlatform || '').trim() || 'Delegated session',
|
||||
clientInfo: String(clientInfo || '').trim() || 'Delegated session via pairing',
|
||||
});
|
||||
if (createResp.status !== 200) throw opError('CreateAuthSession', createResp);
|
||||
|
||||
const sessionId = createResp?.payload?.sessionId;
|
||||
if (!sessionId) throw new Error('CreateAuthSession: не вернулся sessionId');
|
||||
|
||||
return {
|
||||
login: cleanLogin,
|
||||
sessionId,
|
||||
storagePwd,
|
||||
sessionKey: cleanSessionKey,
|
||||
sessionType: Number(sessionType) || SESSION_TYPE_WALLET,
|
||||
clientPlatform: String(clientPlatform || '').trim() || 'Delegated session',
|
||||
};
|
||||
} finally {
|
||||
tempAuth.ws.close();
|
||||
}
|
||||
}
|
||||
|
||||
async persistSelectedKeys(login, storagePwd, keyBundle, saveOptions = { saveRoot: true, saveBlockchain: true }) {
|
||||
let currentSecrets = {};
|
||||
try {
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import {
|
||||
base64ToBytes,
|
||||
bytesToBase64,
|
||||
deriveOpaqueArgon2Hash,
|
||||
exportEd25519PublicKeyB64,
|
||||
exportPkcs8B64,
|
||||
generateEd25519Pair,
|
||||
sha256Bytes,
|
||||
sha256Text,
|
||||
utf8Bytes,
|
||||
} from './crypto-utils.js';
|
||||
import {
|
||||
@@ -14,8 +14,9 @@ import {
|
||||
x25519,
|
||||
} from 'https://esm.sh/@noble/curves@1.5.0/ed25519';
|
||||
|
||||
const PAIRING_HASH_SUFFIX = 'esp.pairing.password';
|
||||
const PAIRING_ENVELOPE_PREFIX = 'shine-esp-pairing-v1:';
|
||||
const PAIRING_HASH_PREFIX = 'sha256$';
|
||||
const PAIRING_HASH_VERSION = 'shine-pairing';
|
||||
const ED25519_PKCS8_PREFIX = new Uint8Array([
|
||||
0x30, 0x2e, 0x02, 0x01, 0x00, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x70, 0x04, 0x22, 0x04, 0x20,
|
||||
]);
|
||||
@@ -84,10 +85,11 @@ export function detectPairingPayloadType(keys = {}) {
|
||||
}
|
||||
|
||||
export async function deriveEspPairingPasswordHash(login, password) {
|
||||
return deriveOpaqueArgon2Hash(password, {
|
||||
login,
|
||||
suffix: PAIRING_HASH_SUFFIX,
|
||||
});
|
||||
const loginLower = String(login || '').trim().toLowerCase();
|
||||
const preimage = `${PAIRING_HASH_VERSION}|${loginLower}|${String(password ?? '')}`;
|
||||
const digest = await sha256Text(preimage);
|
||||
const hex = [...digest].map((byte) => byte.toString(16).padStart(2, '0')).join('');
|
||||
return `${PAIRING_HASH_PREFIX}${hex}`;
|
||||
}
|
||||
|
||||
export async function createRequesterPairingMaterial() {
|
||||
@@ -158,3 +160,19 @@ export function buildSecretsPayload({ login, keys, mode }) {
|
||||
createdAtMs: Date.now(),
|
||||
};
|
||||
}
|
||||
|
||||
export function buildSessionAttachPayload({ login, session }) {
|
||||
return {
|
||||
v: 1,
|
||||
type: 'shine-esp-session-attach',
|
||||
login: String(login || '').trim(),
|
||||
session: {
|
||||
sessionId: String(session?.sessionId || '').trim(),
|
||||
sessionKey: String(session?.sessionKey || '').trim(),
|
||||
storagePwd: String(session?.storagePwd || '').trim(),
|
||||
sessionType: Number(session?.sessionType || 50) || 50,
|
||||
clientPlatform: String(session?.clientPlatform || '').trim(),
|
||||
},
|
||||
createdAtMs: Date.now(),
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user