'use strict'; exports = module.exports = { clients: { get, list, add, update, del }, 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 add(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.clients.add(clientId, data)); if (error) return next(BoxError.toHttpError(error)); data.id = clientId; next(new HttpSuccess(201, data)); } async function get(req, res, next) { assert.strictEqual(typeof req.params.clientId, 'string'); const [error, client] = await safe(oidc.clients.get(req.params.clientId)); if (error) return next(BoxError.toHttpError(error)); if (!client) return next(new HttpError(404, 'OpenID connect client not found')); if (client.appId) return next(new HttpError(422, 'OpenID connect client from an internal app')); next(new HttpSuccess(200, client)); } async function update(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 [error, client] = await safe(oidc.clients.get(req.params.clientId)); if (error) return next(BoxError.toHttpError(error)); if (!client) return next(new HttpError(404, 'OpenID connect client not found')); if (client.appId) return next(new HttpError(422, 'OpenID connect client from an internal app')); 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.clients.update(req.params.clientId, data)); if (updateError) return next(BoxError.toHttpError(updateError)); next(new HttpSuccess(201, {})); } async function list(req, res, next) { const [error, result] = await safe(oidc.clients.list()); if (error) return next(BoxError.toHttpError(error)); next(new HttpSuccess(200, { clients: result.filter(client => !client.appId) })); } async function del(req, res, next) { assert.strictEqual(typeof req.params.clientId, 'string'); const [error, client] = await safe(oidc.clients.get(req.params.clientId)); if (error) return next(BoxError.toHttpError(error)); if (!client) return next(new HttpError(404, 'OpenID connect client not found')); if (client.appId) return next(new HttpError(422, 'OpenID connect client from an internal app')); const [delError] = await safe(oidc.clients.del(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)); }