verivy email before log in

This commit is contained in:
Dobromir Popov
2024-05-24 19:01:24 +03:00
parent 0f6e094f24
commit a9deca22f0
6 changed files with 128 additions and 12 deletions

View File

@ -10,6 +10,7 @@ import CredentialsProvider from "next-auth/providers/credentials"
import { PrismaAdapter } from "@auth/prisma-adapter" import { PrismaAdapter } from "@auth/prisma-adapter"
import bcrypt from "bcrypt" import bcrypt from "bcrypt"
const emailHelper = require('../../../src/helpers/email');
//microsoft //microsoft
import AzureADProvider from "next-auth/providers/azure-ad"; import AzureADProvider from "next-auth/providers/azure-ad";
@ -87,32 +88,51 @@ export const authOptions: NextAuthOptions = {
const prisma = common.getPrismaClient(); const prisma = common.getPrismaClient();
const user = await prisma.user.findUnique({ where: { email: credentials.username } }); const user = await prisma.user.findUnique({ where: { email: credentials.username } });
if (user) { if (user) {
const match = await bcrypt.compare(credentials?.password, user.passwordHashLocalAccount); if (!user.emailVerified) {
if (match) { const mailVerifyToken = await bcrypt.hash(credentials.username, 10);
console.log("User authenticated successfully."); const date = new Date().getTime();
//create access token const emailVerifyToken = date + "_" + mailVerifyToken;
user.accessToken = await getAccessToken(); await prisma.user.update({
where: { email: credentials.username },
return user; data: { emailVerifyToken: emailVerifyToken }
});
emailHelper.SendEmail_ValidateTemplate(credentials.username, emailVerifyToken);
throw new Error('Моля потвърди имейла си преди да влезеш в системата.');
} }
else { else {
console.log("Password mismatch."); const match = await bcrypt.compare(credentials?.password, user.passwordHashLocalAccount);
throw new Error('невалидна парола'); if (match) {
console.log("User authenticated successfully.");
//create access token
user.accessToken = await getAccessToken();
return user;
}
else {
console.log("Password mismatch.");
throw new Error('невалидна парола');
}
} }
} }
else { else {
const pub = await prisma.publisher.findUnique({ where: { email: credentials.username } }); const pub = await prisma.publisher.findUnique({ where: { email: credentials.username } });
if (pub) { if (pub) {
const passHash = await bcrypt.hash(credentials.password, 10); const passHash = await bcrypt.hash(credentials.password, 10);
const mailVerifyToken = await bcrypt.hash(pub.email, 10);
const date = new Date().getTime();
const emailVerifyToken = date + "_" + mailVerifyToken;
const newUser = await prisma.user.create({ const newUser = await prisma.user.create({
data: { data: {
name: credentials.username, name: credentials.username,
email: credentials.username, email: credentials.username,
passwordHashLocalAccount: passHash passwordHashLocalAccount: passHash,
emailVerifyToken: emailVerifyToken
} }
}); });
console.log("New local credential user created for publisher ", pub.firstName, " ", pub.lastName, " (", pub.email, ")"); console.log("New local credential user created for publisher ", pub.firstName, " ", pub.lastName, " (", pub.email, ")");
return newUser; emailHelper.SendEmail_ValidateTemplate(pub.email, emailVerifyToken, pub.firstName, pub.lastName);
//return newUser;
throw new Error("Моля проверете вашия имейл '" + credentials?.username + "' за да потвърдите регистрацията си.");
} }
else { else {

View File

@ -13,11 +13,20 @@ const logger = require('../../src/logger');
import fs from 'fs'; import fs from 'fs';
import path from 'path'; import path from 'path';
import { log } from "console";
const handlebars = require("handlebars"); const handlebars = require("handlebars");
const router = createRouter<NextApiRequest, NextApiResponse>(); const router = createRouter<NextApiRequest, NextApiResponse>();
// programatically sign in
import { getSession } from "next-auth/react";
import { signIn } from "next-auth/react";
import { authOptions } from './auth/[...nextauth]';
// import NextAuth from 'next-auth';
// import { setCookie } from 'nookies';
//action to accept coverme request from email //action to accept coverme request from email
@ -33,10 +42,54 @@ export default async function handler(req, res) {
const emailaction = req.query.emailaction; const emailaction = req.query.emailaction;
// Retrieve and validate the JWT token // Retrieve and validate the JWT token
let email = req.body.email || req.query.email;
//response is a special action that does not require a token //response is a special action that does not require a token
//PUBLIC //PUBLIC
if (action == "email_response" || action == "account") { if (action == "email_response" || action == "account") {
switch (emailaction) { switch (emailaction) {
case "validateEmail":
let token = req.query.token;
let user = await prisma.user.findUnique({
where: {
email: email
}
});
let pub = await prisma.publisher.findUnique({
where: {
email: email
}
});
if (!user && !pub) {
return res.status(400).json({ message: "Invalid user" });
}
if (user) {
await prisma.user.update({
where: {
email: email
},
data: {
emailVerified: new Date()
}
});
}
logger.info("User: " + email + " validated his email.");
console.log("User: " + email + " validated his email. Logging in...");
return res.redirect("/dash");
// log in the user using nextauth and redirect to the dashboard
//how to login the user with nextauth? maybe use the signIn callback
// const result = await signIn("credentials", {
// // redirect: false,
// email,
// account: user
// });
// if (result.error) {
// return res.status(401).json({ message: "Invalid credentials" });
// }
// return res.status(200).json({ message: "Signed in successfully" });
case "coverMeAccept": case "coverMeAccept":
//validate shiftId and assignmentId //validate shiftId and assignmentId
let shiftId = req.query.shiftId; let shiftId = req.query.shiftId;
@ -208,7 +261,6 @@ export default async function handler(req, res) {
// Send password reset form to the user // Send password reset form to the user
//parse the request body //parse the request body
let email = req.body.email || req.query.email;
let actualUser = await prisma.publisher.findUnique({ let actualUser = await prisma.publisher.findUnique({
where: { where: {
email: email email: email
@ -285,6 +337,9 @@ export default async function handler(req, res) {
// const emailResponse = await common.sendEmail(user.email, "Email Action Processed", // const emailResponse = await common.sendEmail(user.email, "Email Action Processed",
// "Your email action was processed successfully"); // "Your email action was processed successfully");
} }
// ########################
// PRIVATE API
// ########################
else { else {
const token = await getToken({ req: req }); const token = await getToken({ req: req });
@ -301,6 +356,17 @@ export default async function handler(req, res) {
//PRIVATE ACTIONS //PRIVATE ACTIONS
switch (action) { switch (action) {
//in nextauth.ts
// case "validateEmail":
// let publisher = await prisma.publisher.findUnique({
// where: {
// email: token.email
// }
// });
// if (!publisher) {
// return res.status(400).json({ message: "Invalid user" });
// }
case "sendCoverMeRequestByEmail": case "sendCoverMeRequestByEmail":
// Send CoverMe request to the users // Send CoverMe request to the users
//get from POST data: shiftId, assignmentId, date //get from POST data: shiftId, assignmentId, date

View File

@ -0,0 +1,2 @@
-- AlterTable
ALTER TABLE `user` ADD COLUMN `emailVerifyToken` VARCHAR(191) NULL;

View File

@ -302,6 +302,7 @@ model User {
id String @id @default(cuid()) id String @id @default(cuid())
name String? name String?
email String? @unique email String? @unique
emailVerifyToken String?
emailVerified DateTime? emailVerified DateTime?
image String? image String?
accounts Account[] accounts Account[]

View File

@ -114,6 +114,17 @@ exports.SendEmail = async function (to, subject, text, html, attachments = []) {
return result; return result;
}; };
exports.SendEmail_ValidateTemplate = async function (to, token, firstName, lastName) {
let validateUrl = process.env.NEXTAUTH_URL + "/api/email?action=email_response&emailaction=validateEmail&token=" + token + "&email=" + to;
return await this.SendEmailHandlebars(to, "emailValidate", {
user: to,
validateUrl: validateUrl,
sentDate: common.getDateFormated(new Date())
});
};
exports.SendEmailHandlebars = async function (to, templateName, model, attachments = []) { exports.SendEmailHandlebars = async function (to, templateName, model, attachments = []) {
try { try {
// Ensure the sender and mailtrapTestClient are correctly defined or imported // Ensure the sender and mailtrapTestClient are correctly defined or imported

View File

@ -0,0 +1,16 @@
{{!--Subject: ССОМ: Потвърдете имейла си--}}
<section>
<p>Здравей {{user}},</p>
<p>Получихме заявка за вход в сайта за Специално свидетелстване на обществени места в София. </p>
<p>За да потвърдиш твоя достъп моля използвай бутона по долу или <a href="{{validateUrl}}">кликни тук</a>.</p>
<p style="text-align: center;">
<a href="{{validateUrl}}"
target="_blank"
style="background-color: #4CAF50; color: white; padding: 10px 20px; text-decoration: none; display: inline-block; border-radius: 5px;">
Потвърждавам</a>
</p>
</section>
<footer style="margin-top: 20px; text-align: center;">
<p>Изпратено до {{user}} {{sentDate}}</p>
</footer>