test v0.1

This commit is contained in:
2026-08-10 14:30:18 -03:00
parent d01238a9f1
commit 5bd2552641
2 changed files with 204 additions and 0 deletions

110
src/config.test.ts Normal file
View File

@@ -0,0 +1,110 @@
// *************************************************************************
// * (C)opyright 2026 by Ruben Carlo Benante *
// * *
// * This program is free software; you can redistribute it and/or modify *
// * it under the terms of the GNU General Public License as published by *
// * the Free Software Foundation, either version 3 of the License, or *
// * (at your option) any later version. *
// * *
// * This program is distributed in the hope that it will be useful, *
// * but WITHOUT ANY WARRANTY; without even the implied warranty of *
// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
// * GNU General Public License for more details. *
// * *
// * You should have received a copy of the GNU General Public License *
// * along with this program. If not, see http://www.gnu.org/licenses/. *
// * *
// * Contact author at: *
// * Ruben Carlo Benante *
// * rcb@beco.cc *
// *************************************************************************
import assert from 'node:assert/strict';
import { test } from 'node:test';
import {
LOGOUT_COOLDOWN_MS,
SUBMIT_INTERVAL_MS,
decideSubmit,
isConfigured,
matchesSite,
} from './config.ts';
import type { Config, State } from './config.ts';
const CONFIG: Config = {
url: 'https://portal.example.br/',
ra: '2000101010',
dn: '01/02/1999',
cpf: '123.456.789-01',
autoSubmit: true,
};
const FRESH: State = { lastSubmitAt: 0, logoutAt: 0 };
const NOW = 1_000_000_000_000;
test('isConfigured requires all four values', () => {
assert.equal(isConfigured(CONFIG), true);
assert.equal(isConfigured({ ...CONFIG, url: '' }), false);
assert.equal(isConfigured({ ...CONFIG, url: 'not a url' }), false);
assert.equal(isConfigured({ ...CONFIG, ra: '' }), false);
assert.equal(isConfigured({ ...CONFIG, dn: '' }), false);
assert.equal(isConfigured({ ...CONFIG, cpf: '' }), false);
});
test('matchesSite compares origins, not prefixes', () => {
assert.equal(matchesSite(CONFIG, 'https://portal.example.br/'), true);
assert.equal(matchesSite(CONFIG, 'https://portal.example.br/autenticacao/ap'), true);
});
test('matchesSite refuses lookalike hosts and scheme downgrades', () => {
// The content script runs on every page, so this guard is the only thing
// standing between the stored CPF and an attacker-chosen page.
assert.equal(matchesSite(CONFIG, 'https://portal.example.br.evil.tld/'), false);
assert.equal(matchesSite(CONFIG, 'https://evil.tld/portal.example.br'), false);
assert.equal(matchesSite(CONFIG, 'http://portal.example.br/'), false);
assert.equal(matchesSite(CONFIG, 'https://sub.portal.example.br/'), false);
assert.equal(matchesSite(CONFIG, 'about:blank'), false);
});
test('a fresh state submits', () => {
assert.deepEqual(decideSubmit(CONFIG, FRESH, NOW), { submit: true });
});
test('the toggle wins over everything else', () => {
assert.deepEqual(decideSubmit({ ...CONFIG, autoSubmit: false }, FRESH, NOW), {
submit: false,
reason: 'disabled',
});
});
test('one submit per hour, then autofill only', () => {
const justTried: State = { ...FRESH, lastSubmitAt: NOW - 1000 };
assert.deepEqual(decideSubmit(CONFIG, justTried, NOW), {
submit: false,
reason: 'rate-limited',
});
const anHourAgo: State = { ...FRESH, lastSubmitAt: NOW - SUBMIT_INTERVAL_MS - 1 };
assert.deepEqual(decideSubmit(CONFIG, anHourAgo, NOW), { submit: true });
});
test('a recent logout suppresses the submit, and expires', () => {
const justLoggedOut: State = { ...FRESH, logoutAt: NOW - 1000 };
assert.deepEqual(decideSubmit(CONFIG, justLoggedOut, NOW), {
submit: false,
reason: 'logout',
});
const staleLogout: State = { ...FRESH, logoutAt: NOW - LOGOUT_COOLDOWN_MS - 1 };
assert.deepEqual(decideSubmit(CONFIG, staleLogout, NOW), { submit: true });
});
test('logout is reported ahead of the rate limit', () => {
// Both apply after a login followed by a logout. The logout is the more
// useful explanation to show the user.
const both: State = { lastSubmitAt: NOW - 1000, logoutAt: NOW - 1000 };
assert.deepEqual(decideSubmit(CONFIG, both, NOW), {
submit: false,
reason: 'logout',
});
});

94
src/format.test.ts Normal file
View File

@@ -0,0 +1,94 @@
// *************************************************************************
// * (C)opyright 2026 by Ruben Carlo Benante *
// * *
// * This program is free software; you can redistribute it and/or modify *
// * it under the terms of the GNU General Public License as published by *
// * the Free Software Foundation, either version 3 of the License, or *
// * (at your option) any later version. *
// * *
// * This program is distributed in the hope that it will be useful, *
// * but WITHOUT ANY WARRANTY; without even the implied warranty of *
// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
// * GNU General Public License for more details. *
// * *
// * You should have received a copy of the GNU General Public License *
// * along with this program. If not, see http://www.gnu.org/licenses/. *
// * *
// * Contact author at: *
// * Ruben Carlo Benante *
// * rcb@beco.cc *
// *************************************************************************
import assert from 'node:assert/strict';
import { test } from 'node:test';
import {
formatCpf,
formatDate,
formatRa,
isCompleteCpf,
isCompleteDate,
toOrigin,
} from './format.ts';
test('formatDate builds dd/mm/yyyy progressively', () => {
assert.equal(formatDate('0'), '0');
assert.equal(formatDate('01'), '01');
assert.equal(formatDate('0102'), '01/02');
assert.equal(formatDate('01021999'), '01/02/1999');
});
test('formatDate is idempotent and tolerates a pasted separator', () => {
assert.equal(formatDate('01/02/1999'), '01/02/1999');
assert.equal(formatDate(formatDate('01021999')), '01/02/1999');
assert.equal(formatDate('1-2-1999'), '12/19/99');
});
test('formatCpf builds 000.000.000-00 progressively', () => {
assert.equal(formatCpf('123'), '123');
assert.equal(formatCpf('123456'), '123.456');
assert.equal(formatCpf('12345678901'), '123.456.789-01');
assert.equal(formatCpf('123.456.789-01'), '123.456.789-01');
});
test('formatters drop overflow instead of growing without bound', () => {
assert.equal(formatCpf('123456789012345'), '123.456.789-01');
assert.equal(formatRa('20001010109999'), '2000101010');
});
test('isCompleteDate rejects impossible calendar dates', () => {
assert.equal(isCompleteDate('01/02/1999'), true);
assert.equal(isCompleteDate('29/02/2000'), true, 'leap year');
assert.equal(isCompleteDate('29/02/1999'), false, 'not a leap year');
assert.equal(isCompleteDate('31/04/1999'), false, 'April has 30 days');
assert.equal(isCompleteDate('00/01/1999'), false);
assert.equal(isCompleteDate('01/13/1999'), false);
assert.equal(isCompleteDate('1/2/1999'), false, 'must be zero padded');
});
test('isCompleteCpf counts digits, not characters', () => {
assert.equal(isCompleteCpf('123.456.789-01'), true);
assert.equal(isCompleteCpf('12345678901'), true);
assert.equal(isCompleteCpf('123.456.789-0'), false);
});
test('toOrigin assumes https and strips path, query and fragment', () => {
assert.equal(toOrigin('https://portal.example.br/'), 'https://portal.example.br');
assert.equal(toOrigin('portal.example.br'), 'https://portal.example.br');
assert.equal(
toOrigin('https://portal.example.br/login?a=1#x'),
'https://portal.example.br',
);
assert.equal(toOrigin(' portal.example.br '), 'https://portal.example.br');
});
test('toOrigin keeps the port, which is part of the origin', () => {
assert.equal(toOrigin('http://localhost:8080/x'), 'http://localhost:8080');
});
test('toOrigin rejects what cannot be a site', () => {
assert.equal(toOrigin(''), null);
assert.equal(toOrigin(' '), null);
assert.equal(toOrigin('javascript:alert(1)'), null);
assert.equal(toOrigin('file:///etc/passwd'), null);
});