From 5d721d7a3ed092f3bd5a8ec686a44f3f7199e22a Mon Sep 17 00:00:00 2001
From: Pontus Abrahamsson
Date: Fri, 8 Dec 2023 15:55:25 +0100
Subject: [PATCH] Mfa
---
.../src/actions/mfa-verify-action.ts | 23 ++++++++++
apps/dashboard/src/actions/schema.ts | 8 +++-
.../src/actions/unenroll-mfa-action.ts | 4 +-
apps/dashboard/src/components/enroll-mfa.tsx | 18 ++++++--
apps/dashboard/src/components/mfa-list.tsx | 2 +-
.../src/components/modals/add-new-device.tsx | 43 ++++++++++++-------
.../src/components/remove-mfa-button.tsx | 6 +--
7 files changed, 78 insertions(+), 26 deletions(-)
create mode 100644 apps/dashboard/src/actions/mfa-verify-action.ts
diff --git a/apps/dashboard/src/actions/mfa-verify-action.ts b/apps/dashboard/src/actions/mfa-verify-action.ts
new file mode 100644
index 0000000000..dcb2cc2407
--- /dev/null
+++ b/apps/dashboard/src/actions/mfa-verify-action.ts
@@ -0,0 +1,23 @@
+"use server";
+
+import { createClient } from "@midday/supabase/server";
+import { revalidatePath } from "next/cache";
+import { action } from "./safe-action";
+import { mfaVerifySchema } from "./schema";
+
+export const mfaVerifyAction = action(
+ mfaVerifySchema,
+ async ({ factorId, challengeId, code }) => {
+ const supabase = createClient();
+
+ const { data } = await supabase.auth.mfa.verify({
+ factorId,
+ challengeId,
+ code,
+ });
+
+ revalidatePath("/settings/security");
+
+ return data;
+ }
+);
diff --git a/apps/dashboard/src/actions/schema.ts b/apps/dashboard/src/actions/schema.ts
index e7eb5a08d3..3ade9b3eae 100644
--- a/apps/dashboard/src/actions/schema.ts
+++ b/apps/dashboard/src/actions/schema.ts
@@ -85,7 +85,13 @@ export const createFolderSchema = z.object({
});
export const unenrollMfaSchema = z.object({
- factoryId: z.string(),
+ factorId: z.string(),
+});
+
+export const mfaVerifySchema = z.object({
+ factorId: z.string(),
+ challengeId: z.string(),
+ code: z.string(),
});
export const shareFileSchema = z.object({
diff --git a/apps/dashboard/src/actions/unenroll-mfa-action.ts b/apps/dashboard/src/actions/unenroll-mfa-action.ts
index ead09e3666..511f4d315f 100644
--- a/apps/dashboard/src/actions/unenroll-mfa-action.ts
+++ b/apps/dashboard/src/actions/unenroll-mfa-action.ts
@@ -7,11 +7,11 @@ import { unenrollMfaSchema } from "./schema";
export const unenrollMfaAction = action(
unenrollMfaSchema,
- async ({ factoryId }) => {
+ async ({ factorId }) => {
const supabase = createClient();
const { data, error } = await supabase.auth.mfa.unenroll({
- factoryId,
+ factorId,
});
if (error) {
diff --git a/apps/dashboard/src/components/enroll-mfa.tsx b/apps/dashboard/src/components/enroll-mfa.tsx
index 56a53264a4..3c17cfd25f 100644
--- a/apps/dashboard/src/components/enroll-mfa.tsx
+++ b/apps/dashboard/src/components/enroll-mfa.tsx
@@ -1,6 +1,6 @@
import { createClient } from "@midday/supabase/client";
+import { Button } from "@midday/ui/button";
import Image from "next/image";
-import Link from "next/link";
import { useRouter } from "next/navigation";
import { useEffect, useState } from "react";
import PinField from "react-pin-field";
@@ -48,6 +48,14 @@ export function EnrollMFA() {
enroll();
}, []);
+ const handleOnCancel = () => {
+ supabase.auth.mfa.unenroll({
+ factorId,
+ });
+
+ router.push("/onboarding");
+ };
+
return (
<>
@@ -75,9 +83,13 @@ export function EnrollMFA() {
-
+
>
);
diff --git a/apps/dashboard/src/components/mfa-list.tsx b/apps/dashboard/src/components/mfa-list.tsx
index e42e74392c..855c6c9eb4 100644
--- a/apps/dashboard/src/components/mfa-list.tsx
+++ b/apps/dashboard/src/components/mfa-list.tsx
@@ -36,7 +36,7 @@ export async function MFAList() {
-
+
);
});
diff --git a/apps/dashboard/src/components/modals/add-new-device.tsx b/apps/dashboard/src/components/modals/add-new-device.tsx
index 48501fead2..9dcb693c38 100644
--- a/apps/dashboard/src/components/modals/add-new-device.tsx
+++ b/apps/dashboard/src/components/modals/add-new-device.tsx
@@ -1,9 +1,11 @@
"use client";
+import { mfaVerifyAction } from "@/actions/mfa-verify-action";
import { createClient } from "@midday/supabase/client";
import { Button } from "@midday/ui/button";
import { Dialog, DialogContent } from "@midday/ui/dialog";
import { cn } from "@midday/ui/utils";
+import { useAction } from "next-safe-action/hook";
import Image from "next/image";
import { usePathname, useRouter, useSearchParams } from "next/navigation";
import { useEffect, useState } from "react";
@@ -20,25 +22,21 @@ export function AddNewDeviceModal() {
const [qr, setQR] = useState("");
const isOpen = searchParams.get("add") === "device";
+ const verify = useAction(mfaVerifyAction, {
+ onSuccess: () => router.push(pathname),
+ });
+
const onComplete = async (code: string) => {
if (!isValidating) {
setValidating(true);
const challenge = await supabase.auth.mfa.challenge({ factorId });
- try {
- const verify = await supabase.auth.mfa.verify({
- factorId,
- challengeId: challenge.data.id,
- code,
- });
-
- if (verify.data) {
- router.push(pathname);
- }
- } catch {
- setError(true);
- }
+ verify.execute({
+ factorId,
+ challengeId: challenge.data.id,
+ code,
+ });
}
};
@@ -65,9 +63,22 @@ export function AddNewDeviceModal() {
}
}, [isOpen]);
+ const handleOnClose = () => {
+ router.push(pathname);
+
+ supabase.auth.mfa.unenroll({
+ factorId,
+ });
+ };
+
return (
-