2023-03-21 13:54:40 +01:00
'use strict' ;
exports = module . exports = {
2023-03-24 20:08:17 +01:00
clients : {
get ,
list ,
add ,
update ,
del
} ,
destroyUserSession
2023-03-21 13:54:40 +01:00
} ;
const assert = require ( 'assert' ) ,
BoxError = require ( '../boxerror.js' ) ,
2023-10-06 14:11:54 +02:00
hat = require ( '../hat.js' ) ,
2023-03-21 13:54:40 +01:00
oidc = require ( '../oidc.js' ) ,
HttpError = require ( 'connect-lastmile' ) . HttpError ,
HttpSuccess = require ( 'connect-lastmile' ) . HttpSuccess ,
2023-06-02 20:47:36 +02:00
safe = require ( 'safetydance' ) ,
tokens = require ( '../tokens.js' ) ;
2023-03-21 13:54:40 +01:00
async function add ( req , res , next ) {
assert . strictEqual ( typeof req . body , 'object' ) ;
2023-03-23 09:27:40 +01:00
if ( typeof req . body . name !== 'string' || ! req . body . name ) return next ( new HttpError ( 400 , 'name must be non-empty string' ) ) ;
2023-09-20 14:33:04 +05:30
if ( typeof req . body . loginRedirectUri !== 'string' ) return next ( new HttpError ( 400 , 'loginRedirectUri must be non-empty string' ) ) ;
2023-04-04 15:38:45 +02:00
if ( req . body . tokenSignatureAlgorithm !== 'EdDSA' && req . body . tokenSignatureAlgorithm !== 'RS256' ) return next ( new HttpError ( 400 , 'tokenSignatureAlgorithm must be either EdDSA or RS256' ) ) ;
2023-03-21 13:54:40 +01:00
2023-04-24 17:16:57 +02:00
// clients with appId are internal only
if ( req . body . appId ) return next ( new HttpError ( 400 , 'appId cannot be specified' ) ) ;
2023-10-06 14:11:54 +02:00
const clientId = 'cid-' + hat ( 128 ) ;
2023-03-23 09:27:40 +01:00
const data = {
2023-10-06 14:11:54 +02:00
secret : hat ( 256 ) ,
2023-03-23 09:27:40 +01:00
name : req . body . name ,
appId : '' , // always empty for custom clients
2023-04-04 15:38:45 +02:00
tokenSignatureAlgorithm : req . body . tokenSignatureAlgorithm ,
2023-07-20 13:26:07 +02:00
loginRedirectUri : req . body . loginRedirectUri
2023-03-23 09:27:40 +01:00
} ;
2023-10-06 14:11:54 +02:00
const [ error ] = await safe ( oidc . clients . add ( clientId , data ) ) ;
2023-03-21 13:54:40 +01:00
if ( error ) return next ( BoxError . toHttpError ( error ) ) ;
2023-10-06 14:11:54 +02:00
data . id = clientId ;
next ( new HttpSuccess ( 201 , data ) ) ;
2023-03-21 13:54:40 +01:00
}
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 ) ) ;
2023-03-21 14:46:09 +01:00
if ( ! client ) return next ( new HttpError ( 404 , 'OpenID connect client not found' ) ) ;
2023-04-24 17:16:57 +02:00
if ( client . appId ) return next ( new HttpError ( 422 , 'OpenID connect client from an internal app' ) ) ;
2023-03-21 13:54:40 +01:00
next ( new HttpSuccess ( 200 , client ) ) ;
}
async function update ( req , res , next ) {
assert . strictEqual ( typeof req . params . clientId , 'string' ) ;
assert . strictEqual ( typeof req . body , 'object' ) ;
2023-03-23 09:27:40 +01:00
if ( typeof req . body . name !== 'string' || ! req . body . name ) return next ( new HttpError ( 400 , 'name must be non-empty string' ) ) ;
2023-03-21 13:54:40 +01:00
if ( typeof req . body . loginRedirectUri !== 'string' || ! req . body . loginRedirectUri ) return next ( new HttpError ( 400 , 'loginRedirectUri must be non-empty string' ) ) ;
2023-04-04 15:38:45 +02:00
if ( req . body . tokenSignatureAlgorithm !== 'EdDSA' && req . body . tokenSignatureAlgorithm !== 'RS256' ) return next ( new HttpError ( 400 , 'tokenSignatureAlgorithm must be either EdDSA or RS256' ) ) ;
2023-03-21 13:54:40 +01:00
2023-04-24 17:16:57 +02:00
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' ) ) ;
2023-03-23 09:27:40 +01:00
const data = {
name : req . body . name ,
appId : '' , // always empty for custom clients
2023-04-04 15:38:45 +02:00
tokenSignatureAlgorithm : req . body . tokenSignatureAlgorithm ,
2023-07-20 13:26:07 +02:00
loginRedirectUri : req . body . loginRedirectUri
2023-03-23 09:27:40 +01:00
} ;
2023-04-24 17:16:57 +02:00
const [ updateError ] = await safe ( oidc . clients . update ( req . params . clientId , data ) ) ;
if ( updateError ) return next ( BoxError . toHttpError ( updateError ) ) ;
2023-03-21 13:54:40 +01:00
2023-03-21 19:09:44 +01:00
next ( new HttpSuccess ( 201 , { } ) ) ;
2023-03-21 13:54:40 +01:00
}
async function list ( req , res , next ) {
const [ error , result ] = await safe ( oidc . clients . list ( ) ) ;
if ( error ) return next ( BoxError . toHttpError ( error ) ) ;
2023-04-24 17:16:57 +02:00
next ( new HttpSuccess ( 200 , { clients : result . filter ( client => ! client . appId ) } ) ) ;
2023-03-21 13:54:40 +01:00
}
2023-03-24 20:08:17 +01:00
async function del ( req , res , next ) {
2023-03-21 13:54:40 +01:00
assert . strictEqual ( typeof req . params . clientId , 'string' ) ;
2023-04-24 17:16:57 +02:00
const [ error , client ] = await safe ( oidc . clients . get ( req . params . clientId ) ) ;
2023-03-21 13:54:40 +01:00
if ( error ) return next ( BoxError . toHttpError ( error ) ) ;
2023-04-24 17:16:57 +02:00
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 ) ) ;
2023-03-21 13:54:40 +01:00
next ( new HttpSuccess ( 204 ) ) ;
}
2023-03-24 20:08:17 +01:00
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 ) ) ;
2023-08-07 16:53:00 +02:00
await safe ( tokens . del ( req . token . id ) ) ;
2023-06-02 20:47:36 +02:00
2023-03-24 20:08:17 +01:00
next ( new HttpSuccess ( 204 ) ) ;
}