E-Commerce-Module/backend/src/routes/auth.js
2025-04-26 12:07:32 -05:00

287 lines
No EOL
7.6 KiB
JavaScript

const express = require('express');
const { v4: uuidv4 } = require('uuid');
const nodemailer = require('nodemailer');
const config = require('../config');
const router = express.Router();
const createTransporter = () => {
return nodemailer.createTransport({
host: config.email.host,
port: config.email.port,
auth: {
user: config.email.user,
pass: config.email.pass
}
});
};
// Mock email transporter for development
const transporter = createTransporter();
module.exports = (pool, query) => {
// Register new user
router.post('/register', async (req, res, next) => {
const { email, firstName, lastName } = req.body;
try {
// Check if user already exists
const userCheck = await query(
'SELECT * FROM users WHERE email = $1',
[email]
);
if (userCheck.rows.length > 0) {
return res.status(400).json({
error: true,
message: 'User with this email already exists'
});
}
// Create new user
const result = await query(
'INSERT INTO users (email, first_name, last_name) VALUES ($1, $2, $3) RETURNING id, email',
[email, firstName, lastName]
);
res.status(201).json({
message: 'User registered successfully',
user: result.rows[0]
});
} catch (error) {
next(error);
}
});
// Request login code
router.post('/login-request', async (req, res, next) => {
const { email } = req.body;
console.log('/login-request')
console.log(JSON.stringify(config, null, 4))
try {
// Check if user exists
const userResult = await query(
'SELECT * FROM users WHERE email = $1',
[email]
);
if (userResult.rows.length === 0) {
return res.status(404).json({
error: true,
message: 'User not found'
});
}
const user = userResult.rows[0];
// Generate a random 6-digit code
// Set expiration time (15 minutes from now)
const authCode = Math.floor(100000 + Math.random() * 900000).toString();
const expiresAt = new Date();
expiresAt.setMinutes(expiresAt.getMinutes() + 15);
// Create auth record
const authResult = await query(
'INSERT INTO authentications (code, expires_at) VALUES ($1, $2) RETURNING id',
[authCode, expiresAt]
);
const authId = authResult.rows[0].id;
// Update user with auth record
await query(
'UPDATE users SET current_auth_id = $1 WHERE id = $2',
[authId, user.id]
);
// Send email with code (mock in development)
const loginLink = `${config.site.protocol}://${config.site.domain}/verify?code=${authCode}&email=${encodeURIComponent(email)}`;
await transporter.sendMail({
from: 'noreply@2many.ca',
to: email,
subject: 'Your Login Code',
html: `
<h1>Your login code is: ${authCode}</h1>
<p>This code will expire in 15 minutes.</p>
<p>Or click <a href="${loginLink}">here</a> to log in directly.</p>
`
});
let retObj = {
message: 'Login code sent to address: ' + email
}
if(process.env.ENVIRONMENT === "beta"){
retObj.code = authCode;
}
res.json(retObj);
} catch (error) {
next(error);
}
});
// Verify login code
router.post('/verify', async (req, res, next) => {
const { email, code } = req.body;
try {
// Get user and auth record
const userResult = await query(
`SELECT u.*, a.code, a.expires_at, a.is_used
FROM users u
JOIN authentications a ON u.current_auth_id = a.id
WHERE u.email = $1`,
[email]
);
if (userResult.rows.length === 0) {
return res.status(400).json({
error: true,
message: 'Invalid request or no login code requested'
});
}
const { code: storedCode, expires_at, is_used, id: userId, is_disabled } = userResult.rows[0];
// Check if account is disabled
if (is_disabled) {
return res.status(403).json({
error: true,
message: 'Your account has been disabled. Please contact support for assistance.'
});
}
// Check code
if (storedCode !== code) {
return res.status(400).json({
error: true,
message: 'Invalid code'
});
}
// Check if expired
if (new Date() > new Date(expires_at)) {
return res.status(400).json({
error: true,
message: 'Code has expired, Please restart login'
});
}
// Check if already used
if (is_used) {
return res.status(400).json({
error: true,
message: 'Code has already been used' ,
data: is_used
});
}
// Mark auth as used
await query(
'UPDATE authentications SET is_used = true WHERE code = $1',
[code]
);
// Generate API key
const apiKey = uuidv4();
// Save API key to user
await query(
'UPDATE users SET api_key = $1, last_login = NOW() WHERE id = $2',
[apiKey, userId]
);
// Get user information including admin status
const userInfo = await query(
'SELECT id, email, first_name, last_name, is_admin FROM users WHERE id = $1',
[userId]
);
res.json({
message: 'Login successful',
userId: userId,
isAdmin: userInfo.rows[0].is_admin,
firstName: userInfo.rows[0].first_name,
lastName: userInfo.rows[0].last_name,
email: userInfo.rows[0].email,
apiKey: apiKey
});
} catch (error) {
next(error);
}
});
//apikey check
router.post('/verify-key', async (req, res, next) => {
const { apiKey, email } = req.body;
try {
// Verify the API key against email
const result = await query(
'SELECT id, email, first_name, last_name, is_admin, is_disabled FROM users WHERE api_key = $1 AND email = $2',
[apiKey, email]
);
if (result.rows.length === 0) {
return res.status(401).json({
error: true,
message: 'Invalid API key'
});
}
if (result.rows[0].is_disabled) {
return res.status(403).json({
error: true,
message: 'Your account has been disabled. Please contact support for assistance.'
});
}
res.json({
valid: true,
user: result.rows[0]
});
} catch (error) {
next(error);
}
});
// Logout
router.post('/logout', async (req, res, next) => {
const { userId } = req.body;
try {
// Get current auth ID
const userResult = await query(
'SELECT current_auth_id FROM users WHERE id = $1',
[userId]
);
if (userResult.rows.length === 0) {
return res.status(404).json({
error: true,
message: 'User not found'
});
}
const authId = userResult.rows[0].current_auth_id;
// Clear auth ID and API key
await query(
'UPDATE users SET current_auth_id = NULL, api_key = NULL WHERE id = $1',
[userId]
);
// Delete auth record
if (authId) {
await query(
'DELETE FROM authentications WHERE id = $1',
[authId]
);
}
res.json({ message: 'Logged out successfully' });
} catch (error) {
next(error);
}
});
return router;
};