Passed
Push — main ( 41db93...062dcb )
by Julia
02:58
created

server/src/models/emp.js   A

Complexity

Total Complexity 11
Complexity/F 1.57

Size

Lines of Code 180
Function Count 7

Duplication

Duplicated Lines 0
Ratio 0 %

Test Coverage

Coverage 100%

Importance

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