server/src/models/emp.js   A
last analyzed

Complexity

Total Complexity 11
Complexity/F 1.57

Size

Lines of Code 177
Function Count 7

Duplication

Duplicated Lines 0
Ratio 0 %

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
wmc 11
eloc 67
mnd 4
bc 4
fnc 7
dl 0
loc 177
ccs 26
cts 26
cp 1
rs 10
bpm 0.5714
cpm 1.5713
noi 0
c 0
b 0
f 0
1
import bcrypt from "bcryptjs";
2
import jwt from "jsonwebtoken";
3
import { db } from "./db.js"
4
5
// eslint-disable-next-line no-unused-vars
6
import express from "express";
7
8
9 1
const jwtSecret = String(process.env.JWT_SECRET);
10
11 1
const emp = {
12
    /**
13
     * Returns id, username,
14
     * password-hash and role.
15
     * Will not return anything if
16
     * the admin's account has been
17
     * deactivated
18
     * @param {String} username 
19
     * @returns {Promise<Object>}
20
     */
21
    getOneFromDb: async function(username) {
22 4
        const result = await db.queryWithArgs(`CALL emp_login(?);`, [username]);
23 4
        return result[0][0];
24
    },
25
    /**
26
     * Checks if a token is valid
27
     * and if it's payload contains
28
     * role attribute with value
29
     * "admin"
30
     * @param {express.Request} req 
31
     * @param {express.Response} res 
32
     * @param {express.NextFunction} next 
33
     */
34
    checkAdminAcc: function(req, res, next) {
35 42
        emp.checkToken(req, res, next, ["admin"]);
36
    },
37
    /**
38
     * Checks if a token is valid
39
     * and if it's payload contains
40
     * role attribute with a value
41
     * that is included in the array
42
     * of acceptable rows
43
     * @param {express.Request} req 
44
     * @param {express.Response} res 
45
     * @param {express.NextFunction} next 
46
     * @param {Array} acceptableRoles array with acceptable roles, for example ["admin"] or ["admin", "superadmin"]
47
     */
48
    checkToken: function(req, res, next, acceptableRoles) {
49 46
        let token = req.headers["x-access-token"];
50
51
        /**
52
         * @typedef {Object} JwtPayload
53
         * @property {String} role
54
         * @property {String} id
55
         */
56 46
        jwt.verify(token, jwtSecret, function (err, /** @type {JwtPayload} */decoded) {
57
            // if no token has been provided,
58
            // or if provided token is expired
59
            // this block will be executed
60 46
            if (err) {
61 2
                return res.status(500).json({
62
                    errors: {
63
                        status: 500,
64
                        source: "authorization",
65
                        title: "Failed authentication",
66
                        detail: err.message
67
                    }
68
                });
69
            }
70
71 44
            if (!acceptableRoles.includes(decoded.role)) {
72
                // if unauthorized request it is safer
73
                // to make it look like the page does not
74
                // exist
75 2
                return res.status(404).json({
76
                    errors: {
77
                        status: 404,
78
                        source: req.originalUrl,
79
                        title: "Not found",
80
                        detail: "Page not found"
81
                    }
82
                });
83
            }
84
            /**
85
             * OBS! osäker på om vi
86
             * behöver lägga till
87
             * dessa detaljer i bodyn,
88
             * jag tror inte att
89
             * det kommer behövas någonstans? 
90
             * Har admin  passerat denna route
91
             * så är det redan säkerställt att man har behörighet
92
             */
93 42
            req.body.emp = {
94
                id: decoded.id,
95
                role: decoded.role
96
            };
97
98 42
            return next();
99
        });
100
    },
101
102
    /**
103
     * @description Function that handles admin login
104
     *
105
     * @param {express.Request} req Request object
106
     * @param {express.Response} res Response object
107
     *
108
     * @returns {Promise<Object>} JSON object
109
     */
110
    login: async function (req, res) {
111 1
        const username = req.body.username;
112 1
        const password = req.body.password;
113
114 1
        const emp = await this.getOneFromDb(username);
115
116
        // om användarnamn saknas kommer
117
        // databasen lyfta ett error
118
        // om lösenord saknas kommer det fångas i bcrypt compare
119
120 1
        return this.comparePasswords(res, password, emp);
121
    },
122
123
    checkPassword: function(res, result, emp) {
124 4
        if (result) {
125 2
            const payload = {
126
                id: emp.id,
127
                role: emp.role
128
            };
129 2
            const jwtToken = jwt.sign(payload, jwtSecret, { expiresIn: "24h" });
130
131 2
            return res.json({
132
                data: {
133
                    type: "success",
134
                    message: "User logged in",
135
                    user: payload,
136
                    token: jwtToken
137
                }
138
            });
139
        }
140
141 2
        return res.status(401).json({
142
            errors: {
143
                status: 401,
144
                source: "/login",
145
                title: "Wrong password",
146
                detail: "Password is incorrect."
147
            }
148
        });
149
    },
150
    /**
151
     * @description Function that compares password to the hash
152
     * stored in db
153
     *
154
     * @param {express.Response} res Response object
155
     * @param {String} password Password
156
     * @param {Object} emp User
157
     *
158
     * @returns {Object} JSON object
159
     */
160
    comparePasswords: async function (res, password, emp) {
161 3
        try {
162 3
            const result = await bcrypt.compare(password, emp.hash);
163 2
            return this.checkPassword(res, result, emp);
164
        } catch (error) {
165 1
            return res.status(500).json({
166
                errors: {
167
                    status: 500,
168
                    source: "/login",
169
                    title: "bcrypt error",
170
                    detail: "bcrypt error"
171
                }
172
            });
173
        }
174
    }
175
};
176
177
export default emp;