@authup/core
Version:
Package containing global constants, types & interfaces.
1,504 lines (1,443 loc) • 64.6 kB
JavaScript
'use strict';
var mongo2js = require('@ucast/mongo2js');
var http = require('@ebec/http');
var nanoid = require('nanoid');
var destr = require('destr');
var hapic = require('hapic');
var oauth2 = require('@hapic/oauth2');
var rapiq = require('rapiq');
var vault = require('@hapic/vault');
/*
* Copyright (c) 2024.
* Author Peter Placzek (tada5hi)
* For the full copyright and license information,
* view the LICENSE file that was distributed with this source code.
*/ function isStringArray(input) {
if (!Array.isArray(input)) {
return false;
}
const items = input.map((item)=>typeof item === 'string');
return items.length === input.length;
}
function buildAbilityFields(input) {
if (!input) {
return undefined;
}
const data = JSON.parse(input);
if (!isStringArray(data) || data.length === 0) {
return undefined;
}
return data;
}
// todo: replace CURRENT_DATE with evaluation of Date.now()
function buildAbility(entity) {
if (typeof entity.permission === 'undefined') {
throw new SyntaxError('The permission relation attribute is mandatory.');
}
return {
name: entity.permission.name,
condition: entity.condition,
power: entity.power,
fields: buildAbilityFields(entity.fields),
inverse: entity.negation,
target: entity.target
};
}
class AbilityManager {
satisfy(name, options = {}) {
let items;
if (typeof name === 'string') {
options.name = name;
items = this.find(options);
} else {
items = this.find({
...name,
...options
});
}
return items.length > 0;
}
/**
* Check if permission is assigned without any restrictions.
*
* @param name
*/ has(name) {
if (Array.isArray(name)) {
return name.some((item)=>this.has(item));
}
const items = this.find({
name
});
return items.length > 0;
}
// ----------------------------------------------
/**
* Find the first matching ability.
*
* @param input
*/ findOne(input) {
const items = this.find(input);
if (items.length === 0) {
return undefined;
}
return items[0];
}
/**
* Find all matching abilities.
*
* @param input
*/ find(input) {
if (typeof input === 'undefined') {
return this.items;
}
let options;
if (typeof input === 'string') {
options = {
name: input
};
} else {
options = input;
}
const output = [];
for(let i = 0; i < this.items.length; i++){
if (options.name && this.items[i].name !== options.name) {
continue;
}
if (!options.inverse && this.items[i].inverse) {
continue;
}
if (this.items[i].condition && options.object) {
const test = mongo2js.guard(this.items[i].condition);
if (!test(options.object)) {
continue;
}
}
if (options.fn) {
if (!options.fn(this.items[i])) {
continue;
}
}
if (options.field && this.items[i].fields) {
const fields = Array.isArray(options.field) ? options.field : [
options.field
];
let index;
let valid = true;
for(let j = 0; j < fields.length; j++){
index = this.items[i].fields.indexOf(fields[i]);
if (index === -1) {
valid = false;
break;
}
}
if (!valid) {
continue;
}
}
if (options.target && this.items[i].target && this.items[i].target !== options.target) {
continue;
}
if (typeof options.power === 'number' && typeof this.items[i].power === 'number' && options.power > this.items[i].power) {
continue;
}
output.push(this.items[i]);
}
return output;
}
set(input, merge) {
const items = Array.isArray(input) ? input : [
input
];
if (merge) {
// todo: check if unique !
this.items = [
...this.items,
...items
];
} else {
this.items = items;
}
this.items.sort((a, b)=>{
if (typeof a.target === 'undefined' || a.target === null) {
return -1;
}
if (typeof b.target === 'undefined' || b.target === null) {
return 1;
}
return 0;
}).sort((a, b)=>b.power - a.power);
}
// ----------------------------------------------
constructor(input = []){
this.set(input);
}
}
/*
* Copyright (c) 2022.
* Author Peter Placzek (tada5hi)
* For the full copyright and license information,
* view the LICENSE file that was distributed with this source code.
*/ exports.JWTAlgorithm = void 0;
(function(JWTAlgorithm) {
JWTAlgorithm["HS256"] = "HS256";
JWTAlgorithm["HS384"] = "HS384";
JWTAlgorithm["HS512"] = "HS512";
JWTAlgorithm["RS256"] = "RS256";
JWTAlgorithm["RS384"] = "RS384";
JWTAlgorithm["RS512"] = "RS512";
JWTAlgorithm["ES256"] = "ES256";
JWTAlgorithm["ES384"] = "ES384";
// 'ES512' = 'ES512',
JWTAlgorithm["PS256"] = "PS256";
JWTAlgorithm["PS384"] = "PS384";
JWTAlgorithm["PS512"] = "PS512";
})(exports.JWTAlgorithm || (exports.JWTAlgorithm = {}));
exports.OAuth2TokenKind = void 0;
(function(OAuth2TokenKind) {
OAuth2TokenKind["ACCESS"] = "access_token";
OAuth2TokenKind["ID_TOKEN"] = "id_token";
OAuth2TokenKind["REFRESH"] = "refresh_token";
})(exports.OAuth2TokenKind || (exports.OAuth2TokenKind = {}));
exports.OAuth2SubKind = void 0;
(function(OAuth2SubKind) {
OAuth2SubKind["CLIENT"] = "client";
OAuth2SubKind["USER"] = "user";
OAuth2SubKind["ROBOT"] = "robot";
})(exports.OAuth2SubKind || (exports.OAuth2SubKind = {}));
/*
* Copyright (c) 2022.
* Author Peter Placzek (tada5hi)
* For the full copyright and license information,
* view the LICENSE file that was distributed with this source code.
*/ exports.ErrorCode = void 0;
(function(ErrorCode) {
ErrorCode["ABILITY_INVALID"] = "invalid_ability";
ErrorCode["HEADER_INVALID"] = "invalid_header";
ErrorCode["HEADER_AUTH_TYPE_UNSUPPORTED"] = "unsupported_auth_header_type";
ErrorCode["CREDENTIALS_INVALID"] = "invalid_credentials";
ErrorCode["ENTITY_INACTIVE"] = "inactive_entity";
ErrorCode["TOKEN_REDIRECT_URI_MISMATCH"] = "redirect_uri_mismatch";
ErrorCode["TOKEN_INVALID"] = "invalid_token";
ErrorCode["TOKEN_INACTIVE"] = "inactive_token";
ErrorCode["TOKEN_EXPIRED"] = "expired_token";
ErrorCode["TOKEN_CLIENT_INVALID"] = "invalid_client";
ErrorCode["TOKEN_GRANT_INVALID"] = "invalid_grant";
ErrorCode["TOKEN_GRANT_TYPE_UNSUPPORTED"] = "unsupported_token_grant_type";
ErrorCode["TOKEN_SCOPE_INVALID"] = "invalid_scope";
ErrorCode["TOKEN_SUB_KIND_INVALID"] = "invalid_token_sub_kind";
})(exports.ErrorCode || (exports.ErrorCode = {}));
class HeaderError extends http.BadRequestError {
static unsupportedHeaderType(type) {
return new HeaderError({
code: exports.ErrorCode.HEADER_AUTH_TYPE_UNSUPPORTED,
message: `The authorization header type ${type} is not supported.`
});
}
constructor(...input){
super({
code: exports.ErrorCode.HEADER_INVALID
}, ...input);
}
}
class TokenError extends http.BadRequestError {
// -------------------------------------------------
static subKindInvalid() {
return new TokenError({
code: exports.ErrorCode.TOKEN_SUB_KIND_INVALID,
message: 'The token sub kind is invalid.'
});
}
static expired(kind) {
return new TokenError({
code: exports.ErrorCode.TOKEN_EXPIRED,
message: `The ${kind || 'token'} has been expired.`
});
}
static kindInvalid() {
return new TokenError({
message: 'The token kind is invalid.'
});
}
static notActiveBefore(date) {
if (typeof date === 'undefined') {
return new TokenError({
code: exports.ErrorCode.TOKEN_INACTIVE,
message: 'The token is not active yet.'
});
}
return new TokenError({
code: exports.ErrorCode.TOKEN_INACTIVE,
message: `The token is not active before: ${date}.`,
data: {
date
}
});
}
static headerInvalid(message) {
return new TokenError({
code: exports.ErrorCode.TOKEN_INVALID,
message: message || 'The token header is malformed.'
});
}
static payloadInvalid(message) {
return new TokenError({
code: exports.ErrorCode.TOKEN_INVALID,
message: message || 'The token payload is malformed.'
});
}
// -------------------------------------------------
static accessTokenRequired() {
return new TokenError({
message: 'An access token is required to authenticate.'
});
}
static clientInvalid() {
return new TokenError({
message: 'Client authentication failed.',
code: exports.ErrorCode.TOKEN_CLIENT_INVALID
});
}
static grantInvalid() {
return new TokenError({
message: 'The provided authorization grant (e.g., authorization code, resource owner credentials) or refresh token ' + 'is invalid, expired, revoked, does not match the redirection URI used in the authorization request, ' + 'or was issued to another client.',
code: exports.ErrorCode.TOKEN_GRANT_INVALID
});
}
static grantTypeUnsupported() {
return new TokenError({
message: 'The authorization grant type is not supported by the authorization server.',
code: exports.ErrorCode.TOKEN_GRANT_TYPE_UNSUPPORTED,
data: {
hint: 'Check that all required parameters have been provided'
}
});
}
static tokenInvalid(kind) {
return new TokenError({
message: `The ${kind || 'token'} is invalid.`
});
}
static tokenNotFound(kind = exports.OAuth2TokenKind.ACCESS) {
return new TokenError({
message: `The ${kind} was not found.`
});
}
static requestInvalid(message) {
return new TokenError({
message: message || 'The request is missing a required parameter, includes an unsupported parameter value, ' + 'repeats a parameter, or is otherwise malformed.',
data: {
hint: 'Check that all parameters have been provided correctly'
}
});
}
static scopeInvalid() {
return new TokenError({
message: ' The requested scope is invalid, unknown or malformed.',
code: exports.ErrorCode.TOKEN_SCOPE_INVALID
});
}
static redirectUriMismatch() {
return new TokenError({
message: 'The redirect URI is missing or do not match',
code: exports.ErrorCode.TOKEN_REDIRECT_URI_MISMATCH
});
}
static responseTypeUnsupported() {
return new TokenError({
message: 'The authorization server does not support obtaining an access token using this method.'
});
}
static targetInactive(kind) {
return new TokenError({
message: `The target token ${kind} is not active.`
});
}
static signingKeyMissing() {
return new TokenError({
message: 'A token signing key could not be retrieved.'
});
}
constructor(...input){
super({
code: exports.ErrorCode.TOKEN_INVALID,
message: 'The Token is invalid.',
statusCode: 400
}, ...input);
}
}
/*
* Copyright (c) 2023.
* Author Peter Placzek (tada5hi)
* For the full copyright and license information,
* view the LICENSE file that was distributed with this source code.
*/ const regex = /(?:(user|robot|client):\/\/)(?:(\w+)(?::(\w+))@)(.*)$/;
function isConnectionString(input) {
return regex.test(input);
}
function parseConnectionString(input) {
const match = input.match(regex);
if (!match) {
return undefined;
}
return {
type: match[1],
url: match[4],
name: match[2],
password: match[3]
};
}
/*
* Copyright (c) 2022.
* Author Peter Placzek (tada5hi)
* For the full copyright and license information,
* view the LICENSE file that was distributed with this source code.
*/ function cleanDoubleSlashes(input) {
if (input.indexOf('://') !== -1) {
return input.split('://').map((str)=>cleanDoubleSlashes(str)).join('://');
}
return input.replace(/\/+/g, '/');
}
/*
* Copyright (c) 2021.
* Author Peter Placzek (tada5hi)
* For the full copyright and license information,
* view the LICENSE file that was distributed with this source code.
*/ // eslint-disable-next-line @typescript-eslint/ban-types
function hasOwnProperty(obj, prop) {
return Object.prototype.hasOwnProperty.call(obj, prop);
}
function isPropertySet(obj, prop) {
return hasOwnProperty(obj, prop);
}
function createNanoID(alphabetOrLen, len) {
if (typeof alphabetOrLen === 'string') {
return nanoid.customAlphabet(alphabetOrLen, len || 21)();
}
if (typeof alphabetOrLen === 'number') {
return nanoid.customAlphabet('0123456789abcdefghijklmnopqrstuvwxyz', alphabetOrLen)();
}
return nanoid.customAlphabet('0123456789abcdefghijklmnopqrstuvwxyz', len || 21)();
}
/*
* Copyright (c) 2023.
* Author Peter Placzek (tada5hi)
* For the full copyright and license information,
* view the LICENSE file that was distributed with this source code.
*/ function isObject(input) {
return !!input && typeof input === 'object' && !Array.isArray(input);
}
function extendObject(target, source) {
const keys = Object.keys(source);
for(let i = 0; i < keys.length; i++){
target[keys[i]] = source[keys[i]];
}
return target;
}
function nullifyEmptyObjectProperties(data) {
const keys = Object.keys(data);
for(let i = 0; i < keys.length; i++){
if (data[keys[i]] === '') {
data[keys[i]] = null;
}
}
return data;
}
function deleteUndefinedObjectProperties(data) {
const keys = Object.keys(data);
for(let i = 0; i < keys.length; i++){
if (typeof data[keys[i]] === 'undefined') {
delete data[keys[i]];
}
}
return data;
}
function extractObjectProperty(data, key) {
if (!data) {
return undefined;
}
if (isPropertySet(data, key)) {
return data[key];
}
return undefined;
}
/*
* Copyright (c) 2023.
* Author Peter Placzek (tada5hi)
* For the full copyright and license information,
* view the LICENSE file that was distributed with this source code.
*/ function parseProxyConnectionString(input) {
const match = input.match(/(?:(https|http):\/\/)(?:(\w+)(?::(\w+))?@)?(?:([^:]+))(?::(\d{1,5}))?$/);
if (!match) {
return undefined;
}
return {
protocol: match[1],
host: match[4],
port: parseInt(match[5], 10),
auth: {
username: match[2],
password: match[3]
}
};
}
/*
* Copyright (c) 2022.
* Author Peter Placzek (tada5hi)
* For the full copyright and license information,
* view the LICENSE file that was distributed with this source code.
*/ function isSelfId(id) {
return id === '@me' || id === '@self';
}
function serialize(input) {
if (typeof input === 'boolean') {
return input ? 'true' : 'false';
}
if (typeof input === 'undefined') {
return 'undefined';
}
if (input === null) {
return 'null';
}
if (typeof input === 'number') {
return `${input}`;
}
if (typeof input === 'string') {
return input;
}
return JSON.stringify(input);
}
function deserialize(input) {
return destr.destr(input);
}
/*
* Copyright (c) 2024.
* Author Peter Placzek (tada5hi)
* For the full copyright and license information,
* view the LICENSE file that was distributed with this source code.
*/ function template(str, data, regex = /\{\{(.+?)\}\}/g) {
return Array.from(str.matchAll(regex)).reduce((acc, match)=>{
if (typeof data[match[1]] !== 'undefined') {
return acc.replace(match[0], data[match[1]]);
}
return acc;
}, str);
}
/*
* Copyright (c) 2022.
* Author Peter Placzek (tada5hi)
* For the full copyright and license information,
* view the LICENSE file that was distributed with this source code.
*/ function makeURLPublicAccessible(url) {
return url.replace('0.0.0.0', '127.0.0.1');
}
/*
* Copyright (c) 2023.
* Author Peter Placzek (tada5hi)
* For the full copyright and license information,
* view the LICENSE file that was distributed with this source code.
*/ function isUUID(input) {
// eslint-disable-next-line prefer-regex-literals
const regexp = new RegExp(/^[0-9a-f]{8}-[0-9a-f]{4}-[0-5][0-9a-f]{3}-[089ab][0-9a-f]{3}-[0-9a-f]{12}$/i);
return regexp.test(input);
}
function isOAuth2OpenIDProviderMetadata(input) {
if (!isObject(input)) {
return false;
}
if (typeof input.issuer !== 'string') {
return false;
}
if (typeof input.authorization_endpoint !== 'string') {
return false;
}
if (typeof input.jwks_uri !== 'string') {
return false;
}
if (!Array.isArray(input.response_type_supported)) {
return false;
}
if (!Array.isArray(input.subject_types_supported)) {
return false;
}
if (!Array.isArray(input.id_token_signing_alg_values_supported)) {
return false;
}
if (typeof input.token_endpoint !== 'string') {
return false;
}
return true;
}
/*
* Copyright (c) 2022.
* Author Peter Placzek (tada5hi)
* For the full copyright and license information,
* view the LICENSE file that was distributed with this source code.
*/ function getOAuth2SubByEntity(entity) {
return entity.robot_id || entity.user_id || entity.client_id;
}
function getOAuth2SubKindByEntity(entity) {
if (entity.robot_id) {
return exports.OAuth2SubKind.ROBOT;
}
if (entity.user_id) {
return exports.OAuth2SubKind.USER;
}
return exports.OAuth2SubKind.CLIENT;
}
/*
* Copyright (c) 2022.
* Author Peter Placzek (tada5hi)
* For the full copyright and license information,
* view the LICENSE file that was distributed with this source code.
*/ exports.KeyType = void 0;
(function(KeyType) {
/**
* Octet/Byte sequence (used to represent symmetric keys)
*/ KeyType["OCT"] = "oct";
/**
* RSA
*/ KeyType["RSA"] = "rsa";
/**
* Elliptic Curve
*/ KeyType["EC"] = "ec";
})(exports.KeyType || (exports.KeyType = {}));
/*
* Copyright (c) 2022.
* Author Peter Placzek (tada5hi)
* For the full copyright and license information,
* view the LICENSE file that was distributed with this source code.
*/ function wrapPem(type, input) {
if (typeof input !== 'string') {
input = Buffer.from(input).toString('base64');
}
return `-----BEGIN ${type}-----\n${input}\n-----END ${type}-----`;
}
function wrapPrivateKeyPem(input) {
return wrapPem('PRIVATE KEY', input);
}
function wrapPublicKeyPem(input) {
return wrapPem('PUBLIC KEY', input);
}
// ------------------------------------------------------------
function unwrapPem(type, input) {
if (typeof input !== 'string') {
input = Buffer.from(input).toString('base64');
}
input = input.replace(`-----BEGIN ${type}-----\n`, '');
input = input.replace(`\n-----END ${type}-----\n`, '');
input = input.replace(`-----END ${type}-----\n`, '');
input = input.replace(`\n-----END ${type}-----`, '');
return input;
}
function unwrapPrivateKeyPem(input) {
return unwrapPem('PRIVATE KEY', input);
}
function unwrapPublicKeyPem(input) {
return unwrapPem('PUBLIC KEY', input);
}
/*
* Copyright (c) 2022-2022.
* Author Peter Placzek (tada5hi)
* For the full copyright and license information,
* view the LICENSE file that was distributed with this source code.
*/ exports.OAuth2TokenGrant = void 0;
(function(OAuth2TokenGrant) {
OAuth2TokenGrant["AUTHORIZATION_CODE"] = "authorization_code";
OAuth2TokenGrant["CLIENT_CREDENTIALS"] = "client_credentials";
OAuth2TokenGrant["PASSWORD"] = "password";
OAuth2TokenGrant["ROBOT_CREDENTIALS"] = "robot_credentials";
OAuth2TokenGrant["REFRESH_TOKEN"] = "refresh_token";
})(exports.OAuth2TokenGrant || (exports.OAuth2TokenGrant = {}));
/*
* Copyright (c) 2022.
* Author Peter Placzek (tada5hi)
* For the full copyright and license information,
* view the LICENSE file that was distributed with this source code.
*/ exports.OAuth2AuthorizationResponseType = void 0;
(function(OAuth2AuthorizationResponseType) {
OAuth2AuthorizationResponseType["NONE"] = "none";
OAuth2AuthorizationResponseType["CODE"] = "code";
OAuth2AuthorizationResponseType["TOKEN"] = "token";
OAuth2AuthorizationResponseType["ID_TOKEN"] = "id_token";
})(exports.OAuth2AuthorizationResponseType || (exports.OAuth2AuthorizationResponseType = {}));
class BaseAPI {
// -----------------------------------------------------------------------------------
setClient(input) {
this.client = hapic.isClient(input) ? input : hapic.createClient(input);
}
// -----------------------------------------------------------------------------------
constructor(context){
context = context || {};
this.setClient(context.client);
}
}
class ClientAPI extends BaseAPI {
async getMany(options) {
const response = await this.client.get(`clients${rapiq.buildQuery(options)}`);
return response.data;
}
async getOne(id, options) {
const response = await this.client.get(`clients/${id}${rapiq.buildQuery(options)}`);
return response.data;
}
async delete(id) {
const response = await this.client.delete(`clients/${id}`);
return response.data;
}
async create(data) {
const response = await this.client.post('clients', nullifyEmptyObjectProperties(data));
return response.data;
}
async update(id, data) {
const response = await this.client.post(`clients/${id}`, nullifyEmptyObjectProperties(data));
return response.data;
}
}
class ClientScopeAPI extends BaseAPI {
async getMany(data) {
const response = await this.client.get(`client-scopes${rapiq.buildQuery(data)}`);
return response.data;
}
async getOne(id) {
const response = await this.client.get(`client-scopes/${id}`);
return response.data;
}
async delete(id) {
const response = await this.client.delete(`client-scopes/${id}`);
return response.data;
}
async create(data) {
const response = await this.client.post('client-scopes', data);
return response.data;
}
}
/*
* Copyright (c) 2022.
* Author Peter Placzek (tada5hi)
* For the full copyright and license information,
* view the LICENSE file that was distributed with this source code.
*/ function buildIdentityProviderAuthorizeCallbackPath(id) {
return `/identity-providers/${id}/authorize-callback`;
}
function buildIdentityProviderAuthorizePath(id) {
return `/identity-providers/${id}/authorize-url`;
}
function isValidIdentityProviderSub(sub) {
return /^[a-z0-9-_]{3,36}$/.test(sub);
}
class IdentityProviderAPI extends BaseAPI {
getAuthorizeUri(baseUrl, id) {
return cleanDoubleSlashes(`${baseUrl}/${buildIdentityProviderAuthorizePath(id)}`);
}
async getMany(record) {
const response = await this.client.get(`identity-providers${rapiq.buildQuery(record)}`);
return response.data;
}
async getOne(id, record) {
const response = await this.client.get(`identity-providers/${id}${rapiq.buildQuery(record)}`);
return response.data;
}
async delete(id) {
const response = await this.client.delete(`identity-providers/${id}`);
return response.data;
}
async create(data) {
const response = await this.client.post('identity-providers', nullifyEmptyObjectProperties(data));
return response.data;
}
async update(id, data) {
const response = await this.client.post(`identity-providers/${id}`, nullifyEmptyObjectProperties(data));
return response.data;
}
}
/*
* Copyright (c) 2022.
* Author Peter Placzek (tada5hi)
* For the full copyright and license information,
* view the LICENSE file that was distributed with this source code.
*/ exports.IdentityProviderProtocol = void 0;
(function(IdentityProviderProtocol) {
IdentityProviderProtocol["LDAP"] = "ldap";
IdentityProviderProtocol["OAUTH2"] = "oauth2";
IdentityProviderProtocol["OIDC"] = "oidc";
})(exports.IdentityProviderProtocol || (exports.IdentityProviderProtocol = {}));
/*
* Copyright (c) 2023.
* Author Peter Placzek (tada5hi)
* For the full copyright and license information,
* view the LICENSE file that was distributed with this source code.
*/ exports.IdentityProviderPreset = void 0;
(function(IdentityProviderPreset) {
IdentityProviderPreset["FACEBOOK"] = "facebook";
IdentityProviderPreset["GITHUB"] = "github";
IdentityProviderPreset["GITLAB"] = "gitlab";
IdentityProviderPreset["GOOGLE"] = "google";
IdentityProviderPreset["PAYPAL"] = "paypal";
IdentityProviderPreset["INSTAGRAM"] = "instagram";
IdentityProviderPreset["STACKOVERFLOW"] = "stackoverflow";
IdentityProviderPreset["TWITTER"] = "twitter";
})(exports.IdentityProviderPreset || (exports.IdentityProviderPreset = {}));
function getIdentityProviderProtocolForPreset(id) {
switch(id){
case exports.IdentityProviderPreset.GITHUB:
case exports.IdentityProviderPreset.GITLAB:
case exports.IdentityProviderPreset.GOOGLE:
case exports.IdentityProviderPreset.FACEBOOK:
case exports.IdentityProviderPreset.INSTAGRAM:
case exports.IdentityProviderPreset.PAYPAL:
case exports.IdentityProviderPreset.STACKOVERFLOW:
case exports.IdentityProviderPreset.TWITTER:
return exports.IdentityProviderProtocol.OIDC;
}
return undefined;
}
class IdentityProviderRoleAPI extends BaseAPI {
async getMany(data) {
const response = await this.client.get(`identity-provider-roles${rapiq.buildQuery(data)}`);
return response.data;
}
async getOne(id) {
const response = await this.client.get(`identity-provider-roles/${id}`);
return response.data;
}
async delete(id) {
const response = await this.client.delete(`identity-provider-roles/${id}`);
return response.data;
}
async create(data) {
const response = await this.client.post('identity-provider-roles', nullifyEmptyObjectProperties(data));
return response.data;
}
async update(id, data) {
const response = await this.client.post(`identity-provider-roles/${id}`, data);
return response.data;
}
}
class PermissionAPI extends BaseAPI {
async getMany(data) {
const response = await this.client.get(`permissions${rapiq.buildQuery(data)}`);
return response.data;
}
async delete(id) {
const response = await this.client.delete(`permissions/${id}`);
return response.data;
}
async getOne(id, record) {
const response = await this.client.get(`permissions/${id}${rapiq.buildQuery(record)}`);
return response.data;
}
async create(data) {
const response = await this.client.post('permissions', nullifyEmptyObjectProperties(data));
return response.data;
}
async update(id, data) {
const response = await this.client.post(`permissions/${id}`, nullifyEmptyObjectProperties(data));
return response.data;
}
}
/*
* Copyright (c) 2021.
* Author Peter Placzek (tada5hi)
* For the full copyright and license information,
* view the LICENSE file that was distributed with this source code.
*/ exports.PermissionName = void 0;
(function(PermissionName) {
PermissionName["CLIENT_ADD"] = "client_add";
PermissionName["CLIENT_DROP"] = "client_drop";
PermissionName["CLIENT_EDIT"] = "client_edit";
PermissionName["PROVIDER_ADD"] = "provider_add";
PermissionName["PROVIDER_DROP"] = "provider_drop";
PermissionName["PROVIDER_EDIT"] = "provider_edit";
PermissionName["PERMISSION_ADD"] = "permission_add";
PermissionName["PERMISSION_DROP"] = "permission_drop";
PermissionName["PERMISSION_EDIT"] = "permission_edit";
PermissionName["REALM_ADD"] = "realm_add";
PermissionName["REALM_DROP"] = "realm_drop";
PermissionName["REALM_EDIT"] = "realm_edit";
PermissionName["ROBOT_ADD"] = "robot_add";
PermissionName["ROBOT_DROP"] = "robot_drop";
PermissionName["ROBOT_EDIT"] = "robot_edit";
PermissionName["ROBOT_PERMISSION_ADD"] = "robot_permission_add";
PermissionName["ROBOT_PERMISSION_DROP"] = "robot_permission_drop";
PermissionName["ROBOT_ROLE_ADD"] = "robot_role_add";
PermissionName["ROBOT_ROLE_DROP"] = "robot_role_drop";
PermissionName["ROBOT_ROLE_EDIT"] = "robot_role_edit";
PermissionName["ROLE_ADD"] = "role_add";
PermissionName["ROLE_DROP"] = "role_drop";
PermissionName["ROLE_EDIT"] = "role_edit";
PermissionName["ROLE_PERMISSION_ADD"] = "role_permission_add";
PermissionName["ROLE_PERMISSION_DROP"] = "role_permission_drop";
PermissionName["SCOPE_ADD"] = "scope_add";
PermissionName["SCOPE_DROP"] = "scope_drop";
PermissionName["SCOPE_EDIT"] = "scope_edit";
PermissionName["TOKEN_VERIFY"] = "token_verify";
PermissionName["USER_ADD"] = "user_add";
PermissionName["USER_DROP"] = "user_drop";
PermissionName["USER_EDIT"] = "user_edit";
PermissionName["USER_PERMISSION_ADD"] = "user_permission_add";
PermissionName["USER_PERMISSION_DROP"] = "user_permission_drop";
PermissionName["USER_ROLE_ADD"] = "user_role_add";
PermissionName["USER_ROLE_DROP"] = "user_role_drop";
PermissionName["USER_ROLE_EDIT"] = "user_role_edit";
})(exports.PermissionName || (exports.PermissionName = {}));
class RealmAPI extends BaseAPI {
async getMany(data) {
const response = await this.client.get(`realms${rapiq.buildQuery(data)}`);
return response.data;
}
async getOne(id) {
const response = await this.client.get(`realms/${id}`);
return response.data;
}
async delete(id) {
const response = await this.client.delete(`realms/${id}`);
return response.data;
}
async create(data) {
const response = await this.client.post('realms', nullifyEmptyObjectProperties(data));
return response.data;
}
async update(realmId, data) {
const response = await this.client.post(`realms/${realmId}`, nullifyEmptyObjectProperties(data));
return response.data;
}
}
/*
* Copyright (c) 2022.
* Author Peter Placzek (tada5hi)
* For the full copyright and license information,
* view the LICENSE file that was distributed with this source code.
*/ const REALM_MASTER_NAME = 'master';
/*
* Copyright (c) 2023.
* Author Peter Placzek (tada5hi)
* For the full copyright and license information,
* view the LICENSE file that was distributed with this source code.
*/ function buildSocketRealmNamespaceName(realmId) {
return `/realm#${realmId}`;
}
function parseSocketRealmNamespaceName(name) {
return name.startsWith('/realm#') ? name.substring('/realm#'.length) : name;
}
/**
* Check if a realm resource is writable.
*
* @param realm
* @param resourceRealmId
*/ function isRealmResourceWritable(realm, resourceRealmId) {
if (Array.isArray(resourceRealmId)) {
for(let i = 0; i < resourceRealmId.length; i++){
if (isRealmResourceWritable(realm, resourceRealmId[i])) {
return true;
}
}
return false;
}
if (!realm) {
return false;
}
if (isPropertySet(realm, 'name') && realm.name === REALM_MASTER_NAME) {
return true;
}
return realm.id === resourceRealmId;
}
/**
* Check if realm resource is readable.
*
* @param realm
* @param resourceRealmId
*/ function isRealmResourceReadable(realm, resourceRealmId) {
if (Array.isArray(resourceRealmId)) {
if (resourceRealmId.length === 0) {
return true;
}
for(let i = 0; i < resourceRealmId.length; i++){
if (isRealmResourceReadable(realm, resourceRealmId[i])) {
return true;
}
}
return false;
}
if (typeof realm === 'undefined') {
return false;
}
if (isPropertySet(realm, 'name') && realm.name === REALM_MASTER_NAME) {
return true;
}
return !resourceRealmId || realm.id === resourceRealmId;
}
function isValidRealmName(name) {
return /^[a-zA-Z0-9-_]{3,128}$/.test(name);
}
class RobotAPI extends BaseAPI {
async getMany(options) {
const response = await this.client.get(`robots${rapiq.buildQuery(options)}`);
return response.data;
}
async getOne(id, options) {
const response = await this.client.get(`robots/${id}${rapiq.buildQuery(options)}`);
return response.data;
}
async delete(id) {
const response = await this.client.delete(`robots/${id}`);
return response.data;
}
async create(data) {
const response = await this.client.post('robots', nullifyEmptyObjectProperties(data));
return response.data;
}
async update(id, data) {
const response = await this.client.post(`robots/${id}`, nullifyEmptyObjectProperties(data));
return response.data;
}
async integrity(id) {
const { data: response } = await this.client.get(`robots/${id}/integrity`);
return response;
}
}
class RobotError extends http.BadRequestError {
static credentialsInvalid() {
return new RobotError({
code: exports.ErrorCode.CREDENTIALS_INVALID,
message: 'The robot credentials are invalid.'
});
}
static inactive() {
return new RobotError({
code: exports.ErrorCode.ENTITY_INACTIVE,
message: 'The robot account is inactive.'
});
}
}
class RobotPermissionAPI extends BaseAPI {
async getMany(data) {
const response = await this.client.get(`robot-permissions${rapiq.buildQuery(data)}`);
return response.data;
}
async getOne(id, data) {
const response = await this.client.get(`robot-permissions/${id}${rapiq.buildQuery(data)}`);
return response.data;
}
async delete(id) {
const response = await this.client.delete(`robot-permissions/${id}`);
return response.data;
}
async create(data) {
const response = await this.client.post('robot-permissions', data);
return response.data;
}
}
class RobotRoleAPI extends BaseAPI {
async getMany(data) {
const response = await this.client.get(`robot-roles${rapiq.buildQuery(data)}`);
return response.data;
}
async getOne(id) {
const response = await this.client.get(`robot-roles/${id}`);
return response.data;
}
async delete(id) {
const response = await this.client.delete(`robot-roles/${id}`);
return response.data;
}
async create(data) {
const response = await this.client.post('robot-roles', data);
return response.data;
}
}
class RoleAPI extends BaseAPI {
async getMany(data) {
const response = await this.client.get(`roles${rapiq.buildQuery(data)}`);
return response.data;
}
async getOne(roleId) {
const response = await this.client.get(`roles/${roleId}`);
return response.data;
}
async delete(roleId) {
const response = await this.client.delete(`roles/${roleId}`);
return response.data;
}
async create(data) {
const response = await this.client.post('roles', nullifyEmptyObjectProperties(data));
return response.data;
}
async update(id, data) {
const response = await this.client.post(`roles/${id}`, nullifyEmptyObjectProperties(data));
return response.data;
}
}
/*
* Copyright (c) 2022.
* Author Peter Placzek (tada5hi)
* For the full copyright and license information,
* view the LICENSE file that was distributed with this source code.
*/ function isValidRoleName(name) {
return /^[A-Za-z0-9-_]{3,128}$/.test(name);
}
class RoleAttributeAPI extends BaseAPI {
async getMany(data) {
const response = await this.client.get(`role-attributes${rapiq.buildQuery(data)}`);
return response.data;
}
async getOne(roleId) {
const response = await this.client.get(`role-attributes/${roleId}`);
return response.data;
}
async delete(roleId) {
const response = await this.client.delete(`role-attributes/${roleId}`);
return response.data;
}
async create(data) {
const response = await this.client.post('role-attributes', nullifyEmptyObjectProperties(data));
return response.data;
}
async update(id, data) {
const response = await this.client.post(`role-attributes/${id}`, nullifyEmptyObjectProperties(data));
return response.data;
}
}
class RolePermissionAPI extends BaseAPI {
async getMany(data) {
const response = await this.client.get(`role-permissions${rapiq.buildQuery(data)}`);
return response.data;
}
async getOne(id) {
const response = await this.client.get(`role-permissions/${id}`);
return response.data;
}
async delete(id) {
const response = await this.client.delete(`role-permissions/${id}`);
return response.data;
}
async create(data) {
const response = await this.client.post('role-permissions', data);
return response.data;
}
}
class ScopeAPI extends BaseAPI {
async getMany(data) {
const response = await this.client.get(`scopes${rapiq.buildQuery(data)}`);
return response.data;
}
async getOne(id) {
const response = await this.client.get(`scopes/${id}`);
return response.data;
}
async delete(id) {
const response = await this.client.delete(`scopes/${id}`);
return response.data;
}
async create(data) {
const response = await this.client.post('scopes', nullifyEmptyObjectProperties(data));
return response.data;
}
async update(id, data) {
const response = await this.client.post(`scopes/${id}`, nullifyEmptyObjectProperties(data));
return response.data;
}
}
/*
* Copyright (c) 2022.
* Author Peter Placzek (tada5hi)
* For the full copyright and license information,
* view the LICENSE file that was distributed with this source code.
*/ exports.ScopeName = void 0;
(function(ScopeName) {
/**
* Full permissions (userinfo & id-token)
*/ ScopeName["GLOBAL"] = "global";
/**
* for Openid usage (id-token)
*/ ScopeName["OPEN_ID"] = "openid";
/**
* /users/@me with email (userinfo & id-token)
*/ ScopeName["EMAIL"] = "email";
/**
* Roles array (id-token)
*/ ScopeName["ROLES"] = "roles";
/**
* /users/@me without email (userinfo & id-token)
*/ ScopeName["IDENTITY"] = "identity";
})(exports.ScopeName || (exports.ScopeName = {}));
function transformOAuth2ScopeToArray(scope) {
if (!scope) {
return [];
}
if (Array.isArray(scope)) {
return scope;
}
return scope.split(/\s+|,+/);
}
function hasOAuth2OpenIDScope(scope) {
return transformOAuth2ScopeToArray(scope).indexOf(exports.ScopeName.OPEN_ID) !== -1;
}
function isOAuth2ScopeAllowed(available, required) {
available = transformOAuth2ScopeToArray(available);
if (available.indexOf(exports.ScopeName.GLOBAL) !== -1) {
return true;
}
if (available.length === 0) {
return false;
}
required = transformOAuth2ScopeToArray(required);
for(let i = 0; i < required.length; i++){
if (available.indexOf(required[i]) === -1) {
return false;
}
}
return true;
}
class UserAPI extends BaseAPI {
async getMany(options) {
const response = await this.client.get(`users${rapiq.buildQuery(options)}`);
return response.data;
}
async getOne(id, options) {
const response = await this.client.get(`users/${id}${rapiq.buildQuery(options)}`);
return response.data;
}
async delete(id) {
const response = await this.client.delete(`users/${id}`);
return response.data;
}
async create(data) {
const response = await this.client.post('users', nullifyEmptyObjectProperties(data));
return response.data;
}
async update(id, data) {
const response = await this.client.post(`users/${id}`, nullifyEmptyObjectProperties(data));
return response.data;
}
}
class UserError extends http.BadRequestError {
static credentialsInvalid() {
return new UserError({
code: exports.ErrorCode.CREDENTIALS_INVALID,
message: 'The user credentials are invalid.'
});
}
static inactive() {
return new UserError({
code: exports.ErrorCode.ENTITY_INACTIVE,
message: 'The user account is inactive.'
});
}
}
/*
* Copyright (c) 2022.
* Author Peter Placzek (tada5hi)
* For the full copyright and license information,
* view the LICENSE file that was distributed with this source code.
*/ function isValidUserName(input) {
if (/\s/g.test(input)) {
return false;
}
return /^[A-Za-z0-9-_.]{3,36}$/.test(input) && input.toLowerCase().indexOf('bot') === -1 && input.toLowerCase().indexOf('system') === -1 && input.toLowerCase() !== 'everyone' && input.toLowerCase() !== 'here';
}
function isValidUserEmail(input) {
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(input);
}
class UserAttributeAPI extends BaseAPI {
async getMany(data) {
const response = await this.client.get(`user-attributes${rapiq.buildQuery(data)}`);
return response.data;
}
async getOne(roleId) {
const response = await this.client.get(`user-attributes/${roleId}`);
return response.data;
}
async delete(roleId) {
const response = await this.client.delete(`user-attributes/${roleId}`);
return response.data;
}
async create(data) {
const response = await this.client.post('user-attributes', nullifyEmptyObjectProperties(data));
return response.data;
}
async update(id, data) {
const response = await this.client.post(`user-attributes/${id}`, nullifyEmptyObjectProperties(data));
return response.data;
}
}
class UserPermissionAPI extends BaseAPI {
async getMany(data) {
const response = await this.client.get(`user-permissions${rapiq.buildQuery(data)}`);
return response.data;
}
async getOne(id) {
const response = await this.client.get(`user-permissions/${id}`);
return response.data;
}
async delete(id) {
const response = await this.client.delete(`user-permissions/${id}`);
return response.data;
}
async create(data) {
const response = await this.client.post('user-permissions', nullifyEmptyObjectProperties(data));
return response.data;
}
}
class UserRoleAPI extends BaseAPI {
async getMany(data) {
const response = await this.client.get(`user-roles${rapiq.buildQuery(data)}`);
return response.data;
}
async getOne(id) {
const response = await this.client.get(`user-roles/${id}`);
return response.data;
}
async delete(id) {
const response = await this.client.delete(`user-roles/${id}`);
return response.data;
}
async create(data) {
const response = await this.client.post('user-roles', data);
return response.data;
}
}
/*
* Copyright (c) 2023.
* Author Peter Placzek (tada5hi)
* For the full copyright and license information,
* view the LICENSE file that was distributed with this source code.
*/ exports.DomainType = void 0;
(function(DomainType) {
DomainType["CLIENT"] = "client";
DomainType["CLIENT_SCOPE"] = "clientScope";
DomainType["IDENTITY_PROVIDER"] = "identityProvider";
DomainType["IDENTITY_PROVIDER_ACCOUNT"] = "identityProviderAccount";
DomainType["IDENTITY_PROVIDER_ATTRIBUTE"] = "identityProviderAttribute";
DomainType["IDENTITY_PROVIDER_ROLE"] = "identityProviderRole";
DomainType["PERMISSION"] = "permission";
DomainType["REALM"] = "realm";
DomainType["ROBOT"] = "robot";
DomainType["ROBOT_PERMISSION"] = "robotPermission";
DomainType["ROBOT_ROLE"] = "robotRole";
DomainType["ROLE"] = "role";
DomainType["ROLE_ATTRIBUTE"] = "roleAttribute";
DomainType["ROLE_PERMISSION"] = "rolePermission";
DomainType["SCOPE"] = "scope";
DomainType["USER"] = "user";
DomainType["USER_ATTRIBUTE"] = "userAttribute";
DomainType["USER_PERMISSION"] = "userPermission";
DomainType["USER_ROLE"] = "userRole";
})(exports.DomainType || (exports.DomainType = {}));
exports.DomainEventName = void 0;
(function(DomainEventName) {
DomainEventName["CREATED"] = "created";
DomainEventName["DELETED"] = "deleted";
DomainEventName["UPDATED"] = "updated";
})(exports.DomainEventName || (exports.DomainEventName = {}));
exports.DomainEventSubscriptionName = void 0;
(function(DomainEventSubscriptionName) {
DomainEventSubscriptionName["SUBSCRIBE"] = "subscribe";
DomainEventSubscriptionName["UNSUBSCRIBE"] = "unsubscribe";
})(exports.DomainEventSubscriptionName || (exports.DomainEventSubscriptionName = {}));
/*
* Copyright (c) 2023.
* Author Peter Placzek (tada5hi)
* For the full copyright and license information,
* view the LICENSE file that was distributed with this source code.
*/ function buildDomainEventFullName(type, event) {
const eventCapitalized = event.substring(0, 1).toUpperCase() + event.substring(1);
return type + eventCapitalized;
}
function buildDomainEventSubscriptionFullName(type, event) {
const eventCapitalized = event.substring(0, 1).toUpperCase() + event.substring(1);
return type + eventCapitalized;
}
function buildDomainChannelName(type, id) {
return `${type}${id ? `:${id}` : ''}`;
}
function buildDomainNamespaceName(id) {
return `/realm#${id}`;
}
class APIClient extends hapic.Client {
async getJwks() {
const response = await this.get('jwks');
return response.data;
}
async getJwk(id) {
const response = await this.get(`jwks/${id}`);
return response.data;
}
constructor(config){
super(config);
const options = {
authorizationEndpoint: 'authorize',
introspectionEndpoint: 'token/introspect',
tokenEndpoint: 'token',
userinfoEndpoint: 'users/@me'
};
const baseURL = this.getBaseURL();
if (typeof baseURL === 'string') {
const keys = Object.keys(options);
for(let i = 0; i < keys.length; i++){
options[keys[i]] = new URL(options[keys[i]], baseURL).href;
}
}
this.authorize = new oauth2.AuthorizeAPI({
client: this,
options
});
this.token = new oauth2.TokenAPI({
client: this,
options
});
this.client = new ClientAPI({
client: this
});
this.clientScope = new ClientScopeAPI({
client: this
});
this.identityProvider = new IdentityProviderAPI({
client: this
});
this.identityProviderRole = new IdentityProviderRoleAPI({
client: this
});
this.permission = new PermissionAPI({
client: this
});
this.realm = new RealmAPI({
client: this
});
this.robot = new RobotAPI({
client: this
});
this.robotPermission = new RobotPermissionAPI({
client: this
});
this.robotRole = new RobotRoleAPI({
client: this
});
this.role = new RoleAPI({
client: this
});
this.roleAttribute = new RoleAttributeAPI({
client: this
});
this.rolePermission = new RolePermissionAPI({
client: this
});
this.scope = new ScopeAPI({
client: this
});
this.user = new UserAPI({
client: this
});
this.userInfo = new oauth2.UserInfoAPI({
client: this,
options
});
this.userAttribute = new UserAttributeAPI({
client: this
});
this.userPermission = new UserPermissionAPI({
client: this
});
this.userRole = new UserRoleAPI({
client: this
});
this.on(hapic.HookName.