45 lines
2.9 KiB
JavaScript
45 lines
2.9 KiB
JavaScript
import test from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import { loadConfig } from '../src/config.js';
|
|
import { safeNext, readCookie, clientIp } from '../src/http.js';
|
|
|
|
const base = { SESSION_SECRET: 'a-secure-test-secret-longer-than-32-chars' };
|
|
|
|
test('Telegram games are optional and use a BotFather short name', () => {
|
|
assert.equal(loadConfig(base).telegram.gameShortName, '');
|
|
assert.equal(loadConfig({ ...base, TELEGRAM_GAME_SHORT_NAME: ' ' }).telegram.gameShortName, '');
|
|
assert.equal(loadConfig({ ...base, TELEGRAM_GAME_SHORT_NAME: ' dungeons_2048 ' }).telegram.gameShortName, 'dungeons_2048');
|
|
for (const name of ['@gamebot', 'https://t.me/gamebot?game=2048', 'my game', 'a'.repeat(31)]) {
|
|
assert.throws(() => loadConfig({ ...base, TELEGRAM_GAME_SHORT_NAME: name }), /TELEGRAM_GAME_SHORT_NAME/);
|
|
}
|
|
});
|
|
|
|
test('configuration rejects unsafe origins, weak secrets, invalid numbers, and incomplete bots', () => {
|
|
for (const options of [
|
|
{ SESSION_SECRET: '' }, { SESSION_SECRET: 'replace-with-a-random-secret-at-least-32-characters' },
|
|
{ UPSTREAM_URL: 'file:///tmp/secret' }, { UPSTREAM_URL: 'https://example.com/path' },
|
|
{ UPSTREAM_URL: 'https://user:password@example.com' }, { UPSTREAM_URL: 'http://localhost:8080' },
|
|
{ CODE_LENGTH: '7' }, { CODE_TTL_DAYS: '0' }, { PORT: '3000x' }, { TRUST_PROXY: 'yes' },
|
|
{ TELEGRAM_BOT_TOKEN: '123:token' }, { DISCORD_BOT_TOKEN: 'secret' },
|
|
{ TELEGRAM_ADMIN_IDS: '@admin' }, { ADMIN_REQUEST_FIELDS: 'password' },
|
|
{ NODE_ENV: 'production' }, { NODE_ENV: 'production', PUBLIC_URL: 'https://gate.example' },
|
|
]) assert.throws(() => loadConfig({ ...base, ...options }));
|
|
const config = loadConfig({ ...base, NODE_ENV: 'production', PUBLIC_URL: 'https://gate.example', TELEGRAM_BOT_TOKEN: '123:token', TELEGRAM_BOT_USERNAME: 'example_bot', TELEGRAM_ADMIN_IDS: '1,2,1' });
|
|
assert.deepEqual(config.telegram.admins, ['1', '2']);
|
|
assert.equal(config.secureCookie, true);
|
|
});
|
|
|
|
test('return paths cannot redirect outside the gateway or back into its controls', () => {
|
|
for (const value of [undefined, 'https://evil.example', '//evil.example', '/\\evil.example', '/%5cevil.example', '/_access/login', '/a/../_access', '/%00', '/x\ny', '/%']) assert.equal(safeNext(value), '/');
|
|
assert.equal(safeNext('/campaigns/123?tab=party#round'), '/campaigns/123?tab=party#round');
|
|
});
|
|
|
|
test('ambiguous cookies and untrusted forwarding cannot grant access or bypass rate limiting', () => {
|
|
assert.equal(readCookie({ headers: { cookie: 'dng_access=first; dng_access=second' } }), '');
|
|
const req = { headers: { 'x-forwarded-for': '192.0.2.1' }, socket: { remoteAddress: '127.0.0.1' } };
|
|
assert.equal(clientIp(req, { trustProxy: false }), '127.0.0.1');
|
|
assert.equal(clientIp(req, { trustProxy: true }), '192.0.2.1');
|
|
req.headers['x-forwarded-for'] = '192.0.2.1, 198.51.100.1';
|
|
assert.equal(clientIp(req, { trustProxy: true }), '127.0.0.1');
|
|
});
|