mirror of
https://github.com/NginxProxyManager/nginx-proxy-manager.git
synced 2025-10-05 12:20:10 +00:00
Add possibility to remove mfa
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
const authModel = require('../models/auth');
|
||||
const error = require('../lib/error');
|
||||
const error = require('../lib/error');
|
||||
const speakeasy = require('speakeasy');
|
||||
|
||||
module.exports = {
|
||||
@@ -13,10 +13,10 @@ module.exports = {
|
||||
throw new error.AuthError('MFA is not enabled for this user.');
|
||||
}
|
||||
const verified = speakeasy.totp.verify({
|
||||
secret: auth.mfa_secret,
|
||||
secret: auth.mfa_secret,
|
||||
encoding: 'base32',
|
||||
token: token,
|
||||
window: 2
|
||||
token: token,
|
||||
window: 2
|
||||
});
|
||||
if (!verified) {
|
||||
throw new error.AuthError('Invalid MFA token.');
|
||||
@@ -58,10 +58,10 @@ module.exports = {
|
||||
throw new error.AuthError('MFA is not set up for this user.');
|
||||
}
|
||||
const verified = speakeasy.totp.verify({
|
||||
secret: auth.mfa_secret,
|
||||
secret: auth.mfa_secret,
|
||||
encoding: 'base32',
|
||||
token: token,
|
||||
window: 2
|
||||
token: token,
|
||||
window: 2
|
||||
});
|
||||
if (!verified) {
|
||||
throw new error.AuthError('Invalid MFA token.');
|
||||
@@ -73,4 +73,25 @@ module.exports = {
|
||||
.then(() => true);
|
||||
});
|
||||
},
|
||||
disableMfaForUser: (data, userId) => {
|
||||
return authModel
|
||||
.query()
|
||||
.where('user_id', userId)
|
||||
.first()
|
||||
.then((auth) => {
|
||||
if (!auth) {
|
||||
throw new error.AuthError('User not found.');
|
||||
}
|
||||
return auth.verifyPassword(data.secret)
|
||||
.then((valid) => {
|
||||
if (!valid) {
|
||||
throw new error.AuthError('Invalid password.');
|
||||
}
|
||||
return authModel
|
||||
.query()
|
||||
.where('user_id', userId)
|
||||
.update({ mfa_enabled: false, mfa_secret: null });
|
||||
});
|
||||
});
|
||||
},
|
||||
};
|
||||
|
@@ -1,37 +1,18 @@
|
||||
const express = require('express');
|
||||
const jwtdecode = require('../lib/express/jwt-decode');
|
||||
const apiValidator = require('../lib/validator/api');
|
||||
const internalToken = require('../internal/token');
|
||||
const schema = require('../schema');
|
||||
const internalMfa = require('../internal/mfa');
|
||||
const qrcode = require('qrcode');
|
||||
const speakeasy = require('speakeasy');
|
||||
const userModel = require('../models/user');
|
||||
const express = require('express');
|
||||
const jwtdecode = require('../lib/express/jwt-decode');
|
||||
const apiValidator = require('../lib/validator/api');
|
||||
const schema = require('../schema');
|
||||
const internalMfa = require('../internal/mfa');
|
||||
const qrcode = require('qrcode');
|
||||
const speakeasy = require('speakeasy');
|
||||
const userModel = require('../models/user');
|
||||
|
||||
let router = express.Router({
|
||||
caseSensitive: true,
|
||||
strict: true,
|
||||
mergeParams: true
|
||||
strict: true,
|
||||
mergeParams: true
|
||||
});
|
||||
|
||||
router
|
||||
.route('/')
|
||||
.options((_, res) => {
|
||||
res.sendStatus(204);
|
||||
})
|
||||
|
||||
.get(async (req, res, next) => {
|
||||
internalToken.getFreshToken(res.locals.access, {
|
||||
expiry: (typeof req.query.expiry !== 'undefined' ? req.query.expiry : null),
|
||||
scope: (typeof req.query.scope !== 'undefined' ? req.query.scope : null)
|
||||
})
|
||||
.then((data) => {
|
||||
res.status(200)
|
||||
.send(data);
|
||||
})
|
||||
.catch(next);
|
||||
});
|
||||
|
||||
router
|
||||
.route('/create')
|
||||
.post(jwtdecode(), (req, res, next) => {
|
||||
@@ -54,7 +35,7 @@ router
|
||||
.then(({ secret, user }) => {
|
||||
const otpAuthUrl = speakeasy.otpauthURL({
|
||||
secret: secret.ascii,
|
||||
label: user.email,
|
||||
label: user.email,
|
||||
issuer: 'Nginx Proxy Manager'
|
||||
});
|
||||
qrcode.toDataURL(otpAuthUrl, (err, dataUrl) => {
|
||||
@@ -71,12 +52,13 @@ router
|
||||
router
|
||||
.route('/enable')
|
||||
.post(jwtdecode(), (req, res, next) => {
|
||||
apiValidator(schema.getValidationSchema('/mfa', 'post'), req.body).then((params) => {
|
||||
apiValidator(schema.getValidationSchema('/mfa/enable', 'post'), req.body).then((params) => {
|
||||
internalMfa.enableMfaForUser(res.locals.access.token.getUserId(), params.token)
|
||||
.then(() => res.status(200).send({ success: true }))
|
||||
.catch(next);
|
||||
}
|
||||
);});
|
||||
).catch(next);
|
||||
});
|
||||
|
||||
router
|
||||
.route('/check')
|
||||
@@ -86,4 +68,14 @@ router
|
||||
.catch(next);
|
||||
});
|
||||
|
||||
router
|
||||
.route('/delete')
|
||||
.delete(jwtdecode(), (req, res, next) => {
|
||||
apiValidator(schema.getValidationSchema('/mfa/delete', 'delete'), req.body).then((params) => {
|
||||
internalMfa.disableMfaForUser(params, res.locals.access.token.getUserId())
|
||||
.then(() => res.status(200).send({ success: true }))
|
||||
.catch(next);
|
||||
}).catch(next);
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
|
44
backend/schema/paths/mfa/delete/delete.json
Normal file
44
backend/schema/paths/mfa/delete/delete.json
Normal file
@@ -0,0 +1,44 @@
|
||||
{
|
||||
"operationId": "disableMfa",
|
||||
"summary": "Disable multi-factor authentication for a user",
|
||||
"tags": [
|
||||
"MFA"
|
||||
],
|
||||
"requestBody": {
|
||||
"description": "Payload to disable MFA",
|
||||
"required": true,
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"secret": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"secret"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "MFA disabled successfully",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"success": {
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,14 +1,15 @@
|
||||
{
|
||||
"operationId": "enableMfa",
|
||||
"summary": "Enable multi-factor authentication for a user",
|
||||
"tags": ["MFA"],
|
||||
"tags": [
|
||||
"MFA"
|
||||
],
|
||||
"requestBody": {
|
||||
"description": "MFA Token Payload",
|
||||
"required": true,
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"token": {
|
||||
@@ -16,7 +17,9 @@
|
||||
"minLength": 1
|
||||
}
|
||||
},
|
||||
"required": ["token"]
|
||||
"required": [
|
||||
"token"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -38,4 +41,4 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -15,9 +15,14 @@
|
||||
"$ref": "./paths/get.json"
|
||||
}
|
||||
},
|
||||
"/mfa": {
|
||||
"/mfa/enable": {
|
||||
"post": {
|
||||
"$ref": "./paths/mfa/post.json"
|
||||
"$ref": "./paths/mfa/enable/post.json"
|
||||
}
|
||||
},
|
||||
"/mfa/delete": {
|
||||
"delete": {
|
||||
"$ref": "./paths/mfa/delete/delete.json"
|
||||
}
|
||||
},
|
||||
"/audit-log": {
|
||||
|
Reference in New Issue
Block a user