Support MFA recovery tokens

This commit is contained in:
garrettmills
2020-05-30 17:21:47 -05:00
parent a1a70e0548
commit 8680242349
25 changed files with 393 additions and 10 deletions

View File

@@ -84,6 +84,41 @@ class AuthController extends Controller {
return res.api(await user.to_api())
}
async attempt_mfa_recovery(req, res, next) {
if (
!req.user.mfa_enabled
|| !Array.isArray(req.user.mfa_token.recovery_codes)
|| req.user.mfa_token.recovery_codes.length < 1
)
return res.status(400)
.message('Your user is not configured to use MFA, or has no recovery codes.')
.api()
if ( !req.body.code )
return res.status(400)
.message('Missing required field: code')
.api()
const success = await req.user.mfa_token.attempt_recovery(req.body.code)
if ( !success )
return res.api({ success })
if ( req.trap.has_trap('mfa_challenge') )
await req.trap.end()
let next_destination = req.session.auth.flow || this.configs.get('auth.default_login_route')
delete req.session.auth.flow
req.session.mfa_remember = true
return res.api({
success: true,
next_destination,
remaining_codes: req.user.mfa_token.recovery_codes.filter(x => !x.used).length,
})
}
async validate_email(req, res, next) {
let is_valid = !!req.body.email
@@ -562,6 +597,37 @@ class AuthController extends Controller {
})
}
async get_mfa_recovery(req, res, next) {
if ( !req.user.mfa_enabled )
return res.status(400)
.message('Your user does not have MFA enabled.')
.api()
const token = req.user.mfa_token
if ( !Array.isArray(token.recovery_codes) || token.recovery_codes.length < 1 )
return res.api({ has_recovery: false })
return res.api({
has_recovery: true,
generated: token.recovery_codes[0].generated,
remaining_codes: token.recovery_codes.filter(x => !x.used).length,
})
}
async generate_mfa_recovery(req, res, next) {
if ( !req.user.mfa_enabled )
return res.status(400)
.message('Your user does not have MFA enabled.')
.api()
const token = req.user.mfa_token
const codes = await token.generate_recovery()
await req.user.save()
return res.api({
codes,
})
}
async generate_mfa_key(req, res, next) {
if ( req.user.mfa_enabled )
return res.status(400)

View File

@@ -54,6 +54,23 @@ class MFAController extends Controller {
...this.Vue.session(req),
})
}
async get_recovery(req, res, next) {
if (
!req.user.mfa_enabled
|| !Array.isArray(req.user.mfa_token.recovery_codes)
|| req.user.mfa_token.recovery_codes.length < 1
) return this.Vue.auth_message(res, {
message: 'Unfortunately, it looks like your account does not have any MFA recovery codes generated.',
next_destination: '/auth/mfa/challenge',
button_text: 'Go Back',
})
return res.page('auth:mfa:recovery', {
...this.Vue.data(),
...this.Vue.session(req),
})
}
}
module.exports = exports = MFAController