43 lines
3.1 KiB
JavaScript
43 lines
3.1 KiB
JavaScript
import test from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import {createRequire} from 'node:module';
|
|
const {parseAuthority,bindConnectAuthority,verifyInnerAuthority}=createRequire(import.meta.url)('../apps/network-broker/tls-authority.cjs');
|
|
|
|
test('canonical DNS, IPv4 and bracketed IPv6 ports and default 443',()=>{
|
|
assert.equal(parseAuthority('Example.COM').authority,'example.com:443');
|
|
assert.equal(parseAuthority('example.com:443').authority,'example.com:443');
|
|
assert.equal(parseAuthority('127.0.0.1:8443').authority,'127.0.0.1:8443');
|
|
assert.equal(parseAuthority('[2001:0DB8:0:0::1]').authority,'[2001:db8::1]:443');
|
|
assert.equal(parseAuthority('xn--bcher-kva.example:65535').port,65535);
|
|
assert.throws(()=>bindConnectAuthority('example.com'),{code:'missing-port'});
|
|
});
|
|
test('reject legacy IP aliases, controls, userinfo, paths and ambiguous ports',()=>{
|
|
for(const value of ['127.1:443','0177.0.0.1:443','2130706433:443','0x7f000001:443','0x7f.0.0.1:443','example.com:0','example.com:0443','example.com:65536','example.com:+443','example.com:','example.com:443:4','[email protected]:443','example.com/path','example.com?x',' example.com','example.com\r\n','example.com.','-bad.example','bad_.example','[fe80::1%25eth0]:443','::1:443','https://example.com:443']) {
|
|
assert.throws(()=>parseAuthority(value),error=>error.name==='AuthorityError'&&!error.message.includes(value));
|
|
}
|
|
});
|
|
test('inner Host, absolute URL and SNI bind to authenticated CONNECT',()=>{
|
|
const binding=bindConnectAuthority('EXAMPLE.com:443');
|
|
assert.equal(verifyInnerAuthority(binding,{rawHeaders:['Host','example.com'],url:'/submit?x=1',servername:'example.com'}),binding);
|
|
assert.equal(verifyInnerAuthority(binding,{rawHeaders:['host','EXAMPLE.com:443'],url:'https://example.com/submit',servername:'EXAMPLE.COM'}),binding);
|
|
assert.ok(Object.isFrozen(binding));
|
|
});
|
|
test('cross authority reuse and missing/duplicate Host or mismatched SNI fail closed',()=>{
|
|
const binding=bindConnectAuthority('example.com:443');
|
|
const valid={rawHeaders:['Host','example.com'],url:'/',servername:'example.com'};
|
|
for(const changed of [
|
|
{rawHeaders:[]},{rawHeaders:['Host','example.com','host','example.com']},
|
|
{rawHeaders:['Host','evil.com']},{rawHeaders:['Host','example.com:8443']},
|
|
{url:'https://evil.com/'},{url:'https://example.com:8443/'},
|
|
{url:'https://[email protected]/'},{url:'http://example.com/'},
|
|
{url:'//evil.com/'},{url:'/x#fragment'},{url:'/x\r\n'},
|
|
{servername:'evil.com'},{servername:'example.com:443'},{servername:undefined}
|
|
])assert.throws(()=>verifyInnerAuthority(binding,{...valid,...changed}));
|
|
assert.throws(()=>verifyInnerAuthority({...binding},valid),{code:'invalid-binding'});
|
|
});
|
|
test('IP CONNECT binding accepts absent SNI but does not accept a different IP',()=>{
|
|
const binding=bindConnectAuthority('[::1]:443');
|
|
assert.equal(verifyInnerAuthority(binding,{rawHeaders:['Host','[0:0:0:0:0:0:0:1]'],url:'https://[::1]/'}),binding);
|
|
assert.throws(()=>verifyInnerAuthority(binding,{rawHeaders:['Host','[::1]'],url:'/',servername:'::2'}),{code:'sni-mismatch'});
|
|
});
|