'use strict'; exports = module.exports = { loadClient, addClient, listClients, getClient, updateClient, delClient, destroyUserSession }; const assert = require('assert'), BoxError = require('../boxerror.js'), hat = require('../hat.js'), oidc = require('../oidc.js'), HttpError = require('connect-lastmile').HttpError, HttpSuccess = require('connect-lastmile').HttpSuccess, safe = require('safetydance'), tokens = require('../tokens.js'); async function addClient(req, res, next) { assert.strictEqual(typeof req.body, 'object'); if (typeof req.body.name !== 'string' || !req.body.name) return next(new HttpError(400, 'name must be non-empty string')); if (typeof req.body.loginRedirectUri !== 'string') return next(new HttpError(400, 'loginRedirectUri must be non-empty string')); if (req.body.tokenSignatureAlgorithm !== 'EdDSA' && req.body.tokenSignatureAlgorithm !== 'RS256') return next(new HttpError(400, 'tokenSignatureAlgorithm must be either EdDSA or RS256')); // clients with appId are internal only if (req.body.appId) return next(new HttpError(400, 'appId cannot be specified')); const clientId = 'cid-' + hat(128); const data = { secret: hat(256), name: req.body.name, appId: '', // always empty for custom clients tokenSignatureAlgorithm: req.body.tokenSignatureAlgorithm, loginRedirectUri: req.body.loginRedirectUri }; const [error] = await safe(oidc.addClient(clientId, data)); if (error) return next(BoxError.toHttpError(error)); data.id = clientId; next(new HttpSuccess(201, data)); } async function loadClient(req, res, next) { assert.strictEqual(typeof req.params.clientId, 'string'); const [error, client] = await safe(oidc.getClient(req.params.clientId)); if (error) return next(BoxError.toHttpError(error)); if (!client) return next(new HttpError(404, 'OIDC client not found')); if (client.appId) return next(new HttpError(422, 'OIDC client of an internal app')); req.oidcClient = client; next(); } async function getClient(req, res, next) { assert.strictEqual(typeof req.params.clientId, 'string'); next(new HttpSuccess(200, req.oidcClient)); } async function updateClient(req, res, next) { assert.strictEqual(typeof req.params.clientId, 'string'); assert.strictEqual(typeof req.body, 'object'); if (typeof req.body.name !== 'string' || !req.body.name) return next(new HttpError(400, 'name must be non-empty string')); if (typeof req.body.loginRedirectUri !== 'string' || !req.body.loginRedirectUri) return next(new HttpError(400, 'loginRedirectUri must be non-empty string')); if (req.body.tokenSignatureAlgorithm !== 'EdDSA' && req.body.tokenSignatureAlgorithm !== 'RS256') return next(new HttpError(400, 'tokenSignatureAlgorithm must be either EdDSA or RS256')); const data = { name: req.body.name, appId: '', // always empty for custom clients tokenSignatureAlgorithm: req.body.tokenSignatureAlgorithm, loginRedirectUri: req.body.loginRedirectUri }; const [updateError] = await safe(oidc.updateClient(req.params.clientId, data)); if (updateError) return next(BoxError.toHttpError(updateError)); next(new HttpSuccess(201, {})); } async function listClients(req, res, next) { const [error, result] = await safe(oidc.listClients()); if (error) return next(BoxError.toHttpError(error)); next(new HttpSuccess(200, { clients: result.filter(client => !client.appId) })); } async function delClient(req, res, next) { assert.strictEqual(typeof req.params.clientId, 'string'); const [delError] = await safe(oidc.delClient(req.params.clientId)); if (delError) return next(BoxError.toHttpError(delError)); next(new HttpSuccess(204)); } async function destroyUserSession(req, res, next) { assert.strictEqual(typeof req.user, 'object'); const [error] = await safe(oidc.revokeByUserId(req.user.id)); if (error) return next(BoxError.toHttpError(error)); await safe(tokens.del(req.token.id)); next(new HttpSuccess(204)); }