/api/user/create-session (POST)
await global.api.user.CreateSession.post(req) Located in Dashboard API
Returns object
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-username | missing posted username |
invalid-password | missing posted password |
Receives
API routes may receive parameters from the URL and POST supporting simple and multipart:
Field | Value | Required | Type |
---|---|---|---|
remember | hours, days | optional | POST |
NodeJS source (edit on github)
If you see a problem with the source submit a pull request on Github.
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 accountid = await dashboard.Storage.read(`${req.appid}/map/usernames/${usernameHash}`)
if (!accountid) {
if (global.minimumUsernameLength > req.body.username.length ||
global.maximumUsernameLength < req.body.username.length) {
throw new Error('invalid-username-length')
}
if (global.minimumPasswordLength > req.body.password.length ||
global.maximumUsernameLength < req.body.password.length) {
throw new Error('invalid-password-length')
}
throw new Error('invalid-username')
}
const passwordHash = await dashboard.StorageObject.getProperty(`${req.appid}/account/${accountid}`, 'passwordHash')
const validPassword = await dashboard.Hash.bcryptHashCompare(req.body.password, passwordHash, dashboardEncryptionKey)
if (!validPassword) {
throw new Error('invalid-password')
}
const query = req.query
req.query = { accountid }
const account = await global.api.administrator.Account.get(req)
req.query = query
let expireSeconds
switch (req.body.remember) {
case 'hours':
expireSeconds = 8 * 60 * 60
break
case 'days':
expireSeconds = 30 * 24 * 60 * 60
break
default:
expireSeconds = 20 * 60
break
}
const sessionid = `session_${await dashboard.UUID.generateID()}`
const sessionToken = dashboard.UUID.random(64)
const sessionKey = await dashboard.StorageObject.getProperty(`${req.appid}/account/${account.accountid}`, 'sessionKey')
const tokenHash = await dashboard.Hash.sha512Hash(`${accountid}/${sessionToken}/${sessionKey}/${dashboardSessionKey}`, dashboardEncryptionKey)
const sessionInfo = {
object: 'session',
sessionid: sessionid,
accountid: accountid,
tokenHash: tokenHash,
created: dashboard.Timestamp.now,
expires: dashboard.Timestamp.now + expireSeconds,
sessionKeyNumber: account.sessionKeyNumber
}
await dashboard.StorageObject.setProperty(`${req.appid}/account/${account.accountid}`, 'lastSignedIn', dashboard.Timestamp.now)
await dashboard.Storage.write(`${req.appid}/session/${sessionid}`, sessionInfo)
await dashboard.Storage.write(`${req.appid}/map/sessionids/${sessionid}`, accountid)
await dashboard.StorageList.addMany({
[`${req.appid}/sessions`]: sessionid,
[`${req.appid}/account/sessions/${accountid}`]: sessionid
})
req.session = sessionInfo
req.session.token = sessionToken
return req.session
}
}
Test source (edit on github)
Tests perform real HTTP requests against a running Dashboard server.
/* eslint-env mocha */
const TestHelper = require('../../../../test-helper.js')
const assert = require('assert')
const dashboard = require('../../../../index.js')
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((session.expires - dashboard.Timestamp.now) / 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((session2.expires - dashboard.Timestamp.now) / 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((session.expires - dashboard.Timestamp.now) / 60)
assert.strictEqual(minutes, 20)
})
})
})