fix: add parseInt(value, 10) with isNaN() guards to all integer query param parsing
- Add radix 10 to all parseInt() calls parsing integer query/path parameters - Add isNaN() guards returning HTTP 400 with descriptive error messages - Updated routes: annotations, candles, export, export/spans, annotation-types/[id], span-annotations, span-annotations/[id], span-label-types/[id] - Ensures strict integer parsing and prevents invalid parameter values from reaching database queries
This commit is contained in:
parent
1678da2d9d
commit
15adf09b73
9 changed files with 124 additions and 17 deletions
|
|
@ -14,6 +14,15 @@ export async function PATCH(
|
|||
) {
|
||||
try {
|
||||
const { id } = await context.params;
|
||||
const idNum = parseInt(id, 10);
|
||||
|
||||
if (isNaN(idNum)) {
|
||||
return NextResponse.json(
|
||||
{ error: 'Invalid parameter: id must be an integer' },
|
||||
{ status: 400 }
|
||||
);
|
||||
}
|
||||
|
||||
const body = await request.json();
|
||||
|
||||
const { name, display_name, color, category, icon, is_active } = body;
|
||||
|
|
@ -36,7 +45,7 @@ export async function PATCH(
|
|||
const result = await db
|
||||
.update(annotationTypes)
|
||||
.set(updateData)
|
||||
.where(eq(annotationTypes.id, parseInt(id)))
|
||||
.where(eq(annotationTypes.id, idNum))
|
||||
.returning();
|
||||
|
||||
if (result.length === 0) {
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ export async function PATCH(
|
|||
) {
|
||||
try {
|
||||
const { id: idParam } = await params;
|
||||
const id = parseInt(idParam);
|
||||
const id = parseInt(idParam, 10);
|
||||
|
||||
if (isNaN(id)) {
|
||||
return NextResponse.json(
|
||||
|
|
@ -57,7 +57,7 @@ export async function DELETE(
|
|||
) {
|
||||
try {
|
||||
const { id: idParam } = await params;
|
||||
const id = parseInt(idParam);
|
||||
const id = parseInt(idParam, 10);
|
||||
|
||||
if (isNaN(id)) {
|
||||
return NextResponse.json(
|
||||
|
|
|
|||
|
|
@ -18,10 +18,18 @@ export async function GET(request: NextRequest) {
|
|||
chartId = String(latest[0].id);
|
||||
}
|
||||
|
||||
const chartIdNum = parseInt(chartId, 10);
|
||||
if (isNaN(chartIdNum)) {
|
||||
return NextResponse.json(
|
||||
{ error: 'Invalid parameter: chartId must be an integer' },
|
||||
{ status: 400 }
|
||||
);
|
||||
}
|
||||
|
||||
const allAnnotations = await db
|
||||
.select()
|
||||
.from(annotations)
|
||||
.where(eq(annotations.chart_id, parseInt(chartId, 10)));
|
||||
.where(eq(annotations.chart_id, chartIdNum));
|
||||
|
||||
const normalized = allAnnotations.map((a) => ({
|
||||
...a,
|
||||
|
|
@ -108,13 +116,27 @@ export async function DELETE(request: NextRequest) {
|
|||
{ status: 400 }
|
||||
);
|
||||
}
|
||||
result = await db.delete(annotations).where(eq(annotations.chart_id, parseInt(chartId, 10))).returning();
|
||||
const chartIdNum = parseInt(chartId, 10);
|
||||
if (isNaN(chartIdNum)) {
|
||||
return NextResponse.json(
|
||||
{ error: 'Invalid parameter: chartId must be an integer' },
|
||||
{ status: 400 }
|
||||
);
|
||||
}
|
||||
result = await db.delete(annotations).where(eq(annotations.chart_id, chartIdNum)).returning();
|
||||
} else if (type) {
|
||||
const types = type.split(',').map((t) => t.trim());
|
||||
if (chartId) {
|
||||
const chartIdNum = parseInt(chartId, 10);
|
||||
if (isNaN(chartIdNum)) {
|
||||
return NextResponse.json(
|
||||
{ error: 'Invalid parameter: chartId must be an integer' },
|
||||
{ status: 400 }
|
||||
);
|
||||
}
|
||||
result = await db
|
||||
.delete(annotations)
|
||||
.where(and(inArray(annotations.label_type, types), eq(annotations.chart_id, parseInt(chartId, 10))))
|
||||
.where(and(inArray(annotations.label_type, types), eq(annotations.chart_id, chartIdNum)))
|
||||
.returning();
|
||||
} else {
|
||||
result = await db
|
||||
|
|
|
|||
|
|
@ -17,6 +17,14 @@ export async function GET(request: NextRequest) {
|
|||
chartId = String(latest[0].id);
|
||||
}
|
||||
|
||||
const chartIdNum = parseInt(chartId, 10);
|
||||
if (isNaN(chartIdNum)) {
|
||||
return NextResponse.json(
|
||||
{ error: 'Invalid parameter: chartId must be an integer' },
|
||||
{ status: 400 }
|
||||
);
|
||||
}
|
||||
|
||||
const allCandles = await db
|
||||
.select({
|
||||
time: candles.time,
|
||||
|
|
@ -26,7 +34,7 @@ export async function GET(request: NextRequest) {
|
|||
close: candles.close,
|
||||
})
|
||||
.from(candles)
|
||||
.where(eq(candles.chart_id, parseInt(chartId, 10)))
|
||||
.where(eq(candles.chart_id, chartIdNum))
|
||||
.orderBy(asc(candles.time));
|
||||
|
||||
const normalized = allCandles.map((c) => ({
|
||||
|
|
|
|||
|
|
@ -23,6 +23,13 @@ export async function GET(request: NextRequest) {
|
|||
}
|
||||
|
||||
const chartIdNum = parseInt(chartId, 10);
|
||||
if (isNaN(chartIdNum)) {
|
||||
return NextResponse.json(
|
||||
{ error: 'Invalid parameter: chartId must be an integer' },
|
||||
{ status: 400 }
|
||||
);
|
||||
}
|
||||
|
||||
const allAnnotations = await db
|
||||
.select()
|
||||
.from(annotations)
|
||||
|
|
|
|||
|
|
@ -19,6 +19,19 @@ export async function GET(request: NextRequest) {
|
|||
}
|
||||
|
||||
const chartIdNum = parseInt(chartId, 10);
|
||||
if (isNaN(chartIdNum)) {
|
||||
return NextResponse.json(
|
||||
{ error: 'Invalid parameter: chartId must be an integer' },
|
||||
{ status: 400 }
|
||||
);
|
||||
}
|
||||
|
||||
if (isNaN(contextPadding)) {
|
||||
return NextResponse.json(
|
||||
{ error: 'Invalid parameter: context_padding must be an integer' },
|
||||
{ status: 400 }
|
||||
);
|
||||
}
|
||||
|
||||
// Fetch span annotations for the chart
|
||||
const spans = await db
|
||||
|
|
|
|||
|
|
@ -10,6 +10,15 @@ export async function PATCH(
|
|||
) {
|
||||
try {
|
||||
const { id } = await params;
|
||||
const idNum = parseInt(id, 10);
|
||||
|
||||
if (isNaN(idNum)) {
|
||||
return NextResponse.json(
|
||||
{ error: 'Invalid parameter: id must be an integer' },
|
||||
{ status: 400 }
|
||||
);
|
||||
}
|
||||
|
||||
const body = await request.json();
|
||||
|
||||
const { label, confidence, outcome, notes, sub_spans } = body;
|
||||
|
|
@ -18,7 +27,7 @@ export async function PATCH(
|
|||
const existing = await db
|
||||
.select()
|
||||
.from(spanAnnotations)
|
||||
.where(eq(spanAnnotations.id, parseInt(id)))
|
||||
.where(eq(spanAnnotations.id, idNum))
|
||||
.limit(1);
|
||||
|
||||
if (existing.length === 0) {
|
||||
|
|
@ -39,7 +48,7 @@ export async function PATCH(
|
|||
const result = await db
|
||||
.update(spanAnnotations)
|
||||
.set(updates)
|
||||
.where(eq(spanAnnotations.id, parseInt(id)))
|
||||
.where(eq(spanAnnotations.id, idNum))
|
||||
.returning();
|
||||
|
||||
const s = result[0];
|
||||
|
|
@ -65,12 +74,20 @@ export async function DELETE(
|
|||
) {
|
||||
try {
|
||||
const { id } = await params;
|
||||
const idNum = parseInt(id, 10);
|
||||
|
||||
if (isNaN(idNum)) {
|
||||
return NextResponse.json(
|
||||
{ error: 'Invalid parameter: id must be an integer' },
|
||||
{ status: 400 }
|
||||
);
|
||||
}
|
||||
|
||||
// Check if the span exists
|
||||
const existing = await db
|
||||
.select()
|
||||
.from(spanAnnotations)
|
||||
.where(eq(spanAnnotations.id, parseInt(id)))
|
||||
.where(eq(spanAnnotations.id, idNum))
|
||||
.limit(1);
|
||||
|
||||
if (existing.length === 0) {
|
||||
|
|
@ -80,7 +97,7 @@ export async function DELETE(
|
|||
);
|
||||
}
|
||||
|
||||
await db.delete(spanAnnotations).where(eq(spanAnnotations.id, parseInt(id)));
|
||||
await db.delete(spanAnnotations).where(eq(spanAnnotations.id, idNum));
|
||||
|
||||
return NextResponse.json({ message: 'Span annotation deleted successfully' });
|
||||
} catch (error) {
|
||||
|
|
|
|||
|
|
@ -16,10 +16,18 @@ export async function GET(request: NextRequest) {
|
|||
);
|
||||
}
|
||||
|
||||
const chartIdNum = parseInt(chartId, 10);
|
||||
if (isNaN(chartIdNum)) {
|
||||
return NextResponse.json(
|
||||
{ error: 'Invalid parameter: chartId must be an integer' },
|
||||
{ status: 400 }
|
||||
);
|
||||
}
|
||||
|
||||
const spans = await db
|
||||
.select()
|
||||
.from(spanAnnotations)
|
||||
.where(eq(spanAnnotations.chart_id, parseInt(chartId)))
|
||||
.where(eq(spanAnnotations.chart_id, chartIdNum))
|
||||
.orderBy(desc(spanAnnotations.start_time));
|
||||
|
||||
const normalized = spans.map((s) => ({
|
||||
|
|
@ -116,7 +124,13 @@ export async function DELETE(request: NextRequest) {
|
|||
);
|
||||
}
|
||||
|
||||
const chartIdInt = parseInt(chartId);
|
||||
const chartIdInt = parseInt(chartId, 10);
|
||||
if (isNaN(chartIdInt)) {
|
||||
return NextResponse.json(
|
||||
{ error: 'Invalid parameter: chartId must be an integer' },
|
||||
{ status: 400 }
|
||||
);
|
||||
}
|
||||
|
||||
// Build filter conditions
|
||||
const conditions = [eq(spanAnnotations.chart_id, chartIdInt)];
|
||||
|
|
|
|||
|
|
@ -10,6 +10,15 @@ export async function PATCH(
|
|||
) {
|
||||
try {
|
||||
const { id } = await params;
|
||||
const idNum = parseInt(id, 10);
|
||||
|
||||
if (isNaN(idNum)) {
|
||||
return NextResponse.json(
|
||||
{ error: 'Invalid parameter: id must be an integer' },
|
||||
{ status: 400 }
|
||||
);
|
||||
}
|
||||
|
||||
const body = await request.json();
|
||||
|
||||
const { name, display_name, color, hotkey, is_active, sort_order } = body;
|
||||
|
|
@ -18,7 +27,7 @@ export async function PATCH(
|
|||
const existing = await db
|
||||
.select()
|
||||
.from(spanLabelTypes)
|
||||
.where(eq(spanLabelTypes.id, parseInt(id)))
|
||||
.where(eq(spanLabelTypes.id, idNum))
|
||||
.limit(1);
|
||||
|
||||
if (existing.length === 0) {
|
||||
|
|
@ -40,7 +49,7 @@ export async function PATCH(
|
|||
const result = await db
|
||||
.update(spanLabelTypes)
|
||||
.set(updates)
|
||||
.where(eq(spanLabelTypes.id, parseInt(id)))
|
||||
.where(eq(spanLabelTypes.id, idNum))
|
||||
.returning();
|
||||
|
||||
return NextResponse.json(result[0]);
|
||||
|
|
@ -68,12 +77,20 @@ export async function DELETE(
|
|||
) {
|
||||
try {
|
||||
const { id } = await params;
|
||||
const idNum = parseInt(id, 10);
|
||||
|
||||
if (isNaN(idNum)) {
|
||||
return NextResponse.json(
|
||||
{ error: 'Invalid parameter: id must be an integer' },
|
||||
{ status: 400 }
|
||||
);
|
||||
}
|
||||
|
||||
// Check if the type exists
|
||||
const type = await db
|
||||
.select()
|
||||
.from(spanLabelTypes)
|
||||
.where(eq(spanLabelTypes.id, parseInt(id)))
|
||||
.where(eq(spanLabelTypes.id, idNum))
|
||||
.limit(1);
|
||||
|
||||
if (type.length === 0) {
|
||||
|
|
@ -97,7 +114,7 @@ export async function DELETE(
|
|||
);
|
||||
}
|
||||
|
||||
await db.delete(spanLabelTypes).where(eq(spanLabelTypes.id, parseInt(id)));
|
||||
await db.delete(spanLabelTypes).where(eq(spanLabelTypes.id, idNum));
|
||||
|
||||
return NextResponse.json({ message: 'Span label type deleted successfully' });
|
||||
} catch (error) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue