Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix invite and reset passwd email service #482

Merged
merged 7 commits into from
Jan 13, 2025
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .env
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ DEV_DB_PORT=5432
# JWT Secret Key
JWT_SECRET="NKrbO2lpCsOpVAlqAPsjZ0tZXzIoKru7gAmYZ7XlHn0=qqwqeq"

EMAIL=autobluewave@gmail.com
EMAIL=bluewaveguidefox@gmail.com
EMAIL_PASSWORD=passwor
EMAIL_HOST=smtp.gmail.com
EMAIL_PORT=465
APP_PASSWORD=password
APP_PASSWORD=ukzwakckupguegiw
EMAIL_ENABLE=false
12 changes: 11 additions & 1 deletion backend/.env
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ DEV_DB_NAME=onboarding_db
DEV_DB_HOST=db
DEV_DB_PORT=5432

EMAIL_ENABLE=false
EMAIL_ENABLE=true
thomastepi marked this conversation as resolved.
Show resolved Hide resolved

# JWT Secret Key
JWT_SECRET="NKrbO2lpCsOpVAlqAPsjZ0tZXzIoKru7gAmYZ7XlHn0=qqwqeq"
Expand All @@ -19,8 +19,18 @@ TEST_DB_NAME=onboarding_db_test
TEST_DB_HOST=localhost
TEST_DB_PORT=5432

[email protected]
EMAIL_PASSWORD=passwor
EMAIL_HOST=smtp.gmail.com
EMAIL_PORT=465
APP_PASSWORD=ukzwakckupguegiw
erenfn marked this conversation as resolved.
Show resolved Hide resolved
EMAIL_ENABLE=true

ENABLE_IP_CHECK=false
# Allowed IP range for the API "baseIp/rangeStart-rangeEnd" (e.g. 192.168.1/1-255) separated by comma
ALLOWED_IP_RANGE=11.22.33/10-200, 192.168.65/1-255
# Allowed IP addresses for the API separated by comma
ALLOWED_IPS=127.0.0.1, 11.22.33.44, 11.22.33.45, 11.22.33.46, 192.168.65.1

# FRONTEND_URL=https://onboarding-demo.bluewavelabs.ca/
FRONTEND_URL=http://localhost:4173/
1 change: 0 additions & 1 deletion backend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions backend/src/controllers/auth.controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ const sequelize = db.sequelize;
const { generateToken, verifyToken } = require('../utils/jwt.helper');
const crypto = require('crypto');
const { TOKEN_LIFESPAN } = require('../utils/constants.helper');
const { sendSignupEmail, sendPasswordResetEmail, findUserByEmail } = require('../service/email.service');
const { sendPasswordResetEmail, findUserByEmail } = require('../service/email.service');
const settings = require('../../config/settings');
const { decode } = require('../utils/auth.helper');

Expand Down Expand Up @@ -81,8 +81,6 @@ const register = async (req, res) => {

await Token.create({ token, userId: newUser.id, type: 'auth' });

await sendSignupEmail(newUser.email, newUser.name);

res.status(201).json({
user: {
id: newUser.id,
Expand Down Expand Up @@ -160,6 +158,8 @@ const forgetPassword = async (req, res) => {
const user = await findUserByEmail(email);
if (!user) return res.status(400).json({ error: 'User not found' });

await Token.destroy({ where: { userId: user.id, type: 'reset' } });

const resetToken = crypto.randomBytes(32).toString('hex');
const hash = await bcrypt.hash(resetToken, 10);
const expiresAt = new Date(Date.now() + TOKEN_LIFESPAN);
Expand Down
4 changes: 2 additions & 2 deletions backend/src/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ const cors = require("cors");
const helmet = require("helmet");
const dotenv = require("dotenv");
const bodyParser = require("body-parser");
const compression = require("compression");
// const compression = require("compression");
const jsonErrorMiddleware = require("./middleware/jsonError.middleware");
const fileSizeValidator = require("./middleware/fileSizeValidator.middleware");
const { MAX_FILE_SIZE } = require("./utils/constants.helper");
Expand Down Expand Up @@ -32,7 +32,7 @@ app.use(cors());
app.options('*', cors()); // this is for preflight requests
app.use(helmet());
app.use(bodyParser.json({ limit: MAX_FILE_SIZE }));
app.use(compression());
// app.use(compression());
app.use(jsonErrorMiddleware);
if (process.env.ENABLE_IP_CHECK === 'true') {
app.use(ipFilter);
Expand Down
20 changes: 16 additions & 4 deletions backend/src/service/email.service.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,21 @@ const nodemailer = require("nodemailer");
const handlebars = require("handlebars");
const fs = require("fs");
const path = require("path");
const { API_BASE_URL } = require("../utils/constants.helper");
const { API_BASE_URL, FRONTEND_URL } = require('../utils/constants.helper');
const db = require("../models");
const User = db.User;

const transporter = nodemailer.createTransport({
host: process.env.EMAIL_HOST || "localhost",
host: process.env.EMAIL_HOST || 'localhost',
port: process.env.EMAIL_PORT || 465,
secure: true,
auth: {
user: process.env.EMAIL,
pass: process.env.APP_PASSWORD,
},
tls: {
rejectUnauthorized: process.env.NODE_ENV === 'production',
},
erenfn marked this conversation as resolved.
Show resolved Hide resolved
});

const readHTMLFile = (filePath) => {
Expand Down Expand Up @@ -59,16 +62,25 @@ const sendSignupEmail = async (email, name) => {
};

const sendPasswordResetEmail = async (email, name, resetToken) => {
const resetLink = `${API_BASE_URL}reset-password?token=${resetToken}`;
await sendEmail(email, "Password Reset", "resetPassword", {
const resetLink = `${FRONTEND_URL}set-new-password?token=${resetToken}`;
await sendEmail(email, 'Reset your password for Guidefox', 'resetPassword', {
name,
resetLink,
});
thomastepi marked this conversation as resolved.
Show resolved Hide resolved
};

const sendInviteEmail = async (email) => {
const inviteLink = FRONTEND_URL;
await sendEmail(email, 'You’re invited to join Guidefox!', 'invite', {
inviteLink,
});
};
erenfn marked this conversation as resolved.
Show resolved Hide resolved


module.exports = {
sendSignupEmail,
sendPasswordResetEmail,
sendInviteEmail,
findUserByEmail,
transporter,
};
3 changes: 3 additions & 0 deletions backend/src/service/invite.service.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
const settings = require("../../config/settings");
const { sendInviteEmail } = require("./email.service");
const db = require("../models");
const Invite = db.Invite;
const User = db.User;
Expand All @@ -22,13 +23,15 @@ class InviteService {
invitedBy: userId,
role: settings.user.role[role],
})
sendInviteEmail(invitedEmail);
thomastepi marked this conversation as resolved.
Show resolved Hide resolved
}
else {
await Invite.create({
invitedBy: userId,
invitedEmail: invitedEmail,
role: settings.user.role[role],
});
sendInviteEmail(invitedEmail);
}
}
catch (err) {
Expand Down
7 changes: 7 additions & 0 deletions backend/src/templates/invite.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<p>Hello,</p>
<p>You’ve been invited to join Guidefox - a platform designed to help you build better user experiences.</p>
<p>To get started, simply click the link below to create your account:</p>
<p><a href="{{inviteLink}}">Join Guidefox</a></p>
<p>Once you’ve created your account, you’ll be able to log in and start exploring all the features we’ve prepared for you.</p>
<p>We’re excited to have you with us and can’t wait for you to experience Guidefox!</p>
<p>--<br>The Guidefox Team</p>
11 changes: 7 additions & 4 deletions backend/src/templates/resetPassword.hbs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
<h1>Password Reset</h1>
<p>Hi {{name}},</p>
<p>Please use the following link to reset your password:</p>
<a href="{{resetLink}}">Reset Password</a>
<p>Hello {{name}},</p>
<p>We received a request to reset your password for your Guidefox account. If you didn’t request a password reset, you can safely ignore this email.</p>
<p>To reset your password, click the link below:</p>
<a href="{{resetLink}}">Reset My Password</a>
<p>Thank you for using Guidefox!</p>
<p>--<br>The Guidefox Team</p>

33 changes: 17 additions & 16 deletions backend/src/utils/constants.helper.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
require('dotenv').config();

module.exports = Object.freeze({
JWT_EXPIRES_IN_1H: '1h',
JWT_EXPIRES_IN_20M: '20m',
TOKEN_LIFESPAN: 3600 * 1000,
// API_BASE_URL: 'https://onboarding-demo.bluewavelabs.ca/api/',
API_BASE_URL: 'localhost:3000/api/',
MAX_FILE_SIZE: 3 * 1024 * 1024,
ROLE: {
ADMIN: '1',
MEMBER: '2'
},
MAX_ORG_NAME_LENGTH: 100,
ORG_NAME_REGEX: /^[a-zA-Z0-9\s\-_&.]+$/,
URL_PROTOCOL_REGEX: /^(https?:\/\/)/,
URL_DOMAIN_REGEX: /^https?:\/\/([a-zA-Z0-9.-]+\.[a-zA-Z]{2,})/,
});

JWT_EXPIRES_IN_1H: '1h',
JWT_EXPIRES_IN_20M: '20m',
TOKEN_LIFESPAN: 3600 * 1000,
API_BASE_URL: process.env.API_BASE_URL || 'localhost:3000/api/',
FRONTEND_URL: process.env.FRONTEND_URL,
MAX_FILE_SIZE: 3 * 1024 * 1024,
ROLE: {
ADMIN: '1',
MEMBER: '2'
},
MAX_ORG_NAME_LENGTH: 100,
ORG_NAME_REGEX: /^[a-zA-Z0-9\s\-_&.]+$/,
URL_PROTOCOL_REGEX: /^(https?:\/\/)/,
URL_DOMAIN_REGEX: /^https?:\/\/([a-zA-Z0-9.-]+\.[a-zA-Z]{2,})/,
});
Loading
Loading