· 5 years ago · Feb 04, 2021, 06:04 PM
1"use strict";
2var __rest = (this && this.__rest) || function (s, e) {
3 var t = {};
4 for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
5 t[p] = s[p];
6 if (s != null && typeof Object.getOwnPropertySymbols === "function")
7 for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
8 if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
9 t[p[i]] = s[p[i]];
10 }
11 return t;
12};
13Object.defineProperty(exports, "__esModule", { value: true });
14const bcrypt = require("bcryptjs");
15const express_1 = require("express");
16const jwt = require("jsonwebtoken");
17const shared_middlewares_1 = require("./shared-middlewares");
18const constants_1 = require("./constants");
19/**
20 * Validate email and password
21 */
22const validate = ({ required }) => (req, res, next) => {
23 const { email, password } = req.body;
24 if (required && (!email || !email.trim() || !password || !password.trim())) {
25 res.status(400).jsonp('Email and password are required');
26 return;
27 }
28 if (email && !email.match(constants_1.EMAIL_REGEX)) {
29 res.status(400).jsonp('Email format is invalid');
30 return;
31 }
32 if (password && password.length < constants_1.MIN_PASSWORD_LENGTH) {
33 res.status(400).jsonp('Password is too short');
34 return;
35 }
36 next();
37};
38/**
39 * Register / Create a user
40 */
41const create = (req, res, next) => {
42 const _a = req.body, { email, password } = _a, rest = __rest(_a, ["email", "password"]);
43 const { db } = req.app;
44 if (db == null) {
45 // json-server CLI expose the router db to the app
46 // (https://github.com/typicode/json-server/blob/master/src/cli/run.js#L74),
47 // but if we use the json-server module API, we must do the same.
48 throw Error('You must bind the router db to the app');
49 }
50 const existingUser = db.get('users').find({ email }).value();
51 if (existingUser) {
52 res.status(400).jsonp('Email already exists');
53 return;
54 }
55 bcrypt
56 .hash(password, constants_1.SALT_LENGTH)
57 .then((hash) => {
58 // Create users collection if doesn't exist,
59 // save password as hash and add any other field without validation
60 try {
61 return db
62 .get('users')
63 .insert(Object.assign({ email, password: hash }, rest))
64 .write();
65 }
66 catch (error) {
67 throw Error('You must add a "users" collection to your db');
68 }
69 })
70 .then((user) => {
71 return new Promise((resolve, reject) => {
72 jwt.sign({ email }, constants_1.JWT_SECRET_KEY, { expiresIn: constants_1.JWT_EXPIRES_IN, subject: String(user.id) }, (error, idToken) => {
73 if (error)
74 reject(error);
75 else
76 resolve(idToken);
77 });
78 });
79 })
80 .then((accessToken) => {
81 _a.accessToken = accessToken;
82 delete _a.password;
83 // in order to encapsulate _a in an object having _a as key,
84 // use res.status(201).jsonp({ _a })
85 res.status(201).jsonp( _a );
86 })
87 .catch(next);
88};
89/**
90 * Login
91 */
92const login = (req, res, next) => {
93 const { email, password, ...rest } = req.body;
94 const { db } = req.app;
95 if (db == null) {
96 throw Error('You must bind the router db to the app');
97 }
98 const user = db.get('users').find({ email }).value();
99 if (!user) {
100 res.status(400).jsonp('Cannot find user');
101 return;
102 }
103
104 bcrypt
105 .compare(password, user.password)
106 .then((same) => {
107 if (!same)
108 throw 400;
109 return new Promise((resolve, reject) => {
110 jwt.sign({ email }, constants_1.JWT_SECRET_KEY, { expiresIn: constants_1.JWT_EXPIRES_IN, subject: String(user.id) }, (error, idToken) => {
111 if (error)
112 reject(error);
113 else
114 resolve(idToken);
115 });
116 });
117 })
118 .then((accessToken) => {
119 user.accessToken = accessToken;
120 res.status(200).jsonp( user );
121 })
122 .catch((err) => {
123 if (err === 400)
124 res.status(400).jsonp('Incorrect password');
125 else
126 next(err);
127 });
128};
129/**
130 * Patch and Put user
131 */
132// TODO: create new access token when password or email changes
133const update = (req, res, next) => {
134 const { password } = req.body;
135 if (!password) {
136 next(); // Simply continue with json-server router
137 return;
138 }
139 bcrypt
140 .hash(password, constants_1.SALT_LENGTH)
141 .then((hash) => {
142 req.body.password = hash;
143 next();
144 })
145 .catch(next);
146};
147/**
148 * Users router
149 */
150exports.default = express_1.Router()
151 .use(shared_middlewares_1.bodyParsingHandler)
152 .post('/users|register|signup', validate({ required: true }), create)
153 // Bypass eventual users guards to still allow creation
154 .post('/[640]{3}/users', validate({ required: true }), create)
155 .post('/login|signin', validate({ required: true }), login)
156 .put('/users/:id', validate({ required: true }), update)
157 .patch('/users/:id', validate({ required: false }), update)
158 .use(shared_middlewares_1.errorHandler);
159