pithos/test/sia-account.test.js

43 lines
2.4 KiB
JavaScript
Raw Normal View History

// Telling which Sia account an s3d uses: BLAKE2b-256 against RFC 7693, and
// requests signed the way indexd's app API checks them (api/app/auth.go).
import test from 'node:test';
import assert from 'node:assert/strict';
import crypto from 'node:crypto';
import { blake2b, blake2b256 } from '../core/blake2b.js';
import { signRequest, fingerprint } from '../core/sia-account.js';
test('BLAKE2b matches RFC 7693 and OpenSSL', () => {
assert.equal(blake2b256('').toString('hex'), '0e5751c026e543b2e8ab2eb06099daa1d1e5df47778f7787faab45cdf12fe3a8');
assert.equal(blake2b('abc', 64).toString('hex'), 'ba80a53f981c4d0d6a2797b69f12f6e94c212f14685ac4b74b12bb6fdbffa2d17d87c5392aab792dc252d5de4533cc9518d38aa8dbf1925ab92386edd4009923');
for (const n of [1, 127, 128, 129, 255, 256, 257, 1000]) {
const b = crypto.randomBytes(n);
assert.ok(blake2b(b, 64).equals(crypto.createHash('blake2b512').update(b).digest()), `length ${n}`);
}
});
test('signed /account request: what indexd verifies', () => {
// A Go types.PrivateKey: 32-byte seed followed by the 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]);
const sv = 1_900_000_000;
const u = signRequest(appKey, 'GET', 'https://sia.storage/account', sv);
const q = u.searchParams;
// Go's base64.URLEncoding: URL-safe alphabet, with padding.
assert.match(q.get('sc'), /^[A-Za-z0-9_-]{43}=$/);
assert.match(q.get('ss'), /^[A-Za-z0-9_-]{86}==$/);
assert.equal(q.get('sv'), String(sv));
assert.ok(Buffer.from(q.get('sc'), 'base64').equals(pub));
const exp = Buffer.alloc(8);
exp.writeBigUInt64LE(BigInt(sv));
const digest = blake2b256(Buffer.concat([Buffer.from('GET'), Buffer.from('sia.storage'), Buffer.from('/account'), exp]));
assert.ok(crypto.verify(null, digest, publicKey, Buffer.from(q.get('ss'), 'base64')));
// Host and path come from the indexer URL, port included.
const v = signRequest(appKey, 'GET', 'http://127.0.0.1:9880/base/account', sv);
const d2 = blake2b256(Buffer.concat([Buffer.from('GET127.0.0.1:9880/base/account'), exp]));
assert.ok(crypto.verify(null, d2, publicKey, Buffer.from(v.searchParams.get('ss'), 'base64')));
assert.equal(fingerprint('3cc1a2f2' + '0'.repeat(52) + 'ac52'), 'ed25519:3cc1a2f2…ac52');
});