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).
29 lines
1.9 KiB
JavaScript
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'))));
|
|
});
|