fix: replace the authentication with more secure one
This commit is contained in:
parent
796b6a71f0
commit
15f309aa7a
15 changed files with 573 additions and 155 deletions
15
.env.example
15
.env.example
|
@ -5,6 +5,21 @@ PORT=3000
|
|||
# If not set, the "attachments" directory in the script root will be used
|
||||
ATTACHMENTS_PATH=
|
||||
|
||||
# MongoDB connection string
|
||||
MONGODB_CONNSTRING=
|
||||
|
||||
# 256-bit secret key and 128-bit IV for password encryption
|
||||
# You can generate the secret key using "openssl rand -base64 32" command
|
||||
# You can generate the IV using "openssl rand -base64 16" command
|
||||
ENCRYPTION_SECRETKEY=
|
||||
ENCRYPTION_IV=
|
||||
|
||||
# JWT secret and cookie options
|
||||
# You can generate the JWT secret using "openssl rand -base64 32" command
|
||||
# If users access the webmail from HTTPS, set JWT_SECURECOOKIE to 1
|
||||
JWT_SECRET=
|
||||
JWT_SECURECOOKIE=
|
||||
|
||||
# Email receiving protocol and host parameters
|
||||
# The EMAIL_RECV_PROTOCOL can be "pop3" or "imap"
|
||||
EMAIL_RECV_PROTOCOL=
|
||||
|
|
|
@ -2,17 +2,17 @@ import LoginForm from "@/layouts/LoginForm.jsx";
|
|||
import Loading from "@/layouts/Loading.jsx";
|
||||
import MainLayout from "@/layouts/MainLayout.jsx";
|
||||
import { useSelector, useDispatch } from "react-redux";
|
||||
import { load, checkAuth } from "@/slices/authSlice.js";
|
||||
import { checkAuth } from "@/slices/authSlice.js";
|
||||
import { useEffect } from "react";
|
||||
|
||||
function App() {
|
||||
const loading = useSelector((state) => state.auth.loading);
|
||||
const auth = useSelector((state) => state.auth.auth);
|
||||
const email = useSelector((state) => state.auth.email);
|
||||
const dispatch = useDispatch();
|
||||
|
||||
useEffect(() => {
|
||||
setTimeout(() => {
|
||||
dispatch(load);
|
||||
dispatch(checkAuth);
|
||||
}, 500);
|
||||
|
||||
const interval = setInterval(() => {
|
||||
|
@ -24,7 +24,7 @@ function App() {
|
|||
|
||||
if (loading) {
|
||||
return <Loading />;
|
||||
} else if (auth === null) {
|
||||
} else if (email === null) {
|
||||
return <LoginForm />;
|
||||
} else {
|
||||
return <MainLayout />;
|
||||
|
|
|
@ -20,9 +20,7 @@ import Content from "@/components/Content.jsx";
|
|||
import { setView } from "@/slices/viewSlice.js";
|
||||
|
||||
function LoginLayout() {
|
||||
const email = useSelector((state) =>
|
||||
state.auth.auth ? state.auth.auth.email : "Unknown"
|
||||
);
|
||||
const email = useSelector((state) => state.auth.email);
|
||||
const menuShown = useSelector((state) => state.menu.shown);
|
||||
const dispatch = useDispatch();
|
||||
const { t } = useTranslation();
|
||||
|
@ -135,7 +133,7 @@ function LoginLayout() {
|
|||
href="#"
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
dispatch(logout());
|
||||
dispatch(logout);
|
||||
}}
|
||||
className="inline-block text-inherit w-8 h-8 py-1 mx-0.5 align-middle rounded-sm hover:bg-primary-foreground/30 hover:text-primary-foreground transition-colors"
|
||||
>
|
||||
|
|
|
@ -5,111 +5,49 @@ export const authSlice = createSlice({
|
|||
initialState: {
|
||||
loading: true,
|
||||
error: null,
|
||||
auth: null
|
||||
email: null
|
||||
},
|
||||
reducers: {
|
||||
load: (state, action) => {
|
||||
if (state.loading) state.loading = false;
|
||||
if (action.payload && action.payload.error !== undefined)
|
||||
state.error = action.payload.error;
|
||||
if (action.payload && action.payload.auth !== undefined) {
|
||||
state.auth = action.payload.auth;
|
||||
if (!localStorage.getItem("credentials"))
|
||||
localStorage.setItem(
|
||||
"credentials",
|
||||
btoa(JSON.stringify(action.payload.auth))
|
||||
);
|
||||
}
|
||||
},
|
||||
login: (state, action) => {
|
||||
if (state.loading) state.loading = false;
|
||||
if (action.payload && action.payload.error !== undefined)
|
||||
state.error = action.payload.error;
|
||||
if (action.payload && action.payload.auth !== undefined) {
|
||||
state.auth = action.payload.auth;
|
||||
localStorage.setItem(
|
||||
"credentials",
|
||||
btoa(JSON.stringify(action.payload.auth))
|
||||
);
|
||||
if (action.payload && action.payload.email !== undefined) {
|
||||
state.email = action.payload.email;
|
||||
}
|
||||
},
|
||||
logout: (state) => {
|
||||
if (state.loading) state.loading = false;
|
||||
localStorage.removeItem("credentials");
|
||||
state.auth = null;
|
||||
state.email = null;
|
||||
},
|
||||
verificationFailed: (state) => {
|
||||
if (state.loading) state.loading = false;
|
||||
state.error = null;
|
||||
state.auth = null;
|
||||
state.email = null;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
export const { logout, verificationFailed } = authSlice.actions;
|
||||
|
||||
export async function load(dispatch) {
|
||||
const state = {};
|
||||
let credentials = {};
|
||||
try {
|
||||
credentials = JSON.parse(atob(localStorage.getItem("credentials")));
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
} catch (err) {
|
||||
// Use empty credentials
|
||||
}
|
||||
try {
|
||||
const res = await fetch("/api/check", {
|
||||
method: "GET",
|
||||
headers: {
|
||||
Authorization:
|
||||
credentials.email && credentials.password
|
||||
? "BasicMERNMail " +
|
||||
btoa(
|
||||
credentials.email.replace(/:/g, "") + ":" + credentials.password
|
||||
)
|
||||
: undefined
|
||||
}
|
||||
});
|
||||
if (res.status == 200) {
|
||||
state.auth =
|
||||
credentials.email && credentials.password
|
||||
? { email: credentials.email, password: credentials.password }
|
||||
: {};
|
||||
}
|
||||
} catch (err) {
|
||||
state.error = err.message;
|
||||
}
|
||||
dispatch(authSlice.actions.load(state));
|
||||
}
|
||||
export const { verificationFailed } = authSlice.actions;
|
||||
|
||||
export function login(email, password) {
|
||||
return async (dispatch) => {
|
||||
const state = {};
|
||||
let credentials = {
|
||||
email: email,
|
||||
password: password
|
||||
};
|
||||
try {
|
||||
const res = await fetch("/api/check", {
|
||||
method: "GET",
|
||||
const res = await fetch("/api/login", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
Authorization:
|
||||
credentials.email && credentials.password
|
||||
? "BasicMERNMail " +
|
||||
btoa(
|
||||
credentials.email.replace(/:/g, "") +
|
||||
":" +
|
||||
credentials.password
|
||||
)
|
||||
: undefined
|
||||
}
|
||||
"Content-Type": "application/json"
|
||||
},
|
||||
body: JSON.stringify({
|
||||
email: email,
|
||||
password: password
|
||||
}),
|
||||
credentials: "include"
|
||||
});
|
||||
const data = await res.json();
|
||||
if (res.status == 200) {
|
||||
state.auth =
|
||||
credentials.email && credentials.password
|
||||
? { email: credentials.email, password: credentials.password }
|
||||
: {};
|
||||
state.email = email;
|
||||
state.error = null;
|
||||
} else {
|
||||
state.error = data.message;
|
||||
|
@ -121,38 +59,38 @@ export function login(email, password) {
|
|||
};
|
||||
}
|
||||
|
||||
export async function checkAuth(dispatch, getState) {
|
||||
export async function checkAuth(dispatch) {
|
||||
const state = {};
|
||||
let credentials = getState().auth.auth;
|
||||
if (credentials === null) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const res = await fetch("/api/check", {
|
||||
method: "GET",
|
||||
headers: {
|
||||
Authorization:
|
||||
credentials.email && credentials.password
|
||||
? "BasicMERNMail " +
|
||||
btoa(
|
||||
credentials.email.replace(/:/g, "") + ":" + credentials.password
|
||||
)
|
||||
: undefined
|
||||
}
|
||||
credentials: "include"
|
||||
});
|
||||
if (res.status == 200) {
|
||||
state.auth =
|
||||
credentials.email && credentials.password
|
||||
? { email: credentials.email, password: credentials.password }
|
||||
: {};
|
||||
} else {
|
||||
state.auth = null;
|
||||
const data = await res.json();
|
||||
state.email = data.email;
|
||||
}
|
||||
} catch (err) {
|
||||
state.error = err.message;
|
||||
}
|
||||
dispatch(authSlice.actions.login(state));
|
||||
}
|
||||
|
||||
export async function logout(dispatch) {
|
||||
try {
|
||||
await fetch("/api/logout", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json"
|
||||
},
|
||||
body: JSON.stringify({}),
|
||||
credentials: "include"
|
||||
});
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
} catch (err) {
|
||||
// Don't display the message
|
||||
// Logout failed
|
||||
}
|
||||
dispatch(authSlice.actions.load(state));
|
||||
dispatch(authSlice.actions.logout());
|
||||
}
|
||||
|
||||
export default authSlice.reducer;
|
||||
|
|
|
@ -75,22 +75,14 @@ export const { initCurrentMailbox, setCurrentMailboxFromURL } =
|
|||
|
||||
export async function setMailboxes(dispatch, getState) {
|
||||
const state = {};
|
||||
let credentials = getState().auth.auth;
|
||||
if (credentials === null) {
|
||||
let email = getState().auth.email;
|
||||
if (email === null) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const res = await fetch("/api/receive/mailboxes", {
|
||||
method: "GET",
|
||||
headers: {
|
||||
Authorization:
|
||||
credentials.email && credentials.password
|
||||
? "BasicMERNMail " +
|
||||
btoa(
|
||||
credentials.email.replace(/:/g, "") + ":" + credentials.password
|
||||
)
|
||||
: undefined
|
||||
}
|
||||
credentials: "include"
|
||||
});
|
||||
const data = await res.json();
|
||||
if (res.status == 200) {
|
||||
|
|
|
@ -29,8 +29,8 @@ export const { resetLoading } = messagesSlice.actions;
|
|||
export function setMessages(signal) {
|
||||
return async (dispatch, getState) => {
|
||||
const state = {};
|
||||
let credentials = getState().auth.auth;
|
||||
if (credentials === null) {
|
||||
let email = getState().auth.email;
|
||||
if (email === null) {
|
||||
return;
|
||||
}
|
||||
let currentMailbox = getState().mailboxes.currentMailbox;
|
||||
|
@ -45,17 +45,7 @@ export function setMessages(signal) {
|
|||
try {
|
||||
const res = await fetch(`/api/receive/mailbox/${currentMailbox}`, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
Authorization:
|
||||
credentials.email && credentials.password
|
||||
? "BasicMERNMail " +
|
||||
btoa(
|
||||
credentials.email.replace(/:/g, "") +
|
||||
":" +
|
||||
credentials.password
|
||||
)
|
||||
: undefined
|
||||
},
|
||||
credentials: "include",
|
||||
signal: signal
|
||||
});
|
||||
const data = await res.json();
|
||||
|
|
323
package-lock.json
generated
323
package-lock.json
generated
|
@ -9,10 +9,14 @@
|
|||
"version": "0.0.0",
|
||||
"hasInstallScript": true,
|
||||
"dependencies": {
|
||||
"body-parser": "^1.20.3",
|
||||
"cookie-parser": "^1.4.7",
|
||||
"dotenv": "^16.4.5",
|
||||
"express": "^4.21.0",
|
||||
"imap-node": "^0.9.9",
|
||||
"jsonwebtoken": "^9.0.2",
|
||||
"mailparser": "^3.7.1",
|
||||
"mongoose": "^8.7.1",
|
||||
"node-pop3": "^0.9.0",
|
||||
"nodemailer": "^6.9.15",
|
||||
"serve-static": "^1.16.2"
|
||||
|
@ -862,6 +866,14 @@
|
|||
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@mongodb-js/saslprep": {
|
||||
"version": "1.1.9",
|
||||
"resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.1.9.tgz",
|
||||
"integrity": "sha512-tVkljjeEaAhCqTzajSdgbQ6gE6f3oneVwa3iXR6csiEwXXOFsiC6Uh9iAjAhXPtqa/XMDHWjjeNH/77m/Yq2dw==",
|
||||
"dependencies": {
|
||||
"sparse-bitfield": "^3.0.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@napi-rs/nice": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@napi-rs/nice/-/nice-1.0.1.tgz",
|
||||
|
@ -1238,6 +1250,19 @@
|
|||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/webidl-conversions": {
|
||||
"version": "7.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.3.tgz",
|
||||
"integrity": "sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA=="
|
||||
},
|
||||
"node_modules/@types/whatwg-url": {
|
||||
"version": "11.0.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-11.0.5.tgz",
|
||||
"integrity": "sha512-coYR071JRaHa+xoEvvYqvnIHaVqaYrLPbsufM9BF63HkwI5Lgmy2QR8Q5K/lYDYo5AK82wOvSOS0UsLTpTG7uQ==",
|
||||
"dependencies": {
|
||||
"@types/webidl-conversions": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/accepts": {
|
||||
"version": "1.3.8",
|
||||
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
|
||||
|
@ -1643,6 +1668,14 @@
|
|||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/bson": {
|
||||
"version": "6.8.0",
|
||||
"resolved": "https://registry.npmjs.org/bson/-/bson-6.8.0.tgz",
|
||||
"integrity": "sha512-iOJg8pr7wq2tg/zSlCCHMi3hMm5JTOxLTagf3zxhcenHsFp+c6uOs6K7W5UE7A4QIJGtqh/ZovFNMP4mOPJynQ==",
|
||||
"engines": {
|
||||
"node": ">=16.20.1"
|
||||
}
|
||||
},
|
||||
"node_modules/buffer": {
|
||||
"version": "5.7.1",
|
||||
"resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
|
||||
|
@ -1667,6 +1700,11 @@
|
|||
"ieee754": "^1.1.13"
|
||||
}
|
||||
},
|
||||
"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=="
|
||||
},
|
||||
"node_modules/bytes": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
|
||||
|
@ -2173,6 +2211,26 @@
|
|||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/cookie-parser": {
|
||||
"version": "1.4.7",
|
||||
"resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.7.tgz",
|
||||
"integrity": "sha512-nGUvgXnotP3BsjiLX2ypbQnWoGUPIIfHQNZkkC668ntrzGWEZVW70HDEB1qnNGMicPje6EttlIgzo51YSwNQGw==",
|
||||
"dependencies": {
|
||||
"cookie": "0.7.2",
|
||||
"cookie-signature": "1.0.6"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/cookie-parser/node_modules/cookie": {
|
||||
"version": "0.7.2",
|
||||
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz",
|
||||
"integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/cookie-signature": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
|
||||
|
@ -2542,6 +2600,14 @@
|
|||
"integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==",
|
||||
"dev": true
|
||||
},
|
||||
"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==",
|
||||
"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",
|
||||
|
@ -4294,6 +4360,59 @@
|
|||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/jsonwebtoken": {
|
||||
"version": "9.0.2",
|
||||
"resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz",
|
||||
"integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==",
|
||||
"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/jsonwebtoken/node_modules/ms": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
|
||||
},
|
||||
"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==",
|
||||
"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==",
|
||||
"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",
|
||||
"integrity": "sha512-C3iHfuGUXK2u8/ipq9LfjFfXFxAZMQJJq7vLS45r3D9Y2xQ/m4S8zaR4zMLFWh9AsNPXmcFfUDhTEO8UIC/V6Q==",
|
||||
"engines": {
|
||||
"node": ">=12.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/keyv": {
|
||||
"version": "4.5.4",
|
||||
"resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
|
||||
|
@ -4769,11 +4888,35 @@
|
|||
"integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==",
|
||||
"dev": true
|
||||
},
|
||||
"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=="
|
||||
},
|
||||
"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=="
|
||||
},
|
||||
"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=="
|
||||
},
|
||||
"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=="
|
||||
},
|
||||
"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==",
|
||||
"dev": true
|
||||
"integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA=="
|
||||
},
|
||||
"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=="
|
||||
},
|
||||
"node_modules/lodash.kebabcase": {
|
||||
"version": "4.1.1",
|
||||
|
@ -4799,6 +4942,11 @@
|
|||
"integrity": "sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/lodash.once": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz",
|
||||
"integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg=="
|
||||
},
|
||||
"node_modules/lodash.snakecase": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/lodash.snakecase/-/lodash.snakecase-4.1.1.tgz",
|
||||
|
@ -5090,6 +5238,11 @@
|
|||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/memory-pager": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz",
|
||||
"integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg=="
|
||||
},
|
||||
"node_modules/meow": {
|
||||
"version": "12.1.1",
|
||||
"resolved": "https://registry.npmjs.org/meow/-/meow-12.1.1.tgz",
|
||||
|
@ -5233,6 +5386,126 @@
|
|||
"node": ">=16 || 14 >=14.17"
|
||||
}
|
||||
},
|
||||
"node_modules/mongodb": {
|
||||
"version": "6.9.0",
|
||||
"resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.9.0.tgz",
|
||||
"integrity": "sha512-UMopBVx1LmEUbW/QE0Hw18u583PEDVQmUmVzzBRH0o/xtE9DBRA5ZYLOjpLIa03i8FXjzvQECJcqoMvCXftTUA==",
|
||||
"dependencies": {
|
||||
"@mongodb-js/saslprep": "^1.1.5",
|
||||
"bson": "^6.7.0",
|
||||
"mongodb-connection-string-url": "^3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16.20.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@aws-sdk/credential-providers": "^3.188.0",
|
||||
"@mongodb-js/zstd": "^1.1.0",
|
||||
"gcp-metadata": "^5.2.0",
|
||||
"kerberos": "^2.0.1",
|
||||
"mongodb-client-encryption": ">=6.0.0 <7",
|
||||
"snappy": "^7.2.2",
|
||||
"socks": "^2.7.1"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@aws-sdk/credential-providers": {
|
||||
"optional": true
|
||||
},
|
||||
"@mongodb-js/zstd": {
|
||||
"optional": true
|
||||
},
|
||||
"gcp-metadata": {
|
||||
"optional": true
|
||||
},
|
||||
"kerberos": {
|
||||
"optional": true
|
||||
},
|
||||
"mongodb-client-encryption": {
|
||||
"optional": true
|
||||
},
|
||||
"snappy": {
|
||||
"optional": true
|
||||
},
|
||||
"socks": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/mongodb-connection-string-url": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-3.0.1.tgz",
|
||||
"integrity": "sha512-XqMGwRX0Lgn05TDB4PyG2h2kKO/FfWJyCzYQbIhXUxz7ETt0I/FqHjUeqj37irJ+Dl1ZtU82uYyj14u2XsZKfg==",
|
||||
"dependencies": {
|
||||
"@types/whatwg-url": "^11.0.2",
|
||||
"whatwg-url": "^13.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/mongoose": {
|
||||
"version": "8.7.1",
|
||||
"resolved": "https://registry.npmjs.org/mongoose/-/mongoose-8.7.1.tgz",
|
||||
"integrity": "sha512-RpNMyhyzLVCVbf8xTVbrf/18G3MqQzNw5pJdvOJ60fzbCa3cOZzz9L+8XpqzBXtRlgZGWv0T7MmOtvrT8ocp1Q==",
|
||||
"dependencies": {
|
||||
"bson": "^6.7.0",
|
||||
"kareem": "2.6.3",
|
||||
"mongodb": "6.9.0",
|
||||
"mpath": "0.9.0",
|
||||
"mquery": "5.0.0",
|
||||
"ms": "2.1.3",
|
||||
"sift": "17.1.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16.20.1"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/mongoose"
|
||||
}
|
||||
},
|
||||
"node_modules/mongoose/node_modules/ms": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
|
||||
},
|
||||
"node_modules/mpath": {
|
||||
"version": "0.9.0",
|
||||
"resolved": "https://registry.npmjs.org/mpath/-/mpath-0.9.0.tgz",
|
||||
"integrity": "sha512-ikJRQTk8hw5DEoFVxHG1Gn9T/xcjtdnOKIU1JTmGjZZlg9LST2mBLmcX3/ICIbgJydT2GOc15RnNy5mHmzfSew==",
|
||||
"engines": {
|
||||
"node": ">=4.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/mquery": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/mquery/-/mquery-5.0.0.tgz",
|
||||
"integrity": "sha512-iQMncpmEK8R8ncT8HJGsGc9Dsp8xcgYMVSbs5jgnm1lFHTZqMJTUWTDx1LBO8+mK3tPNZWFLBghQEIOULSTHZg==",
|
||||
"dependencies": {
|
||||
"debug": "4.x"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/mquery/node_modules/debug": {
|
||||
"version": "4.3.7",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
|
||||
"integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
|
||||
"dependencies": {
|
||||
"ms": "^2.1.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"supports-color": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/mquery/node_modules/ms": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
|
||||
},
|
||||
"node_modules/ms": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||
|
@ -5824,7 +6097,6 @@
|
|||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
|
||||
"integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
|
@ -6158,7 +6430,6 @@
|
|||
"version": "7.6.3",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz",
|
||||
"integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
},
|
||||
|
@ -6311,6 +6582,11 @@
|
|||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/sift": {
|
||||
"version": "17.1.3",
|
||||
"resolved": "https://registry.npmjs.org/sift/-/sift-17.1.3.tgz",
|
||||
"integrity": "sha512-Rtlj66/b0ICeFzYTuNvX/EF1igRbbnGSvEyT79McoZa/DeGhMyC5pWKOEsZKnpkqtSeovd5FL/bjHWC3CIIvCQ=="
|
||||
},
|
||||
"node_modules/signal-exit": {
|
||||
"version": "3.0.7",
|
||||
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
|
||||
|
@ -6411,6 +6687,14 @@
|
|||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/sparse-bitfield": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz",
|
||||
"integrity": "sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==",
|
||||
"dependencies": {
|
||||
"memory-pager": "^1.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/split2": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz",
|
||||
|
@ -6694,6 +6978,17 @@
|
|||
"nodetouch": "bin/nodetouch.js"
|
||||
}
|
||||
},
|
||||
"node_modules/tr46": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/tr46/-/tr46-4.1.1.tgz",
|
||||
"integrity": "sha512-2lv/66T7e5yNyhAAC4NaKe5nVavzuGJQVVtRYLyQ2OI8tsJ61PMLlelehb0wi2Hx6+hT/OJUWZcw8MjlSRnxvw==",
|
||||
"dependencies": {
|
||||
"punycode": "^2.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
}
|
||||
},
|
||||
"node_modules/tree-kill": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz",
|
||||
|
@ -6872,6 +7167,26 @@
|
|||
"defaults": "^1.0.3"
|
||||
}
|
||||
},
|
||||
"node_modules/webidl-conversions": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz",
|
||||
"integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/whatwg-url": {
|
||||
"version": "13.0.0",
|
||||
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-13.0.0.tgz",
|
||||
"integrity": "sha512-9WWbymnqj57+XEuqADHrCJ2eSXzn8WXIW/YSGaZtb2WKAInQ6CHfaUUcTyyver0p8BDg5StLQq8h1vtZuwmOig==",
|
||||
"dependencies": {
|
||||
"tr46": "^4.1.1",
|
||||
"webidl-conversions": "^7.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16"
|
||||
}
|
||||
},
|
||||
"node_modules/which": {
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
|
||||
|
|
|
@ -20,10 +20,14 @@
|
|||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"dependencies": {
|
||||
"body-parser": "^1.20.3",
|
||||
"cookie-parser": "^1.4.7",
|
||||
"dotenv": "^16.4.5",
|
||||
"express": "^4.21.0",
|
||||
"imap-node": "^0.9.9",
|
||||
"jsonwebtoken": "^9.0.2",
|
||||
"mailparser": "^3.7.1",
|
||||
"mongoose": "^8.7.1",
|
||||
"node-pop3": "^0.9.0",
|
||||
"nodemailer": "^6.9.15",
|
||||
"serve-static": "^1.16.2"
|
||||
|
|
|
@ -13,14 +13,31 @@ if (!process.env.ATTACHMENTS_PATH) {
|
|||
}
|
||||
}
|
||||
const express = require("express");
|
||||
const mongoose = require("mongoose");
|
||||
const serveStatic = require("serve-static");
|
||||
const authAndInitReceiveMiddleware = require("./middleware/authAndInitReceive.js");
|
||||
const checkRoute = require("./routes/check.js");
|
||||
const loginRoute = require("./routes/login.js");
|
||||
const logoutRoute = require("./routes/logout.js");
|
||||
const receiveRoute = require("./routes/receive.js");
|
||||
const bodyParser = require("body-parser");
|
||||
const cookieParser = require("cookie-parser");
|
||||
|
||||
mongoose
|
||||
.connect(process.env.MONGODB_CONNSTRING)
|
||||
.then(() => console.log(`Database connected successfully`));
|
||||
|
||||
// Since mongoose's Promise is deprecated, we override it with Node's Promise
|
||||
mongoose.Promise = global.Promise;
|
||||
|
||||
const app = express();
|
||||
|
||||
app.use(cookieParser());
|
||||
|
||||
app.use("/api", bodyParser.json());
|
||||
app.use("/api/login", loginRoute);
|
||||
app.use("/api", authAndInitReceiveMiddleware);
|
||||
app.use("/api/logout", logoutRoute);
|
||||
app.use("/api/check", checkRoute);
|
||||
app.use("/api/receive", receiveRoute);
|
||||
app.use("/api", (req, res, next) => {
|
||||
|
|
|
@ -1,23 +1,41 @@
|
|||
const initReceiveDriver = require("../utils/initReceiveDriver.js");
|
||||
const { decryptPassword } = require("../utils/passwordCrypto.js");
|
||||
const userModel = require("../models/user.js");
|
||||
const jwt = require("jsonwebtoken");
|
||||
|
||||
module.exports = function authAndInitReceiveMiddleware(req, res, next) {
|
||||
// Custom implementation of HTTP Basic authentication
|
||||
const deny = (message) => {
|
||||
res.set("WWW-Authenticate", "BasicMERNMail");
|
||||
res.status(401).json({ message: message || "Authentication required." });
|
||||
};
|
||||
|
||||
const authTPair = (req.headers.authorization || "").split(" ");
|
||||
if (authTPair[0] != "Basic" && authTPair[0] != "BasicMERNMail") {
|
||||
deny();
|
||||
return;
|
||||
}
|
||||
const b64auth = authTPair[1] || "";
|
||||
const authPair = Buffer.from(b64auth, "base64").toString().split(":");
|
||||
const email = authPair[0];
|
||||
const password = authPair[1];
|
||||
|
||||
if (email && password) {
|
||||
jwt.verify(req.cookies.token, process.env.JWT_SECRET, (err, decoded) => {
|
||||
if (err) {
|
||||
res.status(401).json({ message: err.message });
|
||||
return;
|
||||
}
|
||||
const email = decoded.email;
|
||||
userModel
|
||||
.findOne({ email: email })
|
||||
.then((result) => {
|
||||
if (!result) {
|
||||
res.status(401).json({ message: "User not found" });
|
||||
} else {
|
||||
const password = decryptPassword(result.encryptedPassword);
|
||||
initReceiveDriver(email, password, (err, driver) => {
|
||||
if (err) {
|
||||
res.status(401).json({ message: err.message });
|
||||
} else {
|
||||
req.credentials = {
|
||||
email: email,
|
||||
password: password
|
||||
};
|
||||
req.receiveDriver = driver;
|
||||
next();
|
||||
}
|
||||
});
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
res.status(500).json({ message: err.message });
|
||||
});
|
||||
});
|
||||
/*if (email && password) {
|
||||
initReceiveDriver(email, password, (err, driver) => {
|
||||
if (err) {
|
||||
deny(err.message);
|
||||
|
@ -32,5 +50,5 @@ module.exports = function authAndInitReceiveMiddleware(req, res, next) {
|
|||
});
|
||||
} else {
|
||||
deny();
|
||||
}
|
||||
}*/
|
||||
};
|
||||
|
|
18
src/models/user.js
Normal file
18
src/models/user.js
Normal file
|
@ -0,0 +1,18 @@
|
|||
// models/User.js
|
||||
const mongoose = require("mongoose");
|
||||
|
||||
const userSchema = new mongoose.Schema({
|
||||
email: {
|
||||
type: String,
|
||||
required: true,
|
||||
unique: true
|
||||
},
|
||||
encryptedPassword: {
|
||||
type: String,
|
||||
required: true
|
||||
}
|
||||
});
|
||||
|
||||
const User = mongoose.model("users", userSchema);
|
||||
|
||||
module.exports = User;
|
|
@ -3,7 +3,7 @@ const router = express.Router();
|
|||
|
||||
router.get("/", (req, res) => {
|
||||
req.receiveDriver.close();
|
||||
res.json({ message: "OK!" });
|
||||
res.json({ email: req.credentials.email });
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
|
|
76
src/routes/login.js
Normal file
76
src/routes/login.js
Normal file
|
@ -0,0 +1,76 @@
|
|||
const express = require("express");
|
||||
const jwt = require("jsonwebtoken");
|
||||
const userModel = require("../models/user.js");
|
||||
const initReceiveDriver = require("../utils/initReceiveDriver.js");
|
||||
const { encryptPassword } = require("../utils/passwordCrypto.js");
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
router.post("/", (req, res) => {
|
||||
if (!req.body || !req.body.email || !req.body.password)
|
||||
res.status(400).json({ message: "Email and password are required" });
|
||||
initReceiveDriver(
|
||||
String(req.body.email),
|
||||
String(req.body.password),
|
||||
(err, driver) => {
|
||||
if (err) {
|
||||
res.status(401).json({ message: err.message });
|
||||
} else {
|
||||
driver.close();
|
||||
userModel
|
||||
.findOne({ email: req.body.email })
|
||||
.then((result) => {
|
||||
const createCallback = () => {
|
||||
jwt.sign(
|
||||
{ email: req.body.email },
|
||||
process.env.JWT_SECRET,
|
||||
(err, token) => {
|
||||
if (err) {
|
||||
res.status(401).json({ message: err.message });
|
||||
} else {
|
||||
res.cookie("token", token, {
|
||||
maxAge: 315360000000,
|
||||
httpOnly: true,
|
||||
secure: parseInt(process.env.JWT_SECURECOOKIE) > 0,
|
||||
sameSite: "strict"
|
||||
});
|
||||
res.json({ message: "Logged in successfully" });
|
||||
}
|
||||
}
|
||||
);
|
||||
};
|
||||
const encryptedPassword = encryptPassword(req.body.password);
|
||||
if (!result) {
|
||||
userModel
|
||||
.create({
|
||||
email: req.body.email,
|
||||
encryptedPassword: encryptedPassword
|
||||
})
|
||||
.then(createCallback)
|
||||
.catch((err) => {
|
||||
res.status(500).json({ message: err.message });
|
||||
});
|
||||
} else {
|
||||
userModel
|
||||
.replaceOne(
|
||||
{ email: req.body.email },
|
||||
{
|
||||
email: req.body.email,
|
||||
encryptedPassword: encryptedPassword
|
||||
}
|
||||
)
|
||||
.then(createCallback)
|
||||
.catch((err) => {
|
||||
res.status(500).json({ message: err.message });
|
||||
});
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
res.status(500).json({ message: err.message });
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
module.exports = router;
|
11
src/routes/logout.js
Normal file
11
src/routes/logout.js
Normal file
|
@ -0,0 +1,11 @@
|
|||
const express = require("express");
|
||||
const router = express.Router();
|
||||
|
||||
// POST method to prevent logout CSRF
|
||||
router.post("/", (req, res) => {
|
||||
req.receiveDriver.close();
|
||||
res.clearCookie("token");
|
||||
res.json({ message: "Logged out successfully" });
|
||||
});
|
||||
|
||||
module.exports = router;
|
26
src/utils/passwordCrypto.js
Normal file
26
src/utils/passwordCrypto.js
Normal file
|
@ -0,0 +1,26 @@
|
|||
const crypto = require("crypto");
|
||||
|
||||
// Decode the base64 strings to buffers
|
||||
const secretKey = Buffer.from(process.env.ENCRYPTION_SECRETKEY, "base64");
|
||||
const iv = Buffer.from(process.env.ENCRYPTION_IV, "base64");
|
||||
|
||||
// Encrypt the password
|
||||
function encryptPassword(password) {
|
||||
const cipher = crypto.createCipheriv("aes-256-cbc", secretKey, iv);
|
||||
let encrypted = cipher.update(password, "utf8", "hex");
|
||||
encrypted += cipher.final("hex");
|
||||
return encrypted;
|
||||
}
|
||||
|
||||
// Decrypt the password
|
||||
function decryptPassword(encryptedPassword) {
|
||||
const decipher = crypto.createDecipheriv("aes-256-cbc", secretKey, iv);
|
||||
let decrypted = decipher.update(encryptedPassword, "hex", "utf8");
|
||||
decrypted += decipher.final("utf8");
|
||||
return decrypted;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
encryptPassword: encryptPassword,
|
||||
decryptPassword: decryptPassword
|
||||
};
|
Loading…
Reference in a new issue