64 lines
2.4 KiB
JavaScript
64 lines
2.4 KiB
JavaScript
#!/usr/bin/env node
|
|
/* eslint-disable no-console, no-restricted-syntax */
|
|
// This is a standalone Node CLI guard (not app code): console output is its
|
|
// whole purpose, and directory-walk loops are clearer than array gymnastics.
|
|
//
|
|
// Binding guard for proxy_support.md §15 #6: the native tree must never weaken
|
|
// TLS. The bring-your-own-proxy relay is a pure L4 forwarder — the WebView's
|
|
// TLS to the homeserver stays end-to-end validated against the system store,
|
|
// even through an untrusted upstream proxy. This guard fails the build if a
|
|
// future change introduces an SSL-error bypass, a custom TrustManager /
|
|
// HostnameVerifier, or cleartext traffic. Wired into .husky/pre-commit.
|
|
|
|
import { readdirSync, readFileSync, statSync } from 'node:fs';
|
|
import { join } from 'node:path';
|
|
|
|
const ROOT = 'android/app/src/main';
|
|
|
|
const FORBIDDEN = [
|
|
{
|
|
re: /onReceivedSslError/,
|
|
msg: 'onReceivedSslError override (would let a proxy MITM WebView TLS)',
|
|
},
|
|
{
|
|
re: /X509TrustManager|X509ExtendedTrustManager|implements\s+TrustManager/,
|
|
msg: 'custom TrustManager (TLS trust bypass)',
|
|
},
|
|
{ re: /HostnameVerifier|ALLOW_ALL_HOSTNAME_VERIFIER/, msg: 'custom/permissive HostnameVerifier' },
|
|
{ re: /usesCleartextTraffic\s*=\s*"true"/, msg: 'usesCleartextTraffic="true"' },
|
|
{ re: /setHostnameVerifier|setDefaultHostnameVerifier/, msg: 'setHostnameVerifier' },
|
|
];
|
|
|
|
function walk(dir) {
|
|
let out = [];
|
|
for (const name of readdirSync(dir)) {
|
|
const p = join(dir, name);
|
|
const s = statSync(p);
|
|
if (s.isDirectory()) out = out.concat(walk(p));
|
|
else if (/\.(java|kt|xml)$/.test(name)) out.push(p);
|
|
}
|
|
return out;
|
|
}
|
|
|
|
const violations = [];
|
|
for (const file of walk(ROOT)) {
|
|
const lines = readFileSync(file, 'utf8').split('\n');
|
|
lines.forEach((line, i) => {
|
|
const trimmed = line.trimStart();
|
|
// Skip comments (our own code documents that it does NOT do these things).
|
|
if (trimmed.startsWith('//') || trimmed.startsWith('*') || trimmed.startsWith('/*')) return;
|
|
for (const { re, msg } of FORBIDDEN) {
|
|
if (re.test(line)) violations.push(` ${file}:${i + 1} ${msg}\n ${line.trim()}`);
|
|
}
|
|
});
|
|
}
|
|
|
|
if (violations.length) {
|
|
console.error('\n✗ TLS-weakening guard failed (proxy_support.md §15 #6):\n');
|
|
console.error(violations.join('\n'));
|
|
console.error(
|
|
'\nThe proxy is a pure L4 forwarder; WebView TLS must stay end-to-end validated.\n'
|
|
);
|
|
process.exit(1);
|
|
}
|
|
console.log('✓ TLS-weakening guard: clean');
|