import assert from 'node:assert/strict'; import fs from 'node:fs'; const read = path => fs.readFileSync(new URL(`../../${path}`, import.meta.url), 'utf8'); const json = path => JSON.parse(read(path)); const manifest = read('Cargo.toml'); const lib = read('src/lib.rs'); const model = read('src/config/model.rs'); const vhost = read('src/vhost/model.rs'); const forward = read('src/proxy/forward_entry.rs'); const loggingApi = read('src/admin/logging_api.rs'); const ua = read('src/user_agent.rs'); const stored = read('src/admin/file_logs.rs') + read('src/admin/file_logs_query.rs') + read('src/admin/file_log_search.rs'); const html = read('src/admin/web/index.html'); const core = read('src/admin/web/app/core.js'); const editor = read('src/admin/web/vhosts/editor.js'); const traffic = read('src/admin/web/traffic-panel.js'); const fileLogs = read('src/admin/web/file-logs.js'); const openapi = json('src/admin/openapi.json'); const en = json('langs/en_US.json').translations; const pl = json('langs/pl_pl.json').translations; assert.match(manifest, /version = "0\.31\.6"/); assert.match(lib, /pub mod user_agent;/); assert.match(model, /user_agent_blocking: crate::user_agent::Policy/); assert.match(vhost, /user_agent_blocking: crate::user_agent::Policy/); assert.match(loggingApi, /"user-agent-blocking"/); assert.match(ua, /MAX_PATTERNS: usize = 128/); assert.match(ua, /candidate\.contains\(pattern\)/); assert.match(ua, /pattern\.contains\('\*'\)/); const denyPos = forward.indexOf('denied by User-Agent policy'); const redirectPos = forward.indexOf('let redirect = snapshot.redirect_on'); assert.ok(denyPos > 0 && redirectPos > denyPos, 'UA policy must run before redirect/origin processing'); assert.match(html, /id="global-ua-block-form"/); assert.match(core, /saveSection\("user-agent-blocking"/); assert.match(editor, /"ua-block-patterns"/); assert.match(traffic, /traffic-copy-value/); assert.match(traffic, /navigator\.clipboard\?\.writeText/); assert.match(html, /id="file-log-consolidate-vhosts"/); assert.match(html, /id="file-log-aggregate-form"/); assert.match(stored, /group_id/); assert.match(stored, /consolidate_vhosts/); assert.match(stored, /aggregate_field/); assert.match(stored, /FILE_LOG_MAX_AGGREGATE_VALUES: usize = 4096/); assert.match(fileLogs, /member_count/); assert.match(fileLogs, /rp-file-logs-consolidate-vhosts/); assert.match(fileLogs, /localStorage\.getItem\(CONSOLIDATION_STORAGE_KEY\)/); assert.match(fileLogs, /localStorage\.setItem\(CONSOLIDATION_STORAGE_KEY/); assert.match(fileLogs, /aggregate_min_count/); assert.match(fileLogs, /file-log-aggregate-copy/); assert.equal(openapi.info.version, '0.31.6'); assert.ok(openapi.components.schemas.Config.properties.user_agent_blocking); assert.ok(openapi.components.schemas.Vhost.properties.user_agent_blocking); assert.ok(openapi.components.schemas.FileLogSource.properties.group_id); const params = openapi.paths['/api/file-logs/query'].get.parameters.map(item => item.name); for (const name of ['consolidate_vhosts', 'aggregate_field', 'aggregate_min_count', 'aggregate_limit']) assert.ok(params.includes(name), name); const sections = openapi.paths['/api/config/{section}'].put.parameters.find(item => item.name === 'section').schema.enum; assert.ok(sections.includes('user-agent-blocking')); for (const pack of [en, pl]) { for (const key of ['globalUaBlockingTitle', 'vhUaBlockEnabled', 'fileLogsConsolidateVhosts', 'fileLogsAdvancedParser', 'copied', 'copyValue']) { assert.equal(typeof pack[key], 'string', key); assert.ok(pack[key].length > 0, key); } } console.log('PASS: 0.31.6 UA blocking, copy controls, repeated-value parser, vhost log consolidation, OpenAPI and locales.');