mirror of
https://github.com/Portabase/portabase.git
synced 2026-07-14 11:16:13 +02:00
fix: Adding encryption of the settings.
This commit is contained in:
@@ -10,15 +10,16 @@ import {dbmsEnumSchema, EDbmsSchema} from "@/db/schema/types";
|
|||||||
import {withUpdatedAt} from "@/db/utils";
|
import {withUpdatedAt} from "@/db/utils";
|
||||||
import type {StorageInput} from "@/features/storages/types";
|
import type {StorageInput} from "@/features/storages/types";
|
||||||
import {dispatchStorage} from "@/features/storages/dispatch";
|
import {dispatchStorage} from "@/features/storages/dispatch";
|
||||||
|
import {Setting} from "@/db/schema/01_setting";
|
||||||
|
|
||||||
export async function handleDatabases(body: Body, agent: Agent, lastContact: Date) {
|
export async function handleDatabases(body: Body, agent: Agent, lastContact: Date, settings: Setting) {
|
||||||
const databasesResponse = [];
|
const databasesResponse = [];
|
||||||
|
|
||||||
const formatDatabase = (database: DatabaseWith, backupAction: boolean, restoreAction: boolean, UrlBackup: string | null, storages: PingDatabaseStorageChannels[], urlMeta: string | null) => ({
|
const formatDatabase = (database: DatabaseWith, backupAction: boolean, restoreAction: boolean, UrlBackup: string | null, storages: PingDatabaseStorageChannels[], urlMeta: string | null) => ({
|
||||||
generatedId: database.agentDatabaseId,
|
generatedId: database.agentDatabaseId,
|
||||||
dbms: database.dbms,
|
dbms: database.dbms,
|
||||||
storages: storages,
|
storages: storages,
|
||||||
encrypt: false,
|
encrypt: settings.encryption,
|
||||||
data: {
|
data: {
|
||||||
backup: {
|
backup: {
|
||||||
action: backupAction,
|
action: backupAction,
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import {eq} from "drizzle-orm";
|
|||||||
import {isUuidv4} from "@/utils/verify-uuid";
|
import {isUuidv4} from "@/utils/verify-uuid";
|
||||||
import {withUpdatedAt} from "@/db/utils";
|
import {withUpdatedAt} from "@/db/utils";
|
||||||
import {eventEmitter} from "@/features/shared/event";
|
import {eventEmitter} from "@/features/shared/event";
|
||||||
|
import {notFound} from "next/navigation";
|
||||||
|
|
||||||
export type databaseAgent = {
|
export type databaseAgent = {
|
||||||
name: string,
|
name: string,
|
||||||
@@ -48,7 +49,14 @@ export async function POST(
|
|||||||
message = "Agent not found"
|
message = "Agent not found"
|
||||||
return NextResponse.json({error: message}, {status: 404})
|
return NextResponse.json({error: message}, {status: 404})
|
||||||
}
|
}
|
||||||
const databasesResponse = await handleDatabases(body, agent, lastContact)
|
|
||||||
|
const [settings] = await db.select().from(drizzleDb.schemas.setting).where(eq(drizzleDb.schemas.setting.name, "system")).limit(1);
|
||||||
|
if (!settings) {
|
||||||
|
return NextResponse.json({error: "An error occured"}, {status: 404})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const databasesResponse = await handleDatabases(body, agent, lastContact, settings)
|
||||||
|
|
||||||
await db
|
await db
|
||||||
.update(drizzleDb.schemas.agent)
|
.update(drizzleDb.schemas.agent)
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ export const SettingsTabs = ({settings, storageChannels}: SettingsTabsProps) =>
|
|||||||
)
|
)
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Default Storage',
|
name: 'Storage',
|
||||||
value: 'storage',
|
value: 'storage',
|
||||||
icon: Save,
|
icon: Save,
|
||||||
content: (
|
content: (
|
||||||
|
|||||||
+33
-10
@@ -4,7 +4,7 @@ import {Info} from "lucide-react";
|
|||||||
import {ButtonWithLoading} from "@/components/wrappers/common/button/button-with-loading";
|
import {ButtonWithLoading} from "@/components/wrappers/common/button/button-with-loading";
|
||||||
import {useRouter} from "next/navigation";
|
import {useRouter} from "next/navigation";
|
||||||
import {Setting} from "@/db/schema/01_setting";
|
import {Setting} from "@/db/schema/01_setting";
|
||||||
import {Form, FormField, FormItem, useZodForm} from "@/components/ui/form";
|
import {Form, FormControl, FormField, FormItem, FormLabel, FormMessage, useZodForm} from "@/components/ui/form";
|
||||||
import {StorageChannelWith} from "@/db/schema/12_storage-channel";
|
import {StorageChannelWith} from "@/db/schema/12_storage-channel";
|
||||||
import {Select, SelectContent, SelectItem, SelectTrigger, SelectValue} from "@/components/ui/select";
|
import {Select, SelectContent, SelectItem, SelectTrigger, SelectValue} from "@/components/ui/select";
|
||||||
import {useMutation} from "@tanstack/react-query";
|
import {useMutation} from "@tanstack/react-query";
|
||||||
@@ -17,6 +17,7 @@ import {
|
|||||||
updateStorageSettingsAction
|
updateStorageSettingsAction
|
||||||
} from "@/components/wrappers/dashboard/admin/settings/storage/settings-storage.action";
|
} from "@/components/wrappers/dashboard/admin/settings/storage/settings-storage.action";
|
||||||
import {toast} from "sonner";
|
import {toast} from "sonner";
|
||||||
|
import {Switch} from "@/components/ui/switch";
|
||||||
|
|
||||||
export type SettingsStorageSectionProps = {
|
export type SettingsStorageSectionProps = {
|
||||||
settings: Setting;
|
settings: Setting;
|
||||||
@@ -29,7 +30,8 @@ export const SettingsStorageSection = ({settings, storageChannels}: SettingsStor
|
|||||||
const form = useZodForm({
|
const form = useZodForm({
|
||||||
schema: DefaultStorageSchema,
|
schema: DefaultStorageSchema,
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
storageChannelId: settings.defaultStorageChannelId ?? undefined
|
storageChannelId: settings.defaultStorageChannelId ?? undefined,
|
||||||
|
encryption: settings.encryption ?? false
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -59,6 +61,7 @@ export const SettingsStorageSection = ({settings, storageChannels}: SettingsStor
|
|||||||
</Alert>
|
</Alert>
|
||||||
<div className="flex flex-col h-full py-4 ">
|
<div className="flex flex-col h-full py-4 ">
|
||||||
<Form
|
<Form
|
||||||
|
className="space-y-4"
|
||||||
form={form}
|
form={form}
|
||||||
onSubmit={async (values) => {
|
onSubmit={async (values) => {
|
||||||
await mutation.mutateAsync(values);
|
await mutation.mutateAsync(values);
|
||||||
@@ -68,11 +71,12 @@ export const SettingsStorageSection = ({settings, storageChannels}: SettingsStor
|
|||||||
<FormField
|
<FormField
|
||||||
control={form.control}
|
control={form.control}
|
||||||
name="storageChannelId"
|
name="storageChannelId"
|
||||||
render={({ field }) => (
|
render={({field}) => (
|
||||||
<FormItem className="flex-grow min-w-[200px] sm:flex-grow-0 sm:w-64">
|
<FormItem className="flex-grow min-w-[200px] sm:flex-grow-0 sm:w-64">
|
||||||
|
<FormLabel>Default Storage Provider</FormLabel>
|
||||||
<Select value={field.value} onValueChange={field.onChange}>
|
<Select value={field.value} onValueChange={field.onChange}>
|
||||||
<SelectTrigger className="w-full h-full mb-0">
|
<SelectTrigger className="w-full h-full mb-0">
|
||||||
<SelectValue placeholder="Select a default storage channel" />
|
<SelectValue placeholder="Select a default storage channel"/>
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
<SelectContent>
|
<SelectContent>
|
||||||
{storageChannels.map((channel) => (
|
{storageChannels.map((channel) => (
|
||||||
@@ -80,9 +84,10 @@ export const SettingsStorageSection = ({settings, storageChannels}: SettingsStor
|
|||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
{getChannelIcon(channel.provider)}
|
{getChannelIcon(channel.provider)}
|
||||||
<span className="font-medium">{channel.name}</span>
|
<span className="font-medium">{channel.name}</span>
|
||||||
<span className="text-[9px] uppercase bg-secondary px-1.5 py-0.5 rounded">
|
<span
|
||||||
{channel.provider}
|
className="text-[9px] uppercase bg-secondary px-1.5 py-0.5 rounded">
|
||||||
</span>
|
{channel.provider}
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</SelectItem>
|
</SelectItem>
|
||||||
))}
|
))}
|
||||||
@@ -91,11 +96,29 @@ export const SettingsStorageSection = ({settings, storageChannels}: SettingsStor
|
|||||||
</FormItem>
|
</FormItem>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
<ButtonWithLoading className="flex-shrink-0 w-full sm:w-auto" type="submit">
|
|
||||||
Confirm
|
|
||||||
</ButtonWithLoading>
|
<FormField
|
||||||
|
control={form.control}
|
||||||
|
name="encryption"
|
||||||
|
render={({field}) => (
|
||||||
|
<FormItem>
|
||||||
|
<FormLabel>Backups Encryption</FormLabel>
|
||||||
|
<FormControl>
|
||||||
|
<Switch
|
||||||
|
checked={field.value}
|
||||||
|
onCheckedChange={field.onChange}
|
||||||
|
/>
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage/>
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<ButtonWithLoading className="flex-shrink-0 w-full sm:w-auto" type="submit">
|
||||||
|
Confirm
|
||||||
|
</ButtonWithLoading>
|
||||||
</Form>
|
</Form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -20,11 +20,11 @@ export const updateStorageSettingsAction = userAction
|
|||||||
const {name, data} = parsedInput;
|
const {name, data} = parsedInput;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
const [updatedSettings] = await db
|
const [updatedSettings] = await db
|
||||||
.update(drizzleDb.schemas.setting)
|
.update(drizzleDb.schemas.setting)
|
||||||
.set({
|
.set({
|
||||||
defaultStorageChannelId: data.storageChannelId,
|
defaultStorageChannelId: data.storageChannelId,
|
||||||
|
encryption: data.encryption,
|
||||||
})
|
})
|
||||||
.where(eq(drizzleDb.schemas.setting.name, name))
|
.where(eq(drizzleDb.schemas.setting.name, name))
|
||||||
.returning();
|
.returning();
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
import { z } from "zod";
|
import {z} from "zod";
|
||||||
|
|
||||||
export const DefaultStorageSchema = z.object({
|
export const DefaultStorageSchema = z.object({
|
||||||
storageChannelId: z.string(),
|
storageChannelId: z.string(),
|
||||||
|
encryption: z.boolean(),
|
||||||
});
|
});
|
||||||
|
|
||||||
export type DefaultStorageType = z.infer<typeof DefaultStorageSchema>;
|
export type DefaultStorageType = z.infer<typeof DefaultStorageSchema>;
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
ALTER TABLE "settings" ADD COLUMN "encryption" boolean DEFAULT false;
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -232,6 +232,13 @@
|
|||||||
"when": 1769203863305,
|
"when": 1769203863305,
|
||||||
"tag": "0032_sparkling_thunderbolt_ross",
|
"tag": "0032_sparkling_thunderbolt_ross",
|
||||||
"breakpoints": true
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 33,
|
||||||
|
"version": "7",
|
||||||
|
"when": 1770923665015,
|
||||||
|
"tag": "0033_handy_valeria_richards",
|
||||||
|
"breakpoints": true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -1,15 +1,10 @@
|
|||||||
import {boolean, pgTable, timestamp, uuid, varchar} from "drizzle-orm/pg-core";
|
import {boolean, pgTable, timestamp, uuid, varchar} from "drizzle-orm/pg-core";
|
||||||
import {typeStorageEnum} from "./types";
|
|
||||||
import {createSelectSchema} from "drizzle-zod";
|
import {createSelectSchema} from "drizzle-zod";
|
||||||
import {z} from "zod";
|
import {z} from "zod";
|
||||||
import {timestamps} from "@/db/schema/00_common";
|
import {timestamps} from "@/db/schema/00_common";
|
||||||
import {storageChannel} from "@/db/schema/12_storage-channel";
|
import {storageChannel} from "@/db/schema/12_storage-channel";
|
||||||
import {relations} from "drizzle-orm";
|
import {relations} from "drizzle-orm";
|
||||||
import {agent} from "@/db/schema/08_agent";
|
|
||||||
import {project} from "@/db/schema/06_project";
|
|
||||||
import {alertPolicy} from "@/db/schema/10_alert-policy";
|
|
||||||
import {storagePolicy} from "@/db/schema/13_storage-policy";
|
|
||||||
import {backup, database, restoration, retentionPolicy} from "@/db/schema/07_database";
|
|
||||||
|
|
||||||
export const setting = pgTable("settings", {
|
export const setting = pgTable("settings", {
|
||||||
id: uuid("id").primaryKey().defaultRandom(),
|
id: uuid("id").primaryKey().defaultRandom(),
|
||||||
@@ -22,6 +17,7 @@ export const setting = pgTable("settings", {
|
|||||||
smtpSecure: boolean("smtp_secure"),
|
smtpSecure: boolean("smtp_secure"),
|
||||||
defaultStorageChannelId: uuid('default_storage_channel_id')
|
defaultStorageChannelId: uuid('default_storage_channel_id')
|
||||||
.references(() => storageChannel.id, {onDelete: "set null"}),
|
.references(() => storageChannel.id, {onDelete: "set null"}),
|
||||||
|
encryption: boolean("encryption").default(false),
|
||||||
...timestamps
|
...timestamps
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user