/api/user/create-session (POST)
Account information like email addresses is generated with faker-js it is not real user information.
await global.api.user.CreateSession.post(req)Returns object
{
"sessionid": "sess_d8bb0af894d459c5",
"object": "session",
"appid": "tests_1656038576",
"accountid": "acct_ffdf6d417d78f305",
"duration": 1200,
"csrfToken": "4c7fe3d593385d346a639e35202f650ec87bd76e4c37ed47049118d4d65b06994af06220d5e28bcc94487a4f4788b6ed4725bc8d45d9ea0cb93c34eb3531cc75",
"expiresAt": "2022-06-24T03:02:56.000Z",
"lastVerifiedAt": "2022-06-24T02:42:56.000Z",
"ended": false,
"createdAt": "2022-06-24T02:42:56.947Z",
"updatedAt": "2022-06-24T02:42:56.947Z",
"token": "bf31d6dba13a3e46c7c7441dc7112ae66bddca4ea57ca05c66392c1cc15c823d"
}
Receives
API routes may receive parameters from the URL and POST supporting simple and multipart:
Field | Value | Required | Type |
---|---|---|---|
remember | hours, days | optional | POST |
Exceptions
These exceptions are thrown (NodeJS) or returned as JSON (HTTP) if you provide incorrect data or do not meet the requirements:
Exception | Circumstances |
---|---|
invalid-password | missing posted password |
invalid-username | missing posted username |
NodeJS source (view on github)
const crypto = require('crypto')
const dashboard = require('../../../../index.js')
module.exports = {
auth: false,
post: async (req) => {
if (!req || !req.body) {
throw new Error('invalid-username')
}
if (!req.body.username || !req.body.username.length) {
throw new Error('invalid-username')
}
if (!req.body.password || !req.body.password.length) {
throw new Error('invalid-password')
}
let dashboardEncryptionKey = global.dashboardEncryptionKey
let dashboardSessionKey = global.dashboardSessionKey
if (req.server) {
dashboardEncryptionKey = req.server.dashboardEncryptionKey || dashboardEncryptionKey
dashboardSessionKey = req.server.dashboardSessionKey || dashboardSessionKey
}
const usernameHash = await dashboard.Hash.sha512Hash(req.body.username, dashboardEncryptionKey)
const accountData = await dashboard.Storage.Account.findOne({
where: {
usernameHash,
appid: req.appid || global.appid
}
})
const account = accountData ? accountData.dataValues : undefined
if (!account) {
throw new Error('invalid-username')
}
const validPassword = await dashboard.Hash.bcryptHashCompare(req.body.password, account.passwordHash, dashboardEncryptionKey)
if (!validPassword) {
throw new Error('invalid-password')
}
let duration
switch (req.body.remember) {
case 'hours':
duration = 8 * 60 * 60
break
case 'days':
duration = 30 * 24 * 60 * 60
break
default:
duration = 20 * 60
break
}
const sessionToken = crypto.randomBytes(32).toString('hex')
const tokenHash = await dashboard.Hash.sha512Hash(`${account.accountid}/${sessionToken}/${account.sessionKey}/${dashboardSessionKey}`, dashboardEncryptionKey)
const sessionInfo = {
accountid: account.accountid,
appid: req.appid || global.appid,
tokenHash,
sessionKeyNumber: account.sessionKeyNumber,
duration
}
const session = await dashboard.Storage.Session.create(sessionInfo)
await dashboard.Storage.Account.update({
lastSignedInAt: session.createdAt
}, {
where: {
accountid: account.accountid,
appid: req.appid || global.appid
}
})
await dashboard.StorageCache.remove(account.accountid)
req.query = req.query || {}
req.query.sessionid = session.dataValues.sessionid
req.account = account
req.session = await global.api.user.Session.get(req)
req.session.token = sessionToken
return req.session
}
}
Test source (view on github)
/* eslint-env mocha */
const TestHelper = require('../../../../test-helper.js')
const assert = require('assert')
describe('/api/user/create-session', () => {
describe('exceptions', () => {
describe('invalid-username', () => {
it('missing posted username', async () => {
const req = TestHelper.createRequest('/api/user/create-session')
req.body = {
username: '',
password: 'password'
}
let errorMessage
try {
await req.post()
} catch (error) {
errorMessage = error.message
}
assert.strictEqual(errorMessage, 'invalid-username')
})
})
describe('invalid-password', () => {
it('missing posted password', async () => {
const req = TestHelper.createRequest('/api/user/create-session')
req.body = {
username: 'username',
password: ''
}
let errorMessage
try {
await req.post()
} catch (error) {
errorMessage = error.message
}
assert.strictEqual(errorMessage, 'invalid-password')
})
})
})
describe('receives', () => {
it('optional posted remember (hours|days)', async () => {
const user = await TestHelper.createUser()
const req = TestHelper.createRequest('/api/user/create-session')
req.body = {
username: user.account.username,
password: user.account.password,
remember: 'hours'
}
const session = await req.post()
const hours = Math.ceil((new Date(session.expiresAt).getTime() - new Date().getTime()) / 1000 / 60 / 60)
assert.strictEqual(hours, 8)
req.body = {
username: user.account.username,
password: user.account.password,
remember: 'days'
}
const session2 = await req.post()
const days = Math.ceil((new Date(session2.expiresAt).getTime() - new Date().getTime()) / 1000 / 60 / 60 / 24)
assert.strictEqual(days, 30)
})
})
describe('returns', () => {
it('object', async () => {
const user = await TestHelper.createUser()
const req = TestHelper.createRequest('/api/user/create-session')
req.body = {
username: user.account.username,
password: user.account.password
}
req.filename = __filename
req.saveResponse = true
const session = await req.post()
const minutes = Math.ceil((new Date(session.expiresAt).getTime() - new Date().getTime()) / 1000 / 60)
assert.strictEqual(minutes, 20)
})
})
})