Adding mysql support.

This commit is contained in:
charlesgauthereau
2025-11-01 23:16:32 +01:00
parent 5251e01011
commit 2fdd9f1296
9 changed files with 1388 additions and 14 deletions
+15 -4
View File
@@ -2,7 +2,7 @@ import fs from "node:fs";
import forge from "node-forge"; import forge from "node-forge";
export async function decryptedDump(file: File, aesKeyHex: string, ivHex: string): Promise<File> { 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 privateKeyPem = fs.readFileSync("private/keys/server_private.pem", "utf8");
const privateKey = forge.pki.privateKeyFromPem(privateKeyPem); const privateKey = forge.pki.privateKeyFromPem(privateKeyPem);
@@ -10,7 +10,7 @@ export async function decryptedDump(file: File, aesKeyHex: string, ivHex: string
const encryptedAesKey = forge.util.hexToBytes(aesKeyHex); const encryptedAesKey = forge.util.hexToBytes(aesKeyHex);
const aesKey = privateKey.decrypt(encryptedAesKey, "RSA-OAEP", { const aesKey = privateKey.decrypt(encryptedAesKey, "RSA-OAEP", {
md: forge.md.sha256.create(), md: forge.md.sha256.create(),
mgf1: { md: forge.md.sha256.create() }, mgf1: {md: forge.md.sha256.create()},
}); });
// Read encrypted file content // Read encrypted file content
@@ -19,7 +19,7 @@ export async function decryptedDump(file: File, aesKeyHex: string, ivHex: string
// AES decryption // AES decryption
const decipher = forge.cipher.createDecipher("AES-CBC", aesKey); const decipher = forge.cipher.createDecipher("AES-CBC", aesKey);
decipher.start({ iv }); decipher.start({iv});
decipher.update(forge.util.createBuffer(encryptedBuffer.toString("binary"))); decipher.update(forge.util.createBuffer(encryptedBuffer.toString("binary")));
const success = decipher.finish(); const success = decipher.finish();
@@ -33,8 +33,19 @@ export async function decryptedDump(file: File, aesKeyHex: string, ivHex: string
// Return a File so you can use file.arrayBuffer() later // Return a File so you can use file.arrayBuffer() later
return new File( return new File(
[decryptedBuffer], [decryptedBuffer],
file.name.replace(/\.enc$/, ".dump"), // rename if needed file.name.replace(/\.enc$/, fileExtension),
{type: "application/octet-stream"} {type: "application/octet-stream"}
); );
} }
export function getFileExtension(dbType: string) {
switch (dbType) {
case "postgresql":
return ".dump";
case "mysql":
return ".sql";
default:
return ".dump";
}
}
+4 -5
View File
@@ -9,7 +9,7 @@ import {Backup} from "@/db/schema/07_database";
import {and, eq} from "drizzle-orm"; import {and, eq} from "drizzle-orm";
import {env} from "@/env.mjs"; import {env} from "@/env.mjs";
import {withUpdatedAt} from "@/db/utils"; import {withUpdatedAt} from "@/db/utils";
import {decryptedDump} from "./helpers"; import {decryptedDump, getFileExtension} from "./helpers";
export async function POST( export async function POST(
request: Request, request: Request,
@@ -116,11 +116,10 @@ export async function POST(
{status: 400} {status: 400}
); );
} }
const fileExtension = getFileExtension(database.dbms)
const decryptedFile = await decryptedDump(file, aesKeyHex, ivHex); const decryptedFile = await decryptedDump(file, aesKeyHex, ivHex, fileExtension);
const uuid = uuidv4(); const uuid = uuidv4();
const fileName = `${uuid}.dump`; const fileName = `${uuid}${fileExtension}`;
const buffer = Buffer.from(await decryptedFile.arrayBuffer()); const buffer = Buffer.from(await decryptedFile.arrayBuffer());
const [settings] = await db.select().from(drizzleDb.schemas.setting).where(eq(drizzleDb.schemas.setting.name, "system")).limit(1); const [settings] = await db.select().from(drizzleDb.schemas.setting).where(eq(drizzleDb.schemas.setting.name, "system")).limit(1);
Binary file not shown.

After

Width:  |  Height:  |  Size: 175 KiB

@@ -70,7 +70,7 @@ export const SettingsStorageTab = (props: SettingsStorageTabProps) => {
<AlertDescription> <AlertDescription>
Actually you can only store you data in one place : s3 compatible or in local. For exemple you Actually you can only store you data in one place : s3 compatible or in local. For exemple you
cannot choose to store images in one place cannot choose to store images in one place
and .dump files in another. and backups files in another.
</AlertDescription> </AlertDescription>
</Alert> </Alert>
<div className="flex flex-col h-full py-4 "> <div className="flex flex-col h-full py-4 ">
@@ -32,11 +32,9 @@ export const DatabaseCard = (props: databaseCardProps) => {
const { data: database } = props; const { data: database } = props;
return ( return (
<Card className="flex flex-row justify-between"> <Card className="flex flex-row justify-between">
<div className="flex items-center space-x-4 px-4"> <div className="flex items-center space-x-4 px-4">
<Image src="/images/postgresql.png" alt="Database type Icon" width={60} height={60} className="object-cover ml-4" /> <Image src={`/images/${database.dbms}.png`} alt="Database type Icon" width={60} height={60} className="object-cover ml-4" />
<div className="justify-between"> <div className="justify-between">
<div className="font-medium">Name: {database.name}</div> <div className="font-medium">Name: {database.name}</div>
<div className="text-sm text-muted-foreground">Generated Id: {database.agentDatabaseId}</div> <div className="text-sm text-muted-foreground">Generated Id: {database.agentDatabaseId}</div>
@@ -0,0 +1,4 @@
ALTER TABLE "databases" ALTER COLUMN "dbms" SET DATA TYPE text;--> statement-breakpoint
DROP TYPE "public"."dbms_status";--> statement-breakpoint
CREATE TYPE "public"."dbms_status" AS ENUM('postgresql', 'mysql');--> statement-breakpoint
ALTER TABLE "databases" ALTER COLUMN "dbms" SET DATA TYPE "public"."dbms_status" USING "dbms"::"public"."dbms_status";
File diff suppressed because it is too large Load Diff
+7
View File
@@ -43,6 +43,13 @@
"when": 1762004436821, "when": 1762004436821,
"tag": "0005_old_swarm", "tag": "0005_old_swarm",
"breakpoints": true "breakpoints": true
},
{
"idx": 6,
"version": "7",
"when": 1762028639833,
"tag": "0006_moaning_pete_wisdom",
"breakpoints": true
} }
] ]
} }
+1 -1
View File
@@ -2,7 +2,7 @@ import { pgEnum } from "drizzle-orm/pg-core";
import { createSelectSchema } from "drizzle-zod"; import { createSelectSchema } from "drizzle-zod";
import { z } from "zod"; import { z } from "zod";
export const dbmsEnum = pgEnum("dbms_status", ["postgresql", "mongodb"]); export const dbmsEnum = pgEnum("dbms_status", ["postgresql", "mysql"]);
export const statusEnum = pgEnum("status", ["waiting", "ongoing", "failed", "success"]); export const statusEnum = pgEnum("status", ["waiting", "ongoing", "failed", "success"]);
export const typeStorageEnum = pgEnum("type_storage", ["local", "s3"]); export const typeStorageEnum = pgEnum("type_storage", ["local", "s3"]);