From 5735b4d4dbdc8dab745c8f227d8e75c998820f64 Mon Sep 17 00:00:00 2001 From: diegosouzapw Date: Wed, 20 May 2026 01:59:36 -0300 Subject: [PATCH] fix(security): resolve CodeQL random/password-hash alerts and sync docs & tests --- docs/architecture/ARCHITECTURE.md | 2 +- docs/architecture/CODEBASE_DOCUMENTATION.md | 4 ++-- src/app/api/gamification/federation/leaderboard/route.ts | 6 ++++-- src/app/api/gamification/federation/score/route.ts | 7 ++++--- src/lib/gamification/invites.ts | 3 +-- src/lib/gamification/servers.ts | 4 +++- tests/unit/autocombo-unification.test.ts | 9 +++++---- 7 files changed, 20 insertions(+), 15 deletions(-) diff --git a/docs/architecture/ARCHITECTURE.md b/docs/architecture/ARCHITECTURE.md index 17ea85c749..50fe7c681e 100644 --- a/docs/architecture/ARCHITECTURE.md +++ b/docs/architecture/ARCHITECTURE.md @@ -17,7 +17,7 @@ It provides a single OpenAI-compatible endpoint (`/v1/*`) and routes traffic acr Core capabilities: -- OpenAI-compatible API surface for CLI/tools (177 providers, 31 executors) +- OpenAI-compatible API surface for CLI/tools (177 providers, 38 executors) - Request/response translation across provider formats - Model combo fallback (multi-model sequence) - Structured combo steps (`provider + model + connection`) with runtime ordering by `compositeTiers` diff --git a/docs/architecture/CODEBASE_DOCUMENTATION.md b/docs/architecture/CODEBASE_DOCUMENTATION.md index 21c12d0977..8e55302f4b 100644 --- a/docs/architecture/CODEBASE_DOCUMENTATION.md +++ b/docs/architecture/CODEBASE_DOCUMENTATION.md @@ -411,7 +411,7 @@ open-sse/ ├── types.d.ts ├── config/ Provider registries, header profiles, identity, … ├── handlers/ Request handlers (chat, embeddings, audio, image, …) -├── executors/ 31 provider-specific HTTP executors +├── executors/ 38 provider-specific HTTP executors ├── translator/ Format conversion (OpenAI ↔ Claude ↔ Gemini ↔ Cursor ↔ Kiro) ├── transformer/ Responses API ↔ Chat Completions stream transformer ├── services/ 80+ service modules (combos, fallback, quotas, identity, …) @@ -441,7 +441,7 @@ open-sse/ ### 4.2 `open-sse/executors/` -31 provider executors, each extending `BaseExecutor` (`base.ts`): +38 provider executors, each extending `BaseExecutor` (`base.ts`): `antigravity`, `azure-openai`, `blackbox-web`, `chatgpt-web`, `cliproxyapi`, `cloudflare-ai`, `codex`, `commandCode`, `cursor`, `default`, `devin-cli`, diff --git a/src/app/api/gamification/federation/leaderboard/route.ts b/src/app/api/gamification/federation/leaderboard/route.ts index 7092855955..a66c37a7a0 100644 --- a/src/app/api/gamification/federation/leaderboard/route.ts +++ b/src/app/api/gamification/federation/leaderboard/route.ts @@ -1,6 +1,7 @@ import { NextRequest, NextResponse } from "next/server"; import { CORS_HEADERS, handleCorsOptions } from "@/shared/utils/cors"; import { type LeaderboardScope, getTopN } from "@/lib/gamification/leaderboard"; +import crypto from "crypto"; export async function OPTIONS() { return handleCorsOptions(); @@ -22,8 +23,9 @@ export async function GET(request: NextRequest) { } const token = authHeader.slice(7); - const crypto = await import("crypto"); - const tokenHash = crypto.createHash("sha256").update(token).digest("hex"); + const tokenHash = crypto + .pbkdf2Sync(token, "omniroute-federation-salt", 1000, 32, "sha256") + .toString("hex"); const { getDbInstance } = await import("@/lib/db/core"); const db = getDbInstance(); const server = db diff --git a/src/app/api/gamification/federation/score/route.ts b/src/app/api/gamification/federation/score/route.ts index e72cef5064..2351d09459 100644 --- a/src/app/api/gamification/federation/score/route.ts +++ b/src/app/api/gamification/federation/score/route.ts @@ -2,6 +2,7 @@ import { NextRequest, NextResponse } from "next/server"; import { CORS_HEADERS, handleCorsOptions } from "@/shared/utils/cors"; import { updateScore } from "@/lib/gamification/leaderboard"; import { z } from "zod"; +import crypto from "crypto"; export async function OPTIONS() { return handleCorsOptions(); @@ -19,10 +20,10 @@ export async function POST(request: NextRequest) { ); } - // Validate token against connected community servers const token = authHeader.slice(7); - const crypto = await import("crypto"); - const tokenHash = crypto.createHash("sha256").update(token).digest("hex"); + const tokenHash = crypto + .pbkdf2Sync(token, "omniroute-federation-salt", 1000, 32, "sha256") + .toString("hex"); const { getDbInstance } = await import("@/lib/db/core"); const db = getDbInstance(); const server = db diff --git a/src/lib/gamification/invites.ts b/src/lib/gamification/invites.ts index a98d4a5dd1..b99dc9ad6a 100644 --- a/src/lib/gamification/invites.ts +++ b/src/lib/gamification/invites.ts @@ -12,9 +12,8 @@ import crypto from "crypto"; function generateInviteCode(): string { const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; let code = ""; - const bytes = crypto.randomBytes(8); for (let i = 0; i < 8; i++) { - code += chars[bytes[i] % chars.length]; + code += chars[crypto.randomInt(0, chars.length)]; } return code; } diff --git a/src/lib/gamification/servers.ts b/src/lib/gamification/servers.ts index 79cbe9603a..7fa1024908 100644 --- a/src/lib/gamification/servers.ts +++ b/src/lib/gamification/servers.ts @@ -24,7 +24,9 @@ export async function connectServer( apiKey: string ): Promise { const id = crypto.randomUUID(); - const apiKeyHash = crypto.createHash("sha256").update(apiKey).digest("hex"); + const apiKeyHash = crypto + .pbkdf2Sync(apiKey, "omniroute-federation-salt", 1000, 32, "sha256") + .toString("hex"); const { connectServer: dbConnect } = await import("../db/gamification"); dbConnect(id, name, url, apiKeyHash); diff --git a/tests/unit/autocombo-unification.test.ts b/tests/unit/autocombo-unification.test.ts index a242f83628..8d6ea937a4 100644 --- a/tests/unit/autocombo-unification.test.ts +++ b/tests/unit/autocombo-unification.test.ts @@ -136,14 +136,15 @@ test("intelligent combo selection defaults only inside the intelligent filter", test("sidebar visibility excludes the removed auto-combo item", async () => { const sidebarVisibility = await import("../../src/shared/constants/sidebarVisibility.ts"); - const primarySection = sidebarVisibility.SIDEBAR_SECTIONS.find( - (section) => section.id === "primary" + const omniProxySection = sidebarVisibility.SIDEBAR_SECTIONS.find( + (section) => section.id === "omni-proxy" ); assert.equal(sidebarVisibility.HIDEABLE_SIDEBAR_ITEM_IDS.includes("auto-combo"), false); - assert.ok(primarySection); + assert.ok(omniProxySection); + const items = sidebarVisibility.getSectionItems(omniProxySection); assert.equal( - primarySection.items.some((item) => item.id === "auto-combo"), + items.some((item) => item.id === "auto-combo"), false ); assert.deepEqual(sidebarVisibility.normalizeHiddenSidebarItems(["auto-combo", "home"]), ["home"]);