You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
CoreID/app/controllers/api/v1/Password.controller.js

118 lines
3.6 KiB

const { Controller } = require('libflitter')
const zxcvbn = require('zxcvbn')
class PasswordController extends Controller {
static get services() {
return [...super.services, 'auth', 'jobs', 'models']
}
async get_resets(req, res, next) {
return res.api(req.user.password_resets.map(x => {
return {
reset_on: x.reset_on,
reason: x.reason,
}
}))
}
async get_app_passwords(req, res, next) {
return res.api(req.user.app_passwords.map(x => {
return {
created: x.created,
expires: x.expires,
active: x.active,
name: x.name ?? '(unnamed)',
uuid: x.uuid,
}
}))
}
async create_app_password(req, res, next) {
if ( !req.body.name )
return res.status(400)
.message('Missing required field: name')
.api()
const { password, record } = await req.user.app_password(req.body.name)
await req.user.save()
return res.api({
password,
name: req.body.name,
uuid: record.uuid,
})
}
async delete_app_password(req, res, next) {
if ( !req.params.uuid )
return res.status(400)
.message('Missing required parameter: uuid')
.api()
const match = req.user.app_passwords.filter(x => x.uuid === req.params.uuid)[0]
if ( !match )
return res.status(400)
.message('App password not found with that UUID.')
.api()
req.user.app_passwords = req.user.app_passwords.filter(x => x.uuid !== req.params.uuid)
await req.user.save()
return res.api()
}
async reset_password(req, res, next) {
if ( !req.body.password )
return res.status(400)
.message('Missing required field: password')
.api()
// Verify password complexity
const min_score = 3
const result = zxcvbn(req.body.password)
if ( result.score < min_score )
return res.status(400)
.message(`Password does not meet the minimum complexity score of ${min_score}.`)
.api()
// Make sure it's not a re-do
for ( const old_pw of req.user.password_resets ) {
if ( await old_pw.check(req.body.password) ) {
return res.status(400)
.message(`This password is a duplicate of one of your previous passwords.`)
.api()
}
}
// Create the password reset
const reset = await req.user.reset_password(req.body.password)
await req.user.save()
if ( req.trap.has_trap() && req.trap.get_trap() === 'password_reset' ) await req.trap.end()
// invalidate existing tokens and other logins
const flitter = await this.auth.get_provider('flitter')
await flitter.logout(req)
await req.user.kickout()
req.trust.unassume()
return res.api()
}
async request_reset(req, res, next) {
if ( !req.body.email )
return res.status(400)
.message('Missing required field: email')
.api()
const User = this.models.get('auth:User')
const user = await User.findOne({ email: req.body.email })
if ( user ) {
const reset_queue = this.jobs.queue('password_resets')
await reset_queue.add('PasswordReset', { user_id: user.id })
}
return res.api({ success: true })
}
}
module.exports = exports = PasswordController