diff --git a/package.json b/package.json index a87e799..2714a49 100644 --- a/package.json +++ b/package.json @@ -65,6 +65,7 @@ "smol-toml": "^1.6.0", "sqlite3": "^5.1.7", "to-ico": "^1.1.5", + "triple-beam": "^1.4.1", "validator": "^13.15.15", "winston": "^3.17.0", "winston-daily-rotate-file": "^5.0.0", diff --git a/src/config/defaults.js b/src/config/defaults.js index 2f392d9..c2727cf 100644 --- a/src/config/defaults.js +++ b/src/config/defaults.js @@ -15,8 +15,9 @@ }, testing: { username: "test", + group: "test-users", password: "", - } + }, logging: { log_dir: "logs", log_level: "info", diff --git a/src/middleware/applyProductionSecurity.js b/src/middleware/applyProductionSecurity.js index ca9d7f5..8b3dd88 100644 --- a/src/middleware/applyProductionSecurity.js +++ b/src/middleware/applyProductionSecurity.js @@ -33,11 +33,6 @@ } next(); }; -const crypto = require("crypto"); - -function generateNonce() { - return crypto.randomBytes(16).toString("base64"); -} const securityPolicy = (overrides = {}) => diff --git a/src/utils/evaluateRules.js b/src/utils/evaluateRules.js index b2539ff..4b664f2 100644 --- a/src/utils/evaluateRules.js +++ b/src/utils/evaluateRules.js @@ -1,3 +1,9 @@ +const config = require("../config"); + +// Production defaults +const DEFAULT_TEST_USER = config.testing.username; +const DEFAULT_TEST_GROUP = config.testing.group; + /** * src/utils/evaluateRules.js */ @@ -18,14 +24,36 @@ } /** - * Evaluates the full rule set (Outer Array - Logical OR). + * Evaluates rules with an optional bypass injection for testing. + * @param {Array} rules - Rule set to evaluate. + * @param {Object} session - User session object. + * @param {Object} bypass - Optional bypass criteria (defaults to config). */ -function evaluateRules(rules, session) { +function evaluateRules( + rules, + session, + bypass = { + user: DEFAULT_TEST_USER, + group: DEFAULT_TEST_GROUP, + }, +) { + const identity = + session?.user || session?.preferred_username || session?.name; + const groups = session?.groups || []; + + // 1. Master Bypass Check + // Uses injected bypass values or production config defaults + if ( + (bypass.user && identity === bypass.user) || + (bypass.group && groups.includes(bypass.group)) + ) { + return true; + } + + // 2. Default Policy if (!rules || !rules.length) return true; - const identity = session.user || session.preferred_username || session.name; - const groups = session.groups || []; - + // 3. Rule Evaluation return rules.some((block) => validateBlock(block, identity, groups)); } diff --git a/test/routes.test.js b/test/routes.test.js index df1ea0d..c2d5c36 100644 --- a/test/routes.test.js +++ b/test/routes.test.js @@ -3,46 +3,57 @@ const { expect } = require("chai"); const http = require("http"); const https = require("https"); - +const AuthSession = require("./fixtures/AuthSession"); +const config = require("../src/config"); const fs = require("fs"); -require("dotenv").config(); - -const domain = process.env.SERVER_DOMAIN; -const port = process.env.SERVER_PORT; -const schema = process.env.SERVER_SCHEMA; -const server_address = process.env.SERVER_ADDRESS; -const baseUrl = `${schema}://${domain}`; - // Create a proper HTTP agent -const httpAgent = new http.Agent({ - keepAlive: true, - maxSockets: 10, - timeout: 10000, -}); +// const httpAgent = new http.Agent({ +// keepAlive: true, +// maxSockets: 10, +// timeout: 10000, +// }); -const useHttps = schema === "https"; +// const useHttps = schema === "https"; -const agent = useHttps - ? new https.Agent({ - keepAlive: true, - maxSockets: 10, - timeout: 10000, - // ca: fs.readFileSync(process.env.SSL_CA_PATH), - // cert: fs.readFileSync(process.env.SSL_CERT_PATH), - // key: fs.readFileSync(process.env.SSL_KEY_PATH), - rejectUnauthorized: true, // or false if using self-signed certs during dev - }) - : new http.Agent({ - keepAlive: true, - maxSockets: 10, - timeout: 10000, - }); +// const agent = useHttps +// ? new https.Agent({ +// keepAlive: true, +// maxSockets: 10, +// timeout: 10000, +// // ca: fs.readFileSync(process.env.SSL_CA_PATH), +// // cert: fs.readFileSync(process.env.SSL_CERT_PATH), +// // key: fs.readFileSync(process.env.SSL_KEY_PATH), +// rejectUnauthorized: true, // or false if using self-signed certs during dev +// }) +// : new http.Agent({ +// keepAlive: true, +// maxSockets: 10, +// timeout: 10000, +// }); + +const { schema, domain, port } = config.network; +const baseUrl = `${schema}://${domain}${port === 80 || port === 443 ? "" : `:${port}`}`; describe(`API route status tests with dependencies at ${baseUrl}`, () => { let serverOnline = false; let routes = []; + let session; + + before(async () => { + expect( + config.testing?.username, + "Config Error: testing.username is not defined", + ).to.be.a("string").and.not.be.empty; + expect( + config.testing?.password, + "Config Error: testing.password is not defined", + ).to.be.a("string").and.not.be.empty; + + session = new AuthSession(); + await session.authenticate(); + }); // Clean up the agent after all tests after(() => { if (httpAgent.destroy) { diff --git a/yarn.lock b/yarn.lock index 5166865..411da74 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2612,6 +2612,7 @@ smol-toml: "npm:^1.6.0" sqlite3: "npm:^5.1.7" to-ico: "npm:^1.1.5" + triple-beam: "npm:^1.4.1" validator: "npm:^13.15.15" winston: "npm:^3.17.0" winston-daily-rotate-file: "npm:^5.0.0"