mirror of
https://github.com/praveentcom/openproxy.git
synced 2026-02-12 14:02:46 +00:00
Fix multiple small bugs for security and robustness
- Add input validation for hours and limit query parameters to prevent NaN and DoS attacks - Replace || with ?? for proper null coalescing in metrics summary - Fix IPv6 normalization to prevent empty string when IP is malformed - Fix stream parsing to skip empty JSON strings and avoid parse errors - Remove redundant .toString() calls on authorization header
This commit is contained in:
@@ -13,8 +13,14 @@ const validatedTableName = ALLOWED_TABLES.includes(TABLE_NAME) ? TABLE_NAME : 'l
|
|||||||
|
|
||||||
export async function GET(request: NextRequest) {
|
export async function GET(request: NextRequest) {
|
||||||
const { searchParams } = new URL(request.url);
|
const { searchParams } = new URL(request.url);
|
||||||
const hours = parseInt(searchParams.get('hours') || '24', 10);
|
|
||||||
const limit = parseInt(searchParams.get('limit') || '100', 10);
|
// Validate and sanitize hours parameter
|
||||||
|
const hoursParam = parseInt(searchParams.get('hours') || '24', 10);
|
||||||
|
const hours = !isNaN(hoursParam) && hoursParam > 0 && hoursParam <= 720 ? hoursParam : 24;
|
||||||
|
|
||||||
|
// Validate and sanitize limit parameter
|
||||||
|
const limitParam = parseInt(searchParams.get('limit') || '100', 10);
|
||||||
|
const limit = !isNaN(limitParam) && limitParam > 0 && limitParam <= 1000 ? limitParam : 100;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const client = await pool.connect();
|
const client = await pool.connect();
|
||||||
@@ -93,12 +99,12 @@ export async function GET(request: NextRequest) {
|
|||||||
success: true,
|
success: true,
|
||||||
data: {
|
data: {
|
||||||
summary: {
|
summary: {
|
||||||
totalRequests: parseInt(summary.total_requests || '0'),
|
totalRequests: parseInt(summary.total_requests ?? '0'),
|
||||||
totalTokens: parseInt(summary.total_tokens_used || '0'),
|
totalTokens: parseInt(summary.total_tokens_used ?? '0'),
|
||||||
totalCost: parseFloat(summary.total_cost || '0'),
|
totalCost: parseFloat(summary.total_cost ?? '0'),
|
||||||
avgResponseTime: parseFloat(summary.avg_response_time || '0'),
|
avgResponseTime: parseFloat(summary.avg_response_time ?? '0'),
|
||||||
uniqueModels: parseInt(summary.unique_models || '0'),
|
uniqueModels: parseInt(summary.unique_models ?? '0'),
|
||||||
uniqueClients: parseInt(summary.unique_clients || '0'),
|
uniqueClients: parseInt(summary.unique_clients ?? '0'),
|
||||||
},
|
},
|
||||||
recentRequests,
|
recentRequests,
|
||||||
modelBreakdown,
|
modelBreakdown,
|
||||||
|
|||||||
8
proxy.ts
8
proxy.ts
@@ -33,7 +33,7 @@ function generateRequestId(): string {
|
|||||||
function normalizeIp(ip: string | null | undefined): string | null {
|
function normalizeIp(ip: string | null | undefined): string | null {
|
||||||
if (!ip) return null;
|
if (!ip) return null;
|
||||||
// Handle IPv6-mapped IPv4 addresses (::ffff:x.x.x.x)
|
// Handle IPv6-mapped IPv4 addresses (::ffff:x.x.x.x)
|
||||||
if (ip.startsWith('::ffff:')) {
|
if (ip.startsWith('::ffff:') && ip.length > 7) {
|
||||||
return ip.substring(7);
|
return ip.substring(7);
|
||||||
}
|
}
|
||||||
return ip;
|
return ip;
|
||||||
@@ -92,7 +92,7 @@ const server = http.createServer(async (req, res) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const auth = req.headers["authorization"];
|
const auth = req.headers["authorization"];
|
||||||
if (!auth?.toString().startsWith("Bearer ")) {
|
if (!auth?.startsWith("Bearer ")) {
|
||||||
res.statusCode = 401;
|
res.statusCode = 401;
|
||||||
res.end(JSON.stringify({ error: "Missing or invalid Authorization header" }));
|
res.end(JSON.stringify({ error: "Missing or invalid Authorization header" }));
|
||||||
return;
|
return;
|
||||||
@@ -109,7 +109,7 @@ const server = http.createServer(async (req, res) => {
|
|||||||
method,
|
method,
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": (req.headers["content-type"] as string) || "application/json",
|
"Content-Type": (req.headers["content-type"] as string) || "application/json",
|
||||||
Authorization: auth.toString(),
|
Authorization: auth,
|
||||||
},
|
},
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
duplex: "half",
|
duplex: "half",
|
||||||
@@ -156,7 +156,7 @@ const server = http.createServer(async (req, res) => {
|
|||||||
for (const line of lines) {
|
for (const line of lines) {
|
||||||
if (!line.startsWith("data:")) continue;
|
if (!line.startsWith("data:")) continue;
|
||||||
const jsonStr = line.slice(5).trim();
|
const jsonStr = line.slice(5).trim();
|
||||||
if (jsonStr === "[DONE]") continue;
|
if (jsonStr === "[DONE]" || jsonStr === "") continue;
|
||||||
try {
|
try {
|
||||||
const obj = JSON.parse(jsonStr);
|
const obj = JSON.parse(jsonStr);
|
||||||
if (obj.usage) usageFromStream = obj.usage;
|
if (obj.usage) usageFromStream = obj.usage;
|
||||||
|
|||||||
Reference in New Issue
Block a user