monitor/core/lib/misc.test.ts
2025-04-16 22:30:27 +07:00

239 lines
9.1 KiB
TypeScript

import { test, expect, suite, it } from 'vitest';
import * as misc from './misc';
suite('parseSchedule', () => {
it('should parse a valid schedule', () => {
const result = misc.parseSchedule(['00:00', '00:15', '1:30', '12:30']);
expect(result.valid).toEqual([
{ string: '00:00', hours: 0, minutes: 0 },
{ string: '00:15', hours: 0, minutes: 15 },
{ string: '01:30', hours: 1, minutes: 30 },
{ string: '12:30', hours: 12, minutes: 30 },
]);
expect(result.invalid).toEqual([]);
});
it('should let the average american type 24:00', () => {
const result = misc.parseSchedule(['24:00']);
expect(result.valid).toEqual([
{ string: '00:00', hours: 0, minutes: 0 },
]);
expect(result.invalid).toEqual([]);
});
it('should handle invalid stuff', () => {
const result = misc.parseSchedule(['12:34', 'invalid', '1030', '25:00', '1', '01', '']);
expect(result).toBeTruthy();
expect(result.valid).toEqual([
{ string: '12:34', hours: 12, minutes: 34 },
]);
expect(result.invalid).toEqual(['invalid', '1030', '25:00', '1', '01']);
});
it('should remove duplicates', () => {
const result = misc.parseSchedule(['02:00', '02:00', '05:55', '13:55']);
expect(result.valid).toEqual([
{ string: '02:00', hours: 2, minutes: 0 },
{ string: '05:55', hours: 5, minutes: 55 },
{ string: '13:55', hours: 13, minutes: 55 },
]);
expect(result.invalid).toEqual([]);
});
it('should sort the times', () => {
const result = misc.parseSchedule(['00:00', '00:01', '23:59', '01:01', '01:00']);
expect(result.valid).toEqual([
{ string: '00:00', hours: 0, minutes: 0 },
{ string: '00:01', hours: 0, minutes: 1 },
{ string: '01:00', hours: 1, minutes: 0 },
{ string: '01:01', hours: 1, minutes: 1 },
{ string: '23:59', hours: 23, minutes: 59 },
]);
expect(result.invalid).toEqual([]);
});
});
test('redactApiKeys', () => {
expect(misc.redactApiKeys('')).toBe('')
expect(misc.redactApiKeys('abc')).toBe('abc')
const example = `
sv_licenseKey cfxk_NYWn5555555500000000_2TLnnn
sv_licenseKey "cfxk_NYWn5555555500000000_2TLnnn"
sv_licenseKey 'cfxk_NYWn5555555500000000_2TLnnn'
steam_webApiKey A2FAF8CF83B87E795555555500000000
sv_tebexSecret 238a98bec4c0353fee20ac865555555500000000
rcon_password a5555555500000000
rcon_password "a5555555500000000"
rcon_password 'a5555555500000000'
mysql_connection_string "mysql://root:root@localhost:3306/txAdmin"
https://discord.com/api/webhooks/33335555555500000000/xxxxxxxxxxxxxxxxxxxx5555555500000000`;
const result = misc.redactApiKeys(example)
expect(result).toContain('[REDACTED]');
expect(result).toContain('2TLnnn');
expect(result).not.toContain('5555555500000000');
expect(result).not.toContain('mysql://');
})
suite('redactStartupSecrets', () => {
const redactedString = '[REDACTED]';
it('should return an empty array when given an empty array', () => {
expect(misc.redactStartupSecrets([])).toEqual([]);
});
it('should return the same array if no redaction keys are present', () => {
const args = ['node', 'script.js', '--help'];
expect(misc.redactStartupSecrets(args)).toEqual(args);
});
it('should redact a sv_licenseKey secret correctly', () => {
const args = ['sv_licenseKey', 'cfxk_12345_secret'];
// The regex captures "secret" and returns "[REDACTED cfxk...secret]"
const expected = ['sv_licenseKey', '[REDACTED cfxk...secret]'];
expect(misc.redactStartupSecrets(args)).toEqual(expected);
});
it('should not redact sv_licenseKey secret if the secret does not match the regex', () => {
const args = ['sv_licenseKey', 'invalidsecret'];
const expected = ['sv_licenseKey', 'invalidsecret'];
expect(misc.redactStartupSecrets(args)).toEqual(expected);
});
it('should redact steam_webApiKey secret correctly', () => {
const validKey = 'a'.repeat(32);
const args = ['steam_webApiKey', validKey];
const expected = ['steam_webApiKey', redactedString];
expect(misc.redactStartupSecrets(args)).toEqual(expected);
});
it('should redact sv_tebexSecret secret correctly', () => {
const validSecret = 'b'.repeat(40);
const args = ['sv_tebexSecret', validSecret];
const expected = ['sv_tebexSecret', redactedString];
expect(misc.redactStartupSecrets(args)).toEqual(expected);
});
it('should redact rcon_password secret correctly', () => {
const args = ['rcon_password', 'mysecretpassword'];
const expected = ['rcon_password', redactedString];
expect(misc.redactStartupSecrets(args)).toEqual(expected);
});
it('should redact mysql_connection_string secret correctly', () => {
const args = [
'mysql_connection_string',
'Server=myServerAddress;Database=myDataBase;User Id=myUsername;Password=myPassword;',
];
const expected = ['mysql_connection_string', redactedString];
expect(misc.redactStartupSecrets(args)).toEqual(expected);
});
it('should handle multiple redactions in a single array', () => {
const validSteamKey = 'c'.repeat(32);
const args = [
'sv_licenseKey', 'cfxk_12345_abcdef',
'someOtherArg', 'value',
'steam_webApiKey', validSteamKey,
];
const expected = [
'sv_licenseKey', '[REDACTED cfxk...abcdef]',
'someOtherArg', 'value',
'steam_webApiKey', redactedString,
];
expect(misc.redactStartupSecrets(args)).toEqual(expected);
});
it('should handle case-insensitive key matching', () => {
const args = ['SV_LICENSEKEY', 'cfxk_12345_SECRET'];
const expected = ['SV_LICENSEKEY', '[REDACTED cfxk...SECRET]'];
expect(misc.redactStartupSecrets(args)).toEqual(expected);
});
it('should leave a key unchanged if it is the last element', () => {
const args = ['sv_licenseKey'];
const expected = ['sv_licenseKey'];
expect(misc.redactStartupSecrets(args)).toEqual(expected);
});
it('should handle rules without regex', () => {
const args = ['rcon_password', 'whatever'];
const expected = ['rcon_password', redactedString];
expect(misc.redactStartupSecrets(args)).toEqual(expected);
});
it('should handle a real example', () => {
const args = [
"+setr", "txAdmin-debugMode", "true",
"+set", "tx2faSecret", "whatever",
"+set", "sv_licenseKey", "cfxk_xxxxxxxxxxxxxxxxxxxx_yyyyy",
"+set", "onesync", "enabled",
"+set", "sv_enforceGameBuild", "2545",
];
const expected = [
"+setr", "txAdmin-debugMode", "true",
"+set", "tx2faSecret", redactedString,
"+set", "sv_licenseKey", "[REDACTED cfxk...yyyyy]",
"+set", "onesync", "enabled",
"+set", "sv_enforceGameBuild", "2545",
];
expect(misc.redactStartupSecrets(args)).toEqual(expected);
});
it('should redact discord webhooks', () => {
const args = [
"aaa",
"https://discord.com/api/webhooks/33335555555500000000/xxxxxxxxxxxxxxxxxxxx5555555500000000",
"bbb",
];
const expected = [
"aaa",
"https://discord.com/api/webhooks/[REDACTED]/[REDACTED]",
"bbb",
];
expect(misc.redactStartupSecrets(args)).toEqual(expected);
});
});
test('now', () => {
const result = misc.now();
expect(typeof result).toBe('number');
expect(result.toString().length).toBe(10);
expect(result.toString()).not.toContain('.');
expect(result.toString()).not.toContain('-');
});
test('anyUndefined', () => {
expect(misc.anyUndefined(undefined, 'test')).toBe(true);
expect(misc.anyUndefined('test', 'xxxx')).toBe(false);
expect(misc.anyUndefined(undefined, undefined)).toBe(true);
});
test('calcExpirationFromDuration', () => {
const currTs = misc.now();
let result = misc.calcExpirationFromDuration('1 hour');
expect(result?.duration).toBe(3600);
expect(result?.expiration).toBe(currTs + 3600);
result = misc.calcExpirationFromDuration('1 hours');
expect(result?.duration).toBe(3600);
result = misc.calcExpirationFromDuration('permanent');
expect(result?.expiration).toBe(false);
expect(() => misc.calcExpirationFromDuration('x day')).toThrowError('duration number');
expect(() => misc.calcExpirationFromDuration('')).toThrowError('duration number');
expect(() => misc.calcExpirationFromDuration('-1 day')).toThrowError('duration number');
});
test('parseLimitedFloat', () => {
expect(misc.parseLimitedFloat('123.4567899999')).toBe(123.45679);
expect(misc.parseLimitedFloat(123.4567899999)).toBe(123.45679);
expect(misc.parseLimitedFloat(123.4567899999, 2)).toBe(123.46);
expect(misc.parseLimitedFloat(0.1 + 0.2)).toBe(0.3);
});