Skip to content

Commit 0efae19

Browse files
authored
fix(api-2fa): Added 2FA API endpoints to API docs generation ZMS-124 (#626)
* added Generate TOTP seed api endpoint to API generation * added Enable TOTP api endpoint to API docs generation * added Disable TOTP auth api endpoint to API docs generation * added Validate TOTP token api endpoint to API docs generation * added Disable 2FA api endpoint to API docs generation * Added Enable custom 2FA for a user api endpoint for API docs generation * Disable custom 2FA for a user endpoint added to API docs generation. Fix imports * added Get WebAuthN credentials for a user api endpoint to api docs generation * WebAuthN del and registration endpoints added to API docs generation * webAuthN authentication challenge and attestation endpoints added to API docs generation * fix rpId descriptions * add response objects to endpoints
1 parent 0e987de commit 0efae19

File tree

3 files changed

+486
-128
lines changed

3 files changed

+486
-128
lines changed

lib/api/2fa/custom.js

+44-10
Original file line numberDiff line numberDiff line change
@@ -5,20 +5,38 @@ const ObjectId = require('mongodb').ObjectId;
55
const tools = require('../../tools');
66
const roles = require('../../roles');
77
const { sessSchema, sessIPSchema } = require('../../schemas');
8+
const { userId } = require('../../schemas/request/general-schemas');
9+
const { successRes } = require('../../schemas/response/general-schemas');
810

911
// Custom 2FA needs to be enabled if your website handles its own 2FA and you want to disable
1012
// master password usage for IMAP/POP/SMTP clients
1113

1214
module.exports = (db, server, userHandler) => {
1315
server.put(
14-
'/users/:user/2fa/custom',
16+
{
17+
path: '/users/:user/2fa/custom',
18+
tags: ['TwoFactorAuth'],
19+
summary: 'Enable custom 2FA for a user',
20+
description: 'This method disables account password for IMAP/POP3/SMTP',
21+
validationObjs: {
22+
requestBody: {
23+
sess: sessSchema,
24+
ip: sessIPSchema
25+
},
26+
queryParams: {},
27+
pathParams: { user: userId },
28+
response: { 200: { description: 'Success', model: Joi.object({ success: successRes }) } }
29+
}
30+
},
1531
tools.responseWrapper(async (req, res) => {
1632
res.charSet('utf-8');
1733

18-
const schema = Joi.object().keys({
19-
user: Joi.string().hex().lowercase().length(24).required(),
20-
sess: sessSchema,
21-
ip: sessIPSchema
34+
const { pathParams, requestBody, queryParams } = req.route.spec.validationObjs;
35+
36+
const schema = Joi.object({
37+
...pathParams,
38+
...requestBody,
39+
...queryParams
2240
});
2341

2442
const result = schema.validate(req.params, {
@@ -52,14 +70,30 @@ module.exports = (db, server, userHandler) => {
5270
);
5371

5472
server.del(
55-
'/users/:user/2fa/custom',
73+
{
74+
path: '/users/:user/2fa/custom',
75+
tags: ['TwoFactorAuth'],
76+
summary: 'Disable custom 2FA for a user',
77+
description: 'This method disables custom 2FA. If it was the only 2FA set up, then account password for IMAP/POP3/SMTP gets enabled again',
78+
validationObjs: {
79+
requestBody: {},
80+
queryParams: {
81+
sess: sessSchema,
82+
ip: sessIPSchema
83+
},
84+
pathParams: { user: userId },
85+
response: { 200: { description: 'Success', model: Joi.object({ success: successRes }) } }
86+
}
87+
},
5688
tools.responseWrapper(async (req, res) => {
5789
res.charSet('utf-8');
5890

59-
const schema = Joi.object().keys({
60-
user: Joi.string().hex().lowercase().length(24).required(),
61-
sess: sessSchema,
62-
ip: sessIPSchema
91+
const { pathParams, requestBody, queryParams } = req.route.spec.validationObjs;
92+
93+
const schema = Joi.object({
94+
...pathParams,
95+
...requestBody,
96+
...queryParams
6397
});
6498

6599
const result = schema.validate(req.params, {

lib/api/2fa/totp.js

+118-29
Original file line numberDiff line numberDiff line change
@@ -5,20 +5,48 @@ const ObjectId = require('mongodb').ObjectId;
55
const tools = require('../../tools');
66
const roles = require('../../roles');
77
const { sessSchema, sessIPSchema } = require('../../schemas');
8+
const { userId } = require('../../schemas/request/general-schemas');
9+
const { successRes } = require('../../schemas/response/general-schemas');
810

911
module.exports = (db, server, userHandler) => {
1012
// Create TOTP seed and request a QR code
1113

1214
server.post(
13-
'/users/:user/2fa/totp/setup',
15+
{
16+
path: '/users/:user/2fa/totp/setup',
17+
tags: ['TwoFactorAuth'],
18+
summary: 'Generate TOTP seed',
19+
description: 'This method generates TOTP seed and QR code for 2FA. User needs to verify the seed value using 2fa/totp/enable endpoint',
20+
validationObjs: {
21+
requestBody: {
22+
label: Joi.string().empty('').trim().max(255).description('Label text for QR code (defaults to username)'),
23+
issuer: Joi.string().trim().max(255).required().description('Description text for QR code (defaults to "WildDuck")'),
24+
sess: sessSchema,
25+
ip: sessIPSchema
26+
},
27+
queryParams: {},
28+
pathParams: { user: userId },
29+
response: {
30+
200: {
31+
description: 'Success',
32+
model: Joi.object({
33+
success: successRes,
34+
seed: Joi.string().required().description('Generated TOTP seed value'),
35+
qrcode: Joi.string().required().description('Base64 encoded QR code')
36+
})
37+
}
38+
}
39+
}
40+
},
1441
tools.responseWrapper(async (req, res) => {
1542
res.charSet('utf-8');
16-
const schema = Joi.object().keys({
17-
user: Joi.string().hex().lowercase().length(24).required(),
18-
label: Joi.string().empty('').trim().max(255),
19-
issuer: Joi.string().trim().max(255).required(),
20-
sess: sessSchema,
21-
ip: sessIPSchema
43+
44+
const { pathParams, requestBody, queryParams } = req.route.spec.validationObjs;
45+
46+
const schema = Joi.object({
47+
...pathParams,
48+
...requestBody,
49+
...queryParams
2250
});
2351

2452
const result = schema.validate(req.params, {
@@ -54,15 +82,31 @@ module.exports = (db, server, userHandler) => {
5482
);
5583

5684
server.post(
57-
'/users/:user/2fa/totp/enable',
85+
{
86+
path: '/users/:user/2fa/totp/enable',
87+
tags: ['TwoFactorAuth'],
88+
summary: 'Enable TOTP seed',
89+
description: 'This method enables TOTP for a user by verifying the seed value generated from 2fa/totp/setup',
90+
validationObjs: {
91+
requestBody: {
92+
token: Joi.string().length(6).required().description('6-digit number that matches seed value from 2fa/totp/setup'),
93+
sess: sessSchema,
94+
ip: sessIPSchema
95+
},
96+
queryParams: {},
97+
pathParams: { user: userId },
98+
response: { 200: { description: 'Success', model: Joi.object({ success: successRes }) } }
99+
}
100+
},
58101
tools.responseWrapper(async (req, res) => {
59102
res.charSet('utf-8');
60103

61-
const schema = Joi.object().keys({
62-
user: Joi.string().hex().lowercase().length(24).required(),
63-
token: Joi.string().length(6).required(),
64-
sess: sessSchema,
65-
ip: sessIPSchema
104+
const { pathParams, requestBody, queryParams } = req.route.spec.validationObjs;
105+
106+
const schema = Joi.object({
107+
...pathParams,
108+
...requestBody,
109+
...queryParams
66110
});
67111

68112
const result = schema.validate(req.params, {
@@ -113,14 +157,27 @@ module.exports = (db, server, userHandler) => {
113157
);
114158

115159
server.del(
116-
'/users/:user/2fa/totp',
160+
{
161+
path: '/users/:user/2fa/totp',
162+
tags: ['TwoFactorAuth'],
163+
summary: 'Disable TOTP auth',
164+
description: 'This method disables TOTP for a user. Does not affect other 2FA mechanisms a user might have set up',
165+
validationObjs: {
166+
requestBody: {},
167+
queryParams: { sess: sessSchema, ip: sessIPSchema },
168+
pathParams: { user: userId },
169+
response: { 200: { description: 'Success', model: Joi.object({ success: successRes }) } }
170+
}
171+
},
117172
tools.responseWrapper(async (req, res) => {
118173
res.charSet('utf-8');
119174

120-
const schema = Joi.object().keys({
121-
user: Joi.string().hex().lowercase().length(24).required(),
122-
sess: sessSchema,
123-
ip: sessIPSchema
175+
const { pathParams, requestBody, queryParams } = req.route.spec.validationObjs;
176+
177+
const schema = Joi.object({
178+
...pathParams,
179+
...requestBody,
180+
...queryParams
124181
});
125182

126183
const result = schema.validate(req.params, {
@@ -154,15 +211,31 @@ module.exports = (db, server, userHandler) => {
154211
);
155212

156213
server.post(
157-
'/users/:user/2fa/totp/check',
214+
{
215+
path: '/users/:user/2fa/totp/check',
216+
tags: ['TwoFactorAuth'],
217+
summary: 'Validate TOTP Token',
218+
description: 'This method checks if a TOTP token provided by a User is valid for authentication',
219+
validationObjs: {
220+
requestBody: {
221+
token: Joi.string().length(6).required().description('6-digit number'),
222+
sess: sessSchema,
223+
ip: sessIPSchema
224+
},
225+
queryParams: {},
226+
pathParams: { user: userId },
227+
response: { 200: { description: 'Success', model: Joi.object({ success: successRes }) } }
228+
}
229+
},
158230
tools.responseWrapper(async (req, res) => {
159231
res.charSet('utf-8');
160232

161-
const schema = Joi.object().keys({
162-
user: Joi.string().hex().lowercase().length(24).required(),
163-
token: Joi.string().length(6).required(),
164-
sess: sessSchema,
165-
ip: sessIPSchema
233+
const { pathParams, requestBody, queryParams } = req.route.spec.validationObjs;
234+
235+
const schema = Joi.object({
236+
...pathParams,
237+
...requestBody,
238+
...queryParams
166239
});
167240

168241
const result = schema.validate(req.params, {
@@ -204,14 +277,30 @@ module.exports = (db, server, userHandler) => {
204277
);
205278

206279
server.del(
207-
'/users/:user/2fa',
280+
{
281+
path: '/users/:user/2fa',
282+
tags: ['TwoFactorAuth'],
283+
summary: 'Disable 2FA',
284+
description: 'This method disables all 2FA mechanisms a user might have set up',
285+
validationObjs: {
286+
requestBody: {},
287+
queryParams: {
288+
sess: sessSchema,
289+
ip: sessIPSchema
290+
},
291+
pathParams: { user: userId },
292+
response: { 200: { description: 'Success', model: Joi.object({ success: successRes }) } }
293+
}
294+
},
208295
tools.responseWrapper(async (req, res) => {
209296
res.charSet('utf-8');
210297

211-
const schema = Joi.object().keys({
212-
user: Joi.string().hex().lowercase().length(24).required(),
213-
sess: sessSchema,
214-
ip: sessIPSchema
298+
const { pathParams, requestBody, queryParams } = req.route.spec.validationObjs;
299+
300+
const schema = Joi.object({
301+
...pathParams,
302+
...requestBody,
303+
...queryParams
215304
});
216305

217306
const result = schema.validate(req.params, {

0 commit comments

Comments
 (0)