+ signup and + verify
All checks were successful
gitea/MERN_STACK_TEMPLATE/pipeline/head This commit looks good
All checks were successful
gitea/MERN_STACK_TEMPLATE/pipeline/head This commit looks good
This commit is contained in:
@ -1 +1,3 @@
|
||||
Change example.env to .env
|
||||
Change example.env to .env
|
||||
|
||||
>> Join Postman Workspace by following [link](https://app.getpostman.com/join-team?invite_code=2d2ef31819c048b241f82bd7f85ac6dd332460290748fd1f36bee2aedb38200e&target_code=ca1aae0c6efdc09edabb6d99534b9323)
|
@ -0,0 +1,92 @@
|
||||
import { User } from "../models/user.model.js";
|
||||
import bcryptjs from 'bcryptjs';
|
||||
|
||||
import {generateTokenAndSetCookie} from "../utils/generateTokenAndSetCookie.js"
|
||||
import { sendVerificationEmail, sendWelcomeEmail } from "../mailtrap/emails.js";
|
||||
|
||||
export const signup = async (req, res) => {
|
||||
const { email, password, name } = req.body;
|
||||
|
||||
try {
|
||||
if (!email || !password || !name) {
|
||||
throw new Error("All fields are required");
|
||||
}
|
||||
|
||||
const userAlreadyExists = await User.findOne({ email });
|
||||
console.log("userAlreadyExists", userAlreadyExists);
|
||||
|
||||
if (userAlreadyExists) {
|
||||
return res.status(400).json({ success: false, message: "User already exists" });
|
||||
}
|
||||
|
||||
const hashedPassword = await bcryptjs.hash(password, 10);
|
||||
const verificationToken = Math.floor(100000 + Math.random() * 900000).toString();
|
||||
|
||||
const user = new User({
|
||||
email,
|
||||
password: hashedPassword,
|
||||
name,
|
||||
verificationToken,
|
||||
verificationTokenExpiresAt: Date.now() + 24 * 60 * 60 * 1000, // 24 hours
|
||||
});
|
||||
|
||||
await user.save();
|
||||
|
||||
// jwt
|
||||
generateTokenAndSetCookie(res, user._id);
|
||||
await sendVerificationEmail(user.email, verificationToken);
|
||||
|
||||
|
||||
res.status(201).json({
|
||||
success: true,
|
||||
message: "User created successfully",
|
||||
user: {
|
||||
...user._doc,
|
||||
password: undefined,
|
||||
},
|
||||
});
|
||||
} catch (error) {
|
||||
res.status(400).json({ success: false, message: error.message });
|
||||
}
|
||||
};
|
||||
|
||||
export const verifyEmail = async (req, res) => {
|
||||
const { code } = req.body;
|
||||
try {
|
||||
const user = await User.findOne({
|
||||
verificationToken: code,
|
||||
verificationTokenExpiresAt: { $gt: Date.now() },
|
||||
});
|
||||
|
||||
if (!user) {
|
||||
return res.status(400).json({ success: false, message: "Invalid or expired verification code" });
|
||||
}
|
||||
|
||||
user.isVerified = true;
|
||||
user.verificationToken = undefined;
|
||||
user.verificationTokenExpiresAt = undefined;
|
||||
await user.save();
|
||||
|
||||
await sendWelcomeEmail(user.email, user.name);
|
||||
|
||||
res.status(200).json({
|
||||
success: true,
|
||||
message: "Email verified successfully",
|
||||
user: {
|
||||
...user._doc,
|
||||
password: undefined,
|
||||
},
|
||||
});
|
||||
} catch (error) {
|
||||
console.log("error in verifyEmail ", error);
|
||||
res.status(500).json({ success: false, message: "Server error" });
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
export const login = async (req, res) => {
|
||||
res.send("login route");
|
||||
};
|
||||
export const logout = async (req, res) => {
|
||||
res.send("logout route")
|
||||
};
|
95
backend/mailtrap/emailTemplates.js
Normal file
95
backend/mailtrap/emailTemplates.js
Normal file
@ -0,0 +1,95 @@
|
||||
export const VERIFICATION_EMAIL_TEMPLATE = `
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Verify Your Email</title>
|
||||
</head>
|
||||
<body style="font-family: Arial, sans-serif; line-height: 1.6; color: #333; max-width: 600px; margin: 0 auto; padding: 20px;">
|
||||
<div style="background: linear-gradient(to right, #4CAF50, #45a049); padding: 20px; text-align: center;">
|
||||
<h1 style="color: white; margin: 0;">Verify Your Email</h1>
|
||||
</div>
|
||||
<div style="background-color: #f9f9f9; padding: 20px; border-radius: 0 0 5px 5px; box-shadow: 0 2px 5px rgba(0,0,0,0.1);">
|
||||
<p>Hello,</p>
|
||||
<p>Thank you for signing up! Your verification code is:</p>
|
||||
<div style="text-align: center; margin: 30px 0;">
|
||||
<span style="font-size: 32px; font-weight: bold; letter-spacing: 5px; color: #4CAF50;">{verificationCode}</span>
|
||||
</div>
|
||||
<p>Enter this code on the verification page to complete your registration.</p>
|
||||
<p>This code will expire in 15 minutes for security reasons.</p>
|
||||
<p>If you didn't create an account with us, please ignore this email.</p>
|
||||
<p>Best regards,<br>Your App Team</p>
|
||||
</div>
|
||||
<div style="text-align: center; margin-top: 20px; color: #888; font-size: 0.8em;">
|
||||
<p>This is an automated message, please do not reply to this email.</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
`;
|
||||
|
||||
export const PASSWORD_RESET_SUCCESS_TEMPLATE = `
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Password Reset Successful</title>
|
||||
</head>
|
||||
<body style="font-family: Arial, sans-serif; line-height: 1.6; color: #333; max-width: 600px; margin: 0 auto; padding: 20px;">
|
||||
<div style="background: linear-gradient(to right, #4CAF50, #45a049); padding: 20px; text-align: center;">
|
||||
<h1 style="color: white; margin: 0;">Password Reset Successful</h1>
|
||||
</div>
|
||||
<div style="background-color: #f9f9f9; padding: 20px; border-radius: 0 0 5px 5px; box-shadow: 0 2px 5px rgba(0,0,0,0.1);">
|
||||
<p>Hello,</p>
|
||||
<p>We're writing to confirm that your password has been successfully reset.</p>
|
||||
<div style="text-align: center; margin: 30px 0;">
|
||||
<div style="background-color: #4CAF50; color: white; width: 50px; height: 50px; line-height: 50px; border-radius: 50%; display: inline-block; font-size: 30px;">
|
||||
✓
|
||||
</div>
|
||||
</div>
|
||||
<p>If you did not initiate this password reset, please contact our support team immediately.</p>
|
||||
<p>For security reasons, we recommend that you:</p>
|
||||
<ul>
|
||||
<li>Use a strong, unique password</li>
|
||||
<li>Enable two-factor authentication if available</li>
|
||||
<li>Avoid using the same password across multiple sites</li>
|
||||
</ul>
|
||||
<p>Thank you for helping us keep your account secure.</p>
|
||||
<p>Best regards,<br>Your App Team</p>
|
||||
</div>
|
||||
<div style="text-align: center; margin-top: 20px; color: #888; font-size: 0.8em;">
|
||||
<p>This is an automated message, please do not reply to this email.</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
`;
|
||||
|
||||
export const PASSWORD_RESET_REQUEST_TEMPLATE = `
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Reset Your Password</title>
|
||||
</head>
|
||||
<body style="font-family: Arial, sans-serif; line-height: 1.6; color: #333; max-width: 600px; margin: 0 auto; padding: 20px;">
|
||||
<div style="background: linear-gradient(to right, #4CAF50, #45a049); padding: 20px; text-align: center;">
|
||||
<h1 style="color: white; margin: 0;">Password Reset</h1>
|
||||
</div>
|
||||
<div style="background-color: #f9f9f9; padding: 20px; border-radius: 0 0 5px 5px; box-shadow: 0 2px 5px rgba(0,0,0,0.1);">
|
||||
<p>Hello,</p>
|
||||
<p>We received a request to reset your password. If you didn't make this request, please ignore this email.</p>
|
||||
<p>To reset your password, click the button below:</p>
|
||||
<div style="text-align: center; margin: 30px 0;">
|
||||
<a href="{resetURL}" style="background-color: #4CAF50; color: white; padding: 12px 20px; text-decoration: none; border-radius: 5px; font-weight: bold;">Reset Password</a>
|
||||
</div>
|
||||
<p>This link will expire in 1 hour for security reasons.</p>
|
||||
<p>Best regards,<br>Your App Team</p>
|
||||
</div>
|
||||
<div style="text-align: center; margin-top: 20px; color: #888; font-size: 0.8em;">
|
||||
<p>This is an automated message, please do not reply to this email.</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
`;
|
44
backend/mailtrap/emails.js
Normal file
44
backend/mailtrap/emails.js
Normal file
@ -0,0 +1,44 @@
|
||||
import { VERIFICATION_EMAIL_TEMPLATE } from "./emailTemplates.js"
|
||||
import { mailtrapClient, sender} from "./mailtrap.config.js"
|
||||
|
||||
export const sendVerificationEmail = async (email, verificationToken) => {
|
||||
const recepient = [{ email }]
|
||||
|
||||
try {
|
||||
const response = await mailtrapClient.send({
|
||||
from: sender,
|
||||
to: recepient,
|
||||
subject: "Verify your email",
|
||||
html: VERIFICATION_EMAIL_TEMPLATE.replace("{verificationCode}", verificationToken),
|
||||
category: "Email Verification"
|
||||
})
|
||||
} catch (error) {
|
||||
console.error(`Error sending verification`, error);
|
||||
throw new Error(`Error sending verification email: ${error}`);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
export const sendWelcomeEmail = async (email, name) => {
|
||||
const recipients = [{email}];
|
||||
try {
|
||||
const response = await mailtrapClient.send({
|
||||
from: sender,
|
||||
to: recipients,
|
||||
template_uuid: "eee83ead-5e6d-4784-bd67-c7296f4649b5",
|
||||
template_variables: {
|
||||
"company_info_name": "Ai Laplace Lab",
|
||||
"name": name,
|
||||
"company_info_address": "Rinstraße 19C",
|
||||
"company_info_city": "Schwabhausen",
|
||||
"company_info_zip_code": "85247",
|
||||
"company_info_country": "Germany"
|
||||
},
|
||||
});
|
||||
console.log("Welcome email sent successfully", response);
|
||||
} catch (error) {
|
||||
console.error(`Error sending welcome email`, error);
|
||||
|
||||
throw new Error(`Error sending welcome email: ${error}`);
|
||||
}
|
||||
};
|
13
backend/mailtrap/mailtrap.config.js
Normal file
13
backend/mailtrap/mailtrap.config.js
Normal file
@ -0,0 +1,13 @@
|
||||
import { MailtrapClient } from "mailtrap"
|
||||
import dotenv from "dotenv";
|
||||
|
||||
dotenv.config();
|
||||
|
||||
export const mailtrapClient = new MailtrapClient({
|
||||
token: process.env.MAILTRAP_TOKEN,
|
||||
});
|
||||
|
||||
export const sender = {
|
||||
email: "hello@demomailtrap.co",
|
||||
name: "Mailtrap Test",
|
||||
};
|
@ -0,0 +1,34 @@
|
||||
import mongoose from "mongoose";
|
||||
|
||||
const userSchema = new mongoose.Schema(
|
||||
{
|
||||
email: {
|
||||
type: String,
|
||||
required: true,
|
||||
unique: true,
|
||||
},
|
||||
password: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
name: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
lastLogin: {
|
||||
type: Date,
|
||||
default: Date.now,
|
||||
},
|
||||
isVerified: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
resetPasswordToken: String,
|
||||
resetPasswordExpiresAt: Date,
|
||||
verificationToken: String,
|
||||
verificationTokenExpiresAt: Date,
|
||||
},
|
||||
{ timestamps: true }
|
||||
);
|
||||
|
||||
export const User = mongoose.model("User", userSchema);
|
267
backend/package-lock.json
generated
267
backend/package-lock.json
generated
@ -9,8 +9,11 @@
|
||||
"version": "1.0.0",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"bcryptjs": "^3.0.2",
|
||||
"dotenv": "^16.5.0",
|
||||
"express": "^5.1.0",
|
||||
"jsonwebtoken": "^9.0.2",
|
||||
"mailtrap": "^4.1.0",
|
||||
"mongoose": "^8.14.1",
|
||||
"nodemon": "^3.1.10"
|
||||
}
|
||||
@ -65,12 +68,38 @@
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/asynckit": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
|
||||
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/axios": {
|
||||
"version": "1.9.0",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.9.0.tgz",
|
||||
"integrity": "sha512-re4CqKTJaURpzbLHtIi6XpDv20/CnpXOtjRY5/CU32L8gU8ek9UIivcfvSWvmKEngmVbrUtPpdDwWDWL7DNHvg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"follow-redirects": "^1.15.6",
|
||||
"form-data": "^4.0.0",
|
||||
"proxy-from-env": "^1.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/balanced-match": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
||||
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/bcryptjs": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-3.0.2.tgz",
|
||||
"integrity": "sha512-k38b3XOZKv60C4E2hVsXTolJWfkGRMbILBIe2IBITXciy5bOsTKot5kDrf3ZfufQtQOUN5mXceUEpU1rTl9Uog==",
|
||||
"license": "BSD-3-Clause",
|
||||
"bin": {
|
||||
"bcrypt": "bin/bcrypt"
|
||||
}
|
||||
},
|
||||
"node_modules/binary-extensions": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz",
|
||||
@ -134,6 +163,12 @@
|
||||
"node": ">=16.20.1"
|
||||
}
|
||||
},
|
||||
"node_modules/buffer-equal-constant-time": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
|
||||
"integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==",
|
||||
"license": "BSD-3-Clause"
|
||||
},
|
||||
"node_modules/bytes": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
|
||||
@ -196,6 +231,18 @@
|
||||
"fsevents": "~2.3.2"
|
||||
}
|
||||
},
|
||||
"node_modules/combined-stream": {
|
||||
"version": "1.0.8",
|
||||
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
|
||||
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"delayed-stream": "~1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/concat-map": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
||||
@ -258,6 +305,15 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/delayed-stream": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
|
||||
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/depd": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
|
||||
@ -293,6 +349,15 @@
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/ecdsa-sig-formatter": {
|
||||
"version": "1.0.11",
|
||||
"resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz",
|
||||
"integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"safe-buffer": "^5.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/ee-first": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
|
||||
@ -338,6 +403,21 @@
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/es-set-tostringtag": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
|
||||
"integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"es-errors": "^1.3.0",
|
||||
"get-intrinsic": "^1.2.6",
|
||||
"has-tostringtag": "^1.0.2",
|
||||
"hasown": "^2.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/escape-html": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
|
||||
@ -424,6 +504,62 @@
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/follow-redirects": {
|
||||
"version": "1.15.9",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz",
|
||||
"integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
"url": "https://github.com/sponsors/RubenVerborgh"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=4.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"debug": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/form-data": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.2.tgz",
|
||||
"integrity": "sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"asynckit": "^0.4.0",
|
||||
"combined-stream": "^1.0.8",
|
||||
"es-set-tostringtag": "^2.1.0",
|
||||
"mime-types": "^2.1.12"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/form-data/node_modules/mime-db": {
|
||||
"version": "1.52.0",
|
||||
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
|
||||
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/form-data/node_modules/mime-types": {
|
||||
"version": "2.1.35",
|
||||
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
|
||||
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"mime-db": "1.52.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/forwarded": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
|
||||
@ -547,6 +683,21 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/has-tostringtag": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
|
||||
"integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"has-symbols": "^1.0.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/hasown": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
|
||||
@ -656,6 +807,49 @@
|
||||
"integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/jsonwebtoken": {
|
||||
"version": "9.0.2",
|
||||
"resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz",
|
||||
"integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"jws": "^3.2.2",
|
||||
"lodash.includes": "^4.3.0",
|
||||
"lodash.isboolean": "^3.0.3",
|
||||
"lodash.isinteger": "^4.0.4",
|
||||
"lodash.isnumber": "^3.0.3",
|
||||
"lodash.isplainobject": "^4.0.6",
|
||||
"lodash.isstring": "^4.0.1",
|
||||
"lodash.once": "^4.0.0",
|
||||
"ms": "^2.1.1",
|
||||
"semver": "^7.5.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12",
|
||||
"npm": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/jwa": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz",
|
||||
"integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"buffer-equal-constant-time": "1.0.1",
|
||||
"ecdsa-sig-formatter": "1.0.11",
|
||||
"safe-buffer": "^5.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/jws": {
|
||||
"version": "3.2.2",
|
||||
"resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz",
|
||||
"integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"jwa": "^1.4.1",
|
||||
"safe-buffer": "^5.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/kareem": {
|
||||
"version": "2.6.3",
|
||||
"resolved": "https://registry.npmjs.org/kareem/-/kareem-2.6.3.tgz",
|
||||
@ -665,6 +859,73 @@
|
||||
"node": ">=12.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/lodash.includes": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz",
|
||||
"integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/lodash.isboolean": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz",
|
||||
"integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/lodash.isinteger": {
|
||||
"version": "4.0.4",
|
||||
"resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz",
|
||||
"integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/lodash.isnumber": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz",
|
||||
"integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/lodash.isplainobject": {
|
||||
"version": "4.0.6",
|
||||
"resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz",
|
||||
"integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/lodash.isstring": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz",
|
||||
"integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/lodash.once": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz",
|
||||
"integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/mailtrap": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/mailtrap/-/mailtrap-4.1.0.tgz",
|
||||
"integrity": "sha512-rCuumv0ZcLvxMukV8Pn9sh5hmk2TL23THrpwgE/yXwDfeJQdJGVENa2rNzGR9zcGsUK3LSXuyvjKrTwc21RBOQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"axios": ">=0.27"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16.20.1",
|
||||
"yarn": ">=1.22.17"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/nodemailer": "^6.4.9",
|
||||
"nodemailer": "^6.9.4"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/nodemailer": {
|
||||
"optional": true
|
||||
},
|
||||
"nodemailer": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/math-intrinsics": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
|
||||
@ -961,6 +1222,12 @@
|
||||
"node": ">= 0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/proxy-from-env": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
|
||||
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/pstree.remy": {
|
||||
"version": "1.1.8",
|
||||
"resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz",
|
||||
|
@ -13,8 +13,11 @@
|
||||
"license": "ISC",
|
||||
"description": "",
|
||||
"dependencies": {
|
||||
"bcryptjs": "^3.0.2",
|
||||
"dotenv": "^16.5.0",
|
||||
"express": "^5.1.0",
|
||||
"jsonwebtoken": "^9.0.2",
|
||||
"mailtrap": "^4.1.0",
|
||||
"mongoose": "^8.14.1",
|
||||
"nodemon": "^3.1.10"
|
||||
}
|
||||
|
@ -1,18 +1,13 @@
|
||||
import express from "express";
|
||||
|
||||
import {login, signup, logout, verifyEmail} from "../controllers/auth.controller.js";
|
||||
const router = express.Router();
|
||||
|
||||
router.get("/signup", (req, res) => {
|
||||
res.send("Signup route");
|
||||
})
|
||||
router.post("/signup", signup);
|
||||
router.post("/login", login);
|
||||
router.post("/logout", logout);
|
||||
|
||||
router.get("/login", (req, res) => {
|
||||
res.send("Signup route");
|
||||
})
|
||||
router.post("/verify-email", verifyEmail);
|
||||
|
||||
router.get("/logout", (req, res) => {
|
||||
res.send("Signup route");
|
||||
})
|
||||
|
||||
export default router;
|
||||
|
||||
|
@ -1,22 +1,18 @@
|
||||
import express from "express";
|
||||
import dotenv from "dotenv";
|
||||
|
||||
import {connectDB} from "./db/connectDB.js";
|
||||
import { connectDB } from "./db/connectDB.js";
|
||||
|
||||
import authRoutes from "./routes/auth.route.js"
|
||||
import authRoutes from "./routes/auth.route.js";
|
||||
|
||||
dotenv.config();
|
||||
const app = express();
|
||||
|
||||
app.get("/", (req, res) => {
|
||||
res.send("Hello World!");
|
||||
});
|
||||
|
||||
|
||||
app.use("/api/auth", authRoutes)
|
||||
const PORT = process.env.PORT || 8080;
|
||||
app.use(express.json()); // allows us to parse incoming requests:req.body
|
||||
app.use("/api/auth", authRoutes);
|
||||
|
||||
|
||||
app.listen(8080, () => {
|
||||
app.listen(PORT, () => {
|
||||
connectDB();
|
||||
console.log("Server Started at 0.0.0.0:8080");
|
||||
console.log("Server Started at 0.0.0.0: ", PORT);
|
||||
});
|
||||
|
16
backend/utils/generateTokenAndSetCookie.js
Normal file
16
backend/utils/generateTokenAndSetCookie.js
Normal file
@ -0,0 +1,16 @@
|
||||
import jwt from "jsonwebtoken";
|
||||
|
||||
export const generateTokenAndSetCookie = (res, userId) => {
|
||||
const token = jwt.sign({ userId}, process.env.JWT_SECRET, {
|
||||
expiresIn: "7d",
|
||||
});
|
||||
|
||||
res.cookie("token", token, {
|
||||
httpOnly: true,
|
||||
secure: process.env.NODE_ENV === "production",
|
||||
sameSite: "strict",
|
||||
maxAge: 7 * 24 * 60 * 60 * 1000,
|
||||
});
|
||||
|
||||
return token;
|
||||
}
|
10
docker-compose.mongo.yaml
Normal file
10
docker-compose.mongo.yaml
Normal file
@ -0,0 +1,10 @@
|
||||
services:
|
||||
|
||||
mongo:
|
||||
image: mongo
|
||||
restart: always
|
||||
ports:
|
||||
- "27017:27017"
|
||||
environment:
|
||||
MONGO_INITDB_ROOT_USERNAME: admin
|
||||
MONGO_INITDB_ROOT_PASSWORD: test
|
Reference in New Issue
Block a user