mirror of
https://github.com/KeygraphHQ/shannon.git
synced 2026-08-24 04:02:35 +02:00
refactor: migrate to Turborepo + pnpm + Biome monorepo
Restructure into apps/worker, apps/cli, packages/mcp-server with Turborepo task orchestration, pnpm workspaces, Biome linting/formatting, and tsdown CLI bundling. Key changes: - src/ -> apps/worker/src/, cli/ -> apps/cli/, mcp-server/ -> packages/mcp-server/ - prompts/ and configs/ moved into apps/worker/ - npm replaced with pnpm, package-lock.json replaced with pnpm-lock.yaml - Dockerfile updated for pnpm-based builds - CLI logs command rewritten with chokidar for cross-platform reliability - Router health checking added for auto-detected router mode - Centralized path resolution via apps/worker/src/paths.ts
This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
// Copyright (C) 2025 Keygraph, Inc.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License version 3
|
||||
// as published by the Free Software Foundation.
|
||||
|
||||
/**
|
||||
* Queue Validator
|
||||
*
|
||||
* Validates JSON structure for vulnerability queue files.
|
||||
* Ported from tools/save_deliverable.js (lines 56-75).
|
||||
*/
|
||||
|
||||
import type { VulnerabilityQueue } from '../types/deliverables.js';
|
||||
|
||||
export interface ValidationResult {
|
||||
valid: boolean;
|
||||
message?: string;
|
||||
data?: VulnerabilityQueue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate JSON structure for queue files
|
||||
* Queue files must have a 'vulnerabilities' array
|
||||
*/
|
||||
export function validateQueueJson(content: string): ValidationResult {
|
||||
try {
|
||||
const parsed = JSON.parse(content) as unknown;
|
||||
|
||||
// Type guard for the parsed result
|
||||
if (typeof parsed !== 'object' || parsed === null) {
|
||||
return {
|
||||
valid: false,
|
||||
message: `Invalid queue structure: Expected an object. Got: ${typeof parsed}`,
|
||||
};
|
||||
}
|
||||
|
||||
const obj = parsed as Record<string, unknown>;
|
||||
|
||||
// Queue files must have a 'vulnerabilities' array
|
||||
if (!('vulnerabilities' in obj)) {
|
||||
return {
|
||||
valid: false,
|
||||
message: `Invalid queue structure: Missing 'vulnerabilities' property. Expected: {"vulnerabilities": [...]}`,
|
||||
};
|
||||
}
|
||||
|
||||
if (!Array.isArray(obj.vulnerabilities)) {
|
||||
return {
|
||||
valid: false,
|
||||
message: `Invalid queue structure: 'vulnerabilities' must be an array. Expected: {"vulnerabilities": [...]}`,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
valid: true,
|
||||
data: parsed as VulnerabilityQueue,
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
valid: false,
|
||||
message: `Invalid JSON: ${error instanceof Error ? error.message : String(error)}`,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
// Copyright (C) 2025 Keygraph, Inc.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License version 3
|
||||
// as published by the Free Software Foundation.
|
||||
|
||||
/**
|
||||
* TOTP Validator
|
||||
*
|
||||
* Validates TOTP secrets and provides base32 decoding.
|
||||
* Ported from tools/generate-totp-standalone.mjs (lines 43-72).
|
||||
*/
|
||||
|
||||
/**
|
||||
* Base32 decode function
|
||||
* Ported from generate-totp-standalone.mjs
|
||||
*/
|
||||
export function base32Decode(encoded: string): Buffer {
|
||||
const alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567';
|
||||
const cleanInput = encoded.toUpperCase().replace(/[^A-Z2-7]/g, '');
|
||||
|
||||
if (cleanInput.length === 0) {
|
||||
return Buffer.alloc(0);
|
||||
}
|
||||
|
||||
const output: number[] = [];
|
||||
let bits = 0;
|
||||
let value = 0;
|
||||
|
||||
for (const char of cleanInput) {
|
||||
const index = alphabet.indexOf(char);
|
||||
if (index === -1) {
|
||||
throw new Error(`Invalid base32 character: ${char}`);
|
||||
}
|
||||
|
||||
value = (value << 5) | index;
|
||||
bits += 5;
|
||||
|
||||
if (bits >= 8) {
|
||||
output.push((value >>> (bits - 8)) & 255);
|
||||
bits -= 8;
|
||||
}
|
||||
}
|
||||
|
||||
return Buffer.from(output);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate TOTP secret
|
||||
* Must be base32-encoded string
|
||||
*
|
||||
* @returns true if valid, throws Error if invalid
|
||||
*/
|
||||
export function validateTotpSecret(secret: string): boolean {
|
||||
if (!secret || secret.length === 0) {
|
||||
throw new Error('TOTP secret cannot be empty');
|
||||
}
|
||||
|
||||
// Check if it's valid base32 (only A-Z and 2-7, case-insensitive)
|
||||
const base32Regex = /^[A-Z2-7]+$/i;
|
||||
if (!base32Regex.test(secret.replace(/[^A-Z2-7]/gi, ''))) {
|
||||
throw new Error('TOTP secret must be base32-encoded (characters A-Z and 2-7)');
|
||||
}
|
||||
|
||||
// Try to decode to ensure it's valid
|
||||
try {
|
||||
base32Decode(secret);
|
||||
} catch (error) {
|
||||
throw new Error(`Invalid TOTP secret: ${error instanceof Error ? error.message : String(error)}`);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
Reference in New Issue
Block a user