SHA256
Архивация в Arweave
This commit is contained in:
@@ -3157,22 +3157,6 @@ export class AuthService {
|
||||
return response.payload || {};
|
||||
}
|
||||
|
||||
async getTestFreeAvatarQuota() {
|
||||
const response = await this.ws.request('TestGetFreeAvatarQuota', {});
|
||||
if (response.status !== 200) throw opError('TestGetFreeAvatarQuota', response);
|
||||
return response.payload || {};
|
||||
}
|
||||
|
||||
async uploadTestFreeAvatar({ contentType, fileBytesBase64, sha256Hex }) {
|
||||
const response = await this.ws.request('TestUploadFreeAvatar', {
|
||||
contentType,
|
||||
fileBytesBase64,
|
||||
sha256Hex,
|
||||
}, 60000);
|
||||
if (response.status !== 200) throw opError('TestUploadFreeAvatar', response);
|
||||
return response.payload || {};
|
||||
}
|
||||
|
||||
async setUserRelation({ login, toLogin, kind, enabled, storagePwd }) {
|
||||
const cleanKind = String(kind || '').trim().toLowerCase();
|
||||
const kinds = CONNECTION_SUBTYPES[cleanKind];
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { base58ToBytes, base64ToBytes, bytesToBase58, importPkcs8Ed25519, sha256Bytes, signBytes } from './crypto-utils.js';
|
||||
import { base58ToBytes, base64ToBytes, base64UrlToBytes, bytesToBase58, bytesToBase64Url, importPkcs8Ed25519, sha256Bytes, signBytes } from './crypto-utils.js';
|
||||
import { extractSeed32FromPkcs8B64 } from './client-key-utils.js';
|
||||
import {
|
||||
SHINE_LOGIN_GUARD_PROGRAM_ID,
|
||||
@@ -27,6 +27,7 @@ const BLOCK_TYPE_SERVER_PROFILE = 30;
|
||||
const BLOCK_TYPE_ACCESS_SERVERS = 40;
|
||||
const BLOCK_TYPE_SESSIONS = 50;
|
||||
const BLOCK_TYPE_TRUSTED_STATE = 70;
|
||||
const BLOCK_TYPE_ARCHIVE_HEAD = 100;
|
||||
const SESSIONS_MODE_MIXED = 1;
|
||||
const SESSION_TYPE_USER = 1;
|
||||
const SESSION_TYPE_HOMESERVER = 100;
|
||||
@@ -326,6 +327,8 @@ function createPdaState({
|
||||
sessionsMode,
|
||||
sessions,
|
||||
trustedCount,
|
||||
archiveHeadTxId = '',
|
||||
archiveHeadHash = null,
|
||||
}) {
|
||||
const serverProfile = isServer ? {
|
||||
addressFormatType: Number(addressFormatType || 0),
|
||||
@@ -360,6 +363,8 @@ function createPdaState({
|
||||
sessionPubKey32: x?.sessionPubKey32 instanceof Uint8Array ? x.sessionPubKey32 : new Uint8Array(x?.sessionPubKey32 || 32),
|
||||
})) : [],
|
||||
trustedCount: Number(trustedCount || 0) & 0xff,
|
||||
archiveHeadTxId: String(archiveHeadTxId || '').trim(),
|
||||
archiveHeadHash: archiveHeadHash instanceof Uint8Array ? archiveHeadHash : new Uint8Array(archiveHeadHash || 32),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -445,6 +450,8 @@ export function parseShineUserPda(dataBytes) {
|
||||
let sessionsMode = SESSIONS_MODE_MIXED;
|
||||
let sessions = [];
|
||||
let trustedCount = 0;
|
||||
let archiveHeadTxId = '';
|
||||
let archiveHeadHash = new Uint8Array(32);
|
||||
|
||||
for (let i = 0; i < blocksCount; i += 1) {
|
||||
const blockType = reader.readU8();
|
||||
@@ -528,6 +535,11 @@ export function parseShineUserPda(dataBytes) {
|
||||
trustedCount = reader.readU8();
|
||||
continue;
|
||||
}
|
||||
if (blockType === BLOCK_TYPE_ARCHIVE_HEAD) {
|
||||
archiveHeadTxId = bytesToBase64Url(reader.readBytes(32));
|
||||
archiveHeadHash = reader.readBytes(32);
|
||||
continue;
|
||||
}
|
||||
throw new Error(`Неизвестный блок PDA: ${blockType}`);
|
||||
}
|
||||
|
||||
@@ -556,6 +568,8 @@ export function parseShineUserPda(dataBytes) {
|
||||
sessionsMode,
|
||||
sessions,
|
||||
trustedCount,
|
||||
archiveHeadTxId,
|
||||
archiveHeadHash,
|
||||
});
|
||||
|
||||
return {
|
||||
@@ -586,6 +600,8 @@ export function serializeUnsignedRecordFromState(stateLike) {
|
||||
sessionsMode: stateLike.sessionsMode,
|
||||
sessions: stateLike.sessions,
|
||||
trustedCount: stateLike.trustedCount,
|
||||
archiveHeadTxId: stateLike.archiveHeadTxId,
|
||||
archiveHeadHash: stateLike.archiveHeadHash,
|
||||
});
|
||||
|
||||
const buf = [0x53, 0x48, 0x69, 0x4e, 0x45, 1, 0, 0, 0];
|
||||
@@ -594,7 +610,8 @@ export function serializeUnsignedRecordFromState(stateLike) {
|
||||
pushU32LE(buf, state.recordNumber);
|
||||
for (const x of state.prevRecordHash) buf.push(x);
|
||||
pushStrU8(buf, state.login);
|
||||
buf.push(state.isServer ? 8 : 7);
|
||||
const hasArchiveHead = Boolean(state.archiveHeadTxId);
|
||||
buf.push((state.isServer ? 8 : 7) + (hasArchiveHead ? 1 : 0));
|
||||
|
||||
buf.push(BLOCK_TYPE_RECOVERY_KEY, 0);
|
||||
for (const x of state.recoveryKey) buf.push(x);
|
||||
@@ -636,6 +653,16 @@ export function serializeUnsignedRecordFromState(stateLike) {
|
||||
|
||||
buf.push(BLOCK_TYPE_TRUSTED_STATE, 0, state.trustedCount & 0xff);
|
||||
|
||||
if (hasArchiveHead) {
|
||||
const txId32 = base64UrlToBytes(state.archiveHeadTxId);
|
||||
if (txId32.length !== 32 || state.archiveHeadHash.length !== 32) {
|
||||
throw new Error('Archive head должен содержать TX ID/hash по 32 байта');
|
||||
}
|
||||
buf.push(BLOCK_TYPE_ARCHIVE_HEAD, 0);
|
||||
for (const x of txId32) buf.push(x);
|
||||
for (const x of state.archiveHeadHash) buf.push(x);
|
||||
}
|
||||
|
||||
const recordLen = buf.length + 64;
|
||||
buf[7] = recordLen & 0xff;
|
||||
buf[8] = (recordLen >>> 8) & 0xff;
|
||||
@@ -1037,6 +1064,8 @@ export async function updateShineUserPdaOnSolana({
|
||||
serverProfile,
|
||||
accessServers,
|
||||
trustedCount,
|
||||
archiveHeadTxId = '',
|
||||
archiveHeadHash = null,
|
||||
}) {
|
||||
const current = await readShineUserPda({ login, solanaEndpoint });
|
||||
const cleanLogin = current.login;
|
||||
@@ -1134,6 +1163,8 @@ export async function updateShineUserPdaOnSolana({
|
||||
sessionsMode: current.sessionsMode,
|
||||
sessions: current.sessions,
|
||||
trustedCount: trustedCount == null ? current.trustedCount : trustedCount,
|
||||
archiveHeadTxId: current.archiveHeadTxId,
|
||||
archiveHeadHash: current.archiveHeadHash,
|
||||
});
|
||||
|
||||
const unsignedNext = serializeUnsignedRecordFromState(nextState);
|
||||
|
||||
Reference in New Issue
Block a user