#!/usr/bin/env node // Real browser form callbacks with fake DOM; protocol/security checks are // source-level assertions only. Rust unit and live HTTP tests need Cargo. import assert from 'node:assert/strict'; import { readFileSync } from 'node:fs'; import { resolve, dirname } from 'node:path'; import { fileURLToPath } from 'node:url'; import { runInNewContext } from 'node:vm'; const root = resolve(dirname(fileURLToPath(import.meta.url)), '../..'); const read = path => readFileSync(resolve(root, path), 'utf8'); const html = read('src/admin/web/index.html'); const css = read('src/admin/web/style.css'); const administration = read('src/admin/web/settings.js'); const cache = read('src/admin/web/app/settings.js'); const router = read('src/admin/router.rs'); const assets = read('src/admin/panel_assets.rs'); const compression = read('src/admin/panel_content.rs'); const ip = read('src/cache/model/http_invalidation.rs'); const cacheMethods = read('src/proxy/cache_http_invalidation.rs'); for (const codec of ['zstd', 'br', 'gzip']) { assert.match(html, new RegExp(`id="admin-compression-${codec}"[^>]*checked`)); assert(assets.includes('"/assets/app.js"')); } for (const path of ['app.js','management.js','vhosts.js','settings.js','cache-panel.js','traffic-panel.js','style.css','langs.json']) { if (path === "langs.json") assert(router.includes(`"/assets/${path}", get(panel_assets::serve)`), path); else assert(router.includes('"/assets/{fingerprinted}"'), path); assert(assets.includes(`"/assets/${path}"`), path); } assert(compression.includes('preferred_encoding(headers, &settings)')); assert(compression.includes('HeaderValue::from_static("Accept-Encoding")')); assert(compression.includes('header::CONTENT_LENGTH')); assert(compression.includes('header::CONTENT_ENCODING')); assert(compression.includes('crate::compression::no_transform(headers)')); assert(html.includes('id="cache-http-invalidation-cidrs"')); assert(html.includes('class="metric-info cache-maintenance-info"')); assert(html.includes('data-i18n-aria="cacheHttpInvalidationCurlLabel"')); for (const snippet of ["curl -i -X PURGE", "curl -i -X BAN", "X-RustProxy-Confirm-Wide: 1"]) { assert(html.includes(snippet), snippet); } assert(css.includes('.cache-maintenance-info .metric-info-popover')); assert(cache.includes('http_invalidation_allowed_cidrs: $("cache-http-invalidation-cidrs")')); assert(ip.includes('http_invalidation_allowed_cidrs.len() <= 32')); assert(ip.includes('net.prefix_len() > 0')); assert(cacheMethods.includes('snapshot.envelope.config.cache.permits_http_invalidation(client_ip)')); assert(cacheMethods.includes('state.store.audit(')); assert(cacheMethods.includes('spawn_blocking')); assert(cacheMethods.includes('x-rustproxy-confirm-wide')); assert(cacheMethods.includes('InvalidationSelector::Exact')); assert(cacheMethods.includes('InvalidationSelector::Prefix')); assert(read('src/proxy/forward_entry.rs').includes('return cache_http_invalidation(')); const heading = html.lastIndexOf('data-i18n="systemInformation"'); assert(heading > 0); const headerArea = html.slice(heading, heading + 600); assert(headerArea.includes('API')); assert(headerArea.indexOf('API') < headerArea.indexOf('id="system-info-refresh"')); assert.match(css, /\.system-info-heading-actions\s*\{[^}]*display:\s*flex/); for (const lang of ['en_US','pl_pl']) { const strings = JSON.parse(read(`langs/${lang}.json`)); const t = strings.translations; assert(t.panelCompressionTitle && t.panelCompressionHelp && t.cacheHttpInvalidationHelp, lang); assert(t.cacheHttpInvalidationCurlLabel && t.cacheHttpInvalidationCurlIntro && t.cacheHttpInvalidationCurlNote, lang); } // Execute the actual callbacks captured from the shipped frontend settings JS. const fields = new Map(); const field = name => { if (!fields.has(name)) fields.set(name, { checked: false, value: '' }); return fields.get(name); }; for (const name of ['zstd', 'br', 'gzip']) field(`admin-compression-${name}`).checked = true; field('admin-listen').value = '127.0.0.1:9090'; field('admin-session-days').value = '30'; let handlers = new Map(); const bindSettingsForm = (id, handler) => handlers.set(id, handler); const adminStart = administration.indexOf('bindSettingsForm("administration-form", next => {'); const adminEnd = administration.indexOf('bindSettingsForm("tls-policy-form",', adminStart); assert(adminStart > 0 && adminEnd > adminStart); // Use the shipped helper in the extracted callback environment as well. const hostHelperStart = administration.indexOf(' function pinnedAdminHostname(value) {'); const hostHelperEnd = administration.indexOf(' const normalizedRequestedTab', hostHelperStart); assert(hostHelperStart > 0 && hostHelperEnd > hostHelperStart); runInNewContext(administration.slice(hostHelperStart, hostHelperEnd) + administration.slice(adminStart, adminEnd), { $: field, bindSettingsForm, latestStatus: { administration: { listen_locked: false } }, URL, }); const adminNext = {}; handlers.get('administration-form')(adminNext); assert.deepEqual(JSON.parse(JSON.stringify(adminNext.administration.panel_compression)), { zstd: true, br: true, gzip: true }); field('admin-public-origin').value = 'https://panel.example.test'; field('admin-hosts').value = 'panel.example.test\nother.example.test'; const pinnedNext = {}; handlers.get('administration-form')(pinnedNext); assert.deepEqual(JSON.parse(JSON.stringify(pinnedNext.administration.allowed_hosts)), ['other.example.test']); field('admin-compression-br').checked = false; field('admin-compression-zstd').checked = false; const offNext = {}; handlers.get('administration-form')(offNext); assert.deepEqual(JSON.parse(JSON.stringify(offNext.administration.panel_compression)), { zstd: false, br: false, gzip: true }); const cacheStart = cache.indexOf('bindSettingsForm("cache-form", next => {'); const cacheEnd = cache.indexOf('bindSettingsForm("transform-form",', cacheStart); assert(cacheStart > 0 && cacheEnd > cacheStart); handlers = new Map(); field('cache-http-invalidation-cidrs').value = ' 192.0.2.50\n 2001:db8:2::/64, 198.51.100.9 \n'; field('cache-sie-statuses').value = '500,502,503,504'; runInNewContext(cache.slice(cacheStart, cacheEnd), { $: field, bindSettingsForm, selectedCacheMemoryPreset: null, selectedCacheColdPreset: null, }); const cacheNext = { cache: { max_old_setting: 'kept' } }; handlers.get('cache-form')(cacheNext); assert.deepEqual(JSON.parse(JSON.stringify(cacheNext.cache.http_invalidation_allowed_cidrs)), ['192.0.2.50', '2001:db8:2::/64', '198.51.100.9']); assert.equal(cacheNext.cache.max_old_setting, 'kept'); field('cache-http-invalidation-cidrs').value = '\n'; handlers.get('cache-form')(cacheNext); assert.deepEqual(JSON.parse(JSON.stringify(cacheNext.cache.http_invalidation_allowed_cidrs)), []); console.log('PASS: cache CIDR/administration codec UI roundtrip, headers, security source wiring, API badge layout');