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

Feature : Keep me logged In feature added #1129

Merged
merged 10 commits into from
Aug 10, 2024
4 changes: 4 additions & 0 deletions backend/app/models/Admin.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ const adminSchema = new Schema(
type: String,
trim: true,
},
refreshToken:{
type:String,
trim:true
}
},
{ timestamps: { createdAt: 'createdAt', updatedAt: 'updatedAt' } }
);
Expand Down
2 changes: 1 addition & 1 deletion backend/app/routes/admin/changePassword.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ module.exports = async (req, res, next) => {
const hashedPassword = await argon2.hash(newPassword);

const [err] = await to(
Admin.findOneAndUpdate({ email: userRecord.email }, { $set: { passwordHash: hashedPassword } })
Admin.findOneAndUpdate({ email: userRecord.email }, { $set: { passwordHash: hashedPassword,refreshToken:"" } })
);

if (err) {
Expand Down
15 changes: 13 additions & 2 deletions backend/app/routes/admin/getAdmins.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ const to = require('await-to-js').default;
const Admin = require('../../models/Admin');
const { ErrorHandler } = require('../../../helpers/error');
const constants = require('../../../constants');
const { getTokenFromHeader } = require('../../../helpers/middlewares/auth')

const getAdminsAggregate = (match, page) => {
const pipeline = [
Expand All @@ -15,7 +16,7 @@ const getAdminsAggregate = (match, page) => {
email: 1,
contact: 1,
isSuperAdmin: 1,
image:1
image: 1
},
},
{ $skip: constants.PAGINATION_LIMIT.GET_ADMINS * (Number(page) - 1) },
Expand All @@ -37,10 +38,20 @@ module.exports = async (req, res, next) => {
email: req.query.email || '',
};
}
const token = await getTokenFromHeader(req)
const [err, response] = await to(Admin.aggregate(getAdminsAggregate(match, page)));
if (err) {
const error = new ErrorHandler(constants.ERRORS.DATABASE, {
statusCode: '500',
statusCode: 500,
message: 'The server encountered an unexpected condition which prevented it from fulfilling the request.',
errStack: err,
});
return next(error);
}
const refreshToken = await Admin.findOne({ email: response[0].email })
if (token != refreshToken?.refreshToken) {
const error = new ErrorHandler(constants.ERRORS.DATABASE, {
statusCode: 500,
message: 'The server encountered an unexpected condition which prevented it from fulfilling the request.',
errStack: err,
});
Expand Down
2 changes: 1 addition & 1 deletion backend/app/routes/admin/resetPassword.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ module.exports = async (req, res, next) => {
const hashedPassword = await argon2.hash(newPassword);

// Finding and updating the admin password
const [err] = await to(Admin.findOneAndUpdate({ email }, { passwordHash: hashedPassword }, { new: true }));
const [err] = await to(Admin.findOneAndUpdate({ email }, { passwordHash: hashedPassword,refreshToken:"" }, { new: true }));

// Throwing error in admin not found
if (err) {
Expand Down
1 change: 1 addition & 0 deletions backend/app/routes/auth/@validationSchema/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ const Joi = require('joi');
const loginSchema = Joi.object().keys({
email: Joi.string().required(),
password: Joi.string().required(),
keepMeLoggedIn:Joi.boolean()
});

module.exports = loginSchema;
7 changes: 4 additions & 3 deletions backend/app/routes/auth/login.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@
const Admin = require('../../models/Admin');
const { ErrorHandler } = require('../../../helpers/error');
const constants = require('../../../constants');
const { generateJWT } = require('../../../helpers/middlewares/auth');
const { generateJWT,generateJWTWithOutExpire } = require('../../../helpers/middlewares/auth');

module.exports = async (req, res, next) => {
const { email, password } = req.body;
const { email, password,keepMeLoggedIn } = req.body;
const userRecord = await Admin.findOne({ email });

Check failure

Code scanning / CodeQL

Database query built from user-controlled sources High

This query object depends on a
user-provided value
.
if (!userRecord) {
const error = new ErrorHandler(constants.ERRORS.INPUT, {
statusCode: 400,
Expand Down Expand Up @@ -34,7 +34,8 @@
isSuperAdmin: userRecord.isSuperAdmin,
phone: userRecord.contact,
};
const JWT = generateJWT(JWTPayload);
const JWT = keepMeLoggedIn?generateJWTWithOutExpire(JWTPayload):generateJWT(JWTPayload);
const updateRefreshToken=await Admin.findByIdAndUpdate(userRecord.id,{refreshToken:JWT})
const response = { ...JWTPayload, token: JWT };
return res.status(200).send(response);
};
3 changes: 2 additions & 1 deletion backend/helpers/middlewares/auth.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ const constants = require('../../constants');

const generateJWT = (payload, expiry = config.JWT_EXPIRES_IN) =>
sign(payload, config.JWT_SECRET_KEY, { expiresIn: expiry });
const generateJWTWithOutExpire = (payload) => sign(payload, config.JWT_SECRET_KEY)
const getTokenFromHeader = async (req) => {
if (req.headers.authorization && req.headers.authorization.split(' ')[0] === 'Bearer') {
return req.headers.authorization.split(' ')[1];
Expand Down Expand Up @@ -38,4 +39,4 @@ const authMiddleware = async (req, res, next) => {
next();
};

module.exports = { authMiddleware, generateJWT, verifyToken };
module.exports = { authMiddleware, generateJWT, verifyToken,generateJWTWithOutExpire ,getTokenFromHeader};
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import { Button2 } from "../../../../../components/util/Button";
import { END_POINT } from "./../../../../../config/api";
import { SimpleToast } from "./../../../../../components/util/Toast/Toast";
import style from "./reset-password.module.scss";
import { useDispatch } from "react-redux";
import { logout } from "../../../../../store/actions/auth";

export function ResetPassword() {
const [oldPassword, setOldPassword] = useState("");
Expand All @@ -16,6 +18,7 @@ export function ResetPassword() {
const oldPasswordInput = useRef("oldpassword");
const newPasswordInput = useRef("newpassword");
const confirmPasswordInput = useRef("confirmpassword");
const dispatch = useDispatch();

const token = useSelector((state) => state.token);

Expand Down Expand Up @@ -63,6 +66,7 @@ export function ResetPassword() {
if (response.status === 200) {
setOpenSuccessToast(true);
setPasswordChange(true);
logout(dispatch);
}
response
.json()
Expand Down
36 changes: 31 additions & 5 deletions frontend/src/pages/Login/Login.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React, { useState, useRef, useEffect } from "react";
import { Button2 } from "../../components/util/Button/index";
import { Checkbox } from "@material-ui/core";
import style from "./login.module.scss";
import { useDispatch, useSelector } from "react-redux";
import * as actions from "../../store/actions/actions";
Expand All @@ -17,10 +18,11 @@ export function Login(props) {
const dispatch = useDispatch();
const dark = props.theme;
const [errorObj, setErrorObj] = useState({});
const [isLoading,setIsLoading] = useState(false);
const [isLoading, setIsLoading] = useState(false);
const validationSchema = {
email: Joi.string().email().required(),
password: Joi.string().required(),
keepMeLoggedIn: Joi.boolean(),
};

const isFormValid = () => {
Expand Down Expand Up @@ -105,7 +107,7 @@ export function Login(props) {
.json()
.then((res) => {
if (response.status === 200) {
const firstName = res.name.split(' ')[0];
const firstName = res.name.split(" ")[0];
localStorage.setItem("token", res.token);
localStorage.setItem("isSuperAdmin", res.isSuperAdmin);
localStorage.setItem("firstName", firstName);
Expand All @@ -120,12 +122,14 @@ export function Login(props) {
})
.catch((err) => {
console.error(err);
setOpenError3Toast(true)})
setOpenError3Toast(true);
})
)
.catch((err) => {
setOpenError1Toast(true);
console.error("must be a backend problem🤔:", err);
}).finally(()=> {
})
.finally(() => {
setIsLoading(false);
});
}
Expand All @@ -137,7 +141,9 @@ export function Login(props) {

return (
<>
<div className={style["data-loader"]}>{isLoading?<Loader/>:null}</div>
<div className={style["data-loader"]}>
{isLoading ? <Loader /> : null}
</div>
<div
className={
dark
Expand Down Expand Up @@ -233,6 +239,26 @@ export function Login(props) {
)}
</div>
</div>
<div className={style["checkbox-container"]}>
<input
type="checkbox"
name="keepMeLoggedIn"
id="checkBox"
value={credential?.keepMeLoggedIn}
onChange={(e) => {
setCredential({
...credential,
keepMeLoggedIn: e.target.checked,
});
}}
/>
<label
className={style["checkbox-label"]}
htmlFor="checkBox"
>
Keep Me Logged In
</label>
</div>
<div className={style["submit-btn"]}>
<Button2
id="btn"
Expand Down
7 changes: 7 additions & 0 deletions frontend/src/pages/Login/login.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -289,3 +289,10 @@
justify-content: center;
align-items: center;
}
.checkbox-container {
margin-top: 16px;
margin-bottom: 24px;
}
.checkbox-label {
margin-left: 8px !important;
}
Loading