Spaces:
Paused
Paused
| /** | |
| * Test for secret key validation in the actual Invidious companion configuration | |
| * This test verifies that SERVER_SECRET_KEY validation properly rejects special characters | |
| * when the actual config is parsed | |
| */ | |
| import { assert, assertEquals } from "./deps.ts"; | |
| import { parseConfig } from "../lib/helpers/config.ts"; | |
| Deno.test("Secret key validation in Invidious companion config", async (t) => { | |
| // Clean up any existing environment variables that might interfere | |
| Deno.env.delete("SERVER_SECRET_KEY"); | |
| await t.step("accepts valid alphanumeric keys", async () => { | |
| const validKeys = [ | |
| "aaaaaaaaaaaaaaaa", // all lowercase | |
| "AAAAAAAAAAAAAAAA", // all uppercase | |
| "1234567890123456", // all numbers | |
| "Aa1Bb2Cc3Dd4Ee5F", // mixed case | |
| "ABC123DEF456789A", // mixed letters and numbers | |
| ]; | |
| for (const key of validKeys) { | |
| // Set the environment variable for each test | |
| Deno.env.set("SERVER_SECRET_KEY", key); | |
| try { | |
| const config = await parseConfig(); | |
| assertEquals( | |
| config.server.secret_key, | |
| key, | |
| `Key "${key}" should be accepted and stored correctly`, | |
| ); | |
| } catch (error) { | |
| assert( | |
| false, | |
| `Key "${key}" should be valid but config parsing failed: ${ | |
| error instanceof Error ? error.message : String(error) | |
| }`, | |
| ); | |
| } | |
| } | |
| }); | |
| await t.step("rejects keys with special characters", async () => { | |
| const invalidKeys = [ | |
| "my#key!123456789", // Contains # and ! | |
| "test@key12345678", // Contains @ (fixed length) | |
| "key-with-dashes1", // Contains - | |
| "key_with_under_s", // Contains _ | |
| "key with spaces1", // Contains spaces (fixed length to 16) | |
| "key$with$dollar$", // Contains $ | |
| "key+with+plus+12", // Contains + | |
| "key=with=equals=", // Contains = | |
| "key(with)parens1", // Contains () | |
| "key[with]bracket", // Contains [] | |
| ]; | |
| for (const key of invalidKeys) { | |
| // Set the environment variable for each test | |
| Deno.env.set("SERVER_SECRET_KEY", key); | |
| try { | |
| await parseConfig(); | |
| assert( | |
| false, | |
| `Key "${key}" should be invalid but config parsing succeeded`, | |
| ); | |
| } catch (error) { | |
| // Verify it's a config parsing error with the right message | |
| assert( | |
| error instanceof Error && | |
| error.message.includes("Failed to parse configuration"), | |
| `Should get config parsing error, got: ${ | |
| error instanceof Error ? error.message : String(error) | |
| }`, | |
| ); | |
| // Check that the error contains expected validation message content | |
| const errorStr = error instanceof Error | |
| ? error.toString() | |
| : String(error); | |
| assert( | |
| errorStr.includes( | |
| "SERVER_SECRET_KEY contains invalid characters", | |
| ) || | |
| errorStr.includes("alphanumeric characters"), | |
| `Error should mention invalid characters or alphanumeric, got: ${errorStr}`, | |
| ); | |
| } | |
| } | |
| }); | |
| await t.step("rejects keys with wrong length", async () => { | |
| const wrongLengthKeys = [ | |
| "short", // Too short | |
| "thiskeyistoolongtobevalid", // Too long | |
| "", // Empty | |
| "a", // Single character | |
| "exactly15chars", // 15 chars | |
| "exactly17charss", // 17 chars | |
| ]; | |
| for (const key of wrongLengthKeys) { | |
| // Set the environment variable for each test | |
| Deno.env.set("SERVER_SECRET_KEY", key); | |
| try { | |
| await parseConfig(); | |
| assert( | |
| false, | |
| `Key "${key}" (length ${key.length}) should be invalid but config parsing succeeded`, | |
| ); | |
| } catch (error) { | |
| // Verify it's a config parsing error | |
| assert( | |
| error instanceof Error && | |
| error.message.includes("Failed to parse configuration"), | |
| `Should get config parsing error, got: ${ | |
| error instanceof Error ? error.message : String(error) | |
| }`, | |
| ); | |
| // Check that the error mentions length requirement | |
| const errorStr = error instanceof Error | |
| ? error.toString() | |
| : String(error); | |
| assert( | |
| errorStr.includes("exactly 16 character") || | |
| errorStr.includes( | |
| "String must contain exactly 16 character", | |
| ), | |
| `Error should mention 16 characters, got: ${errorStr}`, | |
| ); | |
| } | |
| } | |
| }); | |
| await t.step("validates error message content", async () => { | |
| // Test that special character validation provides the right error | |
| Deno.env.set("SERVER_SECRET_KEY", "my#key!123456789"); | |
| try { | |
| await parseConfig(); | |
| assert(false, "Should have failed with special character key"); | |
| } catch (error) { | |
| const errorStr = error instanceof Error | |
| ? error.toString() | |
| : String(error); | |
| // Check that the error message contains validation details | |
| assert( | |
| errorStr.includes( | |
| "SERVER_SECRET_KEY contains invalid characters", | |
| ) || | |
| errorStr.includes("alphanumeric characters"), | |
| "Should mention SERVER_SECRET_KEY and character validation", | |
| ); | |
| } | |
| // Test that length validation still works and provides clear message | |
| Deno.env.set("SERVER_SECRET_KEY", "short"); | |
| try { | |
| await parseConfig(); | |
| assert(false, "Should have failed with short key"); | |
| } catch (error) { | |
| const errorStr = error instanceof Error | |
| ? error.toString() | |
| : String(error); | |
| assert( | |
| errorStr.includes("exactly 16 character") || | |
| errorStr.includes( | |
| "String must contain exactly 16 character", | |
| ), | |
| `Should mention 16 characters: ${errorStr}`, | |
| ); | |
| } | |
| }); | |
| await t.step( | |
| "validates precedence - length vs character validation", | |
| async () => { | |
| // When both length and character validation fail, length should be checked first | |
| // This is the default Zod behavior | |
| Deno.env.set("SERVER_SECRET_KEY", "bad#"); | |
| try { | |
| await parseConfig(); | |
| assert( | |
| false, | |
| "Should have failed with short key containing special chars", | |
| ); | |
| } catch (error) { | |
| const errorStr = error instanceof Error | |
| ? error.toString() | |
| : String(error); | |
| // Should get length error since it's checked first | |
| assert( | |
| errorStr.includes("exactly 16 character") || | |
| errorStr.includes( | |
| "String must contain exactly 16 character", | |
| ), | |
| `Should get length error first: ${errorStr}`, | |
| ); | |
| } | |
| }, | |
| ); | |
| // Clean up environment variable after tests | |
| await t.step("validates missing SERVER_SECRET_KEY fails", async () => { | |
| // Test with no SERVER_SECRET_KEY set (uses default empty string) | |
| Deno.env.delete("SERVER_SECRET_KEY"); | |
| try { | |
| await parseConfig(); | |
| assert( | |
| false, | |
| "Should have failed with missing/empty SERVER_SECRET_KEY", | |
| ); | |
| } catch (error) { | |
| const errorStr = error instanceof Error | |
| ? error.toString() | |
| : String(error); | |
| assert( | |
| errorStr.includes("exactly 16 character") || | |
| errorStr.includes( | |
| "String must contain exactly 16 character", | |
| ), | |
| `Should get length error for empty key: ${errorStr}`, | |
| ); | |
| } | |
| }); | |
| await t.step("cleanup", () => { | |
| Deno.env.delete("SERVER_SECRET_KEY"); | |
| }); | |
| }); | |