mirror of
https://github.com/felipegcoutinho/openmonetis.git
synced 2026-05-09 11:01:45 +00:00
fix(segurança): endurecer autenticação e rotas privadas
This commit is contained in:
@@ -5,6 +5,10 @@ import { getUserId } from "@/shared/lib/auth/server";
|
||||
import { db } from "@/shared/lib/db";
|
||||
import { createPresignedGetUrl } from "@/shared/lib/storage/presign";
|
||||
|
||||
const PRIVATE_RESPONSE_HEADERS = {
|
||||
"Cache-Control": "private, no-store",
|
||||
};
|
||||
|
||||
export async function GET(
|
||||
_request: Request,
|
||||
{ params }: { params: Promise<{ attachmentId: string }> },
|
||||
@@ -19,9 +23,20 @@ export async function GET(
|
||||
);
|
||||
|
||||
if (!row) {
|
||||
return NextResponse.json({ error: "Not found" }, { status: 404 });
|
||||
return NextResponse.json(
|
||||
{ error: "Not found" },
|
||||
{
|
||||
status: 404,
|
||||
headers: PRIVATE_RESPONSE_HEADERS,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
const url = await createPresignedGetUrl(row.fileKey);
|
||||
return NextResponse.json({ url });
|
||||
return NextResponse.json(
|
||||
{ url },
|
||||
{
|
||||
headers: PRIVATE_RESPONSE_HEADERS,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { headers } from "next/headers";
|
||||
import { NextResponse } from "next/server";
|
||||
import { connection, NextResponse } from "next/server";
|
||||
import { z } from "zod";
|
||||
import { apiTokens } from "@/db/schema";
|
||||
import {
|
||||
@@ -16,14 +16,17 @@ const createTokenSchema = z.object({
|
||||
});
|
||||
|
||||
export async function POST(request: Request) {
|
||||
await connection();
|
||||
|
||||
// Verificar autenticação via sessão web
|
||||
const requestHeaders = new Headers(await headers());
|
||||
const session = await auth.api.getSession({ headers: requestHeaders });
|
||||
|
||||
if (!session?.user) {
|
||||
return NextResponse.json({ error: "Não autenticado" }, { status: 401 });
|
||||
}
|
||||
|
||||
try {
|
||||
// Verificar autenticação via sessão web
|
||||
const session = await auth.api.getSession({ headers: await headers() });
|
||||
|
||||
if (!session?.user) {
|
||||
return NextResponse.json({ error: "Não autenticado" }, { status: 401 });
|
||||
}
|
||||
|
||||
// Validar body
|
||||
const body = await request.json();
|
||||
const { name, deviceId } = createTokenSchema.parse(body);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { and, eq } from "drizzle-orm";
|
||||
import { headers } from "next/headers";
|
||||
import { NextResponse } from "next/server";
|
||||
import { connection, NextResponse } from "next/server";
|
||||
import { apiTokens } from "@/db/schema";
|
||||
import { auth } from "@/shared/lib/auth/config";
|
||||
import { db } from "@/shared/lib/db";
|
||||
@@ -10,16 +10,19 @@ interface RouteParams {
|
||||
}
|
||||
|
||||
export async function DELETE(_request: Request, { params }: RouteParams) {
|
||||
await connection();
|
||||
|
||||
const { tokenId } = await params;
|
||||
|
||||
// Verificar autenticação via sessão web
|
||||
const requestHeaders = new Headers(await headers());
|
||||
const session = await auth.api.getSession({ headers: requestHeaders });
|
||||
|
||||
if (!session?.user) {
|
||||
return NextResponse.json({ error: "Não autenticado" }, { status: 401 });
|
||||
}
|
||||
|
||||
try {
|
||||
const { tokenId } = await params;
|
||||
|
||||
// Verificar autenticação via sessão web
|
||||
const session = await auth.api.getSession({ headers: await headers() });
|
||||
|
||||
if (!session?.user) {
|
||||
return NextResponse.json({ error: "Não autenticado" }, { status: 401 });
|
||||
}
|
||||
|
||||
// Verificar se token pertence ao usuário
|
||||
const token = await db.query.apiTokens.findFirst({
|
||||
where: and(
|
||||
|
||||
@@ -1,19 +1,22 @@
|
||||
import { and, desc, eq, isNull } from "drizzle-orm";
|
||||
import { headers } from "next/headers";
|
||||
import { NextResponse } from "next/server";
|
||||
import { connection, NextResponse } from "next/server";
|
||||
import { apiTokens } from "@/db/schema";
|
||||
import { auth } from "@/shared/lib/auth/config";
|
||||
import { db } from "@/shared/lib/db";
|
||||
|
||||
export async function GET() {
|
||||
await connection();
|
||||
|
||||
// Verificar autenticação via sessão web
|
||||
const requestHeaders = new Headers(await headers());
|
||||
const session = await auth.api.getSession({ headers: requestHeaders });
|
||||
|
||||
if (!session?.user) {
|
||||
return NextResponse.json({ error: "Não autenticado" }, { status: 401 });
|
||||
}
|
||||
|
||||
try {
|
||||
// Verificar autenticação via sessão web
|
||||
const session = await auth.api.getSession({ headers: await headers() });
|
||||
|
||||
if (!session?.user) {
|
||||
return NextResponse.json({ error: "Não autenticado" }, { status: 401 });
|
||||
}
|
||||
|
||||
// Buscar tokens ativos do usuário
|
||||
const activeTokens = await db
|
||||
.select({
|
||||
|
||||
34
src/app/api/insights/saved/route.ts
Normal file
34
src/app/api/insights/saved/route.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import { NextResponse } from "next/server";
|
||||
import {
|
||||
fetchSavedInsights,
|
||||
savedInsightsPeriodSchema,
|
||||
} from "@/features/insights/queries";
|
||||
import { getUserId } from "@/shared/lib/auth/server";
|
||||
|
||||
const PRIVATE_RESPONSE_HEADERS = {
|
||||
"Cache-Control": "private, no-store",
|
||||
};
|
||||
|
||||
export async function GET(request: Request) {
|
||||
const period = new URL(request.url).searchParams.get("period") ?? "";
|
||||
const validatedPeriod = savedInsightsPeriodSchema.safeParse(period);
|
||||
|
||||
if (!validatedPeriod.success) {
|
||||
return NextResponse.json(
|
||||
{
|
||||
error: validatedPeriod.error.issues[0]?.message ?? "Período inválido.",
|
||||
},
|
||||
{
|
||||
status: 400,
|
||||
headers: PRIVATE_RESPONSE_HEADERS,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
const userId = await getUserId();
|
||||
const insights = await fetchSavedInsights(userId, validatedPeriod.data);
|
||||
|
||||
return NextResponse.json(insights, {
|
||||
headers: PRIVATE_RESPONSE_HEADERS,
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
import { NextResponse } from "next/server";
|
||||
import { fetchTransactionAttachments } from "@/features/transactions/attachment-queries";
|
||||
import { getUserId } from "@/shared/lib/auth/server";
|
||||
|
||||
const PRIVATE_RESPONSE_HEADERS = {
|
||||
"Cache-Control": "private, no-store",
|
||||
};
|
||||
|
||||
export async function GET(
|
||||
_request: Request,
|
||||
{ params }: { params: Promise<{ transactionId: string }> },
|
||||
) {
|
||||
const [userId, { transactionId }] = await Promise.all([getUserId(), params]);
|
||||
const attachments = await fetchTransactionAttachments(userId, transactionId);
|
||||
|
||||
return NextResponse.json(attachments, {
|
||||
headers: PRIVATE_RESPONSE_HEADERS,
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
import { NextResponse } from "next/server";
|
||||
import { fetchInstallmentAnticipations } from "@/features/transactions/anticipation-queries";
|
||||
import { getUserId } from "@/shared/lib/auth/server";
|
||||
|
||||
const PRIVATE_RESPONSE_HEADERS = {
|
||||
"Cache-Control": "private, no-store",
|
||||
};
|
||||
|
||||
export async function GET(
|
||||
_request: Request,
|
||||
{ params }: { params: Promise<{ seriesId: string }> },
|
||||
) {
|
||||
try {
|
||||
const [userId, { seriesId }] = await Promise.all([getUserId(), params]);
|
||||
const anticipations = await fetchInstallmentAnticipations(userId, seriesId);
|
||||
|
||||
return NextResponse.json(anticipations, {
|
||||
headers: PRIVATE_RESPONSE_HEADERS,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("Erro ao carregar histórico de antecipações:", error);
|
||||
|
||||
return NextResponse.json(
|
||||
{
|
||||
error: "Erro ao carregar histórico de antecipações.",
|
||||
},
|
||||
{
|
||||
status: 400,
|
||||
headers: PRIVATE_RESPONSE_HEADERS,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user