Dashboard API explorer

/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)
    })
  })
})