SHA256
Checkpoint: первая рабочая версия звонков, сигналинг будет переделан
This commit is contained in:
@@ -1,4 +1,9 @@
|
||||
import { buildArweaveDataUrl, validateArweaveTxId } from './arweave-file-service.js';
|
||||
import {
|
||||
buildArweaveDataUrl,
|
||||
sha256HexFromArrayBuffer,
|
||||
validateArweaveTxId,
|
||||
validateSha256Hex,
|
||||
} from './arweave-file-service.js';
|
||||
|
||||
const DB_NAME = 'shine-ui-avatar-cache';
|
||||
const DB_VERSION = 1;
|
||||
@@ -55,6 +60,14 @@ async function putRecord(record) {
|
||||
});
|
||||
}
|
||||
|
||||
async function verifyBlobSha256(blob, expectedSha256Hex) {
|
||||
const expected = String(expectedSha256Hex || '').trim().toLowerCase();
|
||||
if (!validateSha256Hex(expected)) return true;
|
||||
if (!(blob instanceof Blob)) return false;
|
||||
const actual = await sha256HexFromArrayBuffer(await blob.arrayBuffer());
|
||||
return actual === expected;
|
||||
}
|
||||
|
||||
async function getAllRecords() {
|
||||
return withStore('readonly', (store, _tx, resolve, reject) => {
|
||||
const req = store.getAll();
|
||||
@@ -146,22 +159,41 @@ function detectImageMime(bytes) {
|
||||
return '';
|
||||
}
|
||||
|
||||
async function getBlobFromCacheOrGateway({ gateway, txId }) {
|
||||
async function getBlobFromCacheOrGateway({ gateway, txId, expectedSha256Hex = '' }) {
|
||||
const expected = String(expectedSha256Hex || '').trim().toLowerCase();
|
||||
try {
|
||||
const cached = await getRecord(txId);
|
||||
if (cached?.blob instanceof Blob) {
|
||||
return cached.blob;
|
||||
if (!validateSha256Hex(expected)) return cached.blob;
|
||||
const cacheSha = String(cached?.sha256Hex || '').trim().toLowerCase();
|
||||
if (cacheSha && cacheSha === expected) {
|
||||
return cached.blob;
|
||||
}
|
||||
const ok = await verifyBlobSha256(cached.blob, expected);
|
||||
if (ok) {
|
||||
return cached.blob;
|
||||
}
|
||||
// кэш повреждён или не совпадает с ожидаемым хэшем: удаляем и перекачиваем
|
||||
await deleteRecords([txId]);
|
||||
}
|
||||
} catch {
|
||||
// ignore IndexedDB errors and fallback to fetch
|
||||
}
|
||||
|
||||
const blob = await fetchAvatarBlob({ gateway, txId });
|
||||
if (validateSha256Hex(expected)) {
|
||||
const ok = await verifyBlobSha256(blob, expected);
|
||||
if (!ok) {
|
||||
throw new Error('SHA256_MISMATCH');
|
||||
}
|
||||
}
|
||||
const computedSha256Hex = await sha256HexFromArrayBuffer(await blob.arrayBuffer());
|
||||
const record = {
|
||||
txId,
|
||||
blob,
|
||||
contentType: String(blob.type || 'application/octet-stream'),
|
||||
sizeBytes: Number(blob.size || 0),
|
||||
sha256Hex: computedSha256Hex,
|
||||
cachedAtMs: Date.now(),
|
||||
};
|
||||
try {
|
||||
@@ -173,12 +205,16 @@ async function getBlobFromCacheOrGateway({ gateway, txId }) {
|
||||
return blob;
|
||||
}
|
||||
|
||||
export async function getCachedAvatarObjectUrl({ gateway, txId }) {
|
||||
export async function getCachedAvatarObjectUrl({ gateway, txId, expectedSha256Hex = '' }) {
|
||||
const cleanTxId = String(txId || '').trim();
|
||||
if (!validateArweaveTxId(cleanTxId)) {
|
||||
throw new Error('Некорректный Transaction ID Arweave');
|
||||
}
|
||||
const blob = await getBlobFromCacheOrGateway({ gateway, txId: cleanTxId });
|
||||
const blob = await getBlobFromCacheOrGateway({
|
||||
gateway,
|
||||
txId: cleanTxId,
|
||||
expectedSha256Hex,
|
||||
});
|
||||
return URL.createObjectURL(blob);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user