CI / Build & Quality Checks (pull_request) Successful in 1m54s
CI / Trigger Desktop Build (pull_request) Skipped
CI / Docker image build & smoke test (pull_request) Skipped
CI / Secret scan (gitleaks) (pull_request) Successful in 10s
CI / Playwright smoke (e2e) (pull_request) Successful in 11m45s
The Server ACL editor treated an absent allow_ip_literals as false, so the first save in a room with no ACL (or one omitting the field) silently banned IP-literal servers. The spec default is true. normalizeServerAcl() fills the spec defaults once and feeds the initial state, the dirty check and the save. It also stops showing an existing ACL with no allow list as allow-all: per spec that allows no servers, and the /acl command already keeps it as-is. The checkbox is driven by onClick (folds has no onChange), now readOnly so React stops warning about a checked input without onChange. Fixes #261 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017PCb59uY3UKqDqt7B6hzd5
82 lines
2.7 KiB
TypeScript
82 lines
2.7 KiB
TypeScript
import { test } from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import {
|
|
isValidServerPattern,
|
|
globToRegExp,
|
|
matchesAnyGlob,
|
|
normalizeServerAcl,
|
|
} from './serverAcl';
|
|
|
|
test('isValidServerPattern: accepts hostnames, IPs, and globs', () => {
|
|
for (const v of [
|
|
'*',
|
|
'*.example.com',
|
|
'matrix.org',
|
|
'1.2.3.*',
|
|
'10.0.0.?',
|
|
'*.evil.*',
|
|
'*bad*',
|
|
]) {
|
|
assert.equal(isValidServerPattern(v), true, v);
|
|
}
|
|
});
|
|
|
|
test('isValidServerPattern: rejects empty, malformed, and non-glob junk', () => {
|
|
for (const v of ['', ' ', '.foo', 'foo.', 'a..b', '-', ':', 'under_score', 'a,b', 'a b']) {
|
|
assert.equal(isValidServerPattern(v), false, v);
|
|
}
|
|
});
|
|
|
|
test('globToRegExp: * = any run, ? = single char, other metachars escaped', () => {
|
|
assert.equal(globToRegExp('*').test('anything.org'), true);
|
|
assert.equal(globToRegExp('*.evil.com').test('a.evil.com'), true);
|
|
assert.equal(globToRegExp('*.evil.com').test('evil.com'), false); // needs the leading label
|
|
assert.equal(globToRegExp('1.2.3.?').test('1.2.3.4'), true);
|
|
assert.equal(globToRegExp('1.2.3.?').test('1.2.3.45'), false);
|
|
// The dot is a literal, not a regex wildcard.
|
|
assert.equal(globToRegExp('a.b').test('axb'), false);
|
|
});
|
|
|
|
test('globToRegExp: case-insensitive (hostnames + Synapse IGNORECASE)', () => {
|
|
assert.equal(globToRegExp('MATRIX.foo.org').test('matrix.foo.org'), true);
|
|
});
|
|
|
|
test('matchesAnyGlob: true if any glob matches (self-ban detection)', () => {
|
|
assert.equal(matchesAnyGlob('lotusguild.org', ['*']), true);
|
|
assert.equal(matchesAnyGlob('lotusguild.org', ['*.evil.com', 'lotus*.org']), true);
|
|
assert.equal(matchesAnyGlob('lotusguild.org', ['*.evil.com']), false);
|
|
assert.equal(matchesAnyGlob('lotusguild.org', []), false);
|
|
});
|
|
|
|
test('no ACL event: every server allowed, IP literals allowed (#261)', () => {
|
|
assert.deepEqual(normalizeServerAcl(undefined), {
|
|
allow: ['*'],
|
|
deny: [],
|
|
allow_ip_literals: true,
|
|
});
|
|
});
|
|
|
|
test('a missing allow_ip_literals defaults to true, per the spec (#261)', () => {
|
|
assert.equal(normalizeServerAcl({ allow: ['*'], deny: ['bad.example'] }).allow_ip_literals, true);
|
|
});
|
|
|
|
test('an explicit allow_ip_literals is kept', () => {
|
|
assert.equal(
|
|
normalizeServerAcl({ allow: ['*'], allow_ip_literals: false }).allow_ip_literals,
|
|
false,
|
|
);
|
|
assert.equal(
|
|
normalizeServerAcl({ allow: ['*'], allow_ip_literals: true }).allow_ip_literals,
|
|
true,
|
|
);
|
|
});
|
|
|
|
test('missing or malformed lists become empty, non-strings are dropped', () => {
|
|
assert.deepEqual(normalizeServerAcl({ allow: ['a.example', 3, null] }), {
|
|
allow: ['a.example'],
|
|
deny: [],
|
|
allow_ip_literals: true,
|
|
});
|
|
assert.deepEqual(normalizeServerAcl({ allow: 'a.example', deny: {} }).allow, []);
|
|
});
|