UNPKG

@authup/core

Version:

Package containing global constants, types & interfaces.

1,504 lines (1,443 loc) 64.6 kB
'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.