#!/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');