DodoTransfer/tests/unit/auth.test.js
2026-11-05 10:28:10 +09:00

78 lines
3.1 KiB
JavaScript

'use strict';
const { test } = require('node:test');
const assert = require('node:assert');
const config = require('../../config');
const auth = require('../../lib/auth');
function withPasswords(upload, admin, fn) {
const before = { uploadPass: config.uploadPass, adminPass: config.adminPass, tokenSecret: config.tokenSecret };
Object.assign(config, { uploadPass: upload, adminPass: admin, tokenSecret: '' });
try {
return fn();
} finally {
Object.assign(config, before);
}
}
test('issued token verifies until it expires', () => withPasswords('up', 'ad', () => {
const now = 1_000_000;
const { token, exp } = auth.issue({}, 60, 'session', now);
assert.strictEqual(exp, now + 60_000);
assert.ok(auth.verify(token, 'session', now + 59_000));
assert.strictEqual(auth.verify(token, 'session', now + 60_000), null);
}));
test('tampered token is rejected', () => withPasswords('up', 'ad', () => {
const { token } = auth.issue({}, 60);
const [payload, sig] = token.split('.');
const forged = Buffer.from(JSON.stringify({ exp: Date.now() + 1e12 })).toString('base64url');
assert.strictEqual(auth.verify(`${ forged }.${ sig }`), null);
assert.strictEqual(auth.verify(`${ payload }.${ sig.slice(0, -2) }xx`), null);
assert.strictEqual(auth.verify('garbage'), null);
assert.strictEqual(auth.verify(''), null);
assert.strictEqual(auth.verify(undefined), null);
}));
test('a token is only valid for its purpose', () => withPasswords('up', 'ad', () => {
const { token } = auth.issue({ sid: 'x' }, 60, 'admin-download');
assert.strictEqual(auth.verify(token, 'session'), null);
assert.strictEqual(auth.verify(token, 'admin-download').sid, 'x');
}));
test('changing the upload or the admin password invalidates tokens', () => {
const { token } = withPasswords('up', 'ad', () => auth.issue({}, 60));
assert.ok(withPasswords('up', 'ad', () => auth.verify(token)));
assert.strictEqual(withPasswords('other', 'ad', () => auth.verify(token)), null);
assert.strictEqual(withPasswords('up', 'other', () => auth.verify(token)), null);
// works without an admin password too
const { token: t2 } = withPasswords('up', false, () => auth.issue({}, 60));
assert.ok(withPasswords('up', false, () => auth.verify(t2)));
});
test('an explicit token secret survives password changes', () => {
const issue = pass => {
config.tokenSecret = 'fixed-secret';
return withPasswords(pass, 'ad', () => { config.tokenSecret = 'fixed-secret'; return auth.issue({}, 60); });
};
const { token } = issue('up');
config.tokenSecret = 'fixed-secret';
const before = { uploadPass: config.uploadPass };
config.uploadPass = 'changed';
try {
assert.ok(auth.verify(token));
} finally {
config.tokenSecret = '';
config.uploadPass = before.uploadPass;
}
});
test('safeEqual compares secrets', () => {
assert.strictEqual(auth.safeEqual('abc', 'abc'), true);
assert.strictEqual(auth.safeEqual('abc', 'abd'), false);
assert.strictEqual(auth.safeEqual('abc', 'abcd'), false);
assert.strictEqual(auth.safeEqual(undefined, 'abc'), false);
assert.strictEqual(auth.safeEqual(undefined, undefined), true);
});