53 lines
1.2 KiB
JavaScript
53 lines
1.2 KiB
JavaScript
const { Model } = require('flitter-orm')
|
|
const speakeasy = require('speakeasy')
|
|
const MFARecoveryCode = require('./MFARecoveryCode.model')
|
|
const uuid = require('uuid').v4
|
|
|
|
class MFATokenModel extends Model {
|
|
static get services() {
|
|
return [...super.services, 'MFA']
|
|
}
|
|
|
|
static get schema() {
|
|
return {
|
|
secret: String,
|
|
otpauth_url: String,
|
|
recovery_codes: [MFARecoveryCode],
|
|
}
|
|
}
|
|
|
|
async attempt_recovery(code) {
|
|
for ( const token of this.recovery_codes ) {
|
|
if ( await token.verify(code) && !token.used ) {
|
|
token.used = true
|
|
return true
|
|
}
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
async generate_recovery() {
|
|
this.recovery_codes = []
|
|
const values = []
|
|
|
|
for ( let i = 0; i < 4; i++ ) {
|
|
const value = uuid()
|
|
values.push(value)
|
|
this.recovery_codes.push(await MFARecoveryCode.create(value))
|
|
}
|
|
|
|
return values
|
|
}
|
|
|
|
verify(value) {
|
|
return speakeasy.totp.verify({
|
|
secret: this.secret,
|
|
encoding: 'base32',
|
|
token: value,
|
|
})
|
|
}
|
|
}
|
|
|
|
module.exports = exports = MFATokenModel
|