-
-
Notifications
You must be signed in to change notification settings - Fork 259
/
custom.js
145 lines (125 loc) · 4.91 KB
/
custom.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
'use strict';
const Joi = require('joi');
const ObjectId = require('mongodb').ObjectId;
const tools = require('../../tools');
const roles = require('../../roles');
const { sessSchema, sessIPSchema } = require('../../schemas');
const { userId } = require('../../schemas/request/general-schemas');
const { successRes } = require('../../schemas/response/general-schemas');
// Custom 2FA needs to be enabled if your website handles its own 2FA and you want to disable
// master password usage for IMAP/POP/SMTP clients
module.exports = (db, server, userHandler) => {
server.put(
{
path: '/users/:user/2fa/custom',
tags: ['TwoFactorAuth'],
summary: 'Enable custom 2FA for a user',
description: 'This method disables account password for IMAP/POP3/SMTP',
validationObjs: {
requestBody: {
sess: sessSchema,
ip: sessIPSchema
},
queryParams: {},
pathParams: { user: userId },
response: { 200: { description: 'Success', model: Joi.object({ success: successRes }) } }
}
},
tools.responseWrapper(async (req, res) => {
res.charSet('utf-8');
const { pathParams, requestBody, queryParams } = req.route.spec.validationObjs;
const schema = Joi.object({
...pathParams,
...requestBody,
...queryParams
});
const result = schema.validate(req.params, {
abortEarly: false,
convert: true
});
if (result.error) {
res.status(400);
return res.json({
error: result.error.message,
code: 'InputValidationError',
details: tools.validationErrors(result)
});
}
// permissions check
if (req.user && req.user === result.value.user) {
req.validate(roles.can(req.role).updateOwn('users'));
} else {
req.validate(roles.can(req.role).updateAny('users'));
}
let user = new ObjectId(result.value.user);
let userHandlerResponse = await userHandler.enableCustom2fa(user, result.value);
return res.json({
success: userHandlerResponse.success
});
})
);
server.del(
{
path: '/users/:user/2fa/custom',
tags: ['TwoFactorAuth'],
summary: 'Disable custom 2FA for a user',
description: 'This method disables custom 2FA. If it was the only 2FA set up, then account password for IMAP/POP3/SMTP gets enabled again',
validationObjs: {
requestBody: {},
queryParams: {
sess: sessSchema,
ip: sessIPSchema
},
pathParams: { user: userId },
response: { 200: { description: 'Success', model: Joi.object({ success: successRes }) } }
}
},
tools.responseWrapper(async (req, res) => {
res.charSet('utf-8');
const { pathParams, requestBody, queryParams } = req.route.spec.validationObjs;
const schema = Joi.object({
...pathParams,
...requestBody,
...queryParams
});
const result = schema.validate(req.params, {
abortEarly: false,
convert: true
});
if (result.error) {
res.status(400);
return res.json({
error: result.error.message,
code: 'InputValidationError',
details: tools.validationErrors(result)
});
}
// permissions check
if (req.user && req.user === result.value.user) {
req.validate(roles.can(req.role).updateOwn('users'));
} else {
req.validate(roles.can(req.role).updateAny('users'));
}
let user = new ObjectId(result.value.user);
let disabled2fa = await userHandler.disableCustom2fa(user, result.value);
if (!disabled2fa) {
res.status(500);
return res.json({
error: 'Failed to disable 2FA',
code: '2FADisableFailed'
});
}
if (disabled2fa && req.accessToken && typeof req.accessToken.update === 'function') {
try {
// update access token data for current session after custom 2FA disabled
await req.accessToken.update();
} catch (err) {
// ignore
}
}
return res.json({
success: true
});
})
);
};