43 lines
2.4 KiB
JavaScript
43 lines
2.4 KiB
JavaScript
|
|
// 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');
|
||
|
|
});
|