SHA256
Добавить Turbo-загрузку и превью для вложений
This commit is contained in:
@@ -17,6 +17,34 @@ const BASE58_MAP = (() => {
|
||||
return out;
|
||||
})();
|
||||
|
||||
function encodeBase58(bytesLike) {
|
||||
const bytes = bytesLike instanceof Uint8Array ? bytesLike : Uint8Array.from(bytesLike || []);
|
||||
if (!bytes.length) return '';
|
||||
|
||||
const digits = [0];
|
||||
for (let i = 0; i < bytes.length; i += 1) {
|
||||
let carry = bytes[i];
|
||||
for (let j = 0; j < digits.length; j += 1) {
|
||||
const value = (digits[j] << 8) + carry;
|
||||
digits[j] = value % 58;
|
||||
carry = (value / 58) | 0;
|
||||
}
|
||||
while (carry > 0) {
|
||||
digits.push(carry % 58);
|
||||
carry = (carry / 58) | 0;
|
||||
}
|
||||
}
|
||||
|
||||
let out = '';
|
||||
for (let i = 0; i < bytes.length && bytes[i] === 0; i += 1) {
|
||||
out += BASE58_ALPHABET[0];
|
||||
}
|
||||
for (let i = digits.length - 1; i >= 0; i -= 1) {
|
||||
out += BASE58_ALPHABET[digits[i]];
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
function normalizeEndpoint(url) {
|
||||
const raw = String(url || '').trim();
|
||||
if (!raw) return DEFAULT_SOLANA_ENDPOINT;
|
||||
@@ -65,13 +93,27 @@ function decodeBase58(input) {
|
||||
async function keypairFromPkcs8(pkcs8B64) {
|
||||
const solana = await loadSolanaLib();
|
||||
const seed32 = extractClientKey32FromStoredValue(pkcs8B64);
|
||||
return solana.Keypair.fromSeed(seed32);
|
||||
try {
|
||||
return solana.Keypair.fromSeed(seed32);
|
||||
} finally {
|
||||
seed32.fill(0);
|
||||
}
|
||||
}
|
||||
|
||||
async function keypairFromStoredSecret(storedSecret) {
|
||||
const solana = await loadSolanaLib();
|
||||
const seed32 = extractClientKey32FromStoredValue(storedSecret);
|
||||
try {
|
||||
return solana.Keypair.fromSeed(seed32);
|
||||
} finally {
|
||||
seed32.fill(0);
|
||||
}
|
||||
}
|
||||
|
||||
export async function createRandomSolanaWallet() {
|
||||
const solana = await loadSolanaLib();
|
||||
const keypair = solana.Keypair.generate();
|
||||
const privateKey32Base58 = solana.bs58.encode(keypair.secretKey.slice(0, 32));
|
||||
const privateKey32Base58 = encodeBase58(keypair.secretKey.slice(0, 32));
|
||||
return {
|
||||
address: keypair.publicKey.toBase58(),
|
||||
privateKey32Base58,
|
||||
@@ -107,7 +149,7 @@ export async function getWalletFromStoredClientKey({ login, storagePwd }) {
|
||||
if (!clientPrivate) {
|
||||
throw new Error('На устройстве не найден client.key');
|
||||
}
|
||||
const keypair = await keypairFromPkcs8(clientPrivate);
|
||||
const keypair = await keypairFromStoredSecret(clientPrivate);
|
||||
return {
|
||||
address: keypair.publicKey.toBase58(),
|
||||
keypair,
|
||||
@@ -115,6 +157,66 @@ export async function getWalletFromStoredClientKey({ login, storagePwd }) {
|
||||
};
|
||||
}
|
||||
|
||||
export async function getWalletFromStoredRootKey({ login, storagePwd }) {
|
||||
const cleanLogin = String(login || '').trim();
|
||||
const cleanPwd = String(storagePwd || '').trim();
|
||||
if (!cleanLogin || !cleanPwd) {
|
||||
throw new Error('Нет активной сессии для доступа к root key');
|
||||
}
|
||||
const secrets = await loadEncryptedUserSecrets(cleanLogin, cleanPwd);
|
||||
const rootPrivate = String(secrets?.rootKey || '').trim();
|
||||
if (!rootPrivate) {
|
||||
throw new Error('На устройстве не найден root key');
|
||||
}
|
||||
const keypair = await keypairFromStoredSecret(rootPrivate);
|
||||
return {
|
||||
address: keypair.publicKey.toBase58(),
|
||||
keypair,
|
||||
rootPrivatePkcs8B64: rootPrivate,
|
||||
};
|
||||
}
|
||||
|
||||
export async function getStoredSolanaWalletChoices({ login, storagePwd, includeRoot = true } = {}) {
|
||||
const cleanLogin = String(login || '').trim();
|
||||
const cleanPwd = String(storagePwd || '').trim();
|
||||
if (!cleanLogin || !cleanPwd) {
|
||||
throw new Error('Нет активной сессии для доступа к ключам');
|
||||
}
|
||||
|
||||
const choices = [];
|
||||
const clientWallet = await getWalletFromStoredClientKey({ login: cleanLogin, storagePwd: cleanPwd });
|
||||
choices.push({
|
||||
id: 'client-key',
|
||||
keySource: 'client',
|
||||
label: 'client key',
|
||||
address: clientWallet.address,
|
||||
keypair: clientWallet.keypair,
|
||||
});
|
||||
|
||||
if (includeRoot) {
|
||||
try {
|
||||
const rootWallet = await getWalletFromStoredRootKey({ login: cleanLogin, storagePwd: cleanPwd });
|
||||
choices.push({
|
||||
id: 'root-key',
|
||||
keySource: 'root',
|
||||
label: 'root key',
|
||||
address: rootWallet.address,
|
||||
keypair: rootWallet.keypair,
|
||||
});
|
||||
} catch {
|
||||
// root key на устройстве может отсутствовать, это допустимо
|
||||
}
|
||||
}
|
||||
|
||||
return choices;
|
||||
}
|
||||
|
||||
export async function encodeSolanaSecretKeyBase58(secretKey) {
|
||||
const bytes = secretKey instanceof Uint8Array ? secretKey : Uint8Array.from(secretKey || []);
|
||||
if (!bytes.length) throw new Error('Пустой Solana secret key');
|
||||
return encodeBase58(bytes);
|
||||
}
|
||||
|
||||
export async function getBalanceSol({ endpoint, address }) {
|
||||
const solana = await loadSolanaLib();
|
||||
const rpc = normalizeEndpoint(endpoint);
|
||||
|
||||
Reference in New Issue
Block a user