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

120 lines
3.8 KiB

const { Controller } = require('libflitter')
const zxcvbn = require('zxcvbn')
class PasswordController extends Controller {
static get services() {
return [...super.services, 'auth', 'jobs', 'models', 'activity']
}
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 ?? req.T('common.unnamed'),
uuid: x.uuid,
}
}))
}
async create_app_password(req, res, next) {
if ( !req.body.name )
return res.status(400)
.message(`${req.T('api.missing_field')} name`)
.api()
const { password, record } = await req.user.app_password(req.body.name)
await req.user.save()
await this.activity.app_password_created({ req, name: req.body.name })
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(`${req.T('api.missing_field')} uuid`)
.api()
const match = req.user.app_passwords.filter(x => x.uuid === req.params.uuid)[0]
if ( !match )
return res.status(400)
.message(req.T('api.app_pw_not_found'))
.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(`${req.T('api.missing_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(req.T('auth.password_complexity_fail').replace('MIN_SCORE', 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(req.T('auth.duplicate_pw'))
.api()
}
}
// Create the password reset
const reset = await req.user.reset_password(req.body.password)
await req.user.save()
await this.activity.password_reset({ req, ip: req.ip })
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(`${req.T('api.missing_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