From dc6e80834a36ab5e86d1bbfba6e497c58f8ccb5f Mon Sep 17 00:00:00 2001 From: biersoeckli Date: Fri, 22 Nov 2024 10:22:49 +0000 Subject: [PATCH] fixed redirect if logged out and added NEXTAUTH_URL if available --- .../auth/{login-from.tsx => login-form.tsx} | 1 + src/app/auth/page.tsx | 2 +- src/app/settings/server/actions.ts | 6 ++- .../server/qs-letsencrypt-settings.tsx | 8 +-- src/middleware.ts | 5 +- src/server/services/param.service.ts | 2 +- src/server/services/qs.service.ts | 54 ++++++++++++------- src/server/utils/action-wrapper.utils.ts | 3 +- 8 files changed, 51 insertions(+), 30 deletions(-) rename src/app/auth/{login-from.tsx => login-form.tsx} (99%) diff --git a/src/app/auth/login-from.tsx b/src/app/auth/login-form.tsx similarity index 99% rename from src/app/auth/login-from.tsx rename to src/app/auth/login-form.tsx index a9fbfa4..e50f5aa 100644 --- a/src/app/auth/login-from.tsx +++ b/src/app/auth/login-form.tsx @@ -46,6 +46,7 @@ export default function UserLoginForm() { username: data.email, password: data.password, redirect: true, + callbackUrl: "/", }); } else { setAuthInput(data); // 2fa window will be shown diff --git a/src/app/auth/page.tsx b/src/app/auth/page.tsx index 42e9407..ddbbfb5 100644 --- a/src/app/auth/page.tsx +++ b/src/app/auth/page.tsx @@ -2,7 +2,7 @@ import userService from "@/server/services/user.service"; import UserRegistrationForm from "./register-from"; -import UserLoginForm from "./login-from"; +import UserLoginForm from "./login-form"; import { getUserSession } from "@/server/utils/action-wrapper.utils"; import { redirect } from "next/navigation"; diff --git a/src/app/settings/server/actions.ts b/src/app/settings/server/actions.ts index e8dbc46..575aab7 100644 --- a/src/app/settings/server/actions.ts +++ b/src/app/settings/server/actions.ts @@ -10,9 +10,11 @@ export const updateIngressSettings = async (prevState: any, inputData: QsIngress saveFormAction(inputData, qsIngressSettingsZodModel, async (validatedData) => { await getAuthUserSession(); + const url = new URL(validatedData.serverUrl.includes('://') ? validatedData.serverUrl : `https://${validatedData.serverUrl}`); + await paramService.save({ name: ParamService.QS_SERVER_HOSTNAME, - value: validatedData.serverUrl + value: url.hostname }); await paramService.save({ @@ -22,6 +24,8 @@ export const updateIngressSettings = async (prevState: any, inputData: QsIngress await quickStackService.createOrUpdateService(!validatedData.disableNodePortAccess); await quickStackService.createOrUpdateIngress(validatedData.serverUrl); + await quickStackService.createOrUpdateDeployment(url.hostname); + }); export const updateLetsEncryptSettings = async (prevState: any, inputData: QsLetsEncryptSettingsModel) => diff --git a/src/app/settings/server/qs-letsencrypt-settings.tsx b/src/app/settings/server/qs-letsencrypt-settings.tsx index ecb6499..14f98d2 100644 --- a/src/app/settings/server/qs-letsencrypt-settings.tsx +++ b/src/app/settings/server/qs-letsencrypt-settings.tsx @@ -2,7 +2,7 @@ import { SubmitButton } from "@/components/custom/submit-button"; import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@/components/ui/card"; -import { Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage } from "@/components/ui/form"; +import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "@/components/ui/form"; import { FormUtils } from "@/lib/form.utilts"; import { zodResolver } from "@hookform/resolvers/zod"; import { useForm } from "react-hook-form"; @@ -11,11 +11,7 @@ import { ServerActionResult } from "@/model/server-action-error-return.model"; import { Input } from "@/components/ui/input"; import { useEffect } from "react"; import { toast } from "sonner"; -import { ProfilePasswordChangeModel, profilePasswordChangeZodModel } from "@/model/update-password.model"; -import { QsIngressSettingsModel, qsIngressSettingsZodModel } from "@/model/qs-settings.model"; -import { updateIngressSettings, updateLetsEncryptSettings } from "./actions"; -import SelectFormField from "@/components/custom/select-form-field"; -import CheckboxFormField from "@/components/custom/checkbox-form-field"; +import { updateLetsEncryptSettings } from "./actions"; import { QsLetsEncryptSettingsModel, qsLetsEncryptSettingsZodModel } from "@/model/qs-letsencrypt-settings.model"; export default function QuickStackLetsEncryptSettings({ diff --git a/src/middleware.ts b/src/middleware.ts index 9dfa5e4..1b37f87 100644 --- a/src/middleware.ts +++ b/src/middleware.ts @@ -1,6 +1,7 @@ export { default } from "next-auth/middleware" export const config = { - matcher: ["/"], - exclude: ["/auth"] + matcher: ["/"], + exclude: ["/auth"], + } \ No newline at end of file diff --git a/src/server/services/param.service.ts b/src/server/services/param.service.ts index fed5d7b..e4b9419 100644 --- a/src/server/services/param.service.ts +++ b/src/server/services/param.service.ts @@ -110,7 +110,7 @@ export class ParamService { name: item.name as string }, data: { - + value: item.value } }); } else { diff --git a/src/server/services/qs.service.ts b/src/server/services/qs.service.ts index 0370488..7050704 100644 --- a/src/server/services/qs.service.ts +++ b/src/server/services/qs.service.ts @@ -18,7 +18,7 @@ class QuickStackService { await namespaceService.createNamespaceIfNotExists(this.QUICKSTACK_NAMESPACE) const nextAuthSecret = await this.deleteExistingDeployment(); await this.createOrUpdatePvc(); - await this.createDeployment(nextAuthSecret); + await this.createOrUpdateDeployment(undefined, nextAuthSecret); await this.createOrUpdateService(true); console.log('QuickStack successfully initialized'); } @@ -109,14 +109,14 @@ class QuickStackService { } }; // todo - /* const allIssuers = await k3s.network.clus(); - const existingIssuer = allIssuers.body.items.find(i => i.metadata!.name === issuerName); - if (existingIssuer) { - await k3s.certManager.replaceClusterIssuer(issuerName, issuerDefinition); - console.log('Cert Issuer updated'); - } else { - await k3s.certManager.createClusterIssuer(issuerDefinition); - console.log('Cert Issuer created');*/ + /* const allIssuers = await k3s.network.clus(); + const existingIssuer = allIssuers.body.items.find(i => i.metadata!.name === issuerName); + if (existingIssuer) { + await k3s.certManager.replaceClusterIssuer(issuerName, issuerDefinition); + console.log('Cert Issuer updated'); + } else { + await k3s.certManager.createClusterIssuer(issuerDefinition); + console.log('Cert Issuer created');*/ } async createOrUpdateService(openNodePort = false) { @@ -155,7 +155,6 @@ class QuickStackService { } await k3s.core.createNamespacedService(this.QUICKSTACK_NAMESPACE, body); console.log('Service created'); - } @@ -199,14 +198,18 @@ class QuickStackService { } - private async createDeployment(existingNextAuthSecret?: string) { + async createOrUpdateDeployment(nextAuthHostname?: string, inputNextAuthSecret?: string) { const generatedNextAuthSecret = crypto.randomBytes(32).toString('base64'); + const existingDeployment = await this.getExistingDeployment(); const body: V1Deployment = { metadata: { name: this.QUICKSTACK_DEPLOYMENT_NAME, }, spec: { replicas: 1, + strategy: { + type: 'Recreate', + }, selector: { matchLabels: { app: this.QUICKSTACK_DEPLOYMENT_NAME @@ -233,8 +236,12 @@ class QuickStackService { env: [ { name: 'NEXTAUTH_SECRET', - value: existingNextAuthSecret || generatedNextAuthSecret - } + value: inputNextAuthSecret || existingDeployment.nextAuthSecret || generatedNextAuthSecret + }, + ...nextAuthHostname ? [{ + name: 'NEXTAUTH_URL', + value: `https://${nextAuthHostname}` + }] : [] ], volumeMounts: [{ name: 'quickstack-volume', @@ -252,23 +259,34 @@ class QuickStackService { } } }; - await k3s.apps.createNamespacedDeployment(this.QUICKSTACK_NAMESPACE, body); - console.log('Deployment created'); + if (existingDeployment.existingDeployments) { + await k3s.apps.replaceNamespacedDeployment(this.QUICKSTACK_DEPLOYMENT_NAME, this.QUICKSTACK_NAMESPACE, body); + console.log('Deployment updated'); + } else { + await k3s.apps.createNamespacedDeployment(this.QUICKSTACK_NAMESPACE, body); + console.log('Deployment created'); + } } /** * @returns: the existing NEXTAUTH_SECRET if the deployment already exists */ private async deleteExistingDeployment() { - const allDeployments = await k3s.apps.listNamespacedDeployment(this.QUICKSTACK_NAMESPACE); - const existingDeployments = allDeployments.body.items.find(d => d.metadata!.name === this.QUICKSTACK_DEPLOYMENT_NAME); + const { existingDeployments, nextAuthSecret } = await this.getExistingDeployment(); const quickStackAlreadyDeployed = !!existingDeployments; if (quickStackAlreadyDeployed) { console.warn('QuickStack already deployed, deleting existing deployment (data wont be lost)'); await k3s.apps.deleteNamespacedDeployment(this.QUICKSTACK_DEPLOYMENT_NAME, this.QUICKSTACK_NAMESPACE); console.log('Existing deployment deleted'); } - return existingDeployments?.spec?.template?.spec?.containers?.[0].env?.find(e => e.name === 'NEXTAUTH_SECRET')?.value; + return nextAuthSecret; + } + + async getExistingDeployment() { + const allDeployments = await k3s.apps.listNamespacedDeployment(this.QUICKSTACK_NAMESPACE); + const existingDeployments = allDeployments.body.items.find(d => d.metadata!.name === this.QUICKSTACK_DEPLOYMENT_NAME); + const nextAuthSecret = existingDeployments?.spec?.template?.spec?.containers?.[0].env?.find(e => e.name === 'NEXTAUTH_SECRET')?.value; + return { existingDeployments, nextAuthSecret }; } } diff --git a/src/server/utils/action-wrapper.utils.ts b/src/server/utils/action-wrapper.utils.ts index a65d133..9a4b54c 100644 --- a/src/server/utils/action-wrapper.utils.ts +++ b/src/server/utils/action-wrapper.utils.ts @@ -25,7 +25,8 @@ export async function getUserSession(): Promise { export async function getAuthUserSession(): Promise { const session = await getUserSession(); if (!session) { - throw new ServiceException('User is not authenticated.'); + console.error('User is not authenticated.'); + redirect('/auth'); } return session; }