Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 | 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 4x 4x 4x 4x 4x 4x 4x 4x 4x 1x 1x 3x 3x 4x 1x 1x 2x 2x 2x 4x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 4x 4x 1x 1x 1x 1x 1x 1x 1x 1x 1x 6x 6x 6x 6x 5x 5x 4x 1x 1x 1x 1x 1x 6x 3x 3x 6x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 2x 2x 2x 2x 2x 2x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 2x 2x 2x 2x 2x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 8x 8x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x | import { createAccessToken, createPasswordToken, createRefreshToken, createVerificationToken, deleteRefreshToken, verifyRefreshToken } from "../utils/handleTokens.js";
import { sendEmail } from "../utils/handleMailer.js";
import { findOneAndUpdate, findOneRecord, updateOneRecord } from "../utils/handleDB.js";
import User from "../models/User.js";
import bcrypt from 'bcrypt';
import { hideConfidentialFields } from "../utils/handleSchemes.js";
/** *******************************************************
* SEND VERIFICATION MAIL
*/
export const sendVerificationEmail = async (req, res, next) => {
try {
// create verification token
const verificationToken = createVerificationToken(req.document);
let subject = "[RagChat] Account Verification";
let to = req.document.email;
let link = `${process.env.FRONTEND_URL}/signup/${verificationToken}`;
let html = `<p>Hi<p><br><p>Please click on the following <a href="${link}">link</a> to process the password reset.
This Token is valid for ${process.env.PASSWORD_TOKEN_TTL}.</p>
<p>${link}</p>
<p>${verificationToken}</p>
<br><p>If you did not request this, please ignore this email.</p>`;
await sendEmail({ to, subject, html });
// return msg
return res.status(201).json({ message: 'Check your emails for the verification link.' });
} catch (error) {
next(error);
}
};
/** *******************************************************
* CONFIRM VERIFICATION
*/
export const confirmVerification = async (req, res, next) => {
try {
// req.document.verified = true;
// const updatedUser = await updateOneRecord(req.document);
const updatedUser = await findOneAndUpdate(User, { email: req.body.email }, { verified: true });
// remember document but remove confidential info
const document = hideConfidentialFields(User, updatedUser);
return res.json({ message: 'Account successfully verified. You can now login.' });
} catch (error) {
next(error);
}
};
/** *******************************************************
* LOGIN
* check for matching credentials
*
* return accessToken & refreshToken
*/
export const login = async (req, res, next) => {
let foundUser;
// check credentials
try {
// search for matching document
performance.mark('login:start');
foundUser = await findOneRecord(User, { email: req.body.email }, '+password');
// wrong login name
if (!foundUser) {
return res.status(401).json({ message: 'Unknown combination of login credentials.' });
}
// unverified account
if (!foundUser.verified) {
return res.status(401).json({ message: 'Your account is still unverified. Check your emails for the verification link.' });
}
// check for correct password
performance.mark('bcryptComparePassword:start');
if (await bcrypt.compare(req.body.password, foundUser.password)) {
performance.mark('bcryptComparePassword:end');
// remember document but remove confidential info
const user = hideConfidentialFields(User, foundUser);
// create jsonwebtoken
performance.mark('createAccessToken:start');
const accessToken = createAccessToken({ id: user._id, role: user.role });
performance.mark('createAccessToken:end');
performance.mark('createRefreshToken:start');
const refreshToken = await createRefreshToken({ id: user._id });
performance.mark('createRefreshToken:end');
if (refreshToken == null) return res.status(500).json({ message: 'Error creating refresh token' });
performance.mark('login:end');
// success
return res
.cookie('refreshToken', refreshToken, { httpOnly: true, sameSite: 'none', secure: true })
.json({ message: 'Successfully logged in', document: user, accessToken });
} else {
// wrong password
return res.status(401).json({ message: 'Unknown combination of login credentials' });
}
} catch (error) {
console.error('login error: ', error);
next(error);
}
};
/** *******************************************************
* RENEW ACCESS TOKEN
* refresh access token with the refresh token
*
* return new accessToken and refreshToken
*/
export const renewAccessToken = async (req, res, next) => {
try {
// get token from cookie
const refreshToken = req.cookies.refreshToken;
if (!refreshToken) return res.status(401).json({ message: 'Refresh token is missing. Consider to re-login' });
// verify token
const user = await verifyRefreshToken(refreshToken);
if (!user) {
return res.status(403).json({ message: 'Refresh token is invalid' });
}
// create & return
const accessToken = createAccessToken({ id: user._id, role: user.role });
return res.json({ message: 'Access token refreshed', accessToken });
} catch (error) {
next(error);
}
};
/** *******************************************************
* LOGOUT
* deletes refresh token from DB
*/
export const logout = async (req, res, next) => {
try {
// delete
console.log("🚀 ~ logout ~ req.cookies.refreshToken:", req.cookies.refreshToken);
if (req.cookies.refreshToken) await deleteRefreshToken(req.cookies.refreshToken);
// return msg
return res.status(200).json({ message: 'See you soon.' });
} catch (error) {
next(error);
}
};
/**
* REQUEST PASSWORD RESET
* sets a token and sends this to the user
*/
export const requestPasswordReset = async (req, res, next) => {
let foundUser;
try {
// search for matching document
foundUser = await findOneRecord(User, { email: req.body.email }, '+password');
// user found
if (foundUser) {
// create token
const passwordToken = createPasswordToken(foundUser);
// store token in user document
foundUser.resetPasswordToken = passwordToken;
await updateOneRecord(foundUser);
// send info to user
try {
let subject = "Password Reset Token";
let to = foundUser.email;
let link = `${process.env.FRONTEND_URL}/reset_password/${passwordToken}`;
let html = `<p>Hi<p><br><p>Please click on the following <a href="${link}">link</a> to process the password reset. This Token is valid for ${process.env.PASSWORD_TOKEN_TTL}.</p>
<p>${link}</p>
<p>${passwordToken}</p>
<br><p>If you did not request this, please ignore this email.</p>`;
await sendEmail({ to, subject, html });
} catch (error) {
next(error);
}
}
// fin
return res.json({ message: `If the email **${req.body.email}** is correct you will receive an eMail with further instructions.` });
} catch (error) {
next(error);
}
};
/** *******************************************************
* PASSWORD RESET
* resets the password and removes the token
*/
export const passwordReset = async (req, res, next) => {
try {
// set new password & remove token
req.document.password = req.body.password;
req.document.resetPasswordToken = undefined;
// save
const updatedRecord = await updateOneRecord(req.document);
return res.json({ message: 'Password successfully reset. You can now login.' });
} catch (error) {
next(error);
}
};
/**
* VERIFY ACCESS RIGHTS
* check if user is alllowed to access route
*/
export const gateKeeper = async (req, res, next) => {
// admins are allowed to access anything
if (global.currentUserRole >= 4) return next();
// FEATURE
// - check for custom field role (which has to be created via settings before)
// - create a access config, which exports an array of allowed roles for each route
// - fetch array of called route an compare
// const allowed = [];
// if (allowed.includes(pb.authStore.model.role)) {
// return next();
// }
// deny access for others
return res.status(403).json({ message: 'Access Forbidden' });
};
|