Skip to content

Commit

Permalink
first commit
Browse files Browse the repository at this point in the history
  • Loading branch information
Swarga-codes committed May 19, 2024
1 parent 8eb079d commit 6d62277
Show file tree
Hide file tree
Showing 24 changed files with 2,056 additions and 145 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,4 @@ yarn-error.log*
# typescript
*.tsbuildinfo
next-env.d.ts
.env
24 changes: 24 additions & 0 deletions app/api/auth/login/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import USER from "@/app/models/userSchema";
import connectDb from "@/app/util/connectDb";
import { NextRequest, NextResponse } from "next/server";
import bcrypt from 'bcrypt'
import jsonwebtoken from 'jsonwebtoken'
export async function POST(req:NextRequest){
try {
const {email,password}=await req.json()
await connectDb()
if(!email || !password) return NextResponse.json({success:false, message:'One or more fields are missing'},{status:422})
const existingUser=await USER.findOne({email:email})
if(!existingUser) return NextResponse.json({success:false,message:'User doesnt exist with the given email'},{status:404})
const isPasswordMatching=await bcrypt.compare(password,existingUser.password)
if(!isPasswordMatching) return NextResponse.json({success:false,message:'Passwords do not match'},{status:403})
if(!existingUser.isVerified) return NextResponse.json({success:false,message:'User is not verified, please verify to login!'},{status:403})
const token=await jsonwebtoken.sign({email,username:existingUser.username},process.env.SECRET_KEY || "",{expiresIn:'1h'})
const response=NextResponse.json({success:true,message:'Logged in successfully!',email,username:existingUser.username},{status:200})
response.cookies.set('token',token)
return response
} catch (error) {
console.log(error)
return NextResponse.json({success:false,message:'Internal Server Error'},{status:500})
}
}
7 changes: 7 additions & 0 deletions app/api/auth/logout/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { cookies } from "next/headers";
import { NextRequest, NextResponse } from "next/server";

export function POST(req:NextRequest){
cookies().delete('token');
return NextResponse.json({success:true,message:'Logged out successfully!'})
}
32 changes: 32 additions & 0 deletions app/api/auth/passwordResetMail/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import USER from "@/app/models/userSchema";
import connectDb from "@/app/util/connectDb";
import { NextRequest, NextResponse } from "next/server";
import { transporter } from "@/app/util/sendEmailConfig";
export async function PUT(req:NextRequest){
try{

connectDb();
const {email}=await req.json()
if(!email) return NextResponse.json({success:false,message:'Email cannot be empty!'},{status:422})
const isExistingUser=await USER.findOne({email:email})
if(!isExistingUser) return NextResponse.json({success:false,message:'User not found!'},{status:404})
const verifyOtp=Math.floor(100000+Math.random()*900000);
isExistingUser.verifyOtp=verifyOtp
isExistingUser.verifyOtpExpiry=new Date(Date.now()+36000000)
await isExistingUser.save();
const info = await transporter.sendMail({
from: '<myapp@gmail.com>',
to: email,
subject: "My Auth App || Reset Password",

html: `<p>Reset your password using this OTP </p> <b>${verifyOtp}</b>
<p>Note: This OTP is valid only for an hour!</p>
`,
});
return NextResponse.json({success:true,message:'Mail sent, please check your inbox for the OTP!'})
}
catch(err){
console.log(err)
return NextResponse.json({success:false,message:'Could not send mail'},{status:500})
}
}
103 changes: 103 additions & 0 deletions app/api/auth/register/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import USER from "@/app/models/userSchema";
import * as React from 'react'
import connectDb from "@/app/util/connectDb";
import { NextRequest, NextResponse } from "next/server";
import { z } from "zod";
import bcrypt from 'bcrypt';
import { transporter } from "@/app/util/sendEmailConfig";
import jsonwebtoken from 'jsonwebtoken';

export async function POST(req:NextRequest){
try{
await connectDb();
const {username,email,password}=await req.json()
const passwordRegex=/^(?=.*[0-9])(?=.*[A-Z])(?=.*[a-z])(?=.*[@#$%^&+=!])(?!.*\s).{8,}$/
const mySchema=z.object({
username:z.string().min(4, {message:'Must be 4 characters or long!'}),
email:z.string().email({message:'Must be an email!'}),
password:z.string().min(8,{message:'Must be atleast 8 characters long!'}).regex(passwordRegex,{message:'Password should have atleast one lowercase, uppercase, number and special characters!'})
})
const validation=mySchema.safeParse({username,email,password})
if(!validation.success){
return NextResponse.json({success:false,validation},{status:422})
}



/*
if existing user then
check whether or not the user is verified or not
if user verified
then cannot use this username
else
can use this username
*/
const existingUserName=await USER.findOne({username:username})
if(existingUserName && existingUserName?.username!==username && existingUserName.isVerified) return NextResponse.json({success:false, message:'An existing verified user with the same username exists'},{status:409})
const isExistingUser= await USER.findOne({email})
const hashPassword=await bcrypt.hash(password,10);
const verifyOtp=Math.floor(100000+Math.random()*900000);
const mailContent=`
<h1>Welcome, ${username}!</h1>
<p>Please verify your account using this given OTP <b>${verifyOtp}</b></p>
<p>Note: This otp is valid only for an hour. Only verified users will be able to login.</p>
`
if(isExistingUser){
if(isExistingUser.isVerified){
return NextResponse.json({success:false,message:'User with the following details already exists!'},{status:409})
}
else{
isExistingUser.username=username
isExistingUser.password=hashPassword
isExistingUser.verifyOtp=verifyOtp
isExistingUser.verifyOtpExpiry=new Date(Date.now()+36000000)
await isExistingUser.save();

const info = await transporter.sendMail({
from: '<myapp@gmail.com>',
to: [email],
subject: "My Auth App || Verify Email",

html: `<p>Please verify your account using this OTP </p> <b>${verifyOtp}</b>
<p>Note: This OTP is valid only for an hour!</p>
`,
});
const response = NextResponse.json({success:true,message:'User registered successfully, please verify the email'},{status:200})
const token=jsonwebtoken.sign({email,username},process.env.SECRET_KEY || "")
response.cookies.set('token',token)
return response
}
}
const newUser=new USER({
username,
email,
password:hashPassword,
verifyOtp,
verifyOtpExpiry:new Date(Date.now()+36000000),
})

await newUser.save();

const info = await transporter.sendMail({
from: '<myapp@gmail.com>',
to: [email],
subject: "My Auth App || Verify Email",

html: `<p>Please verify your account using this OTP </p> <b>${verifyOtp}</b>
<p>Note: This OTP is valid only for an hour!</p>
`,
});
const response = NextResponse.json({success:true,message:'User registered successfully, please verify the email'},{status:200})
const token=jsonwebtoken.sign({email,username},process.env.SECRET_KEY || "")
response.cookies.set('token',token)
return response
}
catch(err){
console.log(err);

return NextResponse.json({success:false,message:'Could not register user, try again!'},{status:500})
}
}
37 changes: 37 additions & 0 deletions app/api/auth/resetPassword/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import USER from "@/app/models/userSchema";
import connectDb from "@/app/util/connectDb";
import { NextRequest, NextResponse } from "next/server";
import {z} from 'zod'
import bcrypt from 'bcrypt'
export async function PUT(req:NextRequest){
try{
const {email,otp,password}=await req.json()
if(!email || !otp || !password) return NextResponse.json({success:false,message:'One or more fields are missing!'},{status:422})
connectDb()
const isExistingUser=await USER.findOne({email})
if(!isExistingUser) return NextResponse.json({success:false,message:'User not found!'},{status:404})
if(isExistingUser.verifyOtp!==otp) return NextResponse.json({success:false,message:'OTP do not match!'},{status:403})
const currentTime:Date=new Date()
const expiryTime:Date=new Date(isExistingUser.verifyOtpExpiry)
const timeDifference:number=Math.ceil((currentTime.getTime()-expiryTime.getTime())/(1000*60*60))
if(timeDifference>1) return NextResponse.json({success:false,message:'Otp has expired please resend mail again to generate another OTP!'},{status:403})
const passwordRegex=/^(?=.*[0-9])(?=.*[A-Z])(?=.*[a-z])(?=.*[@#$%^&+=!])(?!.*\s).{8,}$/
const mySchema=z.object({
password:z.string().min(8,{message:'Must be atleast 8 characters long!'}).regex(passwordRegex,{message:'Password should have atleast one lowercase, uppercase, number and special characters!'})
})
const validation=mySchema.safeParse({password})
if(!validation.success){
return NextResponse.json({success:false,validation},{status:422})
}
const isExistingPassword=await bcrypt.compare(password,isExistingUser.password)
if(isExistingPassword) return NextResponse.json({success:false,message:'New password cannot be same as current password!'},{status:409})
const hashedPassword=await bcrypt.hash(password,10)
isExistingUser.password=hashedPassword
await isExistingUser.save()
return NextResponse.json({success:true,message:'Password Updated Successfully!'},{status:200})
}
catch(err){
console.log(err)
return NextResponse.json({success:false,message:'Could not update password'},{status:500})
}
}
53 changes: 53 additions & 0 deletions app/api/auth/verifyOtp/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import USER from "@/app/models/userSchema";
import connectDb from "@/app/util/connectDb";
import { NextRequest, NextResponse } from "next/server";
import { checkValidityOfToken } from "@/app/util/checkValidityOfToken";

export async function PUT(req: NextRequest) {
try {
const decodedToken = checkValidityOfToken(req);
if (!decodedToken.success) return NextResponse.json(decodedToken, { status: 401 });

const email = decodedToken?.email;
const { otp } = await req.json();

await connectDb();

if (!otp || !email) {
return NextResponse.json({ success: false, message: 'One or more fields are missing!' }, { status: 422 });
}

const existingUser = await USER.findOne({ email });
if (!existingUser) {
return NextResponse.json({ success: false, message: 'User not found!' }, { status: 404 });
}

if (existingUser.isVerified) {
return NextResponse.json({ success: false, message: 'User is already verified, please login!' }, { status: 409 });
}

// whether the otp is same or not
if (existingUser.verifyOtp !== otp) {
return NextResponse.json({ success: false, message: 'Otp did not match, try again!' });
}

const currentTime: Date = new Date();
const expiryTime: Date = new Date(existingUser.verifyOtpExpiry);

// Calculate the time difference in hours
const timeDifference: number = Math.ceil((currentTime.getTime() - expiryTime.getTime()) / (1000 * 60 * 60));

if (timeDifference > 1) {
return NextResponse.json({ success: false, message: 'Otp has expired, please register again to generate another OTP!' }, { status: 403 });
}

existingUser.isVerified = true;
await existingUser.save();

return NextResponse.json({ success: true, message: 'User verified successfully!', email: existingUser.email, username: existingUser.username }, { status: 200 });

} catch (err) {
console.log(err);
return NextResponse.json({ success: false, message: 'Internal Server error' }, { status: 500 });
}
}
Binary file modified app/favicon.ico
Binary file not shown.
Loading

0 comments on commit 6d62277

Please sign in to comment.