feat: add boss key

This commit is contained in:
Draculabo authored and vin committed 2026-01-10 01:07:09 +08:00
1 parent e7087bc4b1
commit bc775d4fd6
10 files changed
+168 -6

No files matched your search

+7 -1
View File
@@ -4,15 +4,21 @@ import { AppModule } from './app.module';
import { logger } from '../utils/logger';
import { TokenManagerService } from './modules/proxy/token-manager.service';
import { ProxyConfig } from '../types/config';
import { setServerConfig } from './server-config';
let app: NestFastifyApplication | null = null;
let currentPort: number = 0;
export async function bootstrapNestServer(port: number = 8045): Promise<boolean> {
export async function bootstrapNestServer(config: ProxyConfig): Promise<boolean> {
const port = config.port || 8045;
if (app) {
logger.info('NestJS server already running.');
return true;
}
setServerConfig(config);
try {
app = await NestFactory.create<NestFastifyApplication>(AppModule, new FastifyAdapter(), {
logger: ['error', 'warn', 'log'],
+3 -1
View File
@@ -1,10 +1,12 @@
import { Controller, Get, Post, Body, Res, HttpStatus } from '@nestjs/common';
import { Controller, Get, Post, Body, Res, HttpStatus, UseGuards } from '@nestjs/common';
import { FastifyReply } from 'fastify';
import { ProxyService } from './proxy.service';
import { Observable } from 'rxjs';
import { OpenAIChatRequest, AnthropicChatRequest } from './interfaces/request-interfaces';
import { ProxyGuard } from './proxy.guard';
@Controller('v1')
@UseGuards(ProxyGuard)
export class ProxyController {
constructor(private readonly proxyService: ProxyService) {}
+57
View File
@@ -0,0 +1,57 @@
import {
CanActivate,
ExecutionContext,
Injectable,
UnauthorizedException,
Logger,
} from '@nestjs/common';
import { getServerConfig } from '../../server-config';
@Injectable()
export class ProxyGuard implements CanActivate {
private readonly logger = new Logger(ProxyGuard.name);
canActivate(context: ExecutionContext): boolean {
const config = getServerConfig();
// 1. Check for API Key in config
const apiKey = config?.api_key;
// 2. Bypass if no api_key set (Open Mode) or config missing
if (!apiKey || apiKey.trim() === '') {
return true;
}
const request = context.switchToHttp().getRequest();
const headers = request.headers;
// 3. Extract Token from Headers
let clientToken: string | undefined;
// A. standard 'authorization: Bearer <token>'
if (headers['authorization']) {
const parts = headers['authorization'].split(' ');
if (parts.length === 2 && parts[0].toLowerCase() === 'bearer') {
clientToken = parts[1];
}
}
// B. 'x-api-key' (Anthropic)
if (!clientToken && headers['x-api-key']) {
clientToken = headers['x-api-key'] as string;
}
// C. 'x-goog-api-key' (Gemini)
if (!clientToken && headers['x-goog-api-key']) {
clientToken = headers['x-goog-api-key'] as string;
}
// 4. Validate
if (clientToken === apiKey) {
return true;
}
this.logger.warn(`Blocked unauthorized access from ${request.ip}`);
throw new UnauthorizedException('Invalid API Key');
}
}
+11
View File
@@ -0,0 +1,11 @@
import { ProxyConfig } from '../types/config';
let serverConfig: ProxyConfig | null = null;
export function setServerConfig(config: ProxyConfig) {
serverConfig = config;
}
export function getServerConfig(): ProxyConfig | null {
return serverConfig;
}