mirror of
https://github.com/Portabase/portabase.git
synced 2026-07-14 11:16:13 +02:00
Adding mysql support.
This commit is contained in:
@@ -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";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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 |
+1
-1
@@ -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
@@ -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
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -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"]);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user