verivy email before log in
This commit is contained in:
@ -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 {
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
2
prisma/migrations/20240524150310_/migration.sql
Normal file
2
prisma/migrations/20240524150310_/migration.sql
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
-- AlterTable
|
||||||
|
ALTER TABLE `user` ADD COLUMN `emailVerifyToken` VARCHAR(191) NULL;
|
@ -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[]
|
||||||
|
@ -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
|
||||||
|
16
src/templates/emails/emailValidate.hbs
Normal file
16
src/templates/emails/emailValidate.hbs
Normal 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>
|
Reference in New Issue
Block a user