From 81a0fec70d13142a240a21e751c09305acda8c53 Mon Sep 17 00:00:00 2001 From: avsomers25 Date: Wed, 31 Jan 2024 20:27:55 -0500 Subject: [PATCH] Basic auth now works! --- app/lib/actions.ts | 156 ++++++++++++++------------------------------- app/login/page.tsx | 59 ++++++++++++++--- auth.config.ts | 28 ++++---- auth.ts | 34 +++++----- package.json | 2 +- 5 files changed, 134 insertions(+), 145 deletions(-) diff --git a/app/lib/actions.ts b/app/lib/actions.ts index 84007c9..f9d8368 100644 --- a/app/lib/actions.ts +++ b/app/lib/actions.ts @@ -1,12 +1,13 @@ 'use server'; import { z } from 'zod'; -import { sql } from '@vercel/postgres'; import { revalidatePath } from 'next/cache'; import { redirect } from 'next/navigation'; import { signIn } from '@/auth'; import { AuthError } from 'next-auth'; +import { auth } from "../../auth" + const FormSchema = z.object({ id: z.string(), customerId: z.string({ @@ -21,120 +22,61 @@ const FormSchema = z.object({ date: z.string(), }); -const CreateInvoice = FormSchema.omit({ id: true, date: true }); -const UpdateInvoice = FormSchema.omit({ date: true, id: true }); - -// This is temporary -export type State = { - errors?: { - customerId?: string[]; - amount?: string[]; - status?: string[]; - }; - message?: string | null; -}; - -export async function createInvoice(prevState: State, formData: FormData) { - // Validate form fields using Zod - const validatedFields = CreateInvoice.safeParse({ - customerId: formData.get('customerId'), - amount: formData.get('amount'), - status: formData.get('status'), - }); - - // If form validation fails, return errors early. Otherwise, continue. - if (!validatedFields.success) { - return { - errors: validatedFields.error.flatten().fieldErrors, - message: 'Missing Fields. Failed to Create Invoice.', - }; - } - - // Prepare data for insertion into the database - const { customerId, amount, status } = validatedFields.data; - const amountInCents = amount * 100; - const date = new Date().toISOString().split('T')[0]; - - // Insert data into the database - try { - await sql` - INSERT INTO invoices (customer_id, amount, status, date) - VALUES (${customerId}, ${amountInCents}, ${status}, ${date}) - `; - } catch (error) { - // If a database error occurs, return a more specific error. - return { - message: 'Database Error: Failed to Create Invoice.', - }; - } - - // Revalidate the cache for the invoices page and redirect the user. - revalidatePath('/dashboard/invoices'); - redirect('/dashboard/invoices'); -} - -export async function updateInvoice( - id: string, - prevState: State, - formData: FormData, -) { - const validatedFields = UpdateInvoice.safeParse({ - customerId: formData.get('customerId'), - amount: formData.get('amount'), - status: formData.get('status'), - }); - - if (!validatedFields.success) { - return { - errors: validatedFields.error.flatten().fieldErrors, - message: 'Missing Fields. Failed to Update Invoice.', - }; - } - - const { customerId, amount, status } = validatedFields.data; - const amountInCents = amount * 100; - - try { - await sql` - UPDATE invoices - SET customer_id = ${customerId}, amount = ${amountInCents}, status = ${status} - WHERE id = ${id} - `; - } catch (error) { - return { message: 'Database Error: Failed to Update Invoice.' }; - } - - revalidatePath('/dashboard/invoices'); - redirect('/dashboard/invoices'); -} - -export async function deleteInvoice(id: string) { - // throw new Error('Failed to Delete Invoice'); - - try { - await sql`DELETE FROM invoices WHERE id = ${id}`; - revalidatePath('/dashboard/invoices'); - return { message: 'Deleted Invoice' }; - } catch (error) { - return { message: 'Database Error: Failed to Delete Invoice.' }; - } -} export async function authenticate( prevState: string | undefined, formData: FormData, ) { try { + console.log("FORM"); + const session = await auth(); + console.log(session); await signIn('credentials', formData); } catch (error) { - if (error instanceof AuthError) { - switch (error.type) { - case 'CredentialsSignin': - return 'Invalid credentials.'; - default: - return 'Something went wrong.'; + if (error instanceof AuthError) { + switch (error.type) { + case 'CredentialsSignin': + return 'Invalid credentials.'; + default: + return 'Something went wrong.'; + } } - } - throw error; } } + +export async function authUser(email: string, password:string){ + console.log(email); + console.log(password); + let resp = { + error: "", + response: "", + }; + + await fetch("https://api.hackru.org/dev/authorize", { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + email: email, + password: password, + }), + }).then(async (res) => { + let resJSON = await res.json(); + if (resJSON.statusCode === 403) { + resp.error = "Invalid email or password"; + } else if (resJSON.statusCode === 200) { + resp.response = resJSON.body.token; + } else{ + if (resJSON.body) { + resp.error = resJSON.body; + } else { + resp.error = "Unexpected Error"; + } + } + }) + + return resp; +} + + diff --git a/app/login/page.tsx b/app/login/page.tsx index 5c07299..cbe006a 100644 --- a/app/login/page.tsx +++ b/app/login/page.tsx @@ -1,17 +1,60 @@ -import AcmeLogo from '@/app/ui/acme-logo'; -import LoginForm from '@/app/ui/login-form'; +"use client" + +import { Button } from '@/app/ui/button'; + +import { useFormState } from 'react-dom'; + +import { authenticate, authUser } from '../lib/actions'; + export default function LoginPage() { + + const [errorMessage, dispatch] = useFormState(authenticate, undefined); + + return (
-
-
-
- +
+
+
+ +
+ +
+
+
+ +
+ +
- -
+ +
); } diff --git a/auth.config.ts b/auth.config.ts index 381823b..7720ab3 100644 --- a/auth.config.ts +++ b/auth.config.ts @@ -1,23 +1,29 @@ import type { NextAuthConfig } from 'next-auth'; export const authConfig = { - // pages: { - // signIn: '/login', - // }, + pages: { + signIn: '/login', + }, providers: [ // added later in auth.ts since it requires bcrypt which is only compatible with Node.js // while this file is also used in non-Node.js environments ], + session:{ + maxAge: 259200, + }, callbacks: { authorized({ auth, request: { nextUrl } }) { - // const isLoggedIn = !!auth?.user; - // const isOnDashboard = nextUrl.pathname.startsWith('/dashboard'); - // if (isOnDashboard) { - // if (isLoggedIn) return true; - // return false; // Redirect unauthenticated users to login page - // } else if (isLoggedIn) { - // return Response.redirect(new URL('/dashboard', nextUrl)); - // } + console.log("AUTH") + const isLoggedIn = !!auth?.user; + const isOnDashboard = nextUrl.pathname.startsWith('/dashboard'); + if (isOnDashboard) { + if (isLoggedIn) return true; + return false; // Redirect unauthenticated users to login page + } + const isOnLogin = nextUrl.pathname.startsWith('/login'); + if (isOnLogin && isLoggedIn){ + //return Response.redirect(new URL('/dashboard', nextUrl)); + } return true; }, }, diff --git a/auth.ts b/auth.ts index 3eb3a45..f062124 100644 --- a/auth.ts +++ b/auth.ts @@ -3,18 +3,13 @@ import Credentials from 'next-auth/providers/credentials'; import bcrypt from 'bcrypt'; import { sql } from '@vercel/postgres'; import { z } from 'zod'; -import type { User } from '@/app/lib/definitions'; -import { authConfig } from './auth.config'; - -async function getUser(email: string): Promise { - try { - const user = await sql`SELECT * FROM users WHERE email=${email}`; - return user.rows[0]; - } catch (error) { - console.error('Failed to fetch user:', error); - throw new Error('Failed to fetch user.'); - } -} +import { authConfig} from './auth.config'; + +import { authUser } from './app/lib/actions'; + +//https://api.hackru.org/dev/authorize + + export const { auth, signIn, signOut } = NextAuth({ ...authConfig, @@ -22,17 +17,20 @@ export const { auth, signIn, signOut } = NextAuth({ Credentials({ async authorize(credentials) { const parsedCredentials = z - .object({ email: z.string().email(), password: z.string().min(6) }) + .object({ email: z.string().email(), password: z.string() }) .safeParse(credentials); - if (parsedCredentials.success) { const { email, password } = parsedCredentials.data; - const user = await getUser(email); - if (!user) return null; + const resp = await authUser(email, password); + let user = null + if(resp.response != "") + user = {email:email, id:email, name:resp.response} + + console.log("USER"); + console.log(user) - const passwordsMatch = await bcrypt.compare(password, user.password); - if (passwordsMatch) return user; + return user; } console.log('Invalid credentials'); diff --git a/package.json b/package.json index b6f3973..1412326 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,7 @@ "class-variance-authority": "^0.7.0", "clsx": "^2.0.0", "next": "^14.0.2", - "next-auth": "^5.0.0-beta.4", + "next-auth": "5.0.0-beta.4", "postcss": "8.4.31", "react": "18.2.0", "react-dom": "18.2.0",