1
0
Fork 0

wip(backend): moved more logic to user model

This commit is contained in:
joostdecock 2022-11-07 20:42:07 +01:00
parent 487095eecb
commit 819656815c
4 changed files with 136 additions and 75 deletions

View file

@ -21,13 +21,44 @@ export function UserModel(tools) {
* Stores result in this.record
*/
UserModel.prototype.read = async function (where) {
this.record = await this.prisma.user.findUnique({ where })
try {
this.record = await this.prisma.user.findUnique({ where })
} catch (err) {
log.warn({ err, where }, 'Could not read user')
}
if (this.record?.email) this.email = this.decrypt(this.record.email)
if (this.record?.initial) this.initial = this.decrypt(this.record.initial)
return this.setExists()
}
/*
* Finds a user based on one of the accepted unique fields which are:
* - lusername (lowercase username)
* - ehash
* - id
*
* Stores result in this.record
*/
UserModel.prototype.find = async function (body) {
try {
this.record = await this.prisma.user.findFirst({
where: {
OR: [
{ lusername: { equals: clean(body.username) } },
{ ehash: { equals: hash(clean(body.username)) } },
{ id: { equals: parseInt(body.username) || -1 } },
],
},
})
} catch (err) {
log.warn({ err, body }, `Error while trying to find user: ${body.username}`)
}
return this.setExists()
}
/*
* Loads the user that is making the API request
*
@ -84,7 +115,7 @@ UserModel.prototype.create = async function ({ body }) {
initial: email,
username,
lusername: username,
data: asJson({ settings: { language: this.language } }),
data: this.encrypt(asJson({ settings: { language: this.language } })),
password: asJson(hashPassword(body.password)),
},
})
@ -134,6 +165,38 @@ UserModel.prototype.create = async function ({ body }) {
: this.setResponse(201, false, { email: this.email })
}
/*
* Login based on username + password
*/
UserModel.prototype.passwordLogin = async function (req) {
if (Object.keys(req.body) < 1) return this.setReponse(400, 'postBodyMissing')
if (!req.body.username) return this.setReponse(400, 'usernameMissing')
if (!req.body.password) return this.setReponse(400, 'passwordMissing')
await this.find(req.body)
if (!this.exists) {
log.warn(`Login attempt for non-existing user: ${req.body.username} from ${req.ip}`)
return this.setResponse(401, 'loginFailed')
}
// Account found, check password
const [valid, updatedPasswordField] = verifyPassword(req.body.password, this.record.password)
if (!valid) {
log.warn(`Wrong password for existing user: ${req.body.username} from ${req.ip}`)
return this.setResponse(401, 'loginFailed')
}
log.info(`Login by user ${this.record.id} (${this.record.username})`)
// Login success
if (updatedPasswordField) {
// Update the password field with a v3 hash
await this.update({ password: updatedPasswordField })
}
return this.isOk() ? this.loginOk() : this.setResponse(401, 'loginFailed')
}
/*
* Confirms a user account
*/
@ -169,18 +232,14 @@ UserModel.prototype.confirm = async function ({ body, params }) {
// Update user status, consent, and last login
await this.update({
//data: this.encrypt({...this.decrypt(this.record.data), status: 1}),
status: 1,
consent: body.consent,
lastLogin: new Date(),
})
if (this.error) return this
// Account is now active, let's return a passwordless login
return this.setResponse(200, false, {
result: 'success',
token: this.getToken(),
account: this.asAccount(),
})
return this.loginOk()
}
/*
@ -209,9 +268,9 @@ UserModel.prototype.asAccount = function () {
id: this.record.id,
consent: this.record.consent,
createdAt: this.record.createdAt,
data: this.record.data,
email: this.email,
initial: this.initial,
data: JSON.parse(this.decrypt(this.record.data)),
email: this.decrypt(this.record.email),
initial: this.decrypt(this.record.initial),
lastLogin: this.record.lastLogin,
newsletter: this.record.newsletter,
patron: this.record.patron,
@ -277,3 +336,31 @@ UserModel.prototype.sendResponse = async function (res) {
UserModel.prototype.isUnitTest = function (body) {
return body.unittest && this.email.split('@').pop() === this.config.tests.domain
}
/*
* Helper method to check an account is ok
*/
UserModel.prototype.isOk = function () {
if (
this.exists &&
this.record &&
this.record.status > 0 &&
this.record.consent > 0 &&
this.record.role &&
this.record.role !== 'blocked'
)
return true
return false
}
/*
* Helper method to return from successful login
*/
UserModel.prototype.loginOk = function () {
return this.setResponse(200, false, {
result: 'success',
token: this.getToken(),
account: this.asAccount(),
})
}