mirror of
https://github.com/LukeHagar/better-auth.git
synced 2025-12-07 20:37:44 +00:00
chore:lint
This commit is contained in:
@@ -267,32 +267,129 @@ export const Icons = {
|
|||||||
height="1.2em"
|
height="1.2em"
|
||||||
viewBox="0 0 100 100"
|
viewBox="0 0 100 100"
|
||||||
>
|
>
|
||||||
<mask id="a" style={{maskType: "alpha"}} maskUnits="userSpaceOnUse" x="0" y="0" width="100" height="100">
|
<mask
|
||||||
<circle cx="50" cy="50" r="50" className="fill-foreground"/>
|
id="a"
|
||||||
|
style={{ maskType: "alpha" }}
|
||||||
|
maskUnits="userSpaceOnUse"
|
||||||
|
x="0"
|
||||||
|
y="0"
|
||||||
|
width="100"
|
||||||
|
height="100"
|
||||||
|
>
|
||||||
|
<circle cx="50" cy="50" r="50" className="fill-foreground" />
|
||||||
</mask>
|
</mask>
|
||||||
<g mask="url(#a)">
|
<g mask="url(#a)">
|
||||||
<circle cx="11" cy="119" r="52" className="fill-muted-foreground stroke-foreground" strokeWidth="4"/>
|
<circle
|
||||||
<circle cx="10" cy="125" r="52" className="fill-muted-foreground stroke-foreground" strokeWidth="4"/>
|
cx="11"
|
||||||
<circle cx="9" cy="131" r="52" className="fill-muted-foreground stroke-muted-foreground" strokeWidth="4"/>
|
cy="119"
|
||||||
<circle cx="88" cy="119" r="52" className="fill-muted-foreground stroke-foreground" strokeWidth="4"/>
|
r="52"
|
||||||
<path className="fill-foreground" d="M89 35h2v5h-2zM83 34l2 1-1 4h-2zM77 31l2 1-3 4-2-1zM73 27l1 1-3 4-1-2zM70 23l1 1-4 3-1-2zM68 18v2l-4 1-1-2zM68 11l1 2-5 1-1-2zM69 6v2h-5V6z"/>
|
className="fill-muted-foreground stroke-foreground"
|
||||||
<circle cx="89" cy="125" r="52" className="fill-muted-foreground stroke-foreground" strokeWidth="4"/>
|
strokeWidth="4"
|
||||||
<circle cx="90" cy="131" r="52" className="fill-muted-foreground stroke-muted-foreground" strokeWidth="4"/>
|
/>
|
||||||
<ellipse cx="49.5" cy="119" rx="41.5" ry="51" className="fill-muted-foreground"/>
|
<circle
|
||||||
<path d="M34 38v-9c1 1 2 4 5 6l7 30-8 2c-1-23-2-23-4-29Z" className="fill-foreground stroke-muted-foreground"/>
|
cx="10"
|
||||||
<path fillRule="evenodd" clipRule="evenodd" d="M95 123c0 31-20 57-45 57S5 154 5 123c0-27 14-50 33-56l12-2c25 0 45 26 45 58Zm-45 47c22 0 39-22 39-50S72 70 50 70s-39 22-39 50 17 50 39 50Z" className="fill-foreground"/>
|
cy="125"
|
||||||
<path d="M34 29c-4-8-11-5-14-4 2 3 5 4 9 4h5Z" className="fill-foreground stroke-muted-foreground"/>
|
r="52"
|
||||||
<path d="M25 38c-1 6 0 14 2 18 5-7 7-13 7-18v-9c-5 1-7 5-9 9Z" className="fill-muted-foreground"/>
|
className="fill-muted-foreground stroke-foreground"
|
||||||
<path d="M34 29c-1 3-5 11-5 16m5-16c-5 1-7 5-9 9-1 6 0 14 2 18 5-7 7-13 7-18v-9Z" className="stroke-muted-foreground"/>
|
strokeWidth="4"
|
||||||
<path d="M44 18c-10 1-11 7-10 11l4-3c5-4 6-7 6-8Z" className="fill-foreground stroke-muted-foreground"/>
|
/>
|
||||||
<path d="M34 29h7l18 4c-3-6-9-14-21-7l-4 3Z" className="fill-foreground"/>
|
<circle
|
||||||
<path d="M34 29c4-2 12-5 18-1m-18 1h7l18 4c-3-6-9-14-21-7l-4 3Z" className="stroke-muted-foreground"/>
|
cx="9"
|
||||||
<path d="M32 29a1189 1189 0 0 1-16 19c0-17 7-18 13-19h5a14 14 0 0 1-2 0Z" className="fill-foreground"/>
|
cy="131"
|
||||||
<path d="M34 29c-5 1-7 5-9 9l-9 10c0-17 7-18 13-19h5Zm0 0c-5 2-11 3-14 10" className="stroke-muted-foreground"/>
|
r="52"
|
||||||
<path d="M41 29c9 2 13 10 15 14a25 25 0 0 1-22-14h7Z" className="fill-foreground"/>
|
className="fill-muted-foreground stroke-muted-foreground"
|
||||||
<path d="M34 29c3 1 11 5 15 9m-15-9h7c9 2 13 10 15 14a25 25 0 0 1-22-14Z" className="stroke-muted-foreground"/>
|
strokeWidth="4"
|
||||||
<circle cx="91.5" cy="12.5" r="18.5" className="fill-foreground stroke-muted-foreground" strokeWidth="2"/>
|
/>
|
||||||
|
<circle
|
||||||
|
cx="88"
|
||||||
|
cy="119"
|
||||||
|
r="52"
|
||||||
|
className="fill-muted-foreground stroke-foreground"
|
||||||
|
strokeWidth="4"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
className="fill-foreground"
|
||||||
|
d="M89 35h2v5h-2zM83 34l2 1-1 4h-2zM77 31l2 1-3 4-2-1zM73 27l1 1-3 4-1-2zM70 23l1 1-4 3-1-2zM68 18v2l-4 1-1-2zM68 11l1 2-5 1-1-2zM69 6v2h-5V6z"
|
||||||
|
/>
|
||||||
|
<circle
|
||||||
|
cx="89"
|
||||||
|
cy="125"
|
||||||
|
r="52"
|
||||||
|
className="fill-muted-foreground stroke-foreground"
|
||||||
|
strokeWidth="4"
|
||||||
|
/>
|
||||||
|
<circle
|
||||||
|
cx="90"
|
||||||
|
cy="131"
|
||||||
|
r="52"
|
||||||
|
className="fill-muted-foreground stroke-muted-foreground"
|
||||||
|
strokeWidth="4"
|
||||||
|
/>
|
||||||
|
<ellipse
|
||||||
|
cx="49.5"
|
||||||
|
cy="119"
|
||||||
|
rx="41.5"
|
||||||
|
ry="51"
|
||||||
|
className="fill-muted-foreground"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M34 38v-9c1 1 2 4 5 6l7 30-8 2c-1-23-2-23-4-29Z"
|
||||||
|
className="fill-foreground stroke-muted-foreground"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
fillRule="evenodd"
|
||||||
|
clipRule="evenodd"
|
||||||
|
d="M95 123c0 31-20 57-45 57S5 154 5 123c0-27 14-50 33-56l12-2c25 0 45 26 45 58Zm-45 47c22 0 39-22 39-50S72 70 50 70s-39 22-39 50 17 50 39 50Z"
|
||||||
|
className="fill-foreground"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M34 29c-4-8-11-5-14-4 2 3 5 4 9 4h5Z"
|
||||||
|
className="fill-foreground stroke-muted-foreground"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M25 38c-1 6 0 14 2 18 5-7 7-13 7-18v-9c-5 1-7 5-9 9Z"
|
||||||
|
className="fill-muted-foreground"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M34 29c-1 3-5 11-5 16m5-16c-5 1-7 5-9 9-1 6 0 14 2 18 5-7 7-13 7-18v-9Z"
|
||||||
|
className="stroke-muted-foreground"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M44 18c-10 1-11 7-10 11l4-3c5-4 6-7 6-8Z"
|
||||||
|
className="fill-foreground stroke-muted-foreground"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M34 29h7l18 4c-3-6-9-14-21-7l-4 3Z"
|
||||||
|
className="fill-foreground"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M34 29c4-2 12-5 18-1m-18 1h7l18 4c-3-6-9-14-21-7l-4 3Z"
|
||||||
|
className="stroke-muted-foreground"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M32 29a1189 1189 0 0 1-16 19c0-17 7-18 13-19h5a14 14 0 0 1-2 0Z"
|
||||||
|
className="fill-foreground"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M34 29c-5 1-7 5-9 9l-9 10c0-17 7-18 13-19h5Zm0 0c-5 2-11 3-14 10"
|
||||||
|
className="stroke-muted-foreground"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M41 29c9 2 13 10 15 14a25 25 0 0 1-22-14h7Z"
|
||||||
|
className="fill-foreground"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M34 29c3 1 11 5 15 9m-15-9h7c9 2 13 10 15 14a25 25 0 0 1-22-14Z"
|
||||||
|
className="stroke-muted-foreground"
|
||||||
|
/>
|
||||||
|
<circle
|
||||||
|
cx="91.5"
|
||||||
|
cy="12.5"
|
||||||
|
r="18.5"
|
||||||
|
className="fill-foreground stroke-muted-foreground"
|
||||||
|
strokeWidth="2"
|
||||||
|
/>
|
||||||
</g>
|
</g>
|
||||||
</svg>
|
</svg>
|
||||||
)
|
),
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -37,5 +37,5 @@ export const techStackIcons: TechStackIconType = {
|
|||||||
tanstack: {
|
tanstack: {
|
||||||
name: "TanStack Start",
|
name: "TanStack Start",
|
||||||
icon: <Icons.tanstack className="w-10 h-10" />,
|
icon: <Icons.tanstack className="w-10 h-10" />,
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
"use client"
|
"use client";
|
||||||
|
|
||||||
import * as React from "react"
|
import * as React from "react";
|
||||||
import * as AvatarPrimitive from "@radix-ui/react-avatar"
|
import * as AvatarPrimitive from "@radix-ui/react-avatar";
|
||||||
|
|
||||||
import { cn } from "~/lib/utils"
|
import { cn } from "~/lib/utils";
|
||||||
|
|
||||||
const Avatar = React.forwardRef<
|
const Avatar = React.forwardRef<
|
||||||
React.ElementRef<typeof AvatarPrimitive.Root>,
|
React.ElementRef<typeof AvatarPrimitive.Root>,
|
||||||
@@ -13,12 +13,12 @@ const Avatar = React.forwardRef<
|
|||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
"relative flex h-10 w-10 shrink-0 overflow-hidden rounded-full",
|
"relative flex h-10 w-10 shrink-0 overflow-hidden rounded-full",
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
))
|
));
|
||||||
Avatar.displayName = AvatarPrimitive.Root.displayName
|
Avatar.displayName = AvatarPrimitive.Root.displayName;
|
||||||
|
|
||||||
const AvatarImage = React.forwardRef<
|
const AvatarImage = React.forwardRef<
|
||||||
React.ElementRef<typeof AvatarPrimitive.Image>,
|
React.ElementRef<typeof AvatarPrimitive.Image>,
|
||||||
@@ -29,8 +29,8 @@ const AvatarImage = React.forwardRef<
|
|||||||
className={cn("aspect-square h-full w-full", className)}
|
className={cn("aspect-square h-full w-full", className)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
))
|
));
|
||||||
AvatarImage.displayName = AvatarPrimitive.Image.displayName
|
AvatarImage.displayName = AvatarPrimitive.Image.displayName;
|
||||||
|
|
||||||
const AvatarFallback = React.forwardRef<
|
const AvatarFallback = React.forwardRef<
|
||||||
React.ElementRef<typeof AvatarPrimitive.Fallback>,
|
React.ElementRef<typeof AvatarPrimitive.Fallback>,
|
||||||
@@ -40,11 +40,11 @@ const AvatarFallback = React.forwardRef<
|
|||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
"flex h-full w-full items-center justify-center rounded-full bg-muted",
|
"flex h-full w-full items-center justify-center rounded-full bg-muted",
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
))
|
));
|
||||||
AvatarFallback.displayName = AvatarPrimitive.Fallback.displayName
|
AvatarFallback.displayName = AvatarPrimitive.Fallback.displayName;
|
||||||
|
|
||||||
export { Avatar, AvatarImage, AvatarFallback }
|
export { Avatar, AvatarImage, AvatarFallback };
|
||||||
|
|||||||
@@ -1,18 +1,18 @@
|
|||||||
"use client"
|
"use client";
|
||||||
|
|
||||||
import * as React from "react"
|
import * as React from "react";
|
||||||
import * as DialogPrimitive from "@radix-ui/react-dialog"
|
import * as DialogPrimitive from "@radix-ui/react-dialog";
|
||||||
import { X } from "lucide-react"
|
import { X } from "lucide-react";
|
||||||
|
|
||||||
import { cn } from "~/lib/utils"
|
import { cn } from "~/lib/utils";
|
||||||
|
|
||||||
const Dialog = DialogPrimitive.Root
|
const Dialog = DialogPrimitive.Root;
|
||||||
|
|
||||||
const DialogTrigger = DialogPrimitive.Trigger
|
const DialogTrigger = DialogPrimitive.Trigger;
|
||||||
|
|
||||||
const DialogPortal = DialogPrimitive.Portal
|
const DialogPortal = DialogPrimitive.Portal;
|
||||||
|
|
||||||
const DialogClose = DialogPrimitive.Close
|
const DialogClose = DialogPrimitive.Close;
|
||||||
|
|
||||||
const DialogOverlay = React.forwardRef<
|
const DialogOverlay = React.forwardRef<
|
||||||
React.ElementRef<typeof DialogPrimitive.Overlay>,
|
React.ElementRef<typeof DialogPrimitive.Overlay>,
|
||||||
@@ -22,12 +22,12 @@ const DialogOverlay = React.forwardRef<
|
|||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
"fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
|
"fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
))
|
));
|
||||||
DialogOverlay.displayName = DialogPrimitive.Overlay.displayName
|
DialogOverlay.displayName = DialogPrimitive.Overlay.displayName;
|
||||||
|
|
||||||
const DialogContent = React.forwardRef<
|
const DialogContent = React.forwardRef<
|
||||||
React.ElementRef<typeof DialogPrimitive.Content>,
|
React.ElementRef<typeof DialogPrimitive.Content>,
|
||||||
@@ -39,7 +39,7 @@ const DialogContent = React.forwardRef<
|
|||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
"fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg",
|
"fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg",
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
@@ -50,8 +50,8 @@ const DialogContent = React.forwardRef<
|
|||||||
</DialogPrimitive.Close>
|
</DialogPrimitive.Close>
|
||||||
</DialogPrimitive.Content>
|
</DialogPrimitive.Content>
|
||||||
</DialogPortal>
|
</DialogPortal>
|
||||||
))
|
));
|
||||||
DialogContent.displayName = DialogPrimitive.Content.displayName
|
DialogContent.displayName = DialogPrimitive.Content.displayName;
|
||||||
|
|
||||||
const DialogHeader = ({
|
const DialogHeader = ({
|
||||||
className,
|
className,
|
||||||
@@ -60,12 +60,12 @@ const DialogHeader = ({
|
|||||||
<div
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
"flex flex-col space-y-1.5 text-center sm:text-left",
|
"flex flex-col space-y-1.5 text-center sm:text-left",
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
)
|
);
|
||||||
DialogHeader.displayName = "DialogHeader"
|
DialogHeader.displayName = "DialogHeader";
|
||||||
|
|
||||||
const DialogFooter = ({
|
const DialogFooter = ({
|
||||||
className,
|
className,
|
||||||
@@ -74,12 +74,12 @@ const DialogFooter = ({
|
|||||||
<div
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
|
"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
)
|
);
|
||||||
DialogFooter.displayName = "DialogFooter"
|
DialogFooter.displayName = "DialogFooter";
|
||||||
|
|
||||||
const DialogTitle = React.forwardRef<
|
const DialogTitle = React.forwardRef<
|
||||||
React.ElementRef<typeof DialogPrimitive.Title>,
|
React.ElementRef<typeof DialogPrimitive.Title>,
|
||||||
@@ -89,12 +89,12 @@ const DialogTitle = React.forwardRef<
|
|||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
"text-lg font-semibold leading-none tracking-tight",
|
"text-lg font-semibold leading-none tracking-tight",
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
))
|
));
|
||||||
DialogTitle.displayName = DialogPrimitive.Title.displayName
|
DialogTitle.displayName = DialogPrimitive.Title.displayName;
|
||||||
|
|
||||||
const DialogDescription = React.forwardRef<
|
const DialogDescription = React.forwardRef<
|
||||||
React.ElementRef<typeof DialogPrimitive.Description>,
|
React.ElementRef<typeof DialogPrimitive.Description>,
|
||||||
@@ -105,8 +105,8 @@ const DialogDescription = React.forwardRef<
|
|||||||
className={cn("text-sm text-muted-foreground", className)}
|
className={cn("text-sm text-muted-foreground", className)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
))
|
));
|
||||||
DialogDescription.displayName = DialogPrimitive.Description.displayName
|
DialogDescription.displayName = DialogPrimitive.Description.displayName;
|
||||||
|
|
||||||
export {
|
export {
|
||||||
Dialog,
|
Dialog,
|
||||||
@@ -119,4 +119,4 @@ export {
|
|||||||
DialogFooter,
|
DialogFooter,
|
||||||
DialogTitle,
|
DialogTitle,
|
||||||
DialogDescription,
|
DialogDescription,
|
||||||
}
|
};
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
"use client"
|
"use client";
|
||||||
|
|
||||||
import * as React from "react"
|
import * as React from "react";
|
||||||
import * as LabelPrimitive from "@radix-ui/react-label"
|
import * as LabelPrimitive from "@radix-ui/react-label";
|
||||||
import { cva, type VariantProps } from "class-variance-authority"
|
import { cva, type VariantProps } from "class-variance-authority";
|
||||||
|
|
||||||
import { cn } from "~/lib/utils"
|
import { cn } from "~/lib/utils";
|
||||||
|
|
||||||
const labelVariants = cva(
|
const labelVariants = cva(
|
||||||
"text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
|
"text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70",
|
||||||
)
|
);
|
||||||
|
|
||||||
const Label = React.forwardRef<
|
const Label = React.forwardRef<
|
||||||
React.ElementRef<typeof LabelPrimitive.Root>,
|
React.ElementRef<typeof LabelPrimitive.Root>,
|
||||||
@@ -20,7 +20,7 @@ const Label = React.forwardRef<
|
|||||||
className={cn(labelVariants(), className)}
|
className={cn(labelVariants(), className)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
))
|
));
|
||||||
Label.displayName = LabelPrimitive.Root.displayName
|
Label.displayName = LabelPrimitive.Root.displayName;
|
||||||
|
|
||||||
export { Label }
|
export { Label };
|
||||||
|
|||||||
@@ -1,9 +1,12 @@
|
|||||||
import { twoFactorClient } from "better-auth/plugins";
|
import { twoFactorClient } from "better-auth/plugins";
|
||||||
import { createAuthClient } from "better-auth/react";
|
import { createAuthClient } from "better-auth/react";
|
||||||
|
|
||||||
export const { useSession, signIn, signOut, signUp, twoFactor } = createAuthClient({
|
export const { useSession, signIn, signOut, signUp, twoFactor } =
|
||||||
|
createAuthClient({
|
||||||
baseURL: "http://localhost:3000",
|
baseURL: "http://localhost:3000",
|
||||||
plugins: [twoFactorClient({
|
plugins: [
|
||||||
|
twoFactorClient({
|
||||||
twoFactorPage: "/auth/two-factor",
|
twoFactorPage: "/auth/two-factor",
|
||||||
})]
|
}),
|
||||||
});
|
],
|
||||||
|
});
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { twoFactor } from 'better-auth/plugins';
|
import { twoFactor } from "better-auth/plugins";
|
||||||
import { betterAuth } from "better-auth";
|
import { betterAuth } from "better-auth";
|
||||||
import Database from "better-sqlite3";
|
import Database from "better-sqlite3";
|
||||||
|
|
||||||
@@ -19,5 +19,5 @@ export const auth = betterAuth({
|
|||||||
clientSecret: process.env.GITHUB_CLIENT_SECRET!,
|
clientSecret: process.env.GITHUB_CLIENT_SECRET!,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
plugins: [twoFactor()]
|
plugins: [twoFactor()],
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { X } from 'lucide-react-native';
|
import { X } from "lucide-react-native";
|
||||||
import { iconWithClassName } from './iconWithClassName';
|
import { iconWithClassName } from "./iconWithClassName";
|
||||||
iconWithClassName(X);
|
iconWithClassName(X);
|
||||||
export { X };
|
export { X };
|
||||||
@@ -1,14 +1,14 @@
|
|||||||
import type { LucideIcon } from 'lucide-react-native';
|
import type { LucideIcon } from "lucide-react-native";
|
||||||
import { cssInterop } from 'nativewind';
|
import { cssInterop } from "nativewind";
|
||||||
|
|
||||||
export function iconWithClassName(icon: LucideIcon) {
|
export function iconWithClassName(icon: LucideIcon) {
|
||||||
cssInterop(icon, {
|
cssInterop(icon, {
|
||||||
className: {
|
className: {
|
||||||
target: 'style',
|
target: "style",
|
||||||
nativeStyleToProp: {
|
nativeStyleToProp: {
|
||||||
color: true,
|
color: true,
|
||||||
opacity: true,
|
opacity: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
import { LoginForm } from "~/components/login-form"
|
import { LoginForm } from "~/components/login-form";
|
||||||
|
|
||||||
export default function Page() {
|
export default function Page() {
|
||||||
return (
|
return (
|
||||||
<div className="flex h-screen w-full items-center justify-center px-4">
|
<div className="flex h-screen w-full items-center justify-center px-4">
|
||||||
<LoginForm />
|
<LoginForm />
|
||||||
</div>
|
</div>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,111 +10,111 @@
|
|||||||
|
|
||||||
// Import Routes
|
// Import Routes
|
||||||
|
|
||||||
import { Route as rootRoute } from './routes/__root'
|
import { Route as rootRoute } from "./routes/__root";
|
||||||
import { Route as IndexImport } from './routes/index'
|
import { Route as IndexImport } from "./routes/index";
|
||||||
import { Route as AuthTwoFactorImport } from './routes/auth/two-factor'
|
import { Route as AuthTwoFactorImport } from "./routes/auth/two-factor";
|
||||||
import { Route as AuthSignupImport } from './routes/auth/signup'
|
import { Route as AuthSignupImport } from "./routes/auth/signup";
|
||||||
import { Route as AuthSigninImport } from './routes/auth/signin'
|
import { Route as AuthSigninImport } from "./routes/auth/signin";
|
||||||
|
|
||||||
// Create/Update Routes
|
// Create/Update Routes
|
||||||
|
|
||||||
const IndexRoute = IndexImport.update({
|
const IndexRoute = IndexImport.update({
|
||||||
id: '/',
|
id: "/",
|
||||||
path: '/',
|
path: "/",
|
||||||
getParentRoute: () => rootRoute,
|
getParentRoute: () => rootRoute,
|
||||||
} as any)
|
} as any);
|
||||||
|
|
||||||
const AuthTwoFactorRoute = AuthTwoFactorImport.update({
|
const AuthTwoFactorRoute = AuthTwoFactorImport.update({
|
||||||
id: '/auth/two-factor',
|
id: "/auth/two-factor",
|
||||||
path: '/auth/two-factor',
|
path: "/auth/two-factor",
|
||||||
getParentRoute: () => rootRoute,
|
getParentRoute: () => rootRoute,
|
||||||
} as any)
|
} as any);
|
||||||
|
|
||||||
const AuthSignupRoute = AuthSignupImport.update({
|
const AuthSignupRoute = AuthSignupImport.update({
|
||||||
id: '/auth/signup',
|
id: "/auth/signup",
|
||||||
path: '/auth/signup',
|
path: "/auth/signup",
|
||||||
getParentRoute: () => rootRoute,
|
getParentRoute: () => rootRoute,
|
||||||
} as any)
|
} as any);
|
||||||
|
|
||||||
const AuthSigninRoute = AuthSigninImport.update({
|
const AuthSigninRoute = AuthSigninImport.update({
|
||||||
id: '/auth/signin',
|
id: "/auth/signin",
|
||||||
path: '/auth/signin',
|
path: "/auth/signin",
|
||||||
getParentRoute: () => rootRoute,
|
getParentRoute: () => rootRoute,
|
||||||
} as any)
|
} as any);
|
||||||
|
|
||||||
// Populate the FileRoutesByPath interface
|
// Populate the FileRoutesByPath interface
|
||||||
|
|
||||||
declare module '@tanstack/react-router' {
|
declare module "@tanstack/react-router" {
|
||||||
interface FileRoutesByPath {
|
interface FileRoutesByPath {
|
||||||
'/': {
|
"/": {
|
||||||
id: '/'
|
id: "/";
|
||||||
path: '/'
|
path: "/";
|
||||||
fullPath: '/'
|
fullPath: "/";
|
||||||
preLoaderRoute: typeof IndexImport
|
preLoaderRoute: typeof IndexImport;
|
||||||
parentRoute: typeof rootRoute
|
parentRoute: typeof rootRoute;
|
||||||
}
|
};
|
||||||
'/auth/signin': {
|
"/auth/signin": {
|
||||||
id: '/auth/signin'
|
id: "/auth/signin";
|
||||||
path: '/auth/signin'
|
path: "/auth/signin";
|
||||||
fullPath: '/auth/signin'
|
fullPath: "/auth/signin";
|
||||||
preLoaderRoute: typeof AuthSigninImport
|
preLoaderRoute: typeof AuthSigninImport;
|
||||||
parentRoute: typeof rootRoute
|
parentRoute: typeof rootRoute;
|
||||||
}
|
};
|
||||||
'/auth/signup': {
|
"/auth/signup": {
|
||||||
id: '/auth/signup'
|
id: "/auth/signup";
|
||||||
path: '/auth/signup'
|
path: "/auth/signup";
|
||||||
fullPath: '/auth/signup'
|
fullPath: "/auth/signup";
|
||||||
preLoaderRoute: typeof AuthSignupImport
|
preLoaderRoute: typeof AuthSignupImport;
|
||||||
parentRoute: typeof rootRoute
|
parentRoute: typeof rootRoute;
|
||||||
}
|
};
|
||||||
'/auth/two-factor': {
|
"/auth/two-factor": {
|
||||||
id: '/auth/two-factor'
|
id: "/auth/two-factor";
|
||||||
path: '/auth/two-factor'
|
path: "/auth/two-factor";
|
||||||
fullPath: '/auth/two-factor'
|
fullPath: "/auth/two-factor";
|
||||||
preLoaderRoute: typeof AuthTwoFactorImport
|
preLoaderRoute: typeof AuthTwoFactorImport;
|
||||||
parentRoute: typeof rootRoute
|
parentRoute: typeof rootRoute;
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create and export the route tree
|
// Create and export the route tree
|
||||||
|
|
||||||
export interface FileRoutesByFullPath {
|
export interface FileRoutesByFullPath {
|
||||||
'/': typeof IndexRoute
|
"/": typeof IndexRoute;
|
||||||
'/auth/signin': typeof AuthSigninRoute
|
"/auth/signin": typeof AuthSigninRoute;
|
||||||
'/auth/signup': typeof AuthSignupRoute
|
"/auth/signup": typeof AuthSignupRoute;
|
||||||
'/auth/two-factor': typeof AuthTwoFactorRoute
|
"/auth/two-factor": typeof AuthTwoFactorRoute;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface FileRoutesByTo {
|
export interface FileRoutesByTo {
|
||||||
'/': typeof IndexRoute
|
"/": typeof IndexRoute;
|
||||||
'/auth/signin': typeof AuthSigninRoute
|
"/auth/signin": typeof AuthSigninRoute;
|
||||||
'/auth/signup': typeof AuthSignupRoute
|
"/auth/signup": typeof AuthSignupRoute;
|
||||||
'/auth/two-factor': typeof AuthTwoFactorRoute
|
"/auth/two-factor": typeof AuthTwoFactorRoute;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface FileRoutesById {
|
export interface FileRoutesById {
|
||||||
__root__: typeof rootRoute
|
__root__: typeof rootRoute;
|
||||||
'/': typeof IndexRoute
|
"/": typeof IndexRoute;
|
||||||
'/auth/signin': typeof AuthSigninRoute
|
"/auth/signin": typeof AuthSigninRoute;
|
||||||
'/auth/signup': typeof AuthSignupRoute
|
"/auth/signup": typeof AuthSignupRoute;
|
||||||
'/auth/two-factor': typeof AuthTwoFactorRoute
|
"/auth/two-factor": typeof AuthTwoFactorRoute;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface FileRouteTypes {
|
export interface FileRouteTypes {
|
||||||
fileRoutesByFullPath: FileRoutesByFullPath
|
fileRoutesByFullPath: FileRoutesByFullPath;
|
||||||
fullPaths: '/' | '/auth/signin' | '/auth/signup' | '/auth/two-factor'
|
fullPaths: "/" | "/auth/signin" | "/auth/signup" | "/auth/two-factor";
|
||||||
fileRoutesByTo: FileRoutesByTo
|
fileRoutesByTo: FileRoutesByTo;
|
||||||
to: '/' | '/auth/signin' | '/auth/signup' | '/auth/two-factor'
|
to: "/" | "/auth/signin" | "/auth/signup" | "/auth/two-factor";
|
||||||
id: '__root__' | '/' | '/auth/signin' | '/auth/signup' | '/auth/two-factor'
|
id: "__root__" | "/" | "/auth/signin" | "/auth/signup" | "/auth/two-factor";
|
||||||
fileRoutesById: FileRoutesById
|
fileRoutesById: FileRoutesById;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface RootRouteChildren {
|
export interface RootRouteChildren {
|
||||||
IndexRoute: typeof IndexRoute
|
IndexRoute: typeof IndexRoute;
|
||||||
AuthSigninRoute: typeof AuthSigninRoute
|
AuthSigninRoute: typeof AuthSigninRoute;
|
||||||
AuthSignupRoute: typeof AuthSignupRoute
|
AuthSignupRoute: typeof AuthSignupRoute;
|
||||||
AuthTwoFactorRoute: typeof AuthTwoFactorRoute
|
AuthTwoFactorRoute: typeof AuthTwoFactorRoute;
|
||||||
}
|
}
|
||||||
|
|
||||||
const rootRouteChildren: RootRouteChildren = {
|
const rootRouteChildren: RootRouteChildren = {
|
||||||
@@ -122,11 +122,11 @@ const rootRouteChildren: RootRouteChildren = {
|
|||||||
AuthSigninRoute: AuthSigninRoute,
|
AuthSigninRoute: AuthSigninRoute,
|
||||||
AuthSignupRoute: AuthSignupRoute,
|
AuthSignupRoute: AuthSignupRoute,
|
||||||
AuthTwoFactorRoute: AuthTwoFactorRoute,
|
AuthTwoFactorRoute: AuthTwoFactorRoute,
|
||||||
}
|
};
|
||||||
|
|
||||||
export const routeTree = rootRoute
|
export const routeTree = rootRoute
|
||||||
._addFileChildren(rootRouteChildren)
|
._addFileChildren(rootRouteChildren)
|
||||||
._addFileTypes<FileRouteTypes>()
|
._addFileTypes<FileRouteTypes>();
|
||||||
|
|
||||||
/* prettier-ignore-end */
|
/* prettier-ignore-end */
|
||||||
|
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ function RootComponent() {
|
|||||||
const [theme, setTheme] = useState<"light" | "dark">("light");
|
const [theme, setTheme] = useState<"light" | "dark">("light");
|
||||||
const { data, isPending, error } = useSession();
|
const { data, isPending, error } = useSession();
|
||||||
const { navigate } = useRouter();
|
const { navigate } = useRouter();
|
||||||
console.log()
|
console.log();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!data?.user) {
|
if (!data?.user) {
|
||||||
@@ -61,7 +61,6 @@ function RootComponent() {
|
|||||||
);
|
);
|
||||||
}, [data, navigate]);
|
}, [data, navigate]);
|
||||||
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const root = window.document.documentElement;
|
const root = window.document.documentElement;
|
||||||
|
|
||||||
|
|||||||
@@ -1,18 +1,24 @@
|
|||||||
import { createFileRoute } from '@tanstack/react-router'
|
import { createFileRoute } from "@tanstack/react-router";
|
||||||
import { AlertCircle, CheckCircle2 } from 'lucide-react'
|
import { AlertCircle, CheckCircle2 } from "lucide-react";
|
||||||
import { useState } from 'react'
|
import { useState } from "react";
|
||||||
import { Button } from '~/components/ui/button'
|
import { Button } from "~/components/ui/button";
|
||||||
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from '~/components/ui/card'
|
import {
|
||||||
import { Input } from '~/components/ui/input'
|
Card,
|
||||||
import { Label } from '~/components/ui/label'
|
CardContent,
|
||||||
import { twoFactor } from '~/lib/auth-client'
|
CardDescription,
|
||||||
|
CardFooter,
|
||||||
|
CardHeader,
|
||||||
|
CardTitle,
|
||||||
|
} from "~/components/ui/card";
|
||||||
|
import { Input } from "~/components/ui/input";
|
||||||
|
import { Label } from "~/components/ui/label";
|
||||||
|
import { twoFactor } from "~/lib/auth-client";
|
||||||
|
|
||||||
export const Route = createFileRoute('/auth/two-factor')({
|
export const Route = createFileRoute("/auth/two-factor")({
|
||||||
component: TwoFactor
|
component: TwoFactor,
|
||||||
})
|
});
|
||||||
|
|
||||||
|
function TwoFactor() {
|
||||||
function TwoFactor(){
|
|
||||||
const [totpCode, setTotpCode] = useState("");
|
const [totpCode, setTotpCode] = useState("");
|
||||||
const [error, setError] = useState("");
|
const [error, setError] = useState("");
|
||||||
const [success, setSuccess] = useState(false);
|
const [success, setSuccess] = useState(false);
|
||||||
@@ -80,5 +86,5 @@ function TwoFactor(){
|
|||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
</main>
|
</main>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
@@ -4,12 +4,12 @@ import {
|
|||||||
CardDescription,
|
CardDescription,
|
||||||
CardHeader,
|
CardHeader,
|
||||||
CardTitle,
|
CardTitle,
|
||||||
} from '~/components/ui/card'
|
} from "~/components/ui/card";
|
||||||
|
|
||||||
import { twoFactor, useSession } from '~/lib/auth-client'
|
import { twoFactor, useSession } from "~/lib/auth-client";
|
||||||
import { UAParser } from 'ua-parser-js'
|
import { UAParser } from "ua-parser-js";
|
||||||
import { Laptop, Loader2, Phone, ShieldCheck, ShieldOff } from 'lucide-react'
|
import { Laptop, Loader2, Phone, ShieldCheck, ShieldOff } from "lucide-react";
|
||||||
import { useState } from 'react'
|
import { useState } from "react";
|
||||||
import {
|
import {
|
||||||
Dialog,
|
Dialog,
|
||||||
DialogContent,
|
DialogContent,
|
||||||
@@ -18,24 +18,24 @@ import {
|
|||||||
DialogHeader,
|
DialogHeader,
|
||||||
DialogTitle,
|
DialogTitle,
|
||||||
DialogTrigger,
|
DialogTrigger,
|
||||||
} from '~/components/ui/dialog'
|
} from "~/components/ui/dialog";
|
||||||
import { Button } from '~/components/ui/button'
|
import { Button } from "~/components/ui/button";
|
||||||
import { Label } from '~/components/ui/label'
|
import { Label } from "~/components/ui/label";
|
||||||
import { Input } from '~/components/ui/input'
|
import { Input } from "~/components/ui/input";
|
||||||
import { toast } from 'sonner'
|
import { toast } from "sonner";
|
||||||
import QRCode from 'react-qr-code'
|
import QRCode from "react-qr-code";
|
||||||
import { createFileRoute } from '@tanstack/react-router'
|
import { createFileRoute } from "@tanstack/react-router";
|
||||||
|
|
||||||
export const Route = createFileRoute('/')({
|
export const Route = createFileRoute("/")({
|
||||||
component: Home,
|
component: Home,
|
||||||
})
|
});
|
||||||
|
|
||||||
function Home() {
|
function Home() {
|
||||||
const { data } = useSession()
|
const { data } = useSession();
|
||||||
const [twoFactorDialog, setTwoFactorDialog] = useState(false)
|
const [twoFactorDialog, setTwoFactorDialog] = useState(false);
|
||||||
const [twoFaPassword, setTwoFaPassword] = useState('')
|
const [twoFaPassword, setTwoFaPassword] = useState("");
|
||||||
const [isPendingTwoFa, setIsPendingTwoFa] = useState(false)
|
const [isPendingTwoFa, setIsPendingTwoFa] = useState(false);
|
||||||
const [twoFactorVerifyURI, setTwoFactorVerifyURI] = useState<string>('')
|
const [twoFactorVerifyURI, setTwoFactorVerifyURI] = useState<string>("");
|
||||||
return (
|
return (
|
||||||
<div className="container flex justify-center items-center min-h-[80vh]">
|
<div className="container flex justify-center items-center min-h-[80vh]">
|
||||||
<Card className="w-fit">
|
<Card className="w-fit">
|
||||||
@@ -51,12 +51,12 @@ function Home() {
|
|||||||
<div className="flex flex-col">
|
<div className="flex flex-col">
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
{new UAParser(data.session.userAgent).getDevice().type ===
|
{new UAParser(data.session.userAgent).getDevice().type ===
|
||||||
'mobile' ? (
|
"mobile" ? (
|
||||||
<Phone />
|
<Phone />
|
||||||
) : (
|
) : (
|
||||||
<Laptop size={16} />
|
<Laptop size={16} />
|
||||||
)}
|
)}
|
||||||
{new UAParser(data.session.userAgent).getOS().name},{' '}
|
{new UAParser(data.session.userAgent).getOS().name},{" "}
|
||||||
{new UAParser(data.session.userAgent).getBrowser().name}
|
{new UAParser(data.session.userAgent).getBrowser().name}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -70,8 +70,8 @@ function Home() {
|
|||||||
<Button
|
<Button
|
||||||
variant={
|
variant={
|
||||||
data?.user.twoFactorEnabled
|
data?.user.twoFactorEnabled
|
||||||
? 'destructive'
|
? "destructive"
|
||||||
: 'outline'
|
: "outline"
|
||||||
}
|
}
|
||||||
className="gap-2"
|
className="gap-2"
|
||||||
>
|
>
|
||||||
@@ -82,8 +82,8 @@ function Home() {
|
|||||||
)}
|
)}
|
||||||
<span className="md:text-sm text-xs">
|
<span className="md:text-sm text-xs">
|
||||||
{data?.user.twoFactorEnabled
|
{data?.user.twoFactorEnabled
|
||||||
? 'Disable 2FA'
|
? "Disable 2FA"
|
||||||
: 'Enable 2FA'}
|
: "Enable 2FA"}
|
||||||
</span>
|
</span>
|
||||||
</Button>
|
</Button>
|
||||||
</DialogTrigger>
|
</DialogTrigger>
|
||||||
@@ -91,13 +91,13 @@ function Home() {
|
|||||||
<DialogHeader>
|
<DialogHeader>
|
||||||
<DialogTitle>
|
<DialogTitle>
|
||||||
{data?.user.twoFactorEnabled
|
{data?.user.twoFactorEnabled
|
||||||
? 'Disable 2FA'
|
? "Disable 2FA"
|
||||||
: 'Enable 2FA'}
|
: "Enable 2FA"}
|
||||||
</DialogTitle>
|
</DialogTitle>
|
||||||
<DialogDescription>
|
<DialogDescription>
|
||||||
{data?.user.twoFactorEnabled
|
{data?.user.twoFactorEnabled
|
||||||
? 'Disable the second factor authentication from your account'
|
? "Disable the second factor authentication from your account"
|
||||||
: 'Enable 2FA to secure your account'}
|
: "Enable 2FA to secure your account"}
|
||||||
</DialogDescription>
|
</DialogDescription>
|
||||||
</DialogHeader>
|
</DialogHeader>
|
||||||
|
|
||||||
@@ -136,69 +136,68 @@ function Home() {
|
|||||||
!twoFactorVerifyURI
|
!twoFactorVerifyURI
|
||||||
) {
|
) {
|
||||||
toast.error(
|
toast.error(
|
||||||
'Password must be at least 8 characters',
|
"Password must be at least 8 characters",
|
||||||
)
|
);
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
setIsPendingTwoFa(true)
|
setIsPendingTwoFa(true);
|
||||||
if (data?.user.twoFactorEnabled) {
|
if (data?.user.twoFactorEnabled) {
|
||||||
const res = await twoFactor.disable({
|
const res = await twoFactor.disable({
|
||||||
//@ts-ignore
|
//@ts-ignore
|
||||||
password: twoFaPassword,
|
password: twoFaPassword,
|
||||||
fetchOptions: {
|
fetchOptions: {
|
||||||
onError(context) {
|
onError(context) {
|
||||||
toast.error(context.error.message)
|
toast.error(context.error.message);
|
||||||
},
|
},
|
||||||
onSuccess() {
|
onSuccess() {
|
||||||
toast('2FA disabled successfully')
|
toast("2FA disabled successfully");
|
||||||
setTwoFactorDialog(false)
|
setTwoFactorDialog(false);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
})
|
});
|
||||||
} else {
|
} else {
|
||||||
if (twoFactorVerifyURI) {
|
if (twoFactorVerifyURI) {
|
||||||
await twoFactor.verifyTotp({
|
await twoFactor.verifyTotp({
|
||||||
code: twoFaPassword,
|
code: twoFaPassword,
|
||||||
fetchOptions: {
|
fetchOptions: {
|
||||||
onError(context) {
|
onError(context) {
|
||||||
setIsPendingTwoFa(false)
|
setIsPendingTwoFa(false);
|
||||||
setTwoFaPassword('')
|
setTwoFaPassword("");
|
||||||
toast.error(context.error.message)
|
toast.error(context.error.message);
|
||||||
},
|
},
|
||||||
onSuccess() {
|
onSuccess() {
|
||||||
toast('2FA enabled successfully')
|
toast("2FA enabled successfully");
|
||||||
setTwoFactorVerifyURI('')
|
setTwoFactorVerifyURI("");
|
||||||
setIsPendingTwoFa(false)
|
setIsPendingTwoFa(false);
|
||||||
setTwoFaPassword('')
|
setTwoFaPassword("");
|
||||||
setTwoFactorDialog(false)
|
setTwoFactorDialog(false);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
})
|
});
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
await twoFactor.enable({
|
await twoFactor.enable({
|
||||||
password: twoFaPassword,
|
password: twoFaPassword,
|
||||||
fetchOptions: {
|
fetchOptions: {
|
||||||
onError(context) {
|
onError(context) {
|
||||||
toast.error(context.error.message)
|
toast.error(context.error.message);
|
||||||
},
|
},
|
||||||
onSuccess(ctx) {
|
onSuccess(ctx) {
|
||||||
setTwoFactorVerifyURI(ctx.data.totpURI)
|
setTwoFactorVerifyURI(ctx.data.totpURI);
|
||||||
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
setIsPendingTwoFa(false)
|
setIsPendingTwoFa(false);
|
||||||
setTwoFaPassword('')
|
setTwoFaPassword("");
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{isPendingTwoFa ? (
|
{isPendingTwoFa ? (
|
||||||
<Loader2 size={15} className="animate-spin" />
|
<Loader2 size={15} className="animate-spin" />
|
||||||
) : data?.user.twoFactorEnabled ? (
|
) : data?.user.twoFactorEnabled ? (
|
||||||
'Disable 2FA'
|
"Disable 2FA"
|
||||||
) : (
|
) : (
|
||||||
'Enable 2FA'
|
"Enable 2FA"
|
||||||
)}
|
)}
|
||||||
</Button>
|
</Button>
|
||||||
</DialogFooter>
|
</DialogFooter>
|
||||||
@@ -211,5 +210,5 @@ function Home() {
|
|||||||
)}
|
)}
|
||||||
</Card>
|
</Card>
|
||||||
</div>
|
</div>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,4 +3,4 @@ export default {
|
|||||||
tailwindcss: {},
|
tailwindcss: {},
|
||||||
autoprefixer: {},
|
autoprefixer: {},
|
||||||
},
|
},
|
||||||
}
|
};
|
||||||
|
|||||||
@@ -137,12 +137,10 @@ export const jwt = (options?: JwtOptions) => {
|
|||||||
publicKey: JSON.stringify(publicWebKey),
|
publicKey: JSON.stringify(publicWebKey),
|
||||||
privateKey: privateKeyEncryptionEnabled
|
privateKey: privateKeyEncryptionEnabled
|
||||||
? JSON.stringify(
|
? JSON.stringify(
|
||||||
await symmetricEncrypt(
|
await symmetricEncrypt({
|
||||||
{
|
|
||||||
key: ctx.context.options.secret!,
|
key: ctx.context.options.secret!,
|
||||||
data: stringifiedPrivateWebKey,
|
data: stringifiedPrivateWebKey,
|
||||||
}
|
}),
|
||||||
),
|
|
||||||
)
|
)
|
||||||
: stringifiedPrivateWebKey,
|
: stringifiedPrivateWebKey,
|
||||||
createdAt: new Date(),
|
createdAt: new Date(),
|
||||||
@@ -152,12 +150,10 @@ export const jwt = (options?: JwtOptions) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let privateWebKey = privateKeyEncryptionEnabled
|
let privateWebKey = privateKeyEncryptionEnabled
|
||||||
? await symmetricDecrypt(
|
? await symmetricDecrypt({
|
||||||
{
|
|
||||||
key: ctx.context.options.secret!,
|
key: ctx.context.options.secret!,
|
||||||
data: JSON.parse(key.privateKey),
|
data: JSON.parse(key.privateKey),
|
||||||
}
|
})
|
||||||
)
|
|
||||||
: key.privateKey;
|
: key.privateKey;
|
||||||
|
|
||||||
const privateKey = await importJWK(JSON.parse(privateWebKey));
|
const privateKey = await importJWK(JSON.parse(privateWebKey));
|
||||||
|
|||||||
Reference in New Issue
Block a user