fix: refactoring

This commit is contained in:
charlesgauthereau
2026-02-10 19:11:01 +01:00
parent eff7b24b7a
commit 5dfe1b758e
9 changed files with 0 additions and 301 deletions
@@ -1,53 +0,0 @@
import fs from "node:fs";
import forge from "node-forge";
export async function decryptedDump(file: File, aesKeyHex: string, ivHex: string, fileExtension: string): Promise<File> {
const privateKeyPem = fs.readFileSync("private/keys/server_private.pem", "utf8");
const privateKey = forge.pki.privateKeyFromPem(privateKeyPem);
// Decrypt AES key with RSA-OAEP
const encryptedAesKey = forge.util.hexToBytes(aesKeyHex);
const aesKey = privateKey.decrypt(encryptedAesKey, "RSA-OAEP", {
md: forge.md.sha256.create(),
mgf1: {md: forge.md.sha256.create()},
});
// Read encrypted file content
const encryptedBuffer = Buffer.from(await file.arrayBuffer());
const iv = forge.util.hexToBytes(ivHex);
// AES decryption
const decipher = forge.cipher.createDecipher("AES-CBC", aesKey);
decipher.start({iv});
decipher.update(forge.util.createBuffer(encryptedBuffer.toString("binary")));
const success = decipher.finish();
if (!success) {
throw new Error("Decryption failed");
}
const decryptedBytes = decipher.output.getBytes();
const decryptedBuffer = Buffer.from(decryptedBytes, "binary");
// Return a File so you can use file.arrayBuffer() later
return new File(
[decryptedBuffer],
file.name.replace(/\.enc$/, fileExtension),
{type: "application/octet-stream"}
);
}
export function getFileExtension(dbType: string) {
switch (dbType) {
case "postgresql":
return ".dump";
case "mysql":
return ".sql";
default:
return ".dump";
}
}
-169
View File
@@ -1,169 +0,0 @@
import {NextResponse} from "next/server";
import {isUuidv4} from "@/utils/verify-uuid";
import {v4 as uuidv4} from "uuid";
import * as drizzleDb from "@/db";
import {db} from "@/db";
import {Backup} from "@/db/schema/07_database";
import {and, eq} from "drizzle-orm";
import {withUpdatedAt} from "@/db/utils";
import {decryptedDump, getFileExtension} from "./helpers";
import {sendNotificationsBackupRestore} from "@/features/notifications/helpers";
import {storeBackupFiles} from "@/features/storages/helpers";
import {eventEmitter} from "@/features/shared/event";
export async function POST(
request: Request,
{params}: { params: Promise<{ agentId: string }> }
) {
try {
const contentType = request.headers.get("Content-Type");
if (!contentType || !contentType.includes("multipart/form-data")) {
return NextResponse.json(
{error: "Unsupported or missing Content-Type"},
{status: 400}
);
}
eventEmitter.emit('modification', {update: true});
const agentId = (await params).agentId;
const formData = await request.formData();
const aesKeyHex = formData.get("aes_key") as string;
const ivHex = formData.get("iv") as string;
const generatedId = formData.get("generatedId") as string | null;
const method = formData.get("method") as string | null;
if (!generatedId || !isUuidv4(generatedId)) {
return NextResponse.json(
{error: "generatedId is not a valid UUID"},
{status: 400}
);
}
const agent = await db.query.agent.findFirst({
where: eq(drizzleDb.schemas.agent.id, agentId),
});
if (!agent) {
return NextResponse.json(
{error: "Agent not found"},
{status: 404}
);
}
const database = await db.query.database.findFirst({
where: eq(drizzleDb.schemas.database.agentDatabaseId, generatedId),
with: {
project: true,
alertPolicies: true,
storagePolicies: true
}
});
if (!database) {
return NextResponse.json(
{error: "Database associated with generatedId not found"},
{status: 404}
);
}
let backup: Backup | null | undefined = null;
if (method === "automatic") {
[backup] = await db
.insert(drizzleDb.schemas.backup)
.values({
status: 'ongoing',
databaseId: database.id,
})
.returning();
if (!backup) {
return NextResponse.json(
{error: "Unable to create an automatic backup"},
{status: 500}
);
}
} else {
backup = await db.query.backup.findFirst({
where: and(
eq(drizzleDb.schemas.backup.status, 'ongoing'),
eq(drizzleDb.schemas.backup.databaseId, database.id),
),
});
if (!backup) {
return NextResponse.json(
{error: "Unable to find the corresponding backup"},
{status: 404}
);
}
}
const status = formData.get("status") as string | null;
if (status === "success") {
const file = formData.get("file") as File | null;
const extension = formData.get("extension") as string | null;
if (!aesKeyHex || !ivHex) {
return NextResponse.json({error: "Missing fields"}, {status: 400});
}
if (!file) {
return NextResponse.json(
{error: "File is required for successful backup"},
{status: 400}
);
}
const fileSizeBytes = file.size;
// const fileExtension = '.' + (file.name.split('.').pop()?.toLowerCase() || '');
const fileExtension = extension ? extension : getFileExtension(database.dbms)
const decryptedFile = await decryptedDump(file, aesKeyHex, ivHex, fileExtension);
const uuid = uuidv4();
const fileName = `${uuid}${fileExtension}`;
const buffer = Buffer.from(await decryptedFile.arrayBuffer());
const storageResults = await storeBackupFiles(backup, database, buffer, fileName)
eventEmitter.emit('modification', {update: true});
await sendNotificationsBackupRestore(database, "success_backup");
return NextResponse.json(
{
message: "Backup successfully uploaded",
},
{status: 200}
);
} else {
await db
.update(drizzleDb.schemas.backup)
.set(withUpdatedAt({status: 'failed'}))
.where(eq(drizzleDb.schemas.backup.id, backup.id));
eventEmitter.emit('modification', {update: true});
await sendNotificationsBackupRestore(database, "error_backup");
return NextResponse.json(
{
message: "Backup successfully updated with status failed",
},
{status: 200}
);
}
} catch (error) {
console.error("Error in POST handler:", error);
return NextResponse.json(
{error: "Internal server error"},
{status: 500}
);
}
}
-1
View File
@@ -89,7 +89,6 @@ export const PATCH = withAgentCheck(async (request: Request, {params, agent}: {
try {
const body: BodyPatch = await request.json();
console.log(body);
const status = body.status
const backupId = body.backupId
const backupSize = body.size
-4
View File
@@ -7,17 +7,13 @@ export async function POST(request: Request) {
try {
const body = await request.json();
const event = body.Event
console.log(body);
const headers = event.HTTPRequest.Header
const uploadLength = headers["X-File-Size"]?.[0];
const uploadOffset = headers["Upload-Offset"]?.[0];
const status = headers["X-Status"]?.[0];
console.log(headers);
console.log(`Upload ID : ${event.Upload.ID} (${uploadOffset}/${uploadLength})`);
if (status === "success") {
if (
body.Type === "post-receive" &&
-28
View File
@@ -17,35 +17,11 @@ RUN apt-get update && apt-get install -y \
nginx \
&& rm -rf /var/lib/apt/lists/*
#FROM base AS tusd-base
#
#ENV TUSD_VERSION=2.8.0
#
#RUN apt-get update && apt-get install -y \
# curl \
# ca-certificates \
# bash \
# tar \
# gzip \
# libssl-dev \
# && rm -rf /var/lib/apt/lists/*
#
## Download and extract tusd
#RUN curl -L -o /tmp/tusd.tar.gz \
# https://github.com/tus/tusd/releases/download/v${TUSD_VERSION}/tusd_linux_amd64.tar.gz \
# && mkdir -p /usr/local/bin \
# && tar -xzf /tmp/tusd.tar.gz -C /tmp \
# # Move the actual binary, whatever its name/folder inside tar
# && mv /tmp/*/tusd /usr/local/bin/tusd \
# && chmod +x /usr/local/bin/tusd \
# && /usr/local/bin/tusd --version
# Use Debian-based Go for reliable networking/DNS during build
FROM --platform=$BUILDPLATFORM golang:1.23-bookworm AS tusd-base
ARG TUSD_VERSION=2.8.0
# Install git
RUN apt-get update && apt-get install -y --no-install-recommends git ca-certificates \
&& rm -rf /var/lib/apt/lists/*
@@ -54,16 +30,13 @@ WORKDIR /build
RUN git clone https://github.com/tus/tusd.git . \
&& git checkout v${TUSD_VERSION}
# Build statically linked binary
RUN CGO_ENABLED=0 GOOS=linux GOARCH=${TARGETARCH} \
go build -ldflags="-s -w" -o /tusddist/tusd ./cmd/tusd
# Minimal dist stage (scratch keeps final image small)
FROM scratch AS tusd-dist
COPY --from=tusd-base /tusddist/tusd /tusd
FROM base AS build-env
RUN corepack enable && corepack prepare pnpm@latest --activate
@@ -116,7 +89,6 @@ COPY --from=builder --chown=1001:1001 /app/.next/static ./.next/static
COPY --chown=1001:1001 src/db ./src/db
COPY --from=deps /app/node_modules ./node_modules
#COPY --from=tusd-base /usr/local/bin/tusd /usr/local/bin/tusd
COPY --from=tusd-dist /tusd /usr/local/bin/tusd
RUN chmod +x /usr/local/bin/tusd
@@ -9,11 +9,6 @@ fi
mkdir -p /app/private/uploads/tmp
echo "▶ Starting tusd server..."
#tusd --dir /app/private/uploads/tmp --hooks-http http://localhost:80/api/tus/hooks --port 1080 &
#tusd --upload-dir /app/private/uploads/tmp --hooks-http http://localhost:3000/api/tus/hooks --port 1080 --max-size 21474836480 &
#tusd --base-path /tus --upload-dir /app/private/uploads/tmp --hooks-http http://127.0.0.1:3000/api/tus/hooks --port 1080 --max-size 21474836480 --hooks-http-forward-headers "*" &
#tusd --upload-dir /app/private/uploads/tmp --hooks-http http://127.0.0.1:3000/api/tus/hooks --port 1080 --max-size 21474836480 --hooks-http-forward-headers "X-Generated-Id" &
#tusd --upload-dir /app/private/uploads/tmp --hooks-http http://127.0.0.1:3000/api/tus/hooks --port 1080 --max-size 21474836480 --behind-proxy true --hooks-http-forward-headers "X-Generated-Id" &
tusd --base-path /tus/files/ --upload-dir /app/private/uploads/tmp --hooks-http http://127.0.0.1:3000/api/tus/hooks --port 1080 --max-size 21474836480 &
echo "▶ Starting Next.js server..."
@@ -23,5 +18,3 @@ echo "▶ Starting nginx..."
exec nginx -g "daemon off;"
#exec "$@"
-24
View File
@@ -7,48 +7,24 @@ http {
server {
listen 80;
# TUS uploads zero buffering
# location /tus/ {
# proxy_pass http://127.0.0.1:1080/;
# # proxy_request_buffering off;
# # proxy_buffering off;
# # proxy_http_version 1.1;
location /tus/ {
# rewrite ^/tus/(.*)$ /$1 break;
# proxy_pass http://127.0.0.1:1080/;
# proxy_request_buffering off;
# proxy_buffering off;
# proxy_http_version 1.1;
proxy_pass http://127.0.0.1:1080/tus/;
proxy_pass_request_headers on;
# proxy_set_header Host $host;
# proxy_set_header X-Forwarded-Host $host;
# proxy_set_header X-Forwarded-Proto $scheme;
# proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# Disable request and response buffering
proxy_request_buffering off;
proxy_buffering off;
proxy_http_version 1.1;
# Add X-Forwarded-* headers
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-Host $http_host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# proxy_set_header X-Forwarded-Host $host:$server_port;
# proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
# # proxy_set_header Connection "";
client_max_body_size 0;
}
# Next.js
location / {
proxy_pass http://127.0.0.1:3000;
-14
View File
@@ -47,20 +47,6 @@ const nextConfig: NextConfig = {
},
proxyClientMaxBodySize: '10gb',
},
// async rewrites() {
// return [
// {
// source: '/tus/metrics',
// destination: 'http://localhost:1080/metrics',
// },
// {
// source: '/tus/files',
// destination: 'http://localhost:1080/files',
// },
// ]
// },
async headers() {
return [
{
-1
View File
@@ -60,7 +60,6 @@ function checkRouteExists(pathname: string) {
/^\/api\/files\/backups\/?$/,
/^\/api\/tus\/hooks\/?$/,
/^\/api\/events\/?$/,
/^\/api\/init\/?$/,
/^\/api\/config\/?$/,
/^\/api\/google\/drive\/callback\/?$/,
];