pithos/test/space.test.js
Local Dev 05a1941aa3 Pithos: rename drives, folders and files; show free space on Sia
S3 has no rename, so files, folders and drives kept the name they were
made with. s3d copies objects in its own database (the copy points at
the same data on Sia), so a rename is a copy to the new name and a
delete of the old: quick, and it uses no extra storage. A drive rename
makes a new bucket, moves every file, rebuilds public access for the new
name (a policy names its bucket) and removes the old one. Names that
already exist are refused. Drives on Silent Mode encrypt with keys tied
to each name, so their client gets no rename until it can re-encrypt.

The drives page and Overview now show how much of the Sia account is
used and how much is free. s3d does not report it; the indexer's
GET /account does, signed with the app key s3d registered (read from its
database for this one request, BLAKE2b-256 + Ed25519 as indexd expects).
2026-10-04 03:58:21 +02:00

29 lines
1.9 KiB
JavaScript

// The indexer signs requests with BLAKE2b-256 + Ed25519 (indexd api/app);
// a wrong hash or key layout fails with "invalid signature" at the indexer.
import test from 'node:test';
import assert from 'node:assert/strict';
import crypto from 'node:crypto';
import { blake2b256, signIndexerUrl } from '../core/space.js';
test('BLAKE2b-256 matches the RFC 7693 / reference vectors', () => {
const h = (s) => blake2b256(Buffer.from(s)).toString('hex');
assert.equal(h(''), '0e5751c026e543b2e8ab2eb06099daa1d1e5df47778f7787faab45cdf12fe3a8');
assert.equal(h('abc'), 'bddd813c634239723171ef3fee98579b94964e3bb1cb3e427262c8c068d52319');
// multi-block inputs (reference: Python hashlib.blake2b(digest_size=32))
assert.equal(h('a'.repeat(128)), 'ae2aa48507885c4c950fb809b2076f959cde9f8ea6da260d9a3587df33dac450');
assert.equal(h('a'.repeat(129)), '2f64744a6de0d2c0b56e64cf6e29a5aaa255010d415d51c75ccc82f73dccd865');
});
test('signed indexer URL carries sv/sc/ss and verifies against the app public key', () => {
const { privateKey, publicKey } = crypto.generateKeyPairSync('ed25519');
const seed = privateKey.export({ format: 'der', type: 'pkcs8' }).subarray(-32);
const pub = publicKey.export({ format: 'der', type: 'spki' }).subarray(-32);
const appKey = Buffer.concat([seed, pub]); // Sia layout: seed || public key
const u = signIndexerUrl(appKey, 'GET', 'https://sia.storage/account', 1_800_000_000);
const unb64 = (s) => Buffer.from(s.replace(/-/g, '+').replace(/_/g, '/'), 'base64');
assert.equal(u.searchParams.get('sv'), '1800000000');
assert.deepEqual(unb64(u.searchParams.get('sc')), pub);
const until = Buffer.alloc(8); until.writeBigUInt64LE(1_800_000_000n);
const hash = blake2b256(Buffer.concat([Buffer.from('GET'), Buffer.from('sia.storage'), Buffer.from('/account'), until]));
assert.ok(crypto.verify(null, hash, publicKey, unb64(u.searchParams.get('ss'))));
});