diff --git a/sdk/adaptive-proxy/.eslintrc.json b/sdk/adaptive-proxy/.eslintrc.json new file mode 100644 index 0000000..1e9a9b3 --- /dev/null +++ b/sdk/adaptive-proxy/.eslintrc.json @@ -0,0 +1,19 @@ +{ + "env": { + "commonjs": true, + "es6": true, + "node": true + }, + "extends": [ + "google" + ], + "globals": { + "Atomics": "readonly", + "SharedArrayBuffer": "readonly" + }, + "parserOptions": { + "ecmaVersion": 2018, + "sourceType": "module" + }, + "ignorePatterns": ["docs/**", "dist/**"] +} \ No newline at end of file diff --git a/sdk/adaptive-proxy/.gitignore b/sdk/adaptive-proxy/.gitignore new file mode 100644 index 0000000..b711c29 --- /dev/null +++ b/sdk/adaptive-proxy/.gitignore @@ -0,0 +1,133 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage +*.lcov + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# TypeScript v1 declaration files +typings/ + +# TypeScript cache +*.tsbuildinfo + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Microbundle cache +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variables file +.env +.env.test + +# parcel-bundler cache (https://parceljs.org/) +.cache + +# Next.js build output +.next + +# Nuxt.js build / generate output +.nuxt +dist + +# Gatsby files +.cache/ +# Comment in the public line in if your project uses Gatsby and *not* Next.js +# https://nextjs.org/blog/next-9-1#public-directory-support +# public + +# vuepress build output +.vuepress/dist + +# Serverless directories +.serverless/ + +# FuseBox cache +.fusebox/ + +# DynamoDB Local files +.dynamodb/ + +# TernJS port file +.tern-port + +## macOS + +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk \ No newline at end of file diff --git a/sdk/adaptive-proxy/.jsdoc.json b/sdk/adaptive-proxy/.jsdoc.json new file mode 100644 index 0000000..77e963f --- /dev/null +++ b/sdk/adaptive-proxy/.jsdoc.json @@ -0,0 +1,29 @@ +{ + "tags": { + "allowUnknownTags": true, + "dictionaries": ["jsdoc"] + }, + "source": { + "include": ["lib/adaptive.js", "lib/errors", "lib/services", "lib/utils", "README.md"], + "excludePattern": "(node_modules/|docs)" + }, + "plugins": [ + "plugins/markdown" + ], + "templates": { + "cleverLinks": false, + "monospaceLinks": true, + "useLongnameInNav": false, + "showInheritedInNav": true, + "default": { + "includeDate": false + } + }, + "opts": { + "destination": "./docs/", + "encoding": "utf8", + "private": true, + "recurse": true, + "template": "./node_modules/jsdoc-fresh" + } +} \ No newline at end of file diff --git a/sdk/adaptive-proxy/.vscode/settings.json b/sdk/adaptive-proxy/.vscode/settings.json new file mode 100644 index 0000000..03bb571 --- /dev/null +++ b/sdk/adaptive-proxy/.vscode/settings.json @@ -0,0 +1,4 @@ +{ + "eslint.format.enable": true, + "javascript.format.enable": false +} \ No newline at end of file diff --git a/sdk/adaptive-proxy/README.md b/sdk/adaptive-proxy/README.md new file mode 100644 index 0000000..ad132a5 --- /dev/null +++ b/sdk/adaptive-proxy/README.md @@ -0,0 +1,1243 @@ +# IBM Security Verify Adaptive Proxy SDK for JavaScript + +The Proxy SDK for server-side JavaScript ([Node](https://nodejs.org)). +The purpose of this library is to provide an interface for device +authentication, authorization, and risk assessment using IBM Security Verify. + +## Installation + +Use [npm](https://github.com/npm/cli) to install the Proxy SDK: + +```bash +npm install @ibm-verify/adaptive-proxy +``` + +## Configuration Settings + +To use the Proxy SDK, you will need to initialise an `Adaptive` object with a +configuration object. The configuration object should contian the following +parameters: + +| Parameter | Type | Description | +| -------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `tenantUrl` | `string` | The base URL of your [IBM Security Verify Tenant](https://iamdevportal.us-east.mybluemix.net/verify/javascript/civ-getting-started/configuring-your-ci-tenant) | +| `clientId` | `string` | The identifier of your Security Verify application | +| `clientSecret` | `string` | The secret for your Security Verify application | + +See [Initialise an Adaptive object](#initialise-an-adaptive-object) for an +example. + +## Context Object + +A call to each function in this SDK requires a context object as a +parameter. This context object contains information about the +user-agent attempting the request, such as a session identifier. +This device-related information will be used to assess risk during +each request. + +The context object should contain the following parameters: + +| Parameter | Type | Description | +| ----------------------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `sessionId` | `string` | The session ID generated by the user-agent, using an Adaptive client SDK. | +| `userAgent` | `string` | The user-agent, typically obtained from the User-Agent HTTP header. | +| `ipAddress` | `string` | The IP address of the user-agent. | +| `[evaluationContext="login"]` | `string` | The stage in the user-agent for which to perform an evaluation. (Used for continuous assessment throughout the user-agent.) Different "stages" or "contexts" will result in different evaluation results, as configured in the sub-policies of the tenant application's policy. Possible options are `"login"` (default), `"landing"`, `"profile"`, `"resume"`, `"highassurance"`, `"other"`. | + +## Overview +### [`class Adaptive(config, [transactionFunctions])`](#initialise-an-adaptive-object) +| Function | Async | Return | +| -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----- | ----------------- | +| [`assessPolicy(context)`](#assess-a-policy) | ✅ | `Promise` | +| [`lookupIdentitySources(context, transactionId, [sourceName]`](#lookup-identity-sources) | ✅ | `Promise` | +| [`evaluatePassword(context, transactionId, identitySourceId, username, password)`](#evaluate-a-password-verification) | ✅ | `Promise` | +| [`generateFIDO(context, transactionId, relyingPartyId, userId)`](#generate-a-fido-verification) | ✅ | `Promise` | +| [`evaluateFIDO(context, transactionId, relyingPartyId, authenticatorData, userHandle, signature, clientDataJSON)`](#evaluate-a-fido-verification) | ✅ | `Promise` | +| [`generateQR(context, transactionId, profileId)`](#generate-a-qr-login-verification) | ✅ | `Promise` | +| [`evaluateQR(context, transactionId)`](#evaluate-a-qr-login-verification) | ✅ | `Promise` | +| [`generateEmailOTP(context, transactionId, enrollmentId)`](#generate-an-email-otp-verification) | ✅ | `Promise` | +| [`generateSMSOTP(context, transactionId, enrollmentId)`](#generate-an-sms-otp-verification) | ✅ | `Promise` | +| [`generateVoiceOTP(context, transactionId, enrollmentId)`](#generate-a-voice-otp-verification) | ✅ | `Promise` | +| [`evaluateTOTP(context, transactionId, enrollmentId, otp)`](#evaluate-a-totp-verification) | ✅ | `Promise` | +| [`evaluateEmailOTP(context, transactionId, otp)`](#evaluate-an-email-otp-verification) | ✅ | `Promise` | +| [`evaluateSMSOTP(context, transactionId, otp)`](#evaluate-an-sms-otp-verification) | ✅ | `Promise` | +| [`evaluateVoiceOTP(context, transactionId, otp)`](#evaluate-a-voice-otp-verification) | ✅ | `Promise` | +| [`generateQuestions(context, transactionId, enrollmentId)`](#generate-a-knowledge-questions-verification) | ✅ | `Promise` | +| [`evaluateQuestions(context, transactionId, questions)`](#evaluate-a-knowledge-questions-verification) | ✅ | `Promise` | +| [`generatePush(context, transactionId, enrollmentId, authenticatorId, message, pushNotificationTitle, pushNotificationMessage, additionalData)`](#generate-a-push-notification-verification) | ✅ | `Promise` | +| [`evaluatePush(context, transactionId)`](#evaluate-a-push-notification-verification) | ✅ | `Promise` | +| [`getToken(transactionId)`](#get-access-token-for-a-transaction) | | `String` | +| [`logout(accessToken)`](#logout) | ✅ | `undefined` | +| [`refresh(context, refreshToken)`](#refresh) | ✅ | `Promise` | +| [`introspect(token, [tokenTypeHint])`](#introspect) | ✅ | `Promise` | +| [`introspectMiddleware([config])`](#introspect-middleware) | ✅ | `Function` | + +## Usage + +### Import the Proxy SDK + +```javascript +const Adaptive = require('@ibm-verify/adaptive-proxy'); +``` + +### Initialise an Adaptive object + +```javascript +const config = { + tenantUrl: 'https://mytenant.ibmcloudsecurity.com', + clientId: 'e957e707-c032-4076-98cc-3dcf24db8aed', + clientSecret: '05UXCBaJgL', +}; + +const adaptive = new Adaptive(config); +``` + +#### Custom transaction storage + +You may also pass in a `transactionFunctions` object to the Adaptive initialisation, as shown below. + +```javascript +const config = { + tenantUrl: 'https://mytenant.ibmcloudsecurity.com', + clientId: 'e957e707-c032-4076-98cc-3dcf24db8aed', + clientSecret: '05UXCBaJgL', +}; + +const transactionFunctions = { + createTransaction: myCreateTransactionFunction, + getTransaction: myGetTransactionFunction, + updateTransaction: myUpdateTransactionFunction, + deleteTransaction: myDeleteTransactionFunction +}; + +const adaptive = new Adaptive(config, transactionFunctions); +``` + +This parameter is optional, in case you would like to handle the storing, retrieving, updating, and deleting of transactions created during the A2 flow in an external database. Otherwise, a default in-memory option is used for handling transactions. + +If specified, this object must contain four parameters: +* `createTransaction` + * The function used to create (store) a transaction. This function should take one parameter; a transaction `Object`. It should store the object in a database of choice, indexed by a randomly generated v4 UUID (i.e. the transaction ID). After storing the transaction object associated to a transaction ID, the function should return the transaction ID as a `string`. +* `getTransaction` + * The function used to retrieve stored transactions. This function should take one parameter; a transaction ID `string`. It should return the transaction `Object` associated to the given transaction ID. +* `updateTransaction` + * The function used to update (i.e. add additional properties to) an existing transaction. This function should take two parameters (in order); a transaction ID `string` of the transaction to update, and an `Object` of additional properties to add to the transaction. This function shouldn't return anything. + * For example, if the existing transaction is + ```javascript + { + "userId": "123456" + } + ``` + , and the object passed into this function is + ```javascript + { + "name": "John" + } + ``` + , the updated transaction should result in + ```javascript + { + "userId": "123456", + "name": "John" + } + ``` +* `deleteTransaction` + * The function used to delete an existing transaction. This function should take one parameter; a transaction ID `string`. The function should remove the transaction associated with the given transaction ID from the database storage. This function shouldn't return anything. + +Your storage mechanism of choice should ideally have a time-to-live for the transactions (e.g. 1 hour), to prevent accumulating unused/unfinished transactions. + +### Assess a policy + +Performs the initial grant request to OIDC. This will perform risk assessment on the policy, which will result in either a `deny`, or `requires` response. + +#### `assessPolicy(context)` + +| Parameter | Type | Description | +| --------- | -------- | -------------------------------------- | +| `context` | `Object` | See [Context Object](#context-object). | + +#### Responses + +* A `deny` response is received when the policy assessment fails. + ```javascript + { + "status": "deny" + } + ``` + +* A `requires` response will contain an array of allowed factors, indicating that +further verification is required (i.e. first-factor verification must be +performed) to receive a token. The possible first factor options are `"qr"`, +`"fido"`, and `"password"`. You can use the +[`generateQR`](#generate-a-qr-login-verification), +[`generateFIDO`](#generate-a-fido-verification), and +[`evaluatePassword`](#evaluate-a-password-verification) +functions respectively to initiate these first factors. A transaction ID will also be returned, which will be used to associate subsequent requests to this initial grant. + ```javascript + { + "status": "requires", + "transactionId": "36a101c7-7426-4f45-ab3c-55f8dc075c6e", + "allowedFactors": ["qr", "fido", "password"] + } + ``` + +#### Example Usage + +```javascript +adaptive.assessPolicy(context) + .then((result) => { + res.send(result); + }).catch((error) => { + console.log(error); + res.status(404).send({error: error.message}); + }); +``` + +### Lookup Identity Sources + +Lookup identity sources by name. If name not defined then return all password-capable sources. + +#### `lookupIdentitySources(context, transactionId, [sourceName])` + +| Parameter | Type | Description | +| --------------- | -------- | ------------------------------------------------------------------ | +| `context` | `Object` | See [Context Object](#context-object). | +| `transactionId` | `string` | The transaction ID received in [`assessPolicy`](#assess-a-policy). | +| `[sourceName]` | `string` | (Optional) name of identity source. e.g. "Cloud Directory". | + +#### Response + +* A response containing an array of identity source objects: + ```javascript + [ + { + "name": "Cloud Directory", + "location": "https:///v1.0/authnmethods/password/11111111-2222-3333-4444-555555555555", + "id": "11111111-2222-3333-4444-555555555555", + "type": "ibmldap" + } + ] + ``` + +#### Example Usage + +```javascript +let identitySourceId +adaptive.lookupIdentitySources(context, transactionId, "Cloud Directory") + .then((result) => { + identitySourceId = result[0].id; + }).catch((error) => { + console.log(error); + res.status(404).send({error: error.message}); + }); +``` + +### Evaluate a password verification + +Attempt to complete a password first-factor verification after +receiving a `requires` status from [`assessPolicy`](#assess-a-policy). This will result in either an `allow`, `deny`, or `requires` response. + +#### `evaluatePassword(context, transactionId, identitySourceId, username, password)` + +| Parameter | Type | Description | +| ------------------ | -------- | -------------------------------------------------------------------------------- | +| `context` | `Object` | See [Context Object](#context-object). | +| `transactionId` | `string` | The transaction ID received in [`assessPolicy`](#assess-a-policy). | +| `identitySourceId` | `string` | The identifier of the identity source associated with the password registration. | +| `username` | `string` | The username to authenticate as. | +| `password` | `string` | The password to authenticate with. | + +#### Responses + +* An `allow` response will contain a token to access the API with. + ```javascript + { + "status": "allow", + "token": { + "access_token": "zscmjBdvIjudOPLhpbmJi6nBRJg7cZ6WY0Udw1nC", + "refresh_token": "wFTjurPxTvRD1cW09itgQM83XwCm1UKwsxhVFb1H7HJh8JkwZz", + "scope": "openid", + "grant_id": "a0b440b6-fefb-46ea-a603-e1040534cd28", + "id_token": "eyJhbGciOiJSUzI1NiIsInR5cC...5j_rMn7H3ZpE4axt0WvsYu4jbA", + "token_type": "Bearer", + "expires_in": 7120 + } + } + ``` + +* A `deny` response is received when the policy denies access or policy evaluation fails. If error information is available, it will be returned in a details attribute. + ```javascript + { + "status": "deny" + "detail": { + "error": "adaptive_more_info_required", + "error_description": "CSIAQ0298E Adaptive access..." + } + } + ``` + +* A `requires` response will contain an array of allowed authentication +enrollments, indicating that further verification is required (i.e. second-factor +verification must be performed) to receive a token. The possible multi-factor +enrollments are `"emailotp"`, `"smsotp"`, `"voiceotp"`, `"totp"`, `"questions"`, `"push"` and `"fido"`. +You can use the +[`generateEmailOTP`](#generate-an-email-otp-verification), +[`generateSMSOTP`](#generate-an-sms-otp-verification), +[`generateVoiceOTP`](#generate-a-voice-otp-verification), +[`evaluateTOTP`](#evaluate-a-totp-verification), +[`generateQuestions`](#generate-a-knowledge-questions-verification), [`generatePush`](#generate-a-push-verification), +and [`generateFIDO`](#generate-a-fido-verification) functions respectively to +perform these 2FA verifications. You can use any of the returned enrollments to perform the second-factor authentication. Your initial transaction ID will also be +returned. + ```javascript + { + "status": "requires", + "transactionId": "36a101c7-7426-4f45-ab3c-55f8dc075c6e", + "enrolledFactors": [ + { + "id": "61e39f0a-836b-48fa-b4c9-cface6a3ef5a", + "userId": "60300035KP", + "type": "emailotp", + "created": "2020-06-15T02:51:49.131Z", + "updated": "2020-06-15T03:15:18.896Z", + "attempted": "2020-07-16T04:30:14.066Z", + "enabled": true, + "validated": true, + "attributes": { + "emailAddress": "email@email.com" + } + } + ] + } + ``` + +#### Example Usage + +```javascript +adaptive.evaluatePassword(context, transactionId, identitySourceId, username, password) + .then((result) => { + res.send(result); + }).catch((error) => { + console.log(error); + res.status(404).send({error: error.message}); + }); +``` + +### Generate a FIDO verification + +Initiate a FIDO first-factor verification after receiving a `requires` status +from [`assessPolicy`](#assess-a-policy), or a FIDO second-factor verification after +receiving a `requires` status from a first-factor completion +([`evaluateQR`](#evaluate-a-qr-login-verification), +[`evaluatePassword`](#evaluate-a-password-verification), or +[`evaluateFIDO`](#evaluate-a-fido-verification)). This will return a FIDO +challenge to be sent back to the user for signing. + +#### `generateFIDO(context, transactionId, relyingPartyId, userId)` + +| Parameter | Type | Description | +| ---------------- | -------- | -------------------------------------------------------------------------- | +| `context` | `Object` | See [Context Object](#context-object). | +| `transactionId` | `string` | The transaction ID received in [`assessPolicy`](#assess-a-policy). | +| `relyingPartyId` | `string` | The identifier of the relying party associated with the FIDO registration. | +| `userId` | `string` | The identifier of the OIDC user for which to initiate a FIDO verification. | + +#### Response + +* The response will contain a FIDO challenge to be signed by your authenticator, +then sent to [`evaluateFIDO`](#evaluate-a-fido-verification) for +completion. Your initial transaction ID will also be returned. + ```javascript + { + "transactionId": "36a101c7-7426-4f45-ab3c-55f8dc075c6e", + "fido": { + "rpId": "fido.verify.ibm.com", + "challenge": "Q29uZ3JhdHVsYXRpb25zIFlvdSBmb3VuZCBpdAo", + "userVerification": "preferred", + "timeout": 30000, + "allowCredentials": [ + { + "type": "public-key", + "id": "SSBhbSBhIGNyZWRlbnRpYWwK" + } + ] + } + } + ``` + +#### Example Usage + +```javascript +adaptive.generateFIDO(context, transactionId, relyingPartyId, userId) + .then((result) => { + res.send(result); + }).catch((error) => { + console.log(error); + res.status(404).send({error: error.message}); + }); +``` + +### Evaluate a FIDO verification + +Complete a FIDO verification after receiving and signing a FIDO +challenge from [`generateFIDO`](#generate-a-fido-verification). This +will result in either an `allow`, `deny`, or `requires` response. + +#### `evaluateFIDO(context, transactionId, relyingPartyId, authenticatorData, userHandle, signature, clientDataJSON)` + +| Parameter | Type | Description | +| ------------------- | -------- | -------------------------------------------------------------------------------------------- | +| `context` | `Object` | See [Context Object](#context-object). | +| `transactionId` | `string` | The transaction ID received in [`assessPolicy`](#assess-a-policy). | +| `relyingPartyId` | `string` | The identifier of the relying party associated with the FIDO registration. | +| `authenticatorData` | `string` | The information about the authentication produced by the authenticator. | +| `userHandle` | `string` | The identifier for the user who owns this authenticator. | +| `signature` | `string` | The received and signed FIDO challenge from [`generateFIDO`](#generate-a-fido-verification). | +| `clientDataJSON` | `string` | The base64 encoded client data JSON object. | + +#### Responses + +* An `allow` response will contain a token to access the API with. + ```javascript + { + "status": "allow", + "token": { + "access_token": "zscmjBdvIjudOPLhpbmJi6nBRJg7cZ6WY0Udw1nC", + "refresh_token": "wFTjurPxTvRD1cW09itgQM83XwCm1UKwsxhVFb1H7HJh8JkwZz", + "scope": "openid", + "grant_id": "a0b440b6-fefb-46ea-a603-e1040534cd28", + "id_token": "eyJhbGciOiJSUzI1NiIsInR5cC...5j_rMn7H3ZpE4axt0WvsYu4jbA", + "token_type": "Bearer", + "expires_in": 7120 + } + } + ``` + +* A `deny` response is received when the policy denies access or policy evaluation fails. If error information is available, it will be returned in a details attribute. + ```javascript + { + "status": "deny" + "detail": { + "error": "adaptive_more_info_required", + "error_description": "CSIAQ0298E Adaptive access..." + } + } + ``` + +* A `requires` response can only be received during first factor verification. In that case, the response will contain an array of allowed authentication +enrollments, indicating that further verification is required (i.e. second-factor +verification must be performed) to receive a token. The possible multi-factor +enrollments are `"emailotp"`, `"smsotp"`, `"voiceotp"`, `"totp"`, `"questions"`, `"push"` and `"fido"`. +You can use the +[`generateEmailOTP`](#generate-an-email-otp-verification), +[`generateSMSOTP`](#generate-an-sms-otp-verification), +[`generateVoiceOTP`](#generate-a-voice-otp-verification), +[`evaluateTOTP`](#evaluate-a-totp-verification), +[`generateQuestions`](#generate-a-knowledge-questions-verification), [`generatePush`](#generate-a-push-verification), +and [`generateFIDO`](#generate-a-fido-verification) functions respectively to +perform these 2FA verifications. You can use any of the returned enrollments to perform the second-factor authentication. Your initial transaction ID will also be +returned. + ```javascript + { + "status": "requires", + "transactionId": "36a101c7-7426-4f45-ab3c-55f8dc075c6e", + "enrolledFactors": [ + { + "id": "61e39f0a-836b-48fa-b4c9-cface6a3ef5a", + "userId": "60300035KP", + "type": "emailotp", + "created": "2020-06-15T02:51:49.131Z", + "updated": "2020-06-15T03:15:18.896Z", + "attempted": "2020-07-16T04:30:14.066Z", + "enabled": true, + "validated": true, + "attributes": { + "emailAddress": "email@email.com" + } + } + ] + } + ``` + +#### Example Usage + +```javascript +adaptive.evaluateFIDO(context, transactionId, relyingPartyId, authenticatorData, userHandle, signature, clientDataJSON) + .then((result) => { + res.send(result); + }).catch((error) => { + console.log(error); + res.status(404).send({error: error.message}); + }); +``` + +### Generate a QR login verification + +Initiate a QR login first-factor verification after receiving a `requires` +status from [`assessPolicy`](#assess-a-policy). This will return a QR login +code to be sent back to the user for scanning. + +#### `generateQR(context, transactionId, profileId)` + +| Parameter | Type | Description | +| --------------- | -------- | ------------------------------------------------------------------ | +| `context` | `Object` | See [Context Object](#context-object). | +| `transactionId` | `string` | The transaction ID received in [`assessPolicy`](#assess-a-policy). | +| `profileId` | `string` | The identifier of an IBM Verify registration profile. | + +#### Response + +* The response will contain a QR login code to be scanned by your authenticator. Upon scanning, the authenticator should send a request to [`evaluateQR`](#evaluate-a-qr-login-verification) for +completion. Your initial transaction ID will also be returned. + ```javascript + { + "transactionId": "36a101c7-7426-4f45-ab3c-55f8dc075c6e", + "qr": { + "code": "iVBORw0KGgoAAAANSUhEUgAAASwAAAEsAQAAAABR..." + } + } + ``` + +#### Example Usage + +```javascript +adaptive.generateQR(context, transactionId, profileId) + .then((result) => { + res.send(result); + }).catch((error) => { + console.log(error); + res.status(404).send({error: error.message}); + }); +``` + +### Evaluate a QR login verification + +Complete a QR login first-factor verification after receiving and scanning a QR +login code from [`generateQR`](#generate-a-qr-login-verification). +This will result in either a `pending`, `timeout`, `error`, `allow`, `deny`, or `requires` response. + +#### `evaluateQR(context, transactionId)` + +| Parameter | Type | Description | +| --------------- | -------- | ------------------------------------------------------------------ | +| `context` | `Object` | See [Context Object](#context-object). | +| `transactionId` | `string` | The transaction ID received in [`assessPolicy`](#assess-a-policy). | + +#### Responses + +* A `pending` response indicates the QR code transaction has not yet been completed. + ```javascript + { + "status": "pending", + "expiry": "2021-04-26T12:06:06.501Z" + } + ``` +* A `timeout` response indicates the QR code transaction has timed out. + ```javascript + { + "status": "timeout", + "expiry": "2021-04-26T12:06:06.501Z" + } + ``` + +* An `error` response indicates an error querying the QR code transaction. + ```javascript + { + "status": "error" + } + ``` + +* An `allow` response will contain a token to access the API with. + ```javascript + { + "status": "allow", + "token": { + "access_token": "zscmjBdvIjudOPLhpbmJi6nBRJg7cZ6WY0Udw1nC", + "refresh_token": "wFTjurPxTvRD1cW09itgQM83XwCm1UKwsxhVFb1H7HJh8JkwZz", + "scope": "openid", + "grant_id": "a0b440b6-fefb-46ea-a603-e1040534cd28", + "id_token": "eyJhbGciOiJSUzI1NiIsInR5cC...5j_rMn7H3ZpE4axt0WvsYu4jbA", + "token_type": "Bearer", + "expires_in": 7120 + } + } + ``` + +* A `deny` response is received when the policy denies access or policy evaluation fails. If error information is available, it will be returned in a details attribute. + ```javascript + { + "status": "deny" + "detail": { + "error": "adaptive_more_info_required", + "error_description": "CSIAQ0298E Adaptive access..." + } + } + ``` + +* A `requires` response will contain an array of allowed authentication +enrollments, indicating that further verification is required (i.e. second-factor +verification must be performed) to receive a token. The possible multi-factor +enrollments are `"emailotp"`, `"smsotp"`, `"voiceotp"`, `"totp"`, `"questions"`, `"push"` and `"fido"`. +You can use the +[`generateEmailOTP`](#generate-an-email-otp-verification), +[`generateSMSOTP`](#generate-an-sms-otp-verification), +[`generateVoiceOTP`](#generate-a-voice-otp-verification), +[`evaluateTOTP`](#evaluate-a-totp-verification), +[`generateQuestions`](#generate-a-knowledge-questions-verification), [`generatePush`](#generate-a-push-verification), +and [`generateFIDO`](#generate-a-fido-verification) functions respectively to +perform these 2FA verifications. You can use any of the returned enrollments to perform the second-factor authentication. Your initial transaction ID will also be +returned. + ```javascript + { + "status": "requires", + "transactionId": "36a101c7-7426-4f45-ab3c-55f8dc075c6e", + "enrolledFactors": [ + { + "id": "61e39f0a-836b-48fa-b4c9-cface6a3ef5a", + "userId": "60300035KP", + "type": "emailotp", + "created": "2020-06-15T02:51:49.131Z", + "updated": "2020-06-15T03:15:18.896Z", + "attempted": "2020-07-16T04:30:14.066Z", + "enabled": true, + "validated": true, + "attributes": { + "emailAddress": "email@email.com" + } + } + ] + } + ``` + +#### Example Usage + +```javascript +adaptive.evaluateQR(context, transactionId) + .then((result) => { + res.send(result); + }).catch((error) => { + console.log(error); + res.status(404).send({error: error.message}); + }); +``` + +### Generate an email OTP verification + +Request an email OTP multi-factor verification after receiving a `requires` +status from a first factor completion +([`evaluateQR`](#evaluate-a-qr-login-verification), +[`evaluatePassword`](#evaluate-a-password-verification), or +[`evaluateFIDO`](#evaluate-a-fido-verification)). This will send an +OTP to the enroled email address of the user, and return a four-digit +correlation associated with the verification. This correlation will be prefixed +to the one-time password in the SMS to be sent. + +#### `generateEmailOTP(context, transactionId, enrollmentId)` + +| Parameter | Type | Description | +| --------------- | -------- | ----------------------------------------------------------------------------------------------------------- | +| `context` | `Object` | See [Context Object](#context-object). | +| `transactionId` | `string` | The transaction ID received in [`evaluatePolicy`](#evaluate-a-policy). | +| `enrollmentId` | `string` | The identifier of the email OTP enrollment, received in a `requires` response after a first-factor attempt. | + +#### Example Usage + +```javascript +adaptive.generateEmailOTP(context, transactionId, enrollmentId) + .then((result) =>{ + res.send(result); + }).catch((error) => { + console.log(error); + res.status(404).send({error: error.message}); + }); +``` + +### Generate an SMS OTP verification + +Request an SMS OTP multi-factor verification after receiving a `requires` status +from a first factor completion +([`evaluateQR`](#evaluate-a-qr-login-verification), +[`evaluatePassword`](#evaluate-a-password-verification), or +[`evaluateFIDO`](#evaluate-a-fido-verification)). This will send an +OTP to the phone number of the user, and return a four-digit correlation +associated with the verification. This correlation will be prefixed to the +one-time password in the SMS to be sent. + +#### `generateSMSOTP(context, transactionId, enrollmentId)` + +| Parameter | Type | Description | +| --------------- | -------- | --------------------------------------------------------------------------------------------------------- | +| `context` | `Object` | See [Context Object](#context-object). | +| `transactionId` | `string` | The transaction ID received in [`assess`](#assess-a-policy). | +| `enrollmentId` | `string` | The identifier of the SMS OTP enrollment, received in a `requires` response after a first-factor attempt. | + +#### Example Usage + +```javascript +adaptive.generateSMSOTP(context, transactionId, enrollmentId) + .then((result) =>{ + res.send(result); + }).catch((error) => { + console.log(error); + res.status(404).send({error: error.message}); + }); +``` + +### Evaluate a TOTP verification + +Verify a TOTP second-factor verification after receiving a +`requires` status after a first-factor attempt +([`evaluateQR`](#evaluate-a-qr-login-verification), +[`evaluatePassword`](#evaluate-a-password-verification), or +[`evaluateFIDO`](#evaluate-a-fido-verification)). On successful verification, this will result in an `allow` response. + +#### `evaluateTOTP(context, transactionId, enrollmentId, otp)` + +| Parameter | Type | Description | +| --------------- | -------- | ------------------------------------------------------------------------------------------------------ | +| `context` | `Object` | See [Context Object](#context-object). | +| `transactionId` | `string` | The transaction ID received in [`assessPolicy`](#assess-a-policy). | +| `enrollmentId` | `string` | The identifier of the TOTP enrollment, received in a `requires` response after a first-factor attempt. | +| `otp` | `string` | The TOTP to verify with. | + +#### Responses + +* An `allow` response will contain a token to access the API with. + ```javascript + { + "status": "allow", + "token": { + "access_token": "zscmjBdvIjudOPLhpbmJi6nBRJg7cZ6WY0Udw1nC", + "refresh_token": "wFTjurPxTvRD1cW09itgQM83XwCm1UKwsxhVFb1H7HJh8JkwZz", + "scope": "openid", + "grant_id": "a0b440b6-fefb-46ea-a603-e1040534cd28", + "id_token": "eyJhbGciOiJSUzI1NiIsInR5cC...5j_rMn7H3ZpE4axt0WvsYu4jbA", + "token_type": "Bearer", + "expires_in": 7120 + } + } + ``` + +#### Example Usage + +```javascript +adaptive.evaluateTOTP(context, transactionId, enrollmentId, otp) + .then((result) => { + res.send(result); + }).catch((error) => { + console.log(error); + res.status(404).send({error: error.message}); + }); +``` + +### Evaluate an email OTP verification + +Verify an email OTP second-factor verification after receiving an email OTP from [`generateEmailOTP`](#generate-an-email-otp-verification). On successful verification, this will result in an `allow` response. + +#### `evaluateEmailOTP(context, transactionId, otp)` + +| Parameter | Type | Description | +| --------------- | -------- | ------------------------------------------------------------------------------------------------------------------ | +| `context` | `Object` | See [Context Object](#context-object). | +| `transactionId` | `string` | The transaction ID received in [`assessPolicy`](#assess-a-policy). | +| `otp` | `string` | The email OTP to verify with. This OTP shouldn't include the correlation prefix (the four digits before the dash). | + +#### Responses + +* An `allow` response will contain a token to access the API with. + ```javascript + { + "status": "allow", + "token": { + "access_token": "zscmjBdvIjudOPLhpbmJi6nBRJg7cZ6WY0Udw1nC", + "refresh_token": "wFTjurPxTvRD1cW09itgQM83XwCm1UKwsxhVFb1H7HJh8JkwZz", + "scope": "openid", + "grant_id": "a0b440b6-fefb-46ea-a603-e1040534cd28", + "id_token": "eyJhbGciOiJSUzI1NiIsInR5cC...5j_rMn7H3ZpE4axt0WvsYu4jbA", + "token_type": "Bearer", + "expires_in": 7120 + } + } + ``` + +#### Example Usage + +```javascript +adaptive.evaluateEmailOTP(context, transactionId, otp) + .then((result) => { + res.send(result); + }).catch((error) => { + console.log(error); + res.status(404).send({error: error.message}); + }); +``` + +### Evaluate an SMS OTP verification + +Verify an SMS OTP second-factor verification after receiving an SMS OTP from [`generateSMSOTP`](#generate-an-sms-otp-verification). On successful verification, this will result in an `allow` response. + +#### `evaluateSMSOTP(transactionId, otp)` + +| Parameter | Type | Description | +| --------------- | -------- | ---------------------------------------------------------------------------------------------------------------- | +| `context` | `Object` | See [Context Object](#context-object). | +| `transactionId` | `string` | The transaction ID received in [`assessPolicy`](#assess-a-policy). | +| `otp` | `string` | The SMS OTP to verify with. This OTP shouldn't include the correlation prefix (the four digits before the dash). | + +#### Responses + +* An `allow` response will contain a token to access the API with. + ```javascript + { + "status": "allow", + "token": { + "access_token": "zscmjBdvIjudOPLhpbmJi6nBRJg7cZ6WY0Udw1nC", + "refresh_token": "wFTjurPxTvRD1cW09itgQM83XwCm1UKwsxhVFb1H7HJh8JkwZz", + "scope": "openid", + "grant_id": "a0b440b6-fefb-46ea-a603-e1040534cd28", + "id_token": "eyJhbGciOiJSUzI1NiIsInR5cC...5j_rMn7H3ZpE4axt0WvsYu4jbA", + "token_type": "Bearer", + "expires_in": 7120 + } + } + ``` + +#### Example Usage + +```javascript +adaptive.evaluateSMSOTP(context, transactionId, otp) + .then((result) => { + res.send(result); + }).catch((error) => { + console.log(error); + res.status(404).send({error: error.message}); + }); +``` + +### Generate a knowledge questions verification + +Request a knowledge questions second-factor verification after receiving a +`requires` status from a first-factor completion +([`evaluateQR`](#evaluate-a-qr-login-verification), +[`evaluatePassword`](#evaluate-a-password-verification), or +[`evaluateFIDO`](#evaluate-a-fido-verification)). This will return a +set of the user's knowledge questions to answer. + +#### `generateQuestions(context, transactionId, enrollmentId)` + +| Parameter | Type | Description | +| --------------- | -------- | --------------------------------------------------------------------------------------------------------------------- | +| `context` | `Object` | See [Context Object](#context-object). | +| `transactionId` | `string` | The transaction ID received in [`assessPolicy`](#assess-a-policy). | +| `enrollmentId` | `string` | The identifier of the knowledge questions enrollment, received in a `requires` response after a first-factor attempt. | + +#### Response + +* The response will contain a set of knowledge questions to be answered by the +user, then sent to +[`evaluateQuestions`](#evaluate-a-knowledge-questions-verification) for +completion. Your initial transaction ID will also be returned. + ```javascript + { + "transactionId": "36a101c7-7426-4f45-ab3c-55f8dc075c6e", + "questions": [ + { + "questionKey": "firstHouseStreet", + "question": "What was the street name of the first house you ever lived in?" + }, + { + "questionKey": "bestFriend", + "question": "What is the first name of your best friend?" + }, + { + "questionKey": "mothersMaidenName", + "question": "What is your mothers maiden name?" + } + ] + } + ``` + +#### Example Usage + +```javascript +adaptive.generateQuestions(context, transactionId, enrollmentId) + .then((result) => { + res.send(result); + }).catch((error) => { + console.log(error); + res.status(404).send({error: error.message}); + }); +``` + +### Evaluate a knowledge questions verification + +Verify a knowledge questions second-factor verification after receiving and +answering a set of knowledge questions from +[`generateQuestions`](#generate-a-knowledge-questions-verification). +On successful verification, this will result in an `allow` response. + +#### `evaluateQuestions(context, transactionId, questions)` + +| Parameter | Type | Description | +| ------------------------- | ---------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `context` | `Object` | See [Context Object](#context-object). | +| `transactionId` | `string` | The transaction ID received in [`assessPolicy`](#assess-a-policy). | +| `questions` | `Object[]` | The array of objects with a question key (received from [`generateQuestions`](#generate-a-knowledge-questions-verification)) and corresponding answer to verify with. | +| `questions[].questionKey` | `string` | The identifier of the question received from [`generateQuestions`](#generate-a-knowledge-questions-verification). | +| `questions[].answer` | `string` | The answer to the question. | + +#### Responses + +* An `allow` response will contain a token to access the API with. + ```javascript + { + "status": "allow", + "token": { + "access_token": "zscmjBdvIjudOPLhpbmJi6nBRJg7cZ6WY0Udw1nC", + "refresh_token": "wFTjurPxTvRD1cW09itgQM83XwCm1UKwsxhVFb1H7HJh8JkwZz", + "scope": "openid", + "grant_id": "a0b440b6-fefb-46ea-a603-e1040534cd28", + "id_token": "eyJhbGciOiJSUzI1NiIsInR5cC...5j_rMn7H3ZpE4axt0WvsYu4jbA", + "token_type": "Bearer", + "expires_in": 7120 + } + } + ``` + +#### Example Usage + +```javascript +adaptive.evaluateQuestions(context, transactionId, questions) + .then((result) => { + res.send(result); + }).catch((error) => { + console.log(error); + res.status(404).send({error: error.message}); + }); +``` + +### Generate a push notification verification + +Request a push notification second-factor verification after receiving a +`requires` status from a first-factor completion +([`evaluateQR`](#evaluate-a-qr-login-verification), +[`evaluatePassword`](#evaluate-a-password-verification), or +[`evaluateFIDO`](#evaluate-a-fido-verification)). This will return a correlation code associated with the verification transaction. + +#### `generatePush(context, transactionId, enrollmentId, authenticatorId, message, pushNotificationTitle, pushNotificationMessage, additionalData)` + +| Parameter | Type | Description | +| ------------------------- | ---------- | ---------------------------------------------------------------------------------------- | +| `context` | `Object` | See [Context Object](#context-object). | +| `transactionId` | `string` | The transaction ID received in [`assessPolicy`](#assess-a-policy). | +| `enrollmentId` | `string` | The identifier of the signature enrollment to perform second-factor verification with. | +| `authenticatorId` | `string` | The identifier of the authenticator belonging to the signature. | +| `message` | `string` | The verification message to be displayed in-app. | +| `pushNotificationTitle` | `string` | The title to be displayed in the push notification banner. | +| `pushNotificationMessage` | `string` | The message to be displayed in the push notification banner. | +| `additionalData` | `Object[]` | An array of objects containing `"name"` and `"value"` attributes to be displayed in-app. | + +#### Example Usage + +```javascript +adaptive.generatePush(context, transactionId, enrollmentId, authenticatorId, message, pushNotificationMessage, pushNotificationMessage, additionalData) + .then((result) => { + res.send(result); + }).catch((error) => { + console.log(error); + res.status(404).send({error: error.message}); + }); +``` + +### Evaluate a push notification verification + +Verify a push notification second-factor verification after receiving a push notification [`generatePush`](#generate-a-push-notification-verification). On successful verification, this will result in an `allow` response. + +#### `evaluatePush(context, transactionId)` + +| Parameter | Type | Description | +| --------------- | -------- | ------------------------------------------------------------------ | +| `context` | `Object` | See [Context Object](#context-object). | +| `transactionId` | `string` | The transaction ID received in [`assessPolicy`](#assess-a-policy). | + +#### Responses + +* A `pending` response indicates the transaction has not yet been completed. + ```javascript + { + "status": "pending", + "expiry": "2021-04-26T12:06:06.501Z", + "pushState": "SUCCESS" + } + ``` +* A `timeout` response indicates the transaction has timed out. + ```javascript + { + "status": "timeout", + "expiry": "2021-04-26T12:06:06.501Z", + "pushState": "SUCCESS" + } + ``` + +* An `error` response indicates an error querying transaction. + ```javascript + { + "status": "error" + } + ``` + +* An `allow` response will contain a token to access the API with. + ```javascript + { + "status": "allow", + "token": { + "access_token": "zscmjBdvIjudOPLhpbmJi6nBRJg7cZ6WY0Udw1nC", + "refresh_token": "wFTjurPxTvRD1cW09itgQM83XwCm1UKwsxhVFb1H7HJh8JkwZz", + "scope": "openid", + "grant_id": "a0b440b6-fefb-46ea-a603-e1040534cd28", + "id_token": "eyJhbGciOiJSUzI1NiIsInR5cC...5j_rMn7H3ZpE4axt0WvsYu4jbA", + "token_type": "Bearer", + "expires_in": 7120 + } + } + ``` + +#### Example Usage + +```javascript +adaptive.evaluatePush(context, transactionId) + .then((result) => { + res.send(result); + }).catch((error) => { + console.log(error); + res.status(404).send({error: error.message}); + }); +``` + +### Get Access Token for a transaction + +Get the Access Token associated with the in-progress transaction. + +#### `getToken(transactionId)` + +| Parameter | Type | Description | +| --------------- | -------- | ------------------------------------------------------------------ | +| `transactionId` | `string` | The transaction ID received in [`assessPolicy`](#assess-a-policy). | + +#### Response +A String is returned containing the Access Token associated with the transaction. + +#### Example Usage + +```javascript +var txnAccessToken = adaptive.getToken(transactionId); +``` + +### Logout + +End the user's session. + +#### `logout(accessToken)` + +| Parameter | Type | Description | +| ------------- | -------- | ------------------------------------------------------------------------------ | +| `accessToken` | `string` | The access token to revoke, received after a successful second-factor attempt. | + +#### Example Usage + +```javascript +adaptive.logout(accessToken) + .then(() =>{ + res.send(); // Nothing to return + }).catch((error) => { + console.log(error); + res.status(404).send({error: error.message}); + }); +``` + +### Refresh + +Initiate an OAuth Refresh flow to obtain updated tokens. + +#### `refresh(context, refreshToken)` + +| Parameter | Type | Description | +| -------------- | -------- | --------------------------------------------------- | +| `context` | `Object` | See [Context Object](#context-object). | +| `refreshToken` | `string` | The refresh token to refresh the access token with. | + +#### Responses + +* An `allow` response will contain a token to access the API with, along with a new refresh token. + ```javascript + { + "status": "allow", + "token": { + "access_token": "zscmjBdvIjudOPLhpbmJi6nBRJg7cZ6WY0Udw1nC", + "refresh_token": "wFTjurPxTvRD1cW09itgQM83XwCm1UKwsxhVFb1H7HJh8JkwZz", + "scope": "openid", + "grant_id": "a0b440b6-fefb-46ea-a603-e1040534cd28", + "id_token": "eyJhbGciOiJSUzI1NiIsInR5cC...5j_rMn7H3ZpE4axt0WvsYu4jbA", + "token_type": "Bearer", + "expires_in": 7120 + } + } + ``` + +* A `deny` response is received when the policy denies access or policy evaluation fails. If error information is available, it will be returned in a details attribute. + ```javascript + { + "status": "deny" + "detail": { + "error": "adaptive_more_info_required", + "error_description": "CSIAQ0298E Adaptive access..." + } + } + ``` + +* A `requires` response will contain an array of allowed authentication +enrollments, indicating that further verification is required (i.e. second-factor +verification must be performed) to receive a token. The possible multi-factor +enrollments are `"emailotp"`, `"smsotp"`, `"voiceotp"`, `"totp"`, `"questions"`, `"push"` and `"fido"`. +You can use the +[`generateEmailOTP`](#generate-an-email-otp-verification), +[`generateSMSOTP`](#generate-an-sms-otp-verification), +[`generateVoiceOTP`](#generate-a-voice-otp-verification), +[`evaluateTOTP`](#evaluate-a-totp-verification), +[`generateQuestions`](#generate-a-knowledge-questions-verification), [`generatePush`](#generate-a-push-verification), +and [`generateFIDO`](#generate-a-fido-verification) functions respectively to +perform these 2FA verifications. You can use any of the returned enrollments to perform the second-factor authentication. Your initial transaction ID will also be +returned. + ```javascript + { + "status": "requires", + "transactionId": "36a101c7-7426-4f45-ab3c-55f8dc075c6e", + "enrolledFactors": [ + { + "id": "61e39f0a-836b-48fa-b4c9-cface6a3ef5a", + "userId": "60300035KP", + "type": "emailotp", + "created": "2020-06-15T02:51:49.131Z", + "updated": "2020-06-15T03:15:18.896Z", + "attempted": "2020-07-16T04:30:14.066Z", + "enabled": true, + "validated": true, + "attributes": { + "emailAddress": "email@email.com" + } + } + ] + } + ``` + +#### Example Usage + +```javascript +adaptive.refresh(context, refreshToken) + .then((result) => { + res.send(result); + }).catch((error) => { + console.log(error); + res.status(404).send({error: error.message}); + }); +``` + +### Introspect + +Introspect a refresh or access token. + +#### `introspect(token, [tokenTypeHint])` + +| Parameter | Type | Description | +| ----------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `token` | `string` | The refresh or access token to introspect. | +| `[tokenTypeHint]` | `string` | The token type. This attribute is an optional hint about the token that is being introspected. Possible values are `access_token` and `refresh_token`. | + +#### Responses + +* The response will contain an `active` property which indicates whether the introspected token is valid or invalid. Other properties will also be included when the `active` status is `true`. + ```javascript + { + "at_hash": "SivVIXwh1lUxzFHqPAMxJQ", + "ext": { + "tenantId": "..." + }, + "sub": "6040004OML", + "realmName": "cloudIdentityRealm", + "entitlements" : [ + ... + ] + "amr": [ + "emailotp", + "password" + ], + "uniqueSecurityName": "6040004OML", + "iss": "https://.../oidc/endpoint/default", + "active": true, + "preferred_username": "name", + "token_type": "Bearer", + "client_id": "57bd5573-73cf-48e5-a42c-656bd2d2ad06", + "aud": "57bd5573-73cf-48e5-a42c-656bd2d2ad06", + "acr": "urn:ibm:security:policy:id:331844", + "grant_type": "urn:ietf:params:oauth:grant-type:jwt-bearer", + "restrictEntitlements": false, + "scope": "openid", + "grant_id": "393168ec-eb53-46b8-9957-64158719f075", + "userType": "regular", + "category": "application", + "exp": 1598346175, + "app_id": "2624486582876118578", + "iat": 1598338975 + } + ``` + +#### Example Usage + +```javascript +adaptive.introspect(token, tokenTypeHint) + .then((result) => { + res.send(result); + }).catch((error) => { + console.log(error); + res.status(404).send({error: error.message}); + }); +``` + +### Introspect Middleware + +This function returns an Express middleware function, which has a signature of `(req, res, next) => ()`. This middleware will call the [`introspect`](#introspect) function under the hood, and perform additional checks based on the configuration object. If token introspection succeeds, the next middleware will be called in the stack. If an error occurs during token introspection, the error will be passed to the `next()` function. You may write your custom error handler middleware to catch the error, and handle it accordingly. + +A successful introspection result is cached to save on expensive introspection calls for subsequent requests. + +#### `introspectMiddleware([config])` + +| Parameter | Type | Description | +| -------------------------------- | --------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `[config]` | `Object` | The configuration settings used for the token introspection middleware. | +| `[config.cacheMaxSize=0]` | `number` | The maximum size of the cache, i.e. the maximum number of successful token introspection responses to cache. If the cache becomes full, the least-recently-used introspection result will be removed. A value of `0` means no maximum size, i.e. infinity. This value is ignored after first initialisation (i.e. after first call to function). Default value is `0`. | +| `[config.cacheTTL=0]` | `number` | The time (in seconds) to cache a successful introspection result for. If a successful token introspection is done, the result will be cached for the period of time provided, to save expensive introspection calls on each subsequent request. A value of 0 will cache the introspect response for the lifetime of the token as provided in the `exp` property of the introspect response. Default value is `0`. | +| `[config.denyMFAChallenge=true]` | `boolean` | A flag indicating whether an introspected token response with a `scope` of `'mfa_challenge'` should be denied. If `true`, tokens with `scope` of `'mfa_challenge'` will be rejected. If `false`, the `scope` of tokens will be disregarded. | + +#### Example Usage + +```javascript +// Add the middleware so it's called at every request to a protected endpoint. +// Cache at most 50 successful introspection responses for 15 minutes each. +app.use('/protected', adaptive.introspectMiddleware({cacheMaxSize: 50, cacheTTL: 900, denyMFAChallenge: true})); + +// Optionally define a custom error handler, so any errors thrown by previous middleware can be handled. +app.use((err, req, res, next) => { + console.log(err.message); + res.sendStatus(403); +}); +``` + +## Demo + +A demo Node.js application using the Proxy SDK can be found in the +[demo](./demo) folder. + +## Documentation + +Full HTML documentation for the Proxy SDK can be found in the [docs](./docs) +folder. diff --git a/sdk/adaptive-proxy/demo/.env.example b/sdk/adaptive-proxy/demo/.env.example new file mode 100644 index 0000000..763bb8e --- /dev/null +++ b/sdk/adaptive-proxy/demo/.env.example @@ -0,0 +1,4 @@ +TENANT_URL=https://yourtenanturl.com +CLIENT_ID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx +CLIENT_SECRET=xxxxxxxxxx +IDENTITY_SOURCE_ID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx \ No newline at end of file diff --git a/sdk/adaptive-proxy/demo/README.md b/sdk/adaptive-proxy/demo/README.md new file mode 100644 index 0000000..7dac164 --- /dev/null +++ b/sdk/adaptive-proxy/demo/README.md @@ -0,0 +1,17 @@ +# Node.js Demo + +A Node.js demo using the Adaptive SDK. + +## Usage + +Install npm dependencies: + +```bash +npm install +``` + +To run the app on `localhost:3000`: + +```bash +node app.js +``` diff --git a/sdk/adaptive-proxy/demo/app.js b/sdk/adaptive-proxy/demo/app.js new file mode 100644 index 0000000..1df0f64 --- /dev/null +++ b/sdk/adaptive-proxy/demo/app.js @@ -0,0 +1,46 @@ +const reservationsRouter = require( + './components/reservations/reservationsRouter'); +const assessPolicy = require('./components/a2/assessPolicy'); +const evaluateFIDO = require('./components/a2/evaluateFIDO'); +const evaluateTOTP = require('./components/a2/evaluateTOTP'); +const evaluateEmailOTP = require('./components/a2/evaluateEmailOTP'); +const evaluateSMSOTP = require('./components/a2/evaluateSMSOTP'); +const evaluateQR = require('./components/a2/evaluateQR'); +const evaluateQuestions = require('./components/a2/evaluateQuestions'); +const evaluatePassword = require( + './components/a2/evaluatePassword'); +const evaluatePush = require( + './components/a2/evaluatePush'); +const generateEmailOTP = require('./components/a2/generateEmailOTP'); +const generateFIDO = require('./components/a2/generateFIDO'); +const generatePush = require('./components/a2/generatePush'); +const generateQR = require('./components/a2/generateQR'); +const generateQuestions = require('./components/a2/generateQuestions'); +const generateSMSOTP = require('./components/a2/generateSMSOTP'); +const logout = require('./components/a2/logout'); + +const express = require('express'); + + +const app = express(); +app.use(express.json(), + reservationsRouter, + assessPolicy, + evaluateFIDO, + evaluateTOTP, + evaluateEmailOTP, + evaluateSMSOTP, + evaluateQR, + evaluateQuestions, + evaluatePassword, + evaluatePush, + generateEmailOTP, + generateFIDO, + generatePush, + generateQR, + generateQuestions, + generateSMSOTP, + logout); + +const port = process.env.PORT || 3000; +app.listen(port, () => console.log(`Listening on port ${port}...`)); diff --git a/sdk/adaptive-proxy/demo/components/a2/adaptive.js b/sdk/adaptive-proxy/demo/components/a2/adaptive.js new file mode 100644 index 0000000..daaf181 --- /dev/null +++ b/sdk/adaptive-proxy/demo/components/a2/adaptive.js @@ -0,0 +1,16 @@ +// Import the Adaptive SDK. +const Adaptive = require('../../../lib/adaptive'); +// TODO: The above 'require' statement should normally be +// `require('adaptive-proxy-sdk')` after installing the 'adaptive-proxy-sdk' npm +// package. + +// Load contents of `.env` into `process.env`. +require('dotenv').config(); + +const config = { + tenantUrl: process.env.TENANT_URL, + clientId: process.env.CLIENT_ID, + clientSecret: process.env.CLIENT_SECRET, +}; + +module.exports = new Adaptive(config); diff --git a/sdk/adaptive-proxy/demo/components/a2/assessPolicy.js b/sdk/adaptive-proxy/demo/components/a2/assessPolicy.js new file mode 100644 index 0000000..e31ca0f --- /dev/null +++ b/sdk/adaptive-proxy/demo/components/a2/assessPolicy.js @@ -0,0 +1,28 @@ +const adaptive = require('./adaptive'); + +const express = require('express'); + + +// eslint-disable-next-line new-cap +const router = express.Router(); + +router.post('/assessments', (req, res) => { + // Extract parameters from request. + const sessionId = req.body.sessionId; + const userAgent = req.headers['user-agent']; + const ipAddress = req.ip; + const evaluationContext = req.body.evaluationContext; + const context = {sessionId, userAgent, ipAddress, + evaluationContext}; + + // Perform a risk assessment. + adaptive.assessPolicy(context) + .then((result) => { + res.send(result); + }).catch((error) => { + console.log(error); + res.status(404).send({error: error.message}); + }); +}); + +module.exports = router; diff --git a/sdk/adaptive-proxy/demo/components/a2/evaluateEmailOTP.js b/sdk/adaptive-proxy/demo/components/a2/evaluateEmailOTP.js new file mode 100644 index 0000000..6bd8021 --- /dev/null +++ b/sdk/adaptive-proxy/demo/components/a2/evaluateEmailOTP.js @@ -0,0 +1,31 @@ +const adaptive = require('./adaptive'); + +const express = require('express'); + + +// eslint-disable-next-line new-cap +const router = express.Router(); + +router.post('/evaluations/emailotp', (req, res) => { + const sessionId = req.body.sessionId; + const userAgent = req.headers['user-agent']; + const ipAddress = req.ip; + const evaluationContext = req.body.evaluationContext; + const context = {sessionId, userAgent, ipAddress, + evaluationContext}; + + // Extract parameters from request. + const transactionId = req.body.transactionId; + const otp = req.body.otp; + + // Verify an OTP factor. + adaptive.evaluateEmailOTP(context, transactionId, otp) + .then((result) => { + res.send(result); + }).catch((error) => { + console.log(error); + res.status(404).send({error: error.message}); + }); +}); + +module.exports = router; diff --git a/sdk/adaptive-proxy/demo/components/a2/evaluateFIDO.js b/sdk/adaptive-proxy/demo/components/a2/evaluateFIDO.js new file mode 100644 index 0000000..cce8631 --- /dev/null +++ b/sdk/adaptive-proxy/demo/components/a2/evaluateFIDO.js @@ -0,0 +1,36 @@ +const adaptive = require('./adaptive'); + +const express = require('express'); + + +// eslint-disable-next-line new-cap +const router = express.Router(); + +router.post('/evaluations/fido', (req, res) => { + const sessionId = req.body.sessionId; + const userAgent = req.headers['user-agent']; + const ipAddress = req.ip; + const evaluationContext = req.body.evaluationContext; + const context = {sessionId, userAgent, ipAddress, + evaluationContext}; + + // Extract parameters from request. + const transactionId = req.body.transactionId; + const relyingPartyId = req.body.relyingPartyId; + const authenticatorData = req.body.authenticatorData; + const userHandle = req.body.userHandle; + const signature = req.body.signature; + const clientDataJSON = req.body.clientDataJSON; + + // Verify a FIDO factor. + adaptive.evaluateFIDO(context, transactionId, relyingPartyId, + authenticatorData, userHandle, signature, clientDataJSON) + .then((result) => { + res.send(result); + }).catch((error) => { + console.log(error); + res.status(404).send({error: error.message}); + }); +}); + +module.exports = router; diff --git a/sdk/adaptive-proxy/demo/components/a2/evaluatePassword.js b/sdk/adaptive-proxy/demo/components/a2/evaluatePassword.js new file mode 100644 index 0000000..90e2586 --- /dev/null +++ b/sdk/adaptive-proxy/demo/components/a2/evaluatePassword.js @@ -0,0 +1,33 @@ +const adaptive = require('./adaptive'); + +const express = require('express'); + + +// eslint-disable-next-line new-cap +const router = express.Router(); + +router.post('/evaluations/password', (req, res) => { + const sessionId = req.body.sessionId; + const userAgent = req.headers['user-agent']; + const ipAddress = req.ip; + const evaluationContext = req.body.evaluationContext; + const context = {sessionId, userAgent, ipAddress, + evaluationContext}; + + // Extract parameters from request. + const transactionId = req.body.transactionId; + const username = req.body.username; + const password = req.body.password; + + // Verify a password factor. + adaptive.evaluatePassword(context, transactionId, + process.env.IDENTITY_SOURCE_ID, username, password) + .then((result) => { + res.send(result); + }).catch((error) => { + console.log(error); + res.status(404).send({error: error.message}); + }); +}); + +module.exports = router; diff --git a/sdk/adaptive-proxy/demo/components/a2/evaluatePush.js b/sdk/adaptive-proxy/demo/components/a2/evaluatePush.js new file mode 100644 index 0000000..9c91b95 --- /dev/null +++ b/sdk/adaptive-proxy/demo/components/a2/evaluatePush.js @@ -0,0 +1,34 @@ +const adaptive = require('./adaptive'); + +const express = require('express'); + + +// eslint-disable-next-line new-cap +const router = express.Router(); + +router.post('/evaluations/push', (req, res) => { + const sessionId = req.body.sessionId; + const userAgent = req.headers['user-agent']; + const ipAddress = req.ip; + const evaluationContext = req.body.evaluationContext; + const context = {sessionId, userAgent, ipAddress, + evaluationContext}; + + // Extract parameters from request. + const transactionId = req.body.transactionId; + const accessToken = req.body.accessToken; + const userAction = req.body.userAction; + const signedData = req.body.signedData; + + // Request a push verification. + adaptive.evaluatePush(context, transactionId, accessToken, userAction, + signedData) + .then((result) => { + res.send(result); + }).catch((error) => { + console.log(error); + res.status(404).send({error: error.message}); + }); +}); + +module.exports = router; diff --git a/sdk/adaptive-proxy/demo/components/a2/evaluateQR.js b/sdk/adaptive-proxy/demo/components/a2/evaluateQR.js new file mode 100644 index 0000000..98f3b7f --- /dev/null +++ b/sdk/adaptive-proxy/demo/components/a2/evaluateQR.js @@ -0,0 +1,31 @@ +const adaptive = require('./adaptive'); + +const express = require('express'); + + +// eslint-disable-next-line new-cap +const router = express.Router(); + +router.post('/evaluations/qr', (req, res) => { + const sessionId = req.body.sessionId; + const userAgent = req.headers['user-agent']; + const ipAddress = req.ip; + const evaluationContext = req.body.evaluationContext; + const context = {sessionId, userAgent, ipAddress, + evaluationContext}; + + // Extract parameters from request. + const transactionId = req.body.transactionId; + const accessToken = req.body.accessToken; + + // Verify a QR login factor. + adaptive.evaluateQR(context, transactionId, accessToken) + .then((result) => { + res.send(result); + }).catch((error) => { + console.log(error); + res.status(404).send({error: error.message}); + }); +}); + +module.exports = router; diff --git a/sdk/adaptive-proxy/demo/components/a2/evaluateQuestions.js b/sdk/adaptive-proxy/demo/components/a2/evaluateQuestions.js new file mode 100644 index 0000000..b296178 --- /dev/null +++ b/sdk/adaptive-proxy/demo/components/a2/evaluateQuestions.js @@ -0,0 +1,31 @@ +const adaptive = require('./adaptive'); + +const express = require('express'); + + +// eslint-disable-next-line new-cap +const router = express.Router(); + +router.post('/evaluations/questions', (req, res) => { + const sessionId = req.body.sessionId; + const userAgent = req.headers['user-agent']; + const ipAddress = req.ip; + const evaluationContext = req.body.evaluationContext; + const context = {sessionId, userAgent, ipAddress, + evaluationContext}; + + // Extract parameters from request. + const transactionId = req.body.transactionId; + const questions = req.body.questions; + + // Verify a knowledge questions factor. + adaptive.evaluateQuestions(context, transactionId, questions) + .then((result) => { + res.send(result); + }).catch((error) => { + console.log(error); + res.status(404).send({error: error.message}); + }); +}); + +module.exports = router; diff --git a/sdk/adaptive-proxy/demo/components/a2/evaluateSMSOTP.js b/sdk/adaptive-proxy/demo/components/a2/evaluateSMSOTP.js new file mode 100644 index 0000000..6ded871 --- /dev/null +++ b/sdk/adaptive-proxy/demo/components/a2/evaluateSMSOTP.js @@ -0,0 +1,31 @@ +const adaptive = require('./adaptive'); + +const express = require('express'); + + +// eslint-disable-next-line new-cap +const router = express.Router(); + +router.post('/evaluations/smsotp', (req, res) => { + const sessionId = req.body.sessionId; + const userAgent = req.headers['user-agent']; + const ipAddress = req.ip; + const evaluationContext = req.body.evaluationContext; + const context = {sessionId, userAgent, ipAddress, + evaluationContext}; + + // Extract parameters from request. + const transactionId = req.body.transactionId; + const otp = req.body.otp; + + // Verify an OTP factor. + adaptive.evaluateSMSOTP(context, transactionId, otp) + .then((result) => { + res.send(result); + }).catch((error) => { + console.log(error); + res.status(404).send({error: error.message}); + }); +}); + +module.exports = router; diff --git a/sdk/adaptive-proxy/demo/components/a2/evaluateTOTP.js b/sdk/adaptive-proxy/demo/components/a2/evaluateTOTP.js new file mode 100644 index 0000000..07c0f8b --- /dev/null +++ b/sdk/adaptive-proxy/demo/components/a2/evaluateTOTP.js @@ -0,0 +1,32 @@ +const adaptive = require('./adaptive'); + +const express = require('express'); + + +// eslint-disable-next-line new-cap +const router = express.Router(); + +router.post('/evaluations/totp', (req, res) => { + const sessionId = req.body.sessionId; + const userAgent = req.headers['user-agent']; + const ipAddress = req.ip; + const evaluationContext = req.body.evaluationContext; + const context = {sessionId, userAgent, ipAddress, + evaluationContext}; + + // Extract parameters from request. + const transactionId = req.body.transactionId; + const enrollmentId = req.body.enrollmentId; + const otp = req.body.otp; + + // Verify an OTP factor. + adaptive.evaluateTOTP(context, transactionId, enrollmentId, otp) + .then((result) => { + res.send(result); + }).catch((error) => { + console.log(error); + res.status(404).send({error: error.message}); + }); +}); + +module.exports = router; diff --git a/sdk/adaptive-proxy/demo/components/a2/generateEmailOTP.js b/sdk/adaptive-proxy/demo/components/a2/generateEmailOTP.js new file mode 100644 index 0000000..a0f08cf --- /dev/null +++ b/sdk/adaptive-proxy/demo/components/a2/generateEmailOTP.js @@ -0,0 +1,31 @@ +const adaptive = require('./adaptive'); + +const express = require('express'); + + +// eslint-disable-next-line new-cap +const router = express.Router(); + +router.post('/generations/emailotp', (req, res) => { + const sessionId = req.body.sessionId; + const userAgent = req.headers['user-agent']; + const ipAddress = req.ip; + const evaluationContext = req.body.evaluationContext; + const context = {sessionId, userAgent, ipAddress, + evaluationContext}; + + // Extract parameters from request. + const transactionId = req.body.transactionId; + const enrollmentId = req.body.enrollmentId; + + // Request an email OTP verification. + adaptive.generateEmailOTP(context, transactionId, enrollmentId) + .then((result) =>{ + res.send(result); + }).catch((error) => { + console.log(error); + res.status(404).send({error: error.message}); + }); +}); + +module.exports = router; diff --git a/sdk/adaptive-proxy/demo/components/a2/generateFIDO.js b/sdk/adaptive-proxy/demo/components/a2/generateFIDO.js new file mode 100644 index 0000000..28e22fb --- /dev/null +++ b/sdk/adaptive-proxy/demo/components/a2/generateFIDO.js @@ -0,0 +1,32 @@ +const adaptive = require('./adaptive'); + +const express = require('express'); + + +// eslint-disable-next-line new-cap +const router = express.Router(); + +router.post('/generations/fido', (req, res) => { + const sessionId = req.body.sessionId; + const userAgent = req.headers['user-agent']; + const ipAddress = req.ip; + const evaluationContext = req.body.evaluationContext; + const context = {sessionId, userAgent, ipAddress, + evaluationContext}; + + // Extract parameters from request. + const transactionId = req.body.transactionId; + const relyingPartyId = req.body.relyingPartyId; + const userId = req.body.userId; + + // Request a FIDO verification. + adaptive.generateFIDO(context, transactionId, relyingPartyId, userId) + .then((result) => { + res.send(result); + }).catch((error) => { + console.log(error); + res.status(404).send({error: error.message}); + }); +}); + +module.exports = router; diff --git a/sdk/adaptive-proxy/demo/components/a2/generatePush.js b/sdk/adaptive-proxy/demo/components/a2/generatePush.js new file mode 100644 index 0000000..facbc40 --- /dev/null +++ b/sdk/adaptive-proxy/demo/components/a2/generatePush.js @@ -0,0 +1,39 @@ +const adaptive = require('./adaptive'); + +const express = require('express'); + + +// eslint-disable-next-line new-cap +const router = express.Router(); + +router.post('/generations/push', (req, res) => { + const sessionId = req.body.sessionId; + const userAgent = req.headers['user-agent']; + const ipAddress = req.ip; + const evaluationContext = req.body.evaluationContext; + const context = {sessionId, userAgent, ipAddress, + evaluationContext}; + + // Extract parameters from request. + const transactionId = req.body.transactionId; + const signatureId = req.body.signatureId; + const authenticatorId = req.body.authenticatorId; + const message = req.body.message; + const originIpAddress = req.ip; + const originUserAgent = req.headers['user-agent']; + const pushNotificationMessage = req.body.pushNotificationMessage; + const additionalData = req.body.additionalData; + + // Request a push verification. + adaptive.generatePush(context, transactionId, signatureId, + authenticatorId, message, originIpAddress, + originUserAgent, pushNotificationMessage, additionalData) + .then((result) => { + res.send(result); + }).catch((error) => { + console.log(error); + res.status(404).send({error: error.message}); + }); +}); + +module.exports = router; diff --git a/sdk/adaptive-proxy/demo/components/a2/generateQR.js b/sdk/adaptive-proxy/demo/components/a2/generateQR.js new file mode 100644 index 0000000..1292e5e --- /dev/null +++ b/sdk/adaptive-proxy/demo/components/a2/generateQR.js @@ -0,0 +1,32 @@ +const adaptive = require('./adaptive'); + +const express = require('express'); + + +// eslint-disable-next-line new-cap +const router = express.Router(); + +router.post('/generations/qr', (req, res) => { + const sessionId = req.body.sessionId; + const userAgent = req.headers['user-agent']; + const ipAddress = req.ip; + const evaluationContext = req.body.evaluationContext; + const context = {sessionId, userAgent, ipAddress, + evaluationContext}; + + // Extract parameters from request. + const transactionId = req.body.transactionId; + const profileId = req.body.profileId; + const userId = req.body.userId; + + // Request a QR login verification. + adaptive.generateQR(context, transactionId, profileId, userId) + .then((result) => { + res.send(result); + }).catch((error) => { + console.log(error); + res.status(404).send({error: error.message}); + }); +}); + +module.exports = router; diff --git a/sdk/adaptive-proxy/demo/components/a2/generateQuestions.js b/sdk/adaptive-proxy/demo/components/a2/generateQuestions.js new file mode 100644 index 0000000..872947b --- /dev/null +++ b/sdk/adaptive-proxy/demo/components/a2/generateQuestions.js @@ -0,0 +1,31 @@ +const adaptive = require('./adaptive'); + +const express = require('express'); + + +// eslint-disable-next-line new-cap +const router = express.Router(); + +router.post('/generations/questions', (req, res) => { + const sessionId = req.body.sessionId; + const userAgent = req.headers['user-agent']; + const ipAddress = req.ip; + const evaluationContext = req.body.evaluationContext; + const context = {sessionId, userAgent, ipAddress, + evaluationContext}; + + // Extract parameters from request. + const transactionId = req.body.transactionId; + const enrollmentId = req.body.enrollmentId; + + // Request a knowledge questions verification. + adaptive.generateQuestions(context, transactionId, enrollmentId) + .then((result) => { + res.send(result); + }).catch((error) => { + console.log(error); + res.status(404).send({error: error.message}); + }); +}); + +module.exports = router; diff --git a/sdk/adaptive-proxy/demo/components/a2/generateSMSOTP.js b/sdk/adaptive-proxy/demo/components/a2/generateSMSOTP.js new file mode 100644 index 0000000..65195d1 --- /dev/null +++ b/sdk/adaptive-proxy/demo/components/a2/generateSMSOTP.js @@ -0,0 +1,31 @@ +const adaptive = require('./adaptive'); + +const express = require('express'); + + +// eslint-disable-next-line new-cap +const router = express.Router(); + +router.post('/generations/smsotp', (req, res) => { + const sessionId = req.body.sessionId; + const userAgent = req.headers['user-agent']; + const ipAddress = req.ip; + const evaluationContext = req.body.evaluationContext; + const context = {sessionId, userAgent, ipAddress, + evaluationContext}; + + // Extract parameters from request. + const transactionId = req.body.transactionId; + const enrollmentId = req.body.enrollmentId; + + // Request an SMS OTP verification. + adaptive.generateSMSOTP(context, transactionId, enrollmentId) + .then((result) =>{ + res.send(result); + }).catch((error) => { + console.log(error); + res.status(404).send({error: error.message}); + }); +}); + +module.exports = router; diff --git a/sdk/adaptive-proxy/demo/components/a2/logout.js b/sdk/adaptive-proxy/demo/components/a2/logout.js new file mode 100644 index 0000000..da50324 --- /dev/null +++ b/sdk/adaptive-proxy/demo/components/a2/logout.js @@ -0,0 +1,23 @@ +const adaptive = require('./adaptive'); + +const express = require('express'); + + +// eslint-disable-next-line new-cap +const router = express.Router(); + +router.post('/logout', (req, res) => { + // Extract parameters from request. + const accessToken = req.body.access_token; + + // Logout (i.e. revoke the access token). + adaptive.logout(accessToken) + .then(() =>{ + res.send(); + }).catch((error) => { + console.log(error); + res.status(404).send({error: error.message}); + }); +}); + +module.exports = router; diff --git a/sdk/adaptive-proxy/demo/components/reservations/reservations.js b/sdk/adaptive-proxy/demo/components/reservations/reservations.js new file mode 100644 index 0000000..b804c2c --- /dev/null +++ b/sdk/adaptive-proxy/demo/components/reservations/reservations.js @@ -0,0 +1,30 @@ +const reservations = [ + { + 'id': '65d8b11e-60eb-4f70-ac3d-2b076816ef98', + 'displayName': 'Bob Smith', + 'pointsBalance': 123456, + 'status': 'Gold', + 'reservations': [ + { + 'depart': 'OOL - Gold Coast', + 'arrive': 'SYD - Sydney', + 'departDate': '6:00am Monday, November 18th 2019', + 'arriveDate': '8:00pm Tuesday, November 19th 2019', + }], + }, + { + 'id': '1d6d0f1d-2293-4528-9ddc-2adbe3ca353f', + 'displayName': 'Jane Bob', + 'pointsBalance': 654321, + 'status': 'Platinum', + 'reservations': [ + { + 'depart': 'BNE - Brisbane', + 'arrive': 'MEL - Melbourne', + 'departDate': '2:00am Sunday, November 17th 2019', + 'arriveDate': '4:00pm Wednesday, November 20th 2019', + }], + }, +]; + +module.exports = reservations; diff --git a/sdk/adaptive-proxy/demo/components/reservations/reservationsController.js b/sdk/adaptive-proxy/demo/components/reservations/reservationsController.js new file mode 100644 index 0000000..86e8aa8 --- /dev/null +++ b/sdk/adaptive-proxy/demo/components/reservations/reservationsController.js @@ -0,0 +1,112 @@ +const reservationsService = require('./reservationsService'); + +const Joi = require('joi'); + + +/** + * Validate a reservation. + * @param {*} reservation The reservation to validate. + * @return {Boolean} Whether the reservation is valid. + */ +function validateReservation(reservation) { + // Create the reservation schema. + const reservationArraySchema = { + depart: Joi.string().required(), + arrive: Joi.string().required(), + departDate: Joi.string().required(), + arriveDate: Joi.string().required(), + }; + + // Create the reservation schema. + const reservationSchema = { + displayName: Joi.string().required(), + pointsBalance: Joi.number().integer().required(), + status: Joi.string().required(), + reservations: Joi.array().items(reservationArraySchema).required(), + }; + + return Joi.validate(reservation, reservationSchema); +} + +/** + * Get all reservations. + * @param {Object} _ The HTTP request object. + * @param {Object} res The HTTP response object. + */ +function getAllReservations(_, res) { + res.send(reservationsService.getAllReservations()); +} + +/** + * Get a specific reservation. + * @param {Object} req The HTTP request object. + * @param {Object} res The HTTP response object. + * @return {Object} A HTTP response object. + */ +function getReservation(req, res) { + // Find reservation. + const reservation = reservationsService.getReservation(req.params.id); + if (!reservation) { + return res.status(404).send( + `Could not find reservation with ID "${req.params.id}".`); + } + + res.send(reservation); +} + +/** + * Create a new reservation. + * @param {Object} req The HTTP request object. + * @param {Object} res The HTTP response object. + * @return {Object} A HTTP response object. + */ +function createReservation(req, res) { + // Validate request body. + const {error} = validateReservation(req.body); + if (error) return res.status(400).send(error.details[0].message); + + res.send(reservationsService.createReservation(req.body)); +} + +/** + * Update an existing reservation. + * @param {Object} req The HTTP request object. + * @param {Object} res The HTTP response object. + * @return {Object} A HTTP response object. + */ +function updateReservation(req, res) { + // Find reservation. + const reservation = reservationsService.getReservation(req.params.id); + if (!reservation) { + return res.status(404).send( + `Could not find reservation with ID "${req.params.id}".`); + } + + // Validate request body. + const {error} = validateReservation(req.body); + if (error) return res.status(400).send(error.details[0].message); + + res.send(reservationsService.updateReservation(reservation, req.body)); +} + +/** + * Delete an existing reservation. + * @param {Object} req The HTTP request object. + * @param {Object} res The HTTP response object. + * @return {Object} A HTTP response object. + */ +function deleteReservation(req, res) { + // Find reservation. + const reservation = reservationsService.getReservation(req.params.id); + if (!reservation) { + return res.status(404).send( + `Could not find reservation with ID "${req.params.id}".`); + } + + reservationsService.deleteReservation(reservation); + + res.status(204).send(); +} + +module.exports = {createReservation, getAllReservations, getReservation, + updateReservation, deleteReservation}; diff --git a/sdk/adaptive-proxy/demo/components/reservations/reservationsDAL.js b/sdk/adaptive-proxy/demo/components/reservations/reservationsDAL.js new file mode 100644 index 0000000..692cf71 --- /dev/null +++ b/sdk/adaptive-proxy/demo/components/reservations/reservationsDAL.js @@ -0,0 +1,38 @@ +const reservations = require('./reservations'); + +/** + * Get all reservations from the reservations array. + * @return {Object[]} The array of reservations. + */ +function readAllReservations() { + return reservations; +} + +/** + * Get a specific reservation from the reservations array. + * @param {string} id The identifier of the specific reservation. + * @return {Object} The specific reservation. + */ +function readReservation(id) { + return reservations.find((reservation) => reservation.id === id); +} + +/** + * Store a new reservation in the reservations array. + * @param {Object} reservation The reservation to store. + */ +function storeReservation(reservation) { + reservations.push(reservation); +} + +/** + * Delete a reservation from the reservations array. + * @param {Object} reservation The reservation to delete. + */ +function deleteReservation(reservation) { + const index = reservations.indexOf(reservation); + reservations.splice(index, 1); +} + +module.exports = {storeReservation, readAllReservations, readReservation, + deleteReservation}; diff --git a/sdk/adaptive-proxy/demo/components/reservations/reservationsRouter.js b/sdk/adaptive-proxy/demo/components/reservations/reservationsRouter.js new file mode 100644 index 0000000..9175ebf --- /dev/null +++ b/sdk/adaptive-proxy/demo/components/reservations/reservationsRouter.js @@ -0,0 +1,24 @@ +const reservationsController = require('./reservationsController'); + +const express = require('express'); + + +// eslint-disable-next-line new-cap +const router = express.Router(); + +// Get all reservations. +router.get('/reservations', reservationsController.getAllReservations); + +// Get a specific reservation. +router.get('/reservations/:id', reservationsController.getReservation); + +// Create a new reservation. +router.post('/reservations', reservationsController.createReservation); + +// Update a specific reservation. +router.put('/reservations/:id', reservationsController.updateReservation); + +// Delete a specific reservation. +router.delete('/reservations/:id', reservationsController.deleteReservation); + +module.exports = router; diff --git a/sdk/adaptive-proxy/demo/components/reservations/reservationsService.js b/sdk/adaptive-proxy/demo/components/reservations/reservationsService.js new file mode 100644 index 0000000..f07e534 --- /dev/null +++ b/sdk/adaptive-proxy/demo/components/reservations/reservationsService.js @@ -0,0 +1,58 @@ +const {v4: uuid} = require('uuid'); + +const reservationDAL = require('./reservationsDAL'); + + +/** + * Get all reservations through the data access layer. + * @return {Object[]} The array of reservations. + */ +function getAllReservations() { + return reservationDAL.readAllReservations(); +} + +/** + * Get a specific reservation through the data access layer. + * @param {string} id The identifier of the reservation. + * @return {Object} The retrieved reservation. + */ +function getReservation(id) { + return reservationDAL.readReservation(id); +} + +/** + * Create and add a new reservation through the data access layer. + * @param {Object} reservation The reservation object to add. + * @return {Object} The stored reservation. + */ +function createReservation(reservation) { + reservation.id = uuid(); + reservationDAL.storeReservation(reservation); + return reservation; +} + +/** + * Update an existing reservation through the data access layer. + * @param {Object} oldReservation The old reservation to update. + * @param {Object} newReservation The new updated reservation. + * @return {Object} The updated reservation. + */ +function updateReservation(oldReservation, newReservation) { + oldReservation.displayName = newReservation.displayName; + oldReservation.pointsBalance = newReservation.pointsBalance; + oldReservation.status = newReservation.status; + oldReservation.reservations = newReservation.reservations; + + return oldReservation; +} + +/** + * Delete an existing reservation through the data access layer. + * @param {Object} reservation The reservation to delete. + */ +function deleteReservation(reservation) { + reservationDAL.deleteReservation(reservation); +} + +module.exports = {createReservation, getAllReservations, getReservation, + updateReservation, deleteReservation}; diff --git a/sdk/adaptive-proxy/demo/package-lock.json b/sdk/adaptive-proxy/demo/package-lock.json new file mode 100644 index 0000000..fc098b1 --- /dev/null +++ b/sdk/adaptive-proxy/demo/package-lock.json @@ -0,0 +1,966 @@ +{ + "name": "adaptive-proxy-sdk-demo", + "version": "1.0.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "adaptive-proxy-sdk-demo", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "dotenv": "^8.2.0", + "express": "^4.17.1", + "joi": "^14.3.1", + "uuid": "^3.4.0" + } + }, + "node_modules/accepts": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", + "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", + "dependencies": { + "mime-types": "~2.1.24", + "negotiator": "0.6.2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" + }, + "node_modules/body-parser": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", + "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", + "dependencies": { + "bytes": "3.1.0", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "~1.1.2", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "on-finished": "~2.3.0", + "qs": "6.7.0", + "raw-body": "2.4.0", + "type-is": "~1.6.17" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/bytes": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", + "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/content-disposition": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", + "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", + "dependencies": { + "safe-buffer": "5.1.2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", + "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" + }, + "node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" + }, + "node_modules/dotenv": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz", + "integrity": "sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw==", + "engines": { + "node": ">=8" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express": { + "version": "4.17.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", + "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", + "dependencies": { + "accepts": "~1.3.7", + "array-flatten": "1.1.1", + "body-parser": "1.19.0", + "content-disposition": "0.5.3", + "content-type": "~1.0.4", + "cookie": "0.4.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "~1.1.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "~1.1.2", + "fresh": "0.5.2", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.5", + "qs": "6.7.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.1.2", + "send": "0.17.1", + "serve-static": "1.14.1", + "setprototypeof": "1.1.1", + "statuses": "~1.5.0", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/forwarded": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", + "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/hoek": { + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/hoek/-/hoek-6.1.3.tgz", + "integrity": "sha512-YXXAAhmF9zpQbC7LEcREFtXfGq5K1fmd+4PHkBq8NUqmzW3G+Dq10bI/i0KucLRwss3YYFQ0fSfoxBZYiGUqtQ==" + }, + "node_modules/http-errors": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", + "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", + "dependencies": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.1", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/isemail": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/isemail/-/isemail-3.2.0.tgz", + "integrity": "sha512-zKqkK+O+dGqevc93KNsbZ/TqTUFd46MwWjYOoMrjIMZ51eU7DtQG3Wmd9SQQT7i7RVnuTPEiYEWHU3MSbxC1Tg==", + "dependencies": { + "punycode": "2.x.x" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/joi": { + "version": "14.3.1", + "resolved": "https://registry.npmjs.org/joi/-/joi-14.3.1.tgz", + "integrity": "sha512-LQDdM+pkOrpAn4Lp+neNIFV3axv1Vna3j38bisbQhETPMANYRbFJFUyOZcOClYvM/hppMhGWuKSFEK9vjrB+bQ==", + "dependencies": { + "hoek": "6.x.x", + "isemail": "3.x.x", + "topo": "3.x.x" + } + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.43.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.43.0.tgz", + "integrity": "sha512-+5dsGEEovYbT8UY9yD7eE4XTc4UwJ1jBYlgaQQF38ENsKR3wj/8q8RFZrF9WIZpB2V1ArTVFUva8sAul1NzRzQ==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.26", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.26.tgz", + "integrity": "sha512-01paPWYgLrkqAyrlDorC1uDwl2p3qZT7yl806vW7DvDoxwXi46jsjFbg+WdwotBIk6/MbEhO/dh5aZ5sNj/dWQ==", + "dependencies": { + "mime-db": "1.43.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "node_modules/negotiator": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", + "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" + }, + "node_modules/proxy-addr": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.6.tgz", + "integrity": "sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw==", + "dependencies": { + "forwarded": "~0.1.2", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "engines": { + "node": ">=6" + } + }, + "node_modules/qs": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", + "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", + "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", + "dependencies": { + "bytes": "3.1.0", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "node_modules/send": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", + "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", + "dependencies": { + "debug": "2.6.9", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "~1.7.2", + "mime": "1.6.0", + "ms": "2.1.1", + "on-finished": "~2.3.0", + "range-parser": "~1.2.1", + "statuses": "~1.5.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" + }, + "node_modules/serve-static": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", + "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==", + "dependencies": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.17.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/setprototypeof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", + "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" + }, + "node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/toidentifier": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", + "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/topo": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/topo/-/topo-3.0.3.tgz", + "integrity": "sha512-IgpPtvD4kjrJ7CRA3ov2FhWQADwv+Tdqbsf1ZnPUSAtCJ9e1Z44MmoSGDXGk4IppoZA7jd/QRkNddlLJWlUZsQ==", + "dependencies": { + "hoek": "6.x.x" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "bin": { + "uuid": "bin/uuid" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", + "engines": { + "node": ">= 0.8" + } + } + }, + "dependencies": { + "accepts": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", + "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", + "requires": { + "mime-types": "~2.1.24", + "negotiator": "0.6.2" + } + }, + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" + }, + "body-parser": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", + "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", + "requires": { + "bytes": "3.1.0", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "~1.1.2", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "on-finished": "~2.3.0", + "qs": "6.7.0", + "raw-body": "2.4.0", + "type-is": "~1.6.17" + } + }, + "bytes": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", + "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==" + }, + "content-disposition": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", + "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", + "requires": { + "safe-buffer": "5.1.2" + } + }, + "content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" + }, + "cookie": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", + "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==" + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" + }, + "destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" + }, + "dotenv": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz", + "integrity": "sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw==" + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" + }, + "express": { + "version": "4.17.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", + "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", + "requires": { + "accepts": "~1.3.7", + "array-flatten": "1.1.1", + "body-parser": "1.19.0", + "content-disposition": "0.5.3", + "content-type": "~1.0.4", + "cookie": "0.4.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "~1.1.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "~1.1.2", + "fresh": "0.5.2", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.5", + "qs": "6.7.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.1.2", + "send": "0.17.1", + "serve-static": "1.14.1", + "setprototypeof": "1.1.1", + "statuses": "~1.5.0", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + } + }, + "finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" + } + }, + "forwarded": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", + "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" + }, + "hoek": { + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/hoek/-/hoek-6.1.3.tgz", + "integrity": "sha512-YXXAAhmF9zpQbC7LEcREFtXfGq5K1fmd+4PHkBq8NUqmzW3G+Dq10bI/i0KucLRwss3YYFQ0fSfoxBZYiGUqtQ==" + }, + "http-errors": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", + "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.1", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.0" + } + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" + }, + "isemail": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/isemail/-/isemail-3.2.0.tgz", + "integrity": "sha512-zKqkK+O+dGqevc93KNsbZ/TqTUFd46MwWjYOoMrjIMZ51eU7DtQG3Wmd9SQQT7i7RVnuTPEiYEWHU3MSbxC1Tg==", + "requires": { + "punycode": "2.x.x" + } + }, + "joi": { + "version": "14.3.1", + "resolved": "https://registry.npmjs.org/joi/-/joi-14.3.1.tgz", + "integrity": "sha512-LQDdM+pkOrpAn4Lp+neNIFV3axv1Vna3j38bisbQhETPMANYRbFJFUyOZcOClYvM/hppMhGWuKSFEK9vjrB+bQ==", + "requires": { + "hoek": "6.x.x", + "isemail": "3.x.x", + "topo": "3.x.x" + } + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" + }, + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" + }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" + }, + "mime-db": { + "version": "1.43.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.43.0.tgz", + "integrity": "sha512-+5dsGEEovYbT8UY9yD7eE4XTc4UwJ1jBYlgaQQF38ENsKR3wj/8q8RFZrF9WIZpB2V1ArTVFUva8sAul1NzRzQ==" + }, + "mime-types": { + "version": "2.1.26", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.26.tgz", + "integrity": "sha512-01paPWYgLrkqAyrlDorC1uDwl2p3qZT7yl806vW7DvDoxwXi46jsjFbg+WdwotBIk6/MbEhO/dh5aZ5sNj/dWQ==", + "requires": { + "mime-db": "1.43.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "negotiator": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", + "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==" + }, + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "requires": { + "ee-first": "1.1.1" + } + }, + "parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" + }, + "path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" + }, + "proxy-addr": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.6.tgz", + "integrity": "sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw==", + "requires": { + "forwarded": "~0.1.2", + "ipaddr.js": "1.9.1" + } + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" + }, + "qs": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", + "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==" + }, + "range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" + }, + "raw-body": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", + "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", + "requires": { + "bytes": "3.1.0", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "send": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", + "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", + "requires": { + "debug": "2.6.9", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "~1.7.2", + "mime": "1.6.0", + "ms": "2.1.1", + "on-finished": "~2.3.0", + "range-parser": "~1.2.1", + "statuses": "~1.5.0" + }, + "dependencies": { + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" + } + } + }, + "serve-static": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", + "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==", + "requires": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.17.1" + } + }, + "setprototypeof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", + "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" + }, + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" + }, + "toidentifier": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", + "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==" + }, + "topo": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/topo/-/topo-3.0.3.tgz", + "integrity": "sha512-IgpPtvD4kjrJ7CRA3ov2FhWQADwv+Tdqbsf1ZnPUSAtCJ9e1Z44MmoSGDXGk4IppoZA7jd/QRkNddlLJWlUZsQ==", + "requires": { + "hoek": "6.x.x" + } + }, + "type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "requires": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + } + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" + }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" + }, + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" + } + } +} diff --git a/sdk/adaptive-proxy/demo/package.json b/sdk/adaptive-proxy/demo/package.json new file mode 100644 index 0000000..c0e5e23 --- /dev/null +++ b/sdk/adaptive-proxy/demo/package.json @@ -0,0 +1,19 @@ +{ + "name": "adaptive-proxy-sdk-demo", + "version": "1.0.0", + "description": "A demo backend application, making use of adaptive-proxy-sdk.", + "main": "app.js", + "scripts": { + "start": "node app.js", + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "Adam Dorogi-Kaposi ", + "license": "MIT", + "dependencies": { + "dotenv": "^8.2.0", + "express": "^4.17.1", + "joi": "^14.3.1", + "uuid": "^3.4.0" + } +} diff --git a/sdk/adaptive-proxy/docs/Adaptive.html b/sdk/adaptive-proxy/docs/Adaptive.html new file mode 100644 index 0000000..e81f2f4 --- /dev/null +++ b/sdk/adaptive-proxy/docs/Adaptive.html @@ -0,0 +1,11634 @@ + + + + + + + + + Adaptive - Documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + +
+ +

+ Adaptive +

+ + + + +
+
+ +

+ + Adaptive + +

+ + +
+

Class representing the PDA (Policy Driven Authentication) SDK. Used to +perform and validate first- and second-factor verifications on CI (Cloud +Identity).

+
+ + +
+ +
+
+ + + + + +

Constructor

+ + + + + + + + +

+ new Adaptive(config, transactionFunctionsopt) +

+
+ + + + + +
+

Create a new Adaptive object.

+
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDescription
config + + + + Object + + + + + + + + + + + + + +

The configuration settings used for CI requests.

+ +
Properties
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
clientId + + + + string + + + + + + + +

The identifier of the client application.

+ +
clientSecret + + + + string + + + + + + + +

The client application secret.

+ +
tenantUrl + + + + string + + + + + + + +

The URL of the tenant.

+ +
+ + +
transactionFunctions + + + + Object + + + + + + + + + <optional>
+ + + + + +
+

An object containing transaction +operation functions. This parameter is optional, in case the +developer would like to handle the storing, retrieving, updating, and +deleting of transactions created during the A2 flow in an external +database. Otherwise, a default in-memory option is used for handling +transactions. If specified, this object must contain four parameters: +createTransaction, getTransaction, +updateTransaction, and deleteTransaction, each +being the appropriate function to store, retrieve, update, and delete +transactions respectively. The custom storage mechanism should ideally have +a time-to-live for the transactions (e.g. 1 hour), to prevent accumulating +unused/unfinished transactions.

+ +
Properties
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDescription
createTransaction + + + + function + + + + + + + + + <optional>
+ + + + + +
+

The function +used to create (store) a transaction. This function should take one +parameter; a transaction Object. It should store the object in +a database of choice, indexed by a randomly generated v4 UUID (the +transaction ID). After storing the transaction object associated to a +transaction ID, the function should return the transaction ID as a +string.

+ +
getTransaction + + + + function + + + + + + + + + <optional>
+ + + + + +
+

The function used +to retrieve stored transactions. This function should take one parameter; +a transaction ID string. It should return the transaction +Object associated to the given transaction ID.

+ +
updateTransaction + + + + function + + + + + + + + + <optional>
+ + + + + +
+

The function +used to update (i.e. add additional properties to) an existing transaction. +This function should take two parameters (in order); a transaction ID +string of the transaction to update, and an +Object of additional properties to add to the +transaction. For example, if the existing transaction is {"userId": +"123456"}, and the object passed into this function is +{"name": "John"}, the updated transaction should be +{"userId": "123456", "name": "John"}. This function shouldn't +return anything.

+ +
deleteTransaction + + + + function + + + + + + + + + <optional>
+ + + + + +
+

The function +used to delete an existing transaction. This function should take one +parameter; a transaction ID string. The function should remove +the transaction associated with the given transaction ID from the database +storage. This function shouldn't return anything.

+ +
+ + +
+ + + + + + + +
+ + + + + + + + + + + + + + + + +
Author:
+
+ +
+ + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + +
Throws:
+ +
    + +
  • + + +
    +
    +
    +

    The configuration object doesn't contain the +required properties.

    +
    +
    +
    +
    +
    +
    Type
    +
    + + + ConfigurationError + + + + + +
    +
    +
    +
    +
    + + +
  • + +
  • + + +
    +
    +
    +

    The createTransaction, +getTransaction, updateTransaction, or +deleteTransaction functions are missing from the transaction +functions object.

    +
    +
    +
    +
    +
    +
    Type
    +
    + + + TransactionError + + + + + +
    +
    +
    +
    +
    + + +
  • + +
+ + + + + +
+ + + + + + + + + + + + + + +

Methods

+ + + + + + + + + + + + + +

+ (async, private) _validateAssertion(transactionId, context, assertion, userId) +

+
+ + + + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
transactionId + + + + string + + + + + + + +

The identifier of the transaction received in +Adaptive#assessPolicy.

+ +
context + + + + Object + + + + + + + +

The context to send for assessment.

+ +
Properties
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
sessionId + + + + string + + + + + + + + + + + + + + + +

The session ID generated by the +user-agent, using an Adaptive client SDK.

+ +
userAgent + + + + string + + + + + + + + + + + + + + + +

The user-agent, typically obtained form +the User-Agent HTTP header.

+ +
ipAddress + + + + string + + + + + + + + + + + + + + + +

The IP address of the user-agent.

+ +
evaluationContext + + + + string + + + + + + + + + <optional>
+ + + + + +
+ + "login" + + +

The stage in the +user-agent for which to perform an evaluation. (Used for continuous +assessment throughout the user-agent.) Different "stages" or "contexts" +will result in different evaluation results, as configured in the +sub-policies of the tenant application's policy. Possible options are +"login" (default), "landing", "profile", "resume", "highassurance", +"other".

+ +
+ + +
assertion + + + + string + + + + + + + +

The JWT assertion to validate.

+ +
userId + + + + string + + + + + + + +

The user ID for which to retrieve enrollments on a +requires response.

+ +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ (async) assessPolicy(context) → {Promise.<Object>} +

+
+ + + + + +
+

Perform an initial grant request.

+

The initial grant request uses the policyauth grant-type to +evaluate the policy attached to the client application on OIDC with the +risk engine.

+

An in-memory transaction is also created to associate subsequent requests +to a session or "transaction".

+
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
context + + + + Object + + + + + + + +

The context to send for assessment.

+ +
Properties
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
sessionId + + + + string + + + + + + + + + + + + + + + +

The session ID generated by the +user-agent, using an Adaptive client SDK.

+ +
userAgent + + + + string + + + + + + + + + + + + + + + +

The user-agent, typically obtained form +the User-Agent HTTP header.

+ +
ipAddress + + + + string + + + + + + + + + + + + + + + +

The IP address of the user-agent.

+ +
evaluationContext + + + + string + + + + + + + + + <optional>
+ + + + + +
+ + "login" + + +

The stage in the +user-agent for which to perform an evaluation. (Used for continuous +assessment throughout the user-agent.) Different "stages" or "contexts" +will result in different evaluation results, as configured in the +sub-policies of the tenant application's policy. Possible options are +"login" (default), "landing", "profile", "resume", "highassurance", +"other".

+ +
+ + +
+ + + + +
Returns:
+ + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + + + Promise.<Object> + + + + + + + +

The policy evaluation result object. The result +object has a status property of either deny, or +requires. If deny, only the status +property is included in the result object. If requires, a +transaction is created, and the transactionId and an array of +allowedFactors is also included in the result object, +indicating that further first-factor authentication is required.

+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + + + +
+ + + + + +
Examples
+ +

+ deny result object +

+ + +
{
+  status: 'deny'
+}
+ +

+ requires result object +

+ + +
{
+  status: 'requires',
+  transactionId: '36a101c7-7426-4f45-ab3c-55f8dc075c6e',
+  allowedFactors: ['qr', 'fido', 'password']
+}
+ + +
+ + + + + + + + + + + + + + +

+ (async) evaluateEmailOTP(context, transactionId, otp) → {Promise.<Object>} +

+
+ + + + + +
+

Complete an email OTP second-factor verification and validate the resulting +JWT.

+
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
context + + + + Object + + + + + + + +

The context to send for assessment.

+ +
Properties
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
sessionId + + + + string + + + + + + + + + + + + + + + +

The session ID generated by the +user-agent, using an Adaptive client SDK.

+ +
userAgent + + + + string + + + + + + + + + + + + + + + +

The user-agent, typically obtained form +the User-Agent HTTP header.

+ +
ipAddress + + + + string + + + + + + + + + + + + + + + +

The IP address of the user-agent.

+ +
evaluationContext + + + + string + + + + + + + + + <optional>
+ + + + + +
+ + "login" + + +

The stage in the +user-agent for which to perform an evaluation. (Used for continuous +assessment throughout the user-agent.) Different "stages" or "contexts" +will result in different evaluation results, as configured in the +sub-policies of the tenant application's policy. Possible options are +"login" (default), "landing", "profile", "resume", "highassurance", +"other".

+ +
+ + +
transactionId + + + + string + + + + + + + +

The identifier of the transaction received in +Adaptive#assessPolicy.

+ +
otp + + + + string + + + + + + + +

The email OTP received in the email after the email OTP +request in Adaptive#generateEmailOTP. This OTP shouldn't include +the correlation prefix (the four digits before the dash).

+ +
+ + + + +
Returns:
+ + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + + + Promise.<Object> + + + + + + + +

The access and refresh tokens which should have +been received from the JWT validation, along with the status +property of allow.

+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ (async) evaluateFIDO(context, transactionId, relyingPartyId, authenticatorData, userHandle, signature, clientDataJSON) → {Promise.<Object>} +

+
+ + + + + +
+

Complete a FIDO first-factor verification and validate the resulting JWT.

+
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
context + + + + Object + + + + + + + +

The context to send for assessment.

+ +
Properties
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
sessionId + + + + string + + + + + + + + + + + + + + + +

The session ID generated by the +user-agent, using an Adaptive client SDK.

+ +
userAgent + + + + string + + + + + + + + + + + + + + + +

The user-agent, typically obtained form +the User-Agent HTTP header.

+ +
ipAddress + + + + string + + + + + + + + + + + + + + + +

The IP address of the user-agent.

+ +
evaluationContext + + + + string + + + + + + + + + <optional>
+ + + + + +
+ + "login" + + +

The stage in the +user-agent for which to perform an evaluation. (Used for continuous +assessment throughout the user-agent.) Different "stages" or "contexts" +will result in different evaluation results, as configured in the +sub-policies of the tenant application's policy. Possible options are +"login" (default), "landing", "profile", "resume", "highassurance", +"other".

+ +
+ + +
transactionId + + + + string + + + + + + + +

The identifier of the transaction received in +Adaptive#assessPolicy.

+ +
relyingPartyId + + + + string + + + + + + + +

The identifier of relying party associated +with the FIDO registration.

+ +
authenticatorData + + + + string + + + + + + + +

The information about the authentication +that was produced by the user-agent authenticator and verified by the +signature.

+ +
userHandle + + + + string + + + + + + + +

The identifier for the user who owns this +authenticator.

+ +
signature + + + + string + + + + + + + +

The signature of the challenge data that was +produced by the user-agent authenticator.

+ +
clientDataJSON + + + + string + + + + + + + +

The base64 encoded client data JSON object.

+ +
+ + + + +
Returns:
+ + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + + + Promise.<Object> + + + + + + + +

The JWT validation result object. The result +object has a status property of either allow, +deny, or requires. +If allow, a token object is also included in the +result object. +If deny, a details object is returned if an +error message was returned from the token endpoint. +If requires, the allowed second-factor enrollments are +retrieved and included in the result object, indicating that further +second-factor authentication is required.

+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + + + +
+ + + + + +
Examples
+ +

+ allow result object +

+ + +
{
+  status: 'allow',
+  token: {
+    access_token: 'zscmjBdvIjudOPLhpbmJi6nBRJg7cZ6WY0Udw1nC',
+    refresh_token: 'wFTjurPxTvRD1cW09itgQM83XwCm1UKwsxhVFb1H7HJh8JkwZz',
+    scope: 'openid',
+    grant_id: 'a0b440b6-fefb-46ea-a603-e1040534cd28',
+    id_token: 'eyJhbGciOiJSUzI1NiIsInR5cC...5j_rMn7H3ZpE4axt0WvsYu4jbA',
+    token_type: 'Bearer',
+    expires_in: 7120
+  }
+}
+ +

+ deny result object +

+ + +
{
+  status: 'deny',
+  detail: {
+    error: 'adaptive_more_info_required',
+    error_description: 'CSIAQ0298E Adaptive access...'
+  }
+}
+ +

+ requires result object +

+ + +
{
+  status: 'requires',
+  transactionId: '36a101c7-7426-4f45-ab3c-55f8dc075c6e',
+  enrolledFactors: [
+    {
+      id: '61e39f0a-836b-48fa-b4c9-cface6a3ef5a',
+      userId: '60300035KP',
+      type: 'emailotp',
+      created: '2020-06-15T02:51:49.131Z',
+      updated: '2020-06-15T03:15:18.896Z',
+      attempted: '2020-07-16T04:30:14.066Z',
+      enabled: true,
+      validated: true,
+      attributes: {
+        emailAddress: 'email@email.com'
+      }
+    }
+  ]
+}
+ + +
+ + + + + + + + + + + + + + +

+ (async) evaluatePassword(context, transactionId, identitySourceId, username, password) → {Promise.<Object>} +

+
+ + + + + +
+

Complete a password first-factor verification.

+

Complete a password first-factor verification, validate the resulting JWT, +and gather second-factor enrollments if needed.

+
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
context + + + + Object + + + + + + + +

The context to send for assessment.

+ +
Properties
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
sessionId + + + + string + + + + + + + + + + + + + + + +

The session ID generated by the +user-agent, using an Adaptive client SDK.

+ +
userAgent + + + + string + + + + + + + + + + + + + + + +

The user-agent, typically obtained form +the User-Agent HTTP header.

+ +
ipAddress + + + + string + + + + + + + + + + + + + + + +

The IP address of the user-agent.

+ +
evaluationContext + + + + string + + + + + + + + + <optional>
+ + + + + +
+ + "login" + + +

The stage in the +user-agent for which to perform an evaluation. (Used for continuous +assessment throughout the user-agent.) Different "stages" or "contexts" +will result in different evaluation results, as configured in the +sub-policies of the tenant application's policy. Possible options are +"login" (default), "landing", "profile", "resume", "highassurance", +"other".

+ +
+ + +
transactionId + + + + string + + + + + + + +

The identifier of the transaction received in +Adaptive#assessPolicy.

+ +
identitySourceId + + + + string + + + + + + + +

The identifier of the identity source +associated with the password registration.

+ +
username + + + + string + + + + + + + +

The username to authenticate as.

+ +
password + + + + string + + + + + + + +

The password to authenticate with.

+ +
+ + + + +
Returns:
+ + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + + + Promise.<Object> + + + + + + + +

The JWT evaluation result object. The result +object has a status property of either allow, +deny, or requires. +If allow, a token object is also included in the +result object. +If deny, a details object is returned if an +error message was returned from the token endpoint. +If requires, the allowed second-factor enrollments are +retrieved and included in the result object, indicating that further +second-factor authentication is required.

+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + + + +
+ + + + + +
Examples
+ +

+ allow result object +

+ + +
{
+  status: 'allow',
+  token: {
+    access_token: 'zscmjBdvIjudOPLhpbmJi6nBRJg7cZ6WY0Udw1nC',
+    refresh_token: 'wFTjurPxTvRD1cW09itgQM83XwCm1UKwsxhVFb1H7HJh8JkwZz',
+    scope: 'openid',
+    grant_id: 'a0b440b6-fefb-46ea-a603-e1040534cd28',
+    id_token: 'eyJhbGciOiJSUzI1NiIsInR5cC...5j_rMn7H3ZpE4axt0WvsYu4jbA',
+    token_type: 'Bearer',
+    expires_in: 7120
+  }
+}
+ +

+ deny result object +

+ + +
{
+  status: 'deny',
+  detail: {
+    error: 'adaptive_more_info_required',
+    error_description: 'CSIAQ0298E Adaptive access...'
+  }
+}
+ +

+ requires result object +

+ + +
{
+  status: 'requires',
+  transactionId: '36a101c7-7426-4f45-ab3c-55f8dc075c6e',
+  enrolledFactors: [
+    {
+      id: '61e39f0a-836b-48fa-b4c9-cface6a3ef5a',
+      userId: '60300035KP',
+      type: 'emailotp',
+      created: '2020-06-15T02:51:49.131Z',
+      updated: '2020-06-15T03:15:18.896Z',
+      attempted: '2020-07-16T04:30:14.066Z',
+      enabled: true,
+      validated: true,
+      attributes: {
+        emailAddress: 'email@email.com'
+      }
+    }
+  ]
+}
+ + +
+ + + + + + + + + + + + + + +

+ (async) evaluatePush(context, transactionId) → {Promise.<Object>} +

+
+ + + + + +
+

Attempt a push notification verification.

+
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
context + + + + Object + + + + + + + +

The context to send for assessment.

+ +
Properties
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
sessionId + + + + string + + + + + + + + + + + + + + + +

The session ID generated by the +user-agent, using an Adaptive client SDK.

+ +
userAgent + + + + string + + + + + + + + + + + + + + + +

The user-agent, typically obtained form +the User-Agent HTTP header.

+ +
ipAddress + + + + string + + + + + + + + + + + + + + + +

The IP address of the user-agent.

+ +
evaluationContext + + + + string + + + + + + + + + <optional>
+ + + + + +
+ + "login" + + +

The stage in the +user-agent for which to perform an evaluation. (Used for continuous +assessment throughout the user-agent.) Different "stages" or "contexts" +will result in different evaluation results, as configured in the +sub-policies of the tenant application's policy. Possible options are +"login" (default), "landing", "profile", "resume", "highassurance", +"other".

+ +
+ + +
transactionId + + + + string + + + + + + + +

The identifier of the transaction received in +Adaptive#assessPolicy.

+ +
+ + + + +
Returns:
+ + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + + + Promise.<Object> + + + + + + + +

The access and refresh tokens which should have +been received from the JWT validation, along with the status +property of allow.

+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ (async) evaluateQR(context, transactionId) → {Promise.<Object>} +

+
+ + + + + +
+

Evaluate a QR login first-factor verification.

+
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
context + + + + Object + + + + + + + +

The context to send for assessment.

+ +
Properties
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
sessionId + + + + string + + + + + + + + + + + + + + + +

The session ID generated by the +user-agent, using an Adaptive client SDK.

+ +
userAgent + + + + string + + + + + + + + + + + + + + + +

The user-agent, typically obtained form +the User-Agent HTTP header.

+ +
ipAddress + + + + string + + + + + + + + + + + + + + + +

The IP address of the user-agent.

+ +
evaluationContext + + + + string + + + + + + + + + <optional>
+ + + + + +
+ + "login" + + +

The stage in the +user-agent for which to perform an evaluation. (Used for continuous +assessment throughout the user-agent.) Different "stages" or "contexts" +will result in different evaluation results, as configured in the +sub-policies of the tenant application's policy. Possible options are +"login" (default), "landing", "profile", "resume", "highassurance", +"other".

+ +
+ + +
transactionId + + + + string + + + + + + + +

The identifier of the transaction received in +Adaptive#assessPolicy.

+ +
+ + + + +
Returns:
+ + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + + + Promise.<Object> + + + + + + + +

Either QR transaction state result object +(if not complete) or the JWT evaluation result object. +If QR transaction not complete, the result object has status +property of pending, timeout, +or error. +If QR transaction is complete, the result object has a status +property of either allow, deny, +or requires. +If allow, a token object is also included in the +result object. +If deny, a details object is returned if an +error message was returned from the token endpoint. +If requires, the allowed second-factor enrollments are +retrieved and included in the result object, indicating that further +second-factor authentication is required.

+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + + + +
+ + + + + +
Examples
+ +

+ pending result object +

+ + +
{
+  status: 'pending',
+  expiry: '2021-04-26T12:06:06.501Z'
+}
+ +

+ pending result object +

+ + +
{
+  status: 'timeout',
+  expiry: '2021-04-26T12:06:06.501Z'
+}
+ +

+ error result object +

+ + +
{
+  status: 'error'
+}
+ +

+ allow result object +

+ + +
{
+  status: 'allow',
+  token: {
+    access_token: 'zscmjBdvIjudOPLhpbmJi6nBRJg7cZ6WY0Udw1nC',
+    refresh_token: 'wFTjurPxTvRD1cW09itgQM83XwCm1UKwsxhVFb1H7HJh8JkwZz',
+    scope: 'openid',
+    grant_id: 'a0b440b6-fefb-46ea-a603-e1040534cd28',
+    id_token: 'eyJhbGciOiJSUzI1NiIsInR5cC...5j_rMn7H3ZpE4axt0WvsYu4jbA',
+    token_type: 'Bearer',
+    expires_in: 7120
+  }
+}
+ +

+ deny result object +

+ + +
{
+  status: 'deny',
+  detail: {
+    error: 'adaptive_more_info_required',
+    error_description: 'CSIAQ0298E Adaptive access...'
+  }
+}
+ +

+ requires result object +

+ + +
{
+  status: 'requires',
+  transactionId: '36a101c7-7426-4f45-ab3c-55f8dc075c6e',
+  enrolledFactors: [
+    {
+      id: '61e39f0a-836b-48fa-b4c9-cface6a3ef5a',
+      userId: '60300035KP',
+      type: 'emailotp',
+      created: '2020-06-15T02:51:49.131Z',
+      updated: '2020-06-15T03:15:18.896Z',
+      attempted: '2020-07-16T04:30:14.066Z',
+      enabled: true,
+      validated: true,
+      attributes: {
+        emailAddress: 'email@email.com'
+      }
+    }
+  ]
+}
+ + +
+ + + + + + + + + + + + + + +

+ (async) evaluateQuestions(context, transactionId, questions) → {Promise.<Object>} +

+
+ + + + + +
+

Complete a knowledge questions second-factor verification and validate the +resulting JWT.

+
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
context + + + + Object + + + + + + + +

The context to send for assessment.

+ +
Properties
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
sessionId + + + + string + + + + + + + + + + + + + + + +

The session ID generated by the +user-agent, using an Adaptive client SDK.

+ +
userAgent + + + + string + + + + + + + + + + + + + + + +

The user-agent, typically obtained form +the User-Agent HTTP header.

+ +
ipAddress + + + + string + + + + + + + + + + + + + + + +

The IP address of the user-agent.

+ +
evaluationContext + + + + string + + + + + + + + + <optional>
+ + + + + +
+ + "login" + + +

The stage in the +user-agent for which to perform an evaluation. (Used for continuous +assessment throughout the user-agent.) Different "stages" or "contexts" +will result in different evaluation results, as configured in the +sub-policies of the tenant application's policy. Possible options are +"login" (default), "landing", "profile", "resume", "highassurance", +"other".

+ +
+ + +
transactionId + + + + string + + + + + + + +

The identifier of the transaction received in +Adaptive#assessPolicy.

+ +
questions + + + + Array.<Object> + + + + + + + +

The array of question keys and corresponding +answers to attempt verification with.

+ +
Properties
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
questionKey + + + + string + + + + + + + +

The identifier of the question.

+ +
answer + + + + string + + + + + + + +

The answer to the question.

+ +
+ + +
+ + + + +
Returns:
+ + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + + + Promise.<Object> + + + + + + + +

The result of the JWT validation. The result +object has a status property of allow, and +returns an access and a refresh token. There is no requires +status, since this is the last required verification step.

+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + +
Throws:
+ + + +
+
+
+

The transaction ID hasn't requested a knowledge +questions verification in Adaptive#generateQuestions.

+
+
+
+
+
+
Type
+
+ + + TransactionError + + + + + +
+
+
+
+
+ + + + + +
+ + + + + +
Example
+ +

+ allow return value +

+ + +
{
+  status: 'allow',
+  token: {
+    issued_at: 1420262924658,
+    scope: 'READ',
+    application_name: 'ce1e94a2-9c3e-42fa-a2c6-1ee01815476b',
+    refresh_token_issued_at: 1420262924658,
+    expires_in: 1799,
+    token_type: 'BearerToken',
+    refresh_token: 'fYACGW7OCPtCNDEnRSnqFlEgogboFPMm',
+    client_id: '5jUAdGv9pBouF0wOH5keAVI35GBtx3dT',
+    access_token: '2l4IQtZXbn5WBJdL6EF7uenOWRsi',
+    organization_name: 'My Happy Place',
+    refresh_token_expires_in: 86399
+  }
+}
+ + +
+ + + + + + + + + + + + + + +

+ (async) evaluateSMSOTP(context, transactionId, otp) → {Promise.<Object>} +

+
+ + + + + +
+

Complete an SMS OTP second-factor verification and validate the resulting +JWT.

+
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
context + + + + Object + + + + + + + +

The context to send for assessment.

+ +
Properties
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
sessionId + + + + string + + + + + + + + + + + + + + + +

The session ID generated by the +user-agent, using an Adaptive client SDK.

+ +
userAgent + + + + string + + + + + + + + + + + + + + + +

The user-agent, typically obtained form +the User-Agent HTTP header.

+ +
ipAddress + + + + string + + + + + + + + + + + + + + + +

The IP address of the user-agent.

+ +
evaluationContext + + + + string + + + + + + + + + <optional>
+ + + + + +
+ + "login" + + +

The stage in the +user-agent for which to perform an evaluation. (Used for continuous +assessment throughout the user-agent.) Different "stages" or "contexts" +will result in different evaluation results, as configured in the +sub-policies of the tenant application's policy. Possible options are +"login" (default), "landing", "profile", "resume", "highassurance", +"other".

+ +
+ + +
transactionId + + + + string + + + + + + + +

The identifier of the transaction received in +Adaptive#assessPolicy.

+ +
otp + + + + string + + + + + + + +

The SMS OTP received on the phone after the SMS OTP +request in Adaptive#generateSMSOTP. This OTP shouldn't include the +correlation prefix (the four digits before the dash).

+ +
+ + + + +
Returns:
+ + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + + + Promise.<Object> + + + + + + + +

The access and refresh tokens which should have +been received from the JWT validation, along with the status +property of allow.

+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ (async) evaluateTOTP(context, transactionId, enrollmentId, otp) → {Promise.<Object>} +

+
+ + + + + +
+

Complete a TOTP second-factor verification and validate the resulting JWT.

+
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
context + + + + Object + + + + + + + +

The context to send for assessment.

+ +
Properties
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
sessionId + + + + string + + + + + + + + + + + + + + + +

The session ID generated by the +user-agent, using an Adaptive client SDK.

+ +
userAgent + + + + string + + + + + + + + + + + + + + + +

The user-agent, typically obtained form +the User-Agent HTTP header.

+ +
ipAddress + + + + string + + + + + + + + + + + + + + + +

The IP address of the user-agent.

+ +
evaluationContext + + + + string + + + + + + + + + <optional>
+ + + + + +
+ + "login" + + +

The stage in the +user-agent for which to perform an evaluation. (Used for continuous +assessment throughout the user-agent.) Different "stages" or "contexts" +will result in different evaluation results, as configured in the +sub-policies of the tenant application's policy. Possible options are +"login" (default), "landing", "profile", "resume", "highassurance", +"other".

+ +
+ + +
transactionId + + + + string + + + + + + + +

The identifier of the transaction received in +Adaptive#assessPolicy.

+ +
enrollmentId + + + + string + + + + + + + +

The identifier of the enrollment to perform +second-factor verification with.

+ +
otp + + + + string + + + + + + + +

The OTP to attempt verification with.

+ +
+ + + + +
Returns:
+ + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + + + Promise.<Object> + + + + + + + +

The access and refresh tokens which should have +been received from the JWT validation, along with the status +property of allow.

+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ (async) evaluateVoiceOTP(context, transactionId, otp) → {Promise.<Object>} +

+
+ + + + + +
+

Complete an Voice OTP second-factor verification and validate the resulting +JWT.

+
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
context + + + + Object + + + + + + + +

The context to send for assessment.

+ +
Properties
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
sessionId + + + + string + + + + + + + + + + + + + + + +

The session ID generated by the +user-agent, using an Adaptive client SDK.

+ +
userAgent + + + + string + + + + + + + + + + + + + + + +

The user-agent, typically obtained form +the User-Agent HTTP header.

+ +
ipAddress + + + + string + + + + + + + + + + + + + + + +

The IP address of the user-agent.

+ +
evaluationContext + + + + string + + + + + + + + + <optional>
+ + + + + +
+ + "login" + + +

The stage in the +user-agent for which to perform an evaluation. (Used for continuous +assessment throughout the user-agent.) Different "stages" or "contexts" +will result in different evaluation results, as configured in the +sub-policies of the tenant application's policy. Possible options are +"login" (default), "landing", "profile", "resume", "highassurance", +"other".

+ +
+ + +
transactionId + + + + string + + + + + + + +

The identifier of the transaction received in +Adaptive#assessPolicy.

+ +
otp + + + + string + + + + + + + +

The Voice OTP received on the phone after the Voice OTP +request in Adaptive#generateVoiceOTP. This OTP shouldn't include +the correlation prefix (the four digits before the dash).

+ +
+ + + + +
Returns:
+ + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + + + Promise.<Object> + + + + + + + +

The access and refresh tokens which should have +been received from the JWT validation, along with the status +property of allow.

+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ (async) generateEmailOTP(context, transactionId, enrollmentId) → {Promise.<Object>} +

+
+ + + + + +
+

Request an email OTP.

+
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
context + + + + Object + + + + + + + +

The context to send for assessment.

+ +
Properties
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
sessionId + + + + string + + + + + + + + + + + + + + + +

The session ID generated by the +user-agent, using an Adaptive client SDK.

+ +
userAgent + + + + string + + + + + + + + + + + + + + + +

The user-agent, typically obtained form +the User-Agent HTTP header.

+ +
ipAddress + + + + string + + + + + + + + + + + + + + + +

The IP address of the user-agent.

+ +
evaluationContext + + + + string + + + + + + + + + <optional>
+ + + + + +
+ + "login" + + +

The stage in the +user-agent for which to perform an evaluation. (Used for continuous +assessment throughout the user-agent.) Different "stages" or "contexts" +will result in different evaluation results, as configured in the +sub-policies of the tenant application's policy. Possible options are +"login" (default), "landing", "profile", "resume", "highassurance", +"other".

+ +
+ + +
transactionId + + + + string + + + + + + + +

The identifier of the transaction received in

+ +
enrollmentId + + + + string + + + + + + + +

The identifier of the enrollment to perform +second-factor verification with.

+ +
+ + + + +
Returns:
+ + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + + + Promise.<Object> + + + + + + + +

The a four-digit correlation associated with the +verification. It will be prefixed to the one-time password in the Email to +be sent.

+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ (async) generateFIDO(context, transactionId, relyingPartyId, userId) → {Promise.<Object>} +

+
+ + + + + +
+

Initiate a FIDO first-factor verification to be completed by the +user-agent.

+
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
context + + + + Object + + + + + + + +

The context to send for assessment.

+ +
Properties
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
sessionId + + + + string + + + + + + + + + + + + + + + +

The session ID generated by the +user-agent, using an Adaptive client SDK.

+ +
userAgent + + + + string + + + + + + + + + + + + + + + +

The user-agent, typically obtained form +the User-Agent HTTP header.

+ +
ipAddress + + + + string + + + + + + + + + + + + + + + +

The IP address of the user-agent.

+ +
evaluationContext + + + + string + + + + + + + + + <optional>
+ + + + + +
+ + "login" + + +

The stage in the +user-agent for which to perform an evaluation. (Used for continuous +assessment throughout the user-agent.) Different "stages" or "contexts" +will result in different evaluation results, as configured in the +sub-policies of the tenant application's policy. Possible options are +"login" (default), "landing", "profile", "resume", "highassurance", +"other".

+ +
+ + +
transactionId + + + + string + + + + + + + +

The identifier of the transaction received in +Adaptive#assessPolicy.

+ +
relyingPartyId + + + + string + + + + + + + +

The identifier of relying party associated +with the FIDO registration.

+ +
userId + + + + string + + + + + + + +

The identifier of the OIDC user for which to +initiate a FIDO verification.

+ +
+ + + + +
Returns:
+ + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + + + Promise.<Object> + + + + + + + +

A FIDO challenge to be completed by the +user-agent.

+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + + + +
+ + + + + +
Example
+ +

+ FIDO challenge return value +

+ + +
{
+  "transactionId": "36a101c7-7426-4f45-ab3c-55f8dc075c6e",
+  "fido": {
+    "rpId": "fido.verify.ibm.com",
+    "challenge": "Q29uZ3JhdHVsYXRpb25zIFlvdSBmb3VuZCBpdAo",
+    "userVerification": "preferred",
+    "timeout": 30000,
+    "allowCredentials": [
+      {
+        "type": "public-key",
+        "id": "SSBhbSBhIGNyZWRlbnRpYWwK"
+      }
+    ]
+  }
+}
+ + +
+ + + + + + + + + + + + + + +

+ (async) generatePush(context, transactionId, enrollmentId, authenticatorId, message, pushNotificationTitle, pushNotificationMessage, additionalData) → {Promise.<Object>} +

+
+ + + + + +
+

Request a push notification verification.

+
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
context + + + + Object + + + + + + + +

The context to send for assessment.

+ +
Properties
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
sessionId + + + + string + + + + + + + + + + + + + + + +

The session ID generated by the +user-agent, using an Adaptive client SDK.

+ +
userAgent + + + + string + + + + + + + + + + + + + + + +

The user-agent, typically obtained form +the User-Agent HTTP header.

+ +
ipAddress + + + + string + + + + + + + + + + + + + + + +

The IP address of the user-agent.

+ +
evaluationContext + + + + string + + + + + + + + + <optional>
+ + + + + +
+ + "login" + + +

The stage in the +user-agent for which to perform an evaluation. (Used for continuous +assessment throughout the user-agent.) Different "stages" or "contexts" +will result in different evaluation results, as configured in the +sub-policies of the tenant application's policy. Possible options are +"login" (default), "landing", "profile", "resume", "highassurance", +"other".

+ +
+ + +
transactionId + + + + string + + + + + + + +

The identifier of the transaction received in +Adaptive#assessPolicy.

+ +
enrollmentId + + + + string + + + + + + + +

The identifier of the signature enrollment to +perform second-factor verification with.

+ +
authenticatorId + + + + string + + + + + + + +

The identifier of the authenticator +belonging to the signature.

+ +
message + + + + string + + + + + + + +

The verification message to be displayed in-app.

+ +
pushNotificationTitle + + + + string + + + + + + + +

The title to be displayed +in the push notification banner.

+ +
pushNotificationMessage + + + + string + + + + + + + +

The message to be displayed +in the push notification banner.

+ +
additionalData + + + + Array.<Object> + + + + + + + +

An array of objects containing +"name" and "value" attributes to be displayed +in-app.

+ +
+ + + + +
Returns:
+ + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + + + Promise.<Object> + + + + + + + +

correlation will contain +the confirmation number associated with the transaction. This can be +displayed in the user agent to link transaction to verification request +in authenticator app.

+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ (async) generateQR(context, transactionId, profileId) → {Promise.<Object>} +

+
+ + + + + +
+

Initiate a QR login first-factor verification.

+
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
context + + + + Object + + + + + + + +

The context to send for assessment.

+ +
Properties
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
sessionId + + + + string + + + + + + + + + + + + + + + +

The session ID generated by the +user-agent, using an Adaptive client SDK.

+ +
userAgent + + + + string + + + + + + + + + + + + + + + +

The user-agent, typically obtained form +the User-Agent HTTP header.

+ +
ipAddress + + + + string + + + + + + + + + + + + + + + +

The IP address of the user-agent.

+ +
evaluationContext + + + + string + + + + + + + + + <optional>
+ + + + + +
+ + "login" + + +

The stage in the +user-agent for which to perform an evaluation. (Used for continuous +assessment throughout the user-agent.) Different "stages" or "contexts" +will result in different evaluation results, as configured in the +sub-policies of the tenant application's policy. Possible options are +"login" (default), "landing", "profile", "resume", "highassurance", +"other".

+ +
+ + +
transactionId + + + + string + + + + + + + +

The identifier of the transaction received in +Adaptive#assessPolicy.

+ +
profileId + + + + string + + + + + + + +

The identifier of an IBM Verify registration +profile. Can be retrieved from /v1.0/authenticators/clients.

+ +
+ + + + +
Returns:
+ + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + + + Promise.<Object> + + + + + + + +

The QR code login verification.

+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + + + +
+ + + + + +
Example
+ +

+ QR code return value +

+ + +
{
+  transactionId: '36a101c7-7426-4f45-ab3c-55f8dc075c6e',
+  qr: {
+    code: 'iVBORw0KGgoAAAANSUhEUgAAASwAAAEsAQAAAABR...'
+  }
+}
+ + +
+ + + + + + + + + + + + + + +

+ (async) generateQuestions(context, transactionId, enrollmentId) → {Promise.<Object>} +

+
+ + + + + +
+

Request knowledge questions.

+
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
context + + + + Object + + + + + + + +

The context to send for assessment.

+ +
Properties
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
sessionId + + + + string + + + + + + + + + + + + + + + +

The session ID generated by the +user-agent, using an Adaptive client SDK.

+ +
userAgent + + + + string + + + + + + + + + + + + + + + +

The user-agent, typically obtained form +the User-Agent HTTP header.

+ +
ipAddress + + + + string + + + + + + + + + + + + + + + +

The IP address of the user-agent.

+ +
evaluationContext + + + + string + + + + + + + + + <optional>
+ + + + + +
+ + "login" + + +

The stage in the +user-agent for which to perform an evaluation. (Used for continuous +assessment throughout the user-agent.) Different "stages" or "contexts" +will result in different evaluation results, as configured in the +sub-policies of the tenant application's policy. Possible options are +"login" (default), "landing", "profile", "resume", "highassurance", +"other".

+ +
+ + +
transactionId + + + + string + + + + + + + +

The identifier of the transaction received in +Adaptive#assessPolicy.

+ +
enrollmentId + + + + string + + + + + + + +

The identifier of the enrollment to perform +second-factor verification with.

+ +
+ + + + +
Returns:
+ + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + + + Promise.<Object> + + + + + + + +

The knowledge questions to be answered.

+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + + + +
+ + + + + +
Example
+ +

+ Questions generation return value +

+ + +
{
+  transactionId: '36a101c7-7426-4f45-ab3c-55f8dc075c6e',
+  questions: [
+    {
+      questionKey: 'firstHouseStreet',
+      question: 'What was the street name of the first house you lived in?'
+    },
+    {
+      questionKey: 'bestFriend',
+      question: 'What is the first name of your best friend?'
+    },
+    {
+      questionKey: 'mothersMaidenName',
+      question: 'What is your mothers maiden name?'
+    }
+  ]
+}
+ + +
+ + + + + + + + + + + + + + +

+ (async) generateSMSOTP(context, transactionId, enrollmentId) → {Promise.<Object>} +

+
+ + + + + +
+

Request an SMS OTP.

+
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
context + + + + Object + + + + + + + +

The context to send for assessment.

+ +
Properties
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
sessionId + + + + string + + + + + + + + + + + + + + + +

The session ID generated by the +user-agent, using an Adaptive client SDK.

+ +
userAgent + + + + string + + + + + + + + + + + + + + + +

The user-agent, typically obtained form +the User-Agent HTTP header.

+ +
ipAddress + + + + string + + + + + + + + + + + + + + + +

The IP address of the user-agent.

+ +
evaluationContext + + + + string + + + + + + + + + <optional>
+ + + + + +
+ + "login" + + +

The stage in the +user-agent for which to perform an evaluation. (Used for continuous +assessment throughout the user-agent.) Different "stages" or "contexts" +will result in different evaluation results, as configured in the +sub-policies of the tenant application's policy. Possible options are +"login" (default), "landing", "profile", "resume", "highassurance", +"other".

+ +
+ + +
transactionId + + + + string + + + + + + + +

The identifier of the transaction received in

+ +
enrollmentId + + + + string + + + + + + + +

The identifier of the enrollment to perform +second-factor verification with.

+ +
+ + + + +
Returns:
+ + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + + + Promise.<Object> + + + + + + + +

The a four-digit correlation associated with the +verification. It will be prefixed to the one-time password in the SMS to be +sent.

+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ (async) generateVoiceOTP(context, transactionId, enrollmentId) → {Promise.<Object>} +

+
+ + + + + +
+

Request an Voice OTP.

+
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
context + + + + Object + + + + + + + +

The context to send for assessment.

+ +
Properties
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
sessionId + + + + string + + + + + + + + + + + + + + + +

The session ID generated by the +user-agent, using an Adaptive client SDK.

+ +
userAgent + + + + string + + + + + + + + + + + + + + + +

The user-agent, typically obtained form +the User-Agent HTTP header.

+ +
ipAddress + + + + string + + + + + + + + + + + + + + + +

The IP address of the user-agent.

+ +
evaluationContext + + + + string + + + + + + + + + <optional>
+ + + + + +
+ + "login" + + +

The stage in the +user-agent for which to perform an evaluation. (Used for continuous +assessment throughout the user-agent.) Different "stages" or "contexts" +will result in different evaluation results, as configured in the +sub-policies of the tenant application's policy. Possible options are +"login" (default), "landing", "profile", "resume", "highassurance", +"other".

+ +
+ + +
transactionId + + + + string + + + + + + + +

The identifier of the transaction received in

+ +
enrollmentId + + + + string + + + + + + + +

The identifier of the enrollment to perform +second-factor verification with.

+ +
+ + + + +
Returns:
+ + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + + + Promise.<Object> + + + + + + + +

The a four-digit correlation associated with the +verification. This is not used by default in a Voice OTP call.

+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ getToken(transactionId) → {string} +

+
+ + + + + +
+

Get Access Token for a transaction.

+
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
transactionId + + + + string + + + + + + + +

The identifier of the transaction received in +Adaptive#assessPolicy.

+ +
+ + + + +
Returns:
+ + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + + + string + + + + + + + +

The Access Token associated with the transaction.

+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ (async) introspect(token, tokenTypeHintopt) → {Promise.<Object>} +

+
+ + + + + +
+

Introspect a refresh or access token on OIDC.

+
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDescription
token + + + + string + + + + + + + + + + + + + +

The refresh or access token to introspect.

+ +
tokenTypeHint + + + + string + + + + + + + + + <optional>
+ + + + + +
+

The token type. This attribute is an +optional hint about the token that is being introspected. Possible values +are access_token and refresh_token.

+ +
+ + + + +
Returns:
+ + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + + + Promise.<Object> + + + + + + + +

An object containing an "active" +property indicating whether the introspected token is valid or invalid. +Other properties are also included in the introspection result when the +"active" status is true.

+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ introspectMiddleware(configopt) → {function} +

+
+ + + + + +
+

Return an Express middleware to introspect an access token on OIDC. The +access token to introspect should be in the 'Authorization' header of the +request.

+
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDescription
config + + + + Object + + + + + + + + + <optional>
+ + + + + +
+

The configuration settings used for the token +introspection middleware.

+ +
Properties
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
cacheMaxSize + + + + number + + + + + + + + + <optional>
+ + + + + +
+ + 0 + + +

The maximum size of the cache, i.e. +the maximum number of successful token introspection responses to cache. If +the cache becomes full, the least-recently-used introspection result will +be removed. A value of 0 means no maximum size, i.e. infinity. This value +is ignored after first initialisation (i.e. after first call to function).

+ +
cacheTTL + + + + number + + + + + + + + + <optional>
+ + + + + +
+ + 0 + + +

The time (in seconds) to cache a +successful introspection result for. If a successful token introspection +is done, the result will be cached for the period of time provided, to save +expensive introspection calls on each subsequent request. A value of 0 will +cache the introspect response for the lifetime of the token as provided in +the exp property of the introspect response.

+ +
denyMFAChallenge + + + + boolean + + + + + + + + + <optional>
+ + + + + +
+ + true + + +

A flag indicating +whether an introspected token response with a scope of +'mfa_challenge' should be denied. If true, tokens +with scope of 'mfa_challenge' will be rejected. +If false, the scope of tokens will be +disregarded.

+ +
+ + +
+ + + + +
Returns:
+ + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + + + function + + + + + + + +

The Express middleware function.

+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ (async) logout(accessToken) +

+
+ + + + + +
+

Revoke the access token from OIDC.

+
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
accessToken + + + + string + + + + + + + +

The access token to revoke from OIDC.

+ +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ (async) lookupIdentitySources(context, transactionId, sourceNameopt) → {Promise.<Object>} +

+
+ + + + + +
+

Lookup Identity Sources by name. If name not defined then +return all password-capable sources.

+

Complete a FIDO first-factor verification and validate the resulting JWT.

+
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDescription
context + + + + Object + + + + + + + + + + + + + +

The context to send for assessment.

+ +
Properties
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
sessionId + + + + string + + + + + + + + + + + + + + + +

The session ID generated by the +user-agent, using an Adaptive client SDK.

+ +
userAgent + + + + string + + + + + + + + + + + + + + + +

The user-agent, typically obtained form +the User-Agent HTTP header.

+ +
ipAddress + + + + string + + + + + + + + + + + + + + + +

The IP address of the user-agent.

+ +
evaluationContext + + + + string + + + + + + + + + <optional>
+ + + + + +
+ + "login" + + +

The stage in the +user-agent for which to perform an evaluation. (Used for continuous +assessment throughout the user-agent.) Different "stages" or "contexts" +will result in different evaluation results, as configured in the +sub-policies of the tenant application's policy. Possible options are +"login" (default), "landing", "profile", "resume", "highassurance", +"other".

+ +
+ + +
transactionId + + + + string + + + + + + + + + + + + + +

The identifier of the transaction received in +Adaptive#assessPolicy.

+ +
sourceName + + + + string + + + + + + + + + <optional>
+ + + + + +
+

The source name to look up.

+ +
+ + + + +
Returns:
+ + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + + + Promise.<Object> + + + + + + + +

The result object. The result +object contains an array of identity sources for this user.

+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + + + +
+ + + + + +
Example
+ +

+ Result object +

+ + +
[
+  {
+    "name": "Cloud Directory",
+    "location": "https://<tenant_url>/v1.0/authnmethods/password/11111111-2222-3333-4444-555555555555",
+    "id": "11111111-2222-3333-4444-555555555555",
+    "type": "ibmldap"
+  }
+]
+ + +
+ + + + + + + + + + + + + + +

+ (async) refresh(context, refreshToken) → {Promise.<Object>} +

+
+ + + + + +
+

Initiate an OAuth Refresh flow to obtain updated tokens.

+
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
context + + + + Object + + + + + + + +

The context to send for assessment.

+ +
Properties
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
sessionId + + + + string + + + + + + + + + + + + + + + +

The session ID generated by the +user-agent, using an Adaptive client SDK.

+ +
userAgent + + + + string + + + + + + + + + + + + + + + +

The user-agent, typically obtained form +the User-Agent HTTP header.

+ +
ipAddress + + + + string + + + + + + + + + + + + + + + +

The IP address of the user-agent.

+ +
evaluationContext + + + + string + + + + + + + + + <optional>
+ + + + + +
+ + "login" + + +

The stage in the +user-agent for which to perform an evaluation. (Used for continuous +assessment throughout the user-agent.) Different "stages" or "contexts" +will result in different evaluation results, as configured in the +sub-policies of the tenant application's policy. Possible options are +"login" (default), "landing", "profile", "resume", "highassurance", +"other".

+ +
+ + +
refreshToken + + + + string + + + + + + + +

The refresh token to refresh the access token +with.

+ +
+ + + + +
Returns:
+ + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + + + Promise.<Object> + + + + + + + +

The policy evaluation result object. The result +object has a status property of either allow, +deny, or requires. +If allow, then token object contains refresh +response. +If deny, a details object is returned if an +error message was returned from the token endpoint. +If requires, a transaction is created, and the +transactionId and an array of allowedFactors +is also included in the result object, indicating that further +authentication is required.

+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + + + +
+ + + + + +
Examples
+ +

+ allow result object +

+ + +
{
+  status: 'allow',
+  token: {
+    access_token: 'zscmjBdvIjudOPLhpbmJi6nBRJg7cZ6WY0Udw1nC',
+    refresh_token: 'wFTjurPxTvRD1cW09itgQM83XwCm1UKwsxhVFb1H7HJh8JkwZz',
+    scope: 'openid',
+    grant_id: 'a0b440b6-fefb-46ea-a603-e1040534cd28',
+    id_token: 'eyJhbGciOiJSUzI1NiIsInR5cC...5j_rMn7H3ZpE4axt0WvsYu4jbA',
+    token_type: 'Bearer',
+    expires_in: 7120
+  }
+}
+ +

+ deny result object +

+ + +
{
+  status: 'deny',
+  detail: {
+    error_description: 'CSIAQ0158E The ... is invalid.',
+    error: 'invalid_token'
+  }
+}
+ +

+ requires result object +

+ + +
{
+  status: 'requires',
+  transactionId: '36a101c7-7426-4f45-ab3c-55f8dc075c6e',
+  enrolledFactors: [
+    {
+      id: '61e39f0a-836b-48fa-b4c9-cface6a3ef5a',
+      userId: '60300035KP',
+      type: 'emailotp',
+      created: '2020-06-15T02:51:49.131Z',
+      updated: '2020-06-15T03:15:18.896Z',
+      attempted: '2020-07-16T04:30:14.066Z',
+      enabled: true,
+      validated: true,
+      attributes: {
+        emailAddress: 'email@email.com'
+      }
+    }
+  ]
+}
+ + +
+ + + + + + + + +
+
+ + + + +
+ +
+ + + + + + + + + + \ No newline at end of file diff --git a/sdk/adaptive-proxy/docs/ConfigurationError.html b/sdk/adaptive-proxy/docs/ConfigurationError.html new file mode 100644 index 0000000..58f86aa --- /dev/null +++ b/sdk/adaptive-proxy/docs/ConfigurationError.html @@ -0,0 +1,301 @@ + + + + + + + + + ConfigurationError - Documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + +
+ +

+ ConfigurationError +

+ + + + +
+
+ +

+ + ConfigurationError + +

+ + +
+

Indicate that a provided configuration does not contain the +tenantUrl, clientId, or clientSecret +properties.

+
+ + +
+ +
+
+ + + + + +

Constructor

+ + + + + + + + +

+ new ConfigurationError(message) +

+
+ + + + + +
+

Create a ConfigurationError object with a custom error message.

+
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
message + + + + string + + + + + + + +

The error message.

+ +
+ + + + + + + +
+ + + + + + + + + + + + + + + + +
Author:
+
+ +
+ + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + +
+
+ + + + +
+ +
+ + + + + + + + + + \ No newline at end of file diff --git a/sdk/adaptive-proxy/docs/EmailOTPService.html b/sdk/adaptive-proxy/docs/EmailOTPService.html new file mode 100644 index 0000000..7717832 --- /dev/null +++ b/sdk/adaptive-proxy/docs/EmailOTPService.html @@ -0,0 +1,1349 @@ + + + + + + + + + EmailOTPService - Documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + +
+ +

+ EmailOTPService +

+ + + + +
+
+ +

+ + EmailOTPService + +

+ + +
+

A class for making email OTP related requests to OIDC.

+
+ + +
+ +
+
+ + + + + +

Constructor

+ + + + + + + + +

+ new EmailOTPService() +

+
+ + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + +
Author:
+
+ +
+ + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + + + + + +
+ + +

Extends

+ + + + + + + + + + + + + + + + + + + + +

Methods

+ + + + + + + + + + + + + +

+ (async) generate(enrollmentId) → {Promise.<Object>} +

+
+ + + + + +
+

Request an email OTP multi-factor verification for this enrollment.

+
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
enrollmentId + + + + string + + + + + + + +

The identifier of the email OTP enrollment.

+ +
+ + + + +
Returns:
+ + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + + + Promise.<Object> + + + + + + + +

The email OTP verification.

+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ (async) get(path, params) → {Promise.<Object>} +

+
+ + + + + +
+

Send a HTTP GET request.

+
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
path + + + + string + + + + + + + +

The path on the base URL to send the request to.

+ +
params + + + + Object + + + + + + + +

The URL parameters to be sent with the request.

+ +
+ + + + +
Returns:
+ + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + + + Promise.<Object> + + + + + + + +

The response to the HTTP request.

+
+ + + + + +
+ + + + + + +
Inherited From:
+
+ +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ (async) getEnrollments(userId) → {Promise.<Array>} +

+
+ + + + + +
+

Get an email OTP factor enrollment.

+
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
userId + + + + string + + + + + + + +

The identifier of the user for which to retrieve +enrollments.

+ +
+ + + + +
Returns:
+ + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + + + Promise.<Array> + + + + + + + +

The array of enrollments for the given user.

+
+ + + + + +
+ + + + + + +
Inherited From:
+
+ +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ (async) post(path, data, params) → {Promise.<Object>} +

+
+ + + + + +
+

Send a HTTP POST request.

+
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
path + + + + string + + + + + + + +

The path on the base URL to send the request to.

+ +
data + + + + Object + + + + + + + +

The POST body to send with the request.

+ +
params + + + + Object + + + + + + + +

The URL parameters to send with the request.

+ +
+ + + + +
Returns:
+ + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + + + Promise.<Object> + + + + + + + +

The response to the HTTP request.

+
+ + + + + +
+ + + + + + +
Inherited From:
+
+ +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ (async) verify(verificationId, enrollmentId, otp) → {Promise.<string>} +

+
+ + + + + +
+

Attempt to complete an email OTP multi-factor verification.

+
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
verificationId + + + + string + + + + + + + +

The identifier of the email OTP verification +received in EmailOTPService#generate.

+ +
enrollmentId + + + + string + + + + + + + +

The identifier of the email OTP enrollment.

+ +
otp + + + + string + + + + + + + +

The OTP to attempt verification with.

+ +
+ + + + +
Returns:
+ + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + + + Promise.<string> + + + + + + + +

The HTTP response body of the request.

+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + +
+
+ + + + +
+ +
+ + + + + + + + + + \ No newline at end of file diff --git a/sdk/adaptive-proxy/docs/FIDOService.html b/sdk/adaptive-proxy/docs/FIDOService.html new file mode 100644 index 0000000..ebb9411 --- /dev/null +++ b/sdk/adaptive-proxy/docs/FIDOService.html @@ -0,0 +1,1528 @@ + + + + + + + + + FIDOService - Documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + +
+ +

+ FIDOService +

+ + + + +
+
+ +

+ + FIDOService + +

+ + +
+

A class for making FIDO related requests to OIDC. These include initiating +and completing a FIDO verification.

+
+ + +
+ +
+
+ + + + + +

Constructor

+ + + + + + + + +

+ new FIDOService() +

+
+ + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + +
Author:
+
+ +
+ + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + + + + + +
+ + +

Extends

+ + + + + + + + + + + + + + + + + + + + +

Methods

+ + + + + + + + + + + + + +

+ (async) evaluate(relyingPartyId, credentialId, clientDataJSON, authenticatorData, userHandleopt, signature) → {Promise.<string>} +

+
+ + + + + +
+

Complete a FIDO verification.

+
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDescription
relyingPartyId + + + + string + + + + + + + + + + + + + +

The identifier of a relying party resolved +in FIDOService#resolveRelyingParty.

+ +
credentialId + + + + string + + + + + + + + + + + + + +

The identifier of a FIDO credential received +in the assertion options in FIDOService#generate.

+ +
clientDataJSON + + + + string + + + + + + + + + + + + + +

The assertion options received in +FIDOService#generate, in Base64 URL encoded format.

+ +
authenticatorData + + + + string + + + + + + + + + + + + + +

The information about the authenticator +used for the FIDO verification, verified by the signature.

+ +
userHandle + + + + string + + + + + + + + + <optional>
+ + + + + +
+

The identifier of the user who owns the +authenticator used for the FIDO verification.

+ +
signature + + + + string + + + + + + + + + + + + + +

The challenge received in +FIDOService#generate, signed by the authenticator used +for the FIDO verification, in Base64 URL encoded format.

+ +
+ + + + +
Returns:
+ + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + + + Promise.<string> + + + + + + + +

The JWT to be validated by OIDC in +PolicyService#validate.

+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ (async) generate(relyingPartyId, userId) → {Promise.<Object>} +

+
+ + + + + +
+

Initiate a FIDO verification.

+
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
relyingPartyId + + + + string + + + + + + + +

The identifier of a relying party resolved +in FIDOService#resolveRelyingParty.

+ +
userId + + + + string + + + + + + + +

The identifier of the OIDC user for which to +initiate FIDO verification.

+ +
+ + + + +
Returns:
+ + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + + + Promise.<Object> + + + + + + + +

The assertion options, containing FIDO +credentials.

+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ (async) get(path, params) → {Promise.<Object>} +

+
+ + + + + +
+

Send a HTTP GET request.

+
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
path + + + + string + + + + + + + +

The path on the base URL to send the request to.

+ +
params + + + + Object + + + + + + + +

The URL parameters to be sent with the request.

+ +
+ + + + +
Returns:
+ + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + + + Promise.<Object> + + + + + + + +

The response to the HTTP request.

+
+ + + + + +
+ + + + + + +
Inherited From:
+
+ +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ (async) getEnrollments(userId) → {Promise.<Array>} +

+
+ + + + + +
+

Get an email OTP factor enrollment.

+
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
userId + + + + string + + + + + + + +

The identifier of the user for which to retrieve +enrollments.

+ +
+ + + + +
Returns:
+ + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + + + Promise.<Array> + + + + + + + +

The array of enrollments for the given user.

+
+ + + + + +
+ + + + + + +
Inherited From:
+
+ +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ (async) post(path, data, params) → {Promise.<Object>} +

+
+ + + + + +
+

Send a HTTP POST request.

+
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
path + + + + string + + + + + + + +

The path on the base URL to send the request to.

+ +
data + + + + Object + + + + + + + +

The POST body to send with the request.

+ +
params + + + + Object + + + + + + + +

The URL parameters to send with the request.

+ +
+ + + + +
Returns:
+ + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + + + Promise.<Object> + + + + + + + +

The response to the HTTP request.

+
+ + + + + +
+ + + + + + +
Inherited From:
+
+ +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + +
+
+ + + + +
+ +
+ + + + + + + + + + \ No newline at end of file diff --git a/sdk/adaptive-proxy/docs/FactorService.html b/sdk/adaptive-proxy/docs/FactorService.html new file mode 100644 index 0000000..49c9a30 --- /dev/null +++ b/sdk/adaptive-proxy/docs/FactorService.html @@ -0,0 +1,913 @@ + + + + + + + + + FactorService - Documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + +
+ +

+ FactorService +

+ + + + +
+
+ +

+ + FactorService + +

+ + +
+

A class for making Factors requests.

+
+ + +
+ +
+
+ + + + + +

Constructor

+ + + + + + + + +

+ new FactorService() +

+
+ + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + +
Author:
+
+ +
+ + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + + + + + +
+ + +

Extends

+ + + + + + + + + + + + + + + + + + + + +

Methods

+ + + + + + + + + + + + + +

+ (async) get(path, params) → {Promise.<Object>} +

+
+ + + + + +
+

Send a HTTP GET request.

+
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
path + + + + string + + + + + + + +

The path on the base URL to send the request to.

+ +
params + + + + Object + + + + + + + +

The URL parameters to be sent with the request.

+ +
+ + + + +
Returns:
+ + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + + + Promise.<Object> + + + + + + + +

The response to the HTTP request.

+
+ + + + + +
+ + + + + + +
Inherited From:
+
+ +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ (async) getEnrollments(userId) → {Promise.<Array>} +

+
+ + + + + +
+

Get an email OTP factor enrollment.

+
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
userId + + + + string + + + + + + + +

The identifier of the user for which to retrieve +enrollments.

+ +
+ + + + +
Returns:
+ + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + + + Promise.<Array> + + + + + + + +

The array of enrollments for the given user.

+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ (async) post(path, data, params) → {Promise.<Object>} +

+
+ + + + + +
+

Send a HTTP POST request.

+
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
path + + + + string + + + + + + + +

The path on the base URL to send the request to.

+ +
data + + + + Object + + + + + + + +

The POST body to send with the request.

+ +
params + + + + Object + + + + + + + +

The URL parameters to send with the request.

+ +
+ + + + +
Returns:
+ + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + + + Promise.<Object> + + + + + + + +

The response to the HTTP request.

+
+ + + + + +
+ + + + + + +
Inherited From:
+
+ +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + +
+
+ + + + +
+ +
+ + + + + + + + + + \ No newline at end of file diff --git a/sdk/adaptive-proxy/docs/PasswordService.html b/sdk/adaptive-proxy/docs/PasswordService.html new file mode 100644 index 0000000..6f9f19f --- /dev/null +++ b/sdk/adaptive-proxy/docs/PasswordService.html @@ -0,0 +1,1352 @@ + + + + + + + + + PasswordService - Documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + +
+ +

+ PasswordService +

+ + + + +
+
+ +

+ + PasswordService + +

+ + +
+

A class for making password related requests to OIDC.

+
+ + +
+ +
+
+ + + + + +

Constructor

+ + + + + + + + +

+ new PasswordService() +

+
+ + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + +
Author:
+
+ +
+ + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + + + + + +
+ + +

Extends

+ + + + + + + + + + + + + + + + + + + + +

Methods

+ + + + + + + + + + + + + +

+ (async) authenticate(identitySourceId, username, password) → {Promise.<Object>} +

+
+ + + + + +
+

Attempt password authentication with an identity source.

+
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
identitySourceId + + + + string + + + + + + + +

The identifier of an identity source +resolved in PasswordService#resolveIdentitySource.

+ +
username + + + + string + + + + + + + +

The username to authenticate as.

+ +
password + + + + string + + + + + + + +

The password to authenticate with.

+ +
+ + + + +
Returns:
+ + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + + + Promise.<Object> + + + + + + + +

The HTTP response body of the authentication. +This response body also includes the JWT to be validated by OIDC in +PolicyService#validate.

+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ (async) get(path, params) → {Promise.<Object>} +

+
+ + + + + +
+

Send a HTTP GET request.

+
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
path + + + + string + + + + + + + +

The path on the base URL to send the request to.

+ +
params + + + + Object + + + + + + + +

The URL parameters to be sent with the request.

+ +
+ + + + +
Returns:
+ + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + + + Promise.<Object> + + + + + + + +

The response to the HTTP request.

+
+ + + + + +
+ + + + + + +
Inherited From:
+
+ +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ (async) getEnrollments(userId) → {Promise.<Array>} +

+
+ + + + + +
+

Get an email OTP factor enrollment.

+
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
userId + + + + string + + + + + + + +

The identifier of the user for which to retrieve +enrollments.

+ +
+ + + + +
Returns:
+ + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + + + Promise.<Array> + + + + + + + +

The array of enrollments for the given user.

+
+ + + + + +
+ + + + + + +
Inherited From:
+
+ +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ (async) lookupIdentitySources(sourceName) → {Promise.<Object>} +

+
+ + + + + +
+

Lookup identity sources by sourceName (or all password-capable +sources if sourceName not defined)

+
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
sourceName + + + + string + + + + + + + +

The name of the Identity Source.

+ +
+ + + + +
Returns:
+ + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + + + Promise.<Object> + + + + + + + +

The array of sources returned.

+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ (async) post(path, data, params) → {Promise.<Object>} +

+
+ + + + + +
+

Send a HTTP POST request.

+
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
path + + + + string + + + + + + + +

The path on the base URL to send the request to.

+ +
data + + + + Object + + + + + + + +

The POST body to send with the request.

+ +
params + + + + Object + + + + + + + +

The URL parameters to send with the request.

+ +
+ + + + +
Returns:
+ + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + + + Promise.<Object> + + + + + + + +

The response to the HTTP request.

+
+ + + + + +
+ + + + + + +
Inherited From:
+
+ +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + +
+
+ + + + +
+ +
+ + + + + + + + + + \ No newline at end of file diff --git a/sdk/adaptive-proxy/docs/PolicyService.html b/sdk/adaptive-proxy/docs/PolicyService.html new file mode 100644 index 0000000..3fb2740 --- /dev/null +++ b/sdk/adaptive-proxy/docs/PolicyService.html @@ -0,0 +1,1349 @@ + + + + + + + + + PolicyService - Documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + +
+ +

+ PolicyService +

+ + + + +
+
+ +

+ + PolicyService + +

+ + +
+

A class for making policy related requests to OIDC. These include the initial +grant request, as well as validating received JWT assertions.

+
+ + +
+ +
+
+ + + + + +

Constructor

+ + + + + + + + +

+ new PolicyService(auth, baseURL, context) +

+
+ + + + + +
+

Create a new PolicyService object.

+
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
auth + + + + Object + + + + + + + +

The credentials to authenticate to OIDC.

+ +
baseURL + + + + string + + + + + + + +

The base URL for the OIDC API.

+ +
context + + + + Object + + + + + + + +

The context to send for assessment.

+ +
Properties
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
sessionId + + + + string + + + + + + + +

The session ID generated by the +user-agent, using an Adaptive client SDK.

+ +
userAgent + + + + string + + + + + + + +

The user-agent, typically obtained form +the User-Agent HTTP header.

+ +
ipAddress + + + + string + + + + + + + +

The IP address of the user-agent.

+ +
+ + +
+ + + + + + + +
+ + + + + + + + + + + + + + + + +
Author:
+
+ +
+ + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + + + + + +
+ + +

Extends

+ + + + + + + + + + + + + + + + + + + + +

Methods

+ + + + + + + + + + + + + +

+ (async) assess() → {Promise.<Object>} +

+
+ + + + + +
+

Evaluate the policy attached to the client application.

+

Request an access token from OIDC with the policyauth +grant-type. OIDC will in turn evaluate the policy attached to the client +application, and will respond depending on the outocme of the evaluation. +The response from OIDC will be one of two statuses: deny, or +requires. A deny response is indicated by a 401 status code. +A 200 HTTP status code indicates a requires response.

+
+ + + + + + + + + + + +
Returns:
+ + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + + + Promise.<Object> + + + + + + + +

The HTTP response body for a +requires response from OIDC.

+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + +
Throws:
+ + + +
+
+
+

A deny response is received.

+
+
+
+
+
+
Type
+
+ + + Error + + + + + +
+
+
+
+
+ + + + + + + + + + + + + + + + + + +

+ (async) get(path, params) → {Promise.<Object>} +

+
+ + + + + +
+

Send a HTTP GET request.

+
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
path + + + + string + + + + + + + +

The path on the base URL to send the request to.

+ +
params + + + + Object + + + + + + + +

The URL parameters to be sent with the request.

+ +
+ + + + +
Returns:
+ + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + + + Promise.<Object> + + + + + + + +

The response to the HTTP request.

+
+ + + + + +
+ + + + + + + + +
Overrides:
+
+ +
+ + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ (async) post(path, data, params) → {Promise.<Object>} +

+
+ + + + + +
+

Send a HTTP POST request.

+
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
path + + + + string + + + + + + + +

The path on the base URL to send the request to.

+ +
data + + + + Object + + + + + + + +

The POST body to send with the request.

+ +
params + + + + Object + + + + + + + +

The URL parameters to send with the request.

+ +
+ + + + +
Returns:
+ + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + + + Promise.<Object> + + + + + + + +

The response to the HTTP request.

+
+ + + + + +
+ + + + + + + + +
Overrides:
+
+ +
+ + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ (async) validate(jwt) → {Promise.<Object>} +

+
+ + + + + +
+

Validate a JWT assertion received from a first- or second-factor +verification on OIDC.

+

The response from OIDC will be one of three statuses: allow, +deny, or requires. A deny response is indicated +by a 401 status code. A 200 HTTP status code indicates an +allow or requires response.

+
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
jwt + + + + string + + + + + + + +

The JWT assertion to validate.

+ +
+ + + + +
Returns:
+ + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + + + Promise.<Object> + + + + + + + +

The HTTP response body for an allow +or requires response from OIDC.

+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + +
Throws:
+ + + +
+
+
+

A deny response is received.

+
+
+
+
+
+
Type
+
+ + + Error + + + + + +
+
+
+
+
+ + + + + + + + + + + + +
+
+ + + + +
+ +
+ + + + + + + + + + \ No newline at end of file diff --git a/sdk/adaptive-proxy/docs/PushService.html b/sdk/adaptive-proxy/docs/PushService.html new file mode 100644 index 0000000..199fe0c --- /dev/null +++ b/sdk/adaptive-proxy/docs/PushService.html @@ -0,0 +1,1533 @@ + + + + + + + + + PushService - Documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + +
+ +

+ PushService +

+ + + + +
+
+ +

+ + PushService + +

+ + +
+

A class for making push notification related requests to OIDC. These include +initiating and attempting a push notification verification.

+
+ + +
+ +
+
+ + + + + +

Constructor

+ + + + + + + + +

+ new PushService() +

+
+ + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + +
Author:
+
+ +
+ + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + + + + + +
+ + +

Extends

+ + + + + + + + + + + + + + + + + + + + +

Methods

+ + + + + + + + + + + + + +

+ (async) evaluate(authenticatorId, verificationId) → {Promise.<string>} +

+
+ + + + + +
+

Check status of a push notification verification.

+
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
authenticatorId + + + + string + + + + + + + +

The identifier of the authenticator +belonging to the signature.

+ +
verificationId + + + + string + + + + + + + +

The identifier of the verification initiated +in PushService#generate.

+ +
+ + + + +
Returns:
+ + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + + + Promise.<string> + + + + + + + +

The HTTP response body of the request.

+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ (async) generate(signatureId, authenticatorId, message, originIpAddress, originUserAgent, pushNotificationTitle, pushNotificationMessage, additionalData) → {Promise.<string>} +

+
+ + + + + +
+

Request a push notification verification.

+
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
signatureId + + + + string + + + + + + + +

The identifier of the signature enrollment to +perform second-factor verification with.

+ +
authenticatorId + + + + string + + + + + + + +

The identifier of the authenticator +belonging to the signature.

+ +
message + + + + string + + + + + + + +

The verification message to be displayed in-app.

+ +
originIpAddress + + + + string + + + + + + + +

The IP address from which the +authentication is attempted.

+ +
originUserAgent + + + + string + + + + + + + +

The user agent from which the +authentication is attempted.

+ +
pushNotificationTitle + + + + string + + + + + + + +

The title to be displayed +in the push notification notification banner.

+ +
pushNotificationMessage + + + + string + + + + + + + +

The message to be displayed +in the push notification banner.

+ +
additionalData + + + + Array.<Object> + + + + + + + +

An array of objects containing +"name" and "value" attributes to be displayed +in-app.

+ +
+ + + + +
Returns:
+ + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + + + Promise.<string> + + + + + + + +

The HTTP response body of the request.

+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ (async) get(path, params) → {Promise.<Object>} +

+
+ + + + + +
+

Send a HTTP GET request.

+
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
path + + + + string + + + + + + + +

The path on the base URL to send the request to.

+ +
params + + + + Object + + + + + + + +

The URL parameters to be sent with the request.

+ +
+ + + + +
Returns:
+ + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + + + Promise.<Object> + + + + + + + +

The response to the HTTP request.

+
+ + + + + +
+ + + + + + +
Inherited From:
+
+ +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ (async) getEnrollments(userId) → {Promise.<Array>} +

+
+ + + + + +
+

Get an email OTP factor enrollment.

+
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
userId + + + + string + + + + + + + +

The identifier of the user for which to retrieve +enrollments.

+ +
+ + + + +
Returns:
+ + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + + + Promise.<Array> + + + + + + + +

The array of enrollments for the given user.

+
+ + + + + +
+ + + + + + +
Inherited From:
+
+ +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ (async) post(path, data, params) → {Promise.<Object>} +

+
+ + + + + +
+

Send a HTTP POST request.

+
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
path + + + + string + + + + + + + +

The path on the base URL to send the request to.

+ +
data + + + + Object + + + + + + + +

The POST body to send with the request.

+ +
params + + + + Object + + + + + + + +

The URL parameters to send with the request.

+ +
+ + + + +
Returns:
+ + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + + + Promise.<Object> + + + + + + + +

The response to the HTTP request.

+
+ + + + + +
+ + + + + + +
Inherited From:
+
+ +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + +
+
+ + + + +
+ +
+ + + + + + + + + + \ No newline at end of file diff --git a/sdk/adaptive-proxy/docs/QRService.html b/sdk/adaptive-proxy/docs/QRService.html new file mode 100644 index 0000000..1cb43b1 --- /dev/null +++ b/sdk/adaptive-proxy/docs/QRService.html @@ -0,0 +1,1322 @@ + + + + + + + + + QRService - Documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + +
+ +

+ QRService +

+ + + + +
+
+ +

+ + QRService + +

+ + +
+

A class for making QR login related requests to OIDC.

+
+ + +
+ +
+
+ + + + + +

Constructor

+ + + + + + + + +

+ new QRService() +

+
+ + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + +
Author:
+
+ +
+ + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + + + + + +
+ + +

Extends

+ + + + + + + + + + + + + + + + + + + + +

Methods

+ + + + + + + + + + + + + +

+ (async) generate(profileId) → {Promise.<Object>} +

+
+ + + + + +
+

Initiate a QR login verification.

+
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
profileId + + + + string + + + + + + + +

The identifier of an IBM Verify registration +profile.

+ +
+ + + + +
Returns:
+ + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + + + Promise.<Object> + + + + + + + +

The QR code login verification.

+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ (async) get(path, params) → {Promise.<Object>} +

+
+ + + + + +
+

Send a HTTP GET request.

+
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
path + + + + string + + + + + + + +

The path on the base URL to send the request to.

+ +
params + + + + Object + + + + + + + +

The URL parameters to be sent with the request.

+ +
+ + + + +
Returns:
+ + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + + + Promise.<Object> + + + + + + + +

The response to the HTTP request.

+
+ + + + + +
+ + + + + + +
Inherited From:
+
+ +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ (async) getEnrollments(userId) → {Promise.<Array>} +

+
+ + + + + +
+

Get an email OTP factor enrollment.

+
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
userId + + + + string + + + + + + + +

The identifier of the user for which to retrieve +enrollments.

+ +
+ + + + +
Returns:
+ + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + + + Promise.<Array> + + + + + + + +

The array of enrollments for the given user.

+
+ + + + + +
+ + + + + + +
Inherited From:
+
+ +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ (async) post(path, data, params) → {Promise.<Object>} +

+
+ + + + + +
+

Send a HTTP POST request.

+
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
path + + + + string + + + + + + + +

The path on the base URL to send the request to.

+ +
data + + + + Object + + + + + + + +

The POST body to send with the request.

+ +
params + + + + Object + + + + + + + +

The URL parameters to send with the request.

+ +
+ + + + +
Returns:
+ + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + + + Promise.<Object> + + + + + + + +

The response to the HTTP request.

+
+ + + + + +
+ + + + + + +
Inherited From:
+
+ +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ (async) verify(verificationId, dsi) → {Promise.<string>} +

+
+ + + + + +
+

Complete a QR login verification.

+
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
verificationId + + + + string + + + + + + + +

The identifier of the QR login verification +received in QRService#generate.

+ +
dsi + + + + string + + + + + + + +

The DSI of the QR login verification received in +QRService#generate.

+ +
+ + + + +
Returns:
+ + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + + + Promise.<string> + + + + + + + +

The HTTP response body of the request.

+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + +
+
+ + + + +
+ +
+ + + + + + + + + + \ No newline at end of file diff --git a/sdk/adaptive-proxy/docs/QuestionsService.html b/sdk/adaptive-proxy/docs/QuestionsService.html new file mode 100644 index 0000000..80085b4 --- /dev/null +++ b/sdk/adaptive-proxy/docs/QuestionsService.html @@ -0,0 +1,1353 @@ + + + + + + + + + QuestionsService - Documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + +
+ +

+ QuestionsService +

+ + + + +
+
+ +

+ + QuestionsService + +

+ + +
+

A class for making knowledge questions related requests to OIDC.

+
+ + +
+ +
+
+ + + + + +

Constructor

+ + + + + + + + +

+ new QuestionsService() +

+
+ + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + +
Author:
+
+ +
+ + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + + + + + +
+ + +

Extends

+ + + + + + + + + + + + + + + + + + + + +

Methods

+ + + + + + + + + + + + + +

+ (async) generate(enrollmentId) → {Promise.<Object>} +

+
+ + + + + +
+

Request a knowledge questions multi-factor verification for this +enrollment.

+
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
enrollmentId + + + + string + + + + + + + +

The identifier of the knowledge questions +enrollment.

+ +
+ + + + +
Returns:
+ + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + + + Promise.<Object> + + + + + + + +

The knowledge questions verification.

+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ (async) get(path, params) → {Promise.<Object>} +

+
+ + + + + +
+

Send a HTTP GET request.

+
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
path + + + + string + + + + + + + +

The path on the base URL to send the request to.

+ +
params + + + + Object + + + + + + + +

The URL parameters to be sent with the request.

+ +
+ + + + +
Returns:
+ + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + + + Promise.<Object> + + + + + + + +

The response to the HTTP request.

+
+ + + + + +
+ + + + + + +
Inherited From:
+
+ +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ (async) getEnrollments(userId) → {Promise.<Array>} +

+
+ + + + + +
+

Get an email OTP factor enrollment.

+
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
userId + + + + string + + + + + + + +

The identifier of the user for which to retrieve +enrollments.

+ +
+ + + + +
Returns:
+ + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + + + Promise.<Array> + + + + + + + +

The array of enrollments for the given user.

+
+ + + + + +
+ + + + + + +
Inherited From:
+
+ +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ (async) post(path, data, params) → {Promise.<Object>} +

+
+ + + + + +
+

Send a HTTP POST request.

+
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
path + + + + string + + + + + + + +

The path on the base URL to send the request to.

+ +
data + + + + Object + + + + + + + +

The POST body to send with the request.

+ +
params + + + + Object + + + + + + + +

The URL parameters to send with the request.

+ +
+ + + + +
Returns:
+ + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + + + Promise.<Object> + + + + + + + +

The response to the HTTP request.

+
+ + + + + +
+ + + + + + +
Inherited From:
+
+ +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ (async) verify(verificationId, enrollmentId, questions) → {Promise.<string>} +

+
+ + + + + +
+

Attempt to complete a knowledge questions multi-factor verification.

+
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
verificationId + + + + string + + + + + + + +

The identifier of the knowledge questions +verification received in QuestionsService#generate.

+ +
enrollmentId + + + + string + + + + + + + +

The identifier of the knowledge questions +enrollment.

+ +
questions + + + + Array.<Object> + + + + + + + +

The array of question keys and corresponding +answers to attempt verification with.

+ +
+ + + + +
Returns:
+ + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + + + Promise.<string> + + + + + + + +

The HTTP response body of the request.

+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + +
+
+ + + + +
+ +
+ + + + + + + + + + \ No newline at end of file diff --git a/sdk/adaptive-proxy/docs/SMSOTPService.html b/sdk/adaptive-proxy/docs/SMSOTPService.html new file mode 100644 index 0000000..04cae06 --- /dev/null +++ b/sdk/adaptive-proxy/docs/SMSOTPService.html @@ -0,0 +1,1349 @@ + + + + + + + + + SMSOTPService - Documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + +
+ +

+ SMSOTPService +

+ + + + +
+
+ +

+ + SMSOTPService + +

+ + +
+

A class for making SMS OTP related requests to OIDC.

+
+ + +
+ +
+
+ + + + + +

Constructor

+ + + + + + + + +

+ new SMSOTPService() +

+
+ + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + +
Author:
+
+ +
+ + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + + + + + +
+ + +

Extends

+ + + + + + + + + + + + + + + + + + + + +

Methods

+ + + + + + + + + + + + + +

+ (async) generate(enrollmentId) → {Promise.<Object>} +

+
+ + + + + +
+

Request an SMS OTP multi-factor verification for this enrollment.

+
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
enrollmentId + + + + string + + + + + + + +

The identifier of the SMS OTP enrollment.

+ +
+ + + + +
Returns:
+ + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + + + Promise.<Object> + + + + + + + +

The SMS OTP verification.

+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ (async) get(path, params) → {Promise.<Object>} +

+
+ + + + + +
+

Send a HTTP GET request.

+
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
path + + + + string + + + + + + + +

The path on the base URL to send the request to.

+ +
params + + + + Object + + + + + + + +

The URL parameters to be sent with the request.

+ +
+ + + + +
Returns:
+ + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + + + Promise.<Object> + + + + + + + +

The response to the HTTP request.

+
+ + + + + +
+ + + + + + +
Inherited From:
+
+ +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ (async) getEnrollments(userId) → {Promise.<Array>} +

+
+ + + + + +
+

Get an email OTP factor enrollment.

+
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
userId + + + + string + + + + + + + +

The identifier of the user for which to retrieve +enrollments.

+ +
+ + + + +
Returns:
+ + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + + + Promise.<Array> + + + + + + + +

The array of enrollments for the given user.

+
+ + + + + +
+ + + + + + +
Inherited From:
+
+ +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ (async) post(path, data, params) → {Promise.<Object>} +

+
+ + + + + +
+

Send a HTTP POST request.

+
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
path + + + + string + + + + + + + +

The path on the base URL to send the request to.

+ +
data + + + + Object + + + + + + + +

The POST body to send with the request.

+ +
params + + + + Object + + + + + + + +

The URL parameters to send with the request.

+ +
+ + + + +
Returns:
+ + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + + + Promise.<Object> + + + + + + + +

The response to the HTTP request.

+
+ + + + + +
+ + + + + + +
Inherited From:
+
+ +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ (async) verify(verificationId, enrollmentId, otp) → {Promise.<string>} +

+
+ + + + + +
+

Attempt to complete an SMS OTP multi-factor verification.

+
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
verificationId + + + + string + + + + + + + +

The identifier of the SMS OTP verification +received in SMSOTPService#generate.

+ +
enrollmentId + + + + string + + + + + + + +

The identifier of the SMS OTP enrollment.

+ +
otp + + + + string + + + + + + + +

The OTP to attempt verification with.

+ +
+ + + + +
Returns:
+ + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + + + Promise.<string> + + + + + + + +

The HTTP response body of the request.

+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + +
+
+ + + + +
+ +
+ + + + + + + + + + \ No newline at end of file diff --git a/sdk/adaptive-proxy/docs/Service.html b/sdk/adaptive-proxy/docs/Service.html new file mode 100644 index 0000000..502cfd3 --- /dev/null +++ b/sdk/adaptive-proxy/docs/Service.html @@ -0,0 +1,1222 @@ + + + + + + + + + Service - Documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + +
+ +

+ Service +

+ + + + +
+
+ +

+ + Service + +

+ + +
+

A class for making HTTP requests to OIDC.

+
+ + +
+ +
+
+ + + + + +

Constructor

+ + + + + + + + +

+ new Service(auth, baseURL, context, contentTypeHeaderopt, acceptHeaderopt) +

+
+ + + + + +
+

Create a new Service object.

+
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
auth + + + + Object + + + + + + + + + + + + + + + +

The credentials to authenticate to Factors or OIDC. +Either an accessToken, or a clientId and +clientSecret may be used for authentication. If an +accessToken, set this object's +_authorizationHeader property to Authorization: Bearer +${accessToken}. If a clientId and +clientSecret, Base64 encode the clientId and +clientSecret, and set this object's +_authorizationHeader property to Authorization: Basic +${Base64(clientId:clientSecret)}.

+ +
Properties
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDescription
accessToken + + + + string + + + + + + + + + <optional>
+ + + + + +
+

The access token to authenticate to +Factors or OIDC.

+ +
clientId + + + + string + + + + + + + + + <optional>
+ + + + + +
+

The identifier of the client to +authenticate to Factors or OIDC.

+ +
clientSecret + + + + string + + + + + + + + + <optional>
+ + + + + +
+

The client secret to authenticate to +Factors or OIDC.

+ +
+ + +
baseURL + + + + string + + + + + + + + + + + + + + + +

The base URL for the API, normally the tenant URL.

+ +
context + + + + Object + + + + + + + + + + + + + + + +

The context to send for assessment.

+ +
Properties
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
sessionId + + + + string + + + + + + + +

The session ID generated by the +user-agent, using an Adaptive client SDK.

+ +
userAgent + + + + string + + + + + + + +

The user-agent, typically obtained form +the User-Agent HTTP header.

+ +
ipAddress + + + + string + + + + + + + +

The IP address of the user-agent.

+ +
+ + +
contentTypeHeader + + + + string + + + + + + + + + <optional>
+ + + + + +
+ + 'json' + + +

The type of content to send in +the requests. Sets the Content-Type header of the requests +appropriately.

+ +
acceptHeader + + + + string + + + + + + + + + <optional>
+ + + + + +
+ + 'json' + + +

The type of content to receive in the +response. Sets the Accept header of the requests +appropriately.

+ +
+ + + + + + + +
+ + + + + + + + + + + + + + + + +
Author:
+
+ +
+ + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + +

Methods

+ + + + + + + + + + + + + +

+ (async) get(path, params) → {Promise.<Object>} +

+
+ + + + + +
+

Send a HTTP GET request.

+
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
path + + + + string + + + + + + + +

The path on the base URL to send the request to.

+ +
params + + + + Object + + + + + + + +

The URL parameters to be sent with the request.

+ +
+ + + + +
Returns:
+ + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + + + Promise.<Object> + + + + + + + +

The response to the HTTP request.

+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ (async) post(path, data, params) → {Promise.<Object>} +

+
+ + + + + +
+

Send a HTTP POST request.

+
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
path + + + + string + + + + + + + +

The path on the base URL to send the request to.

+ +
data + + + + Object + + + + + + + +

The POST body to send with the request.

+ +
params + + + + Object + + + + + + + +

The URL parameters to send with the request.

+ +
+ + + + +
Returns:
+ + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + + + Promise.<Object> + + + + + + + +

The response to the HTTP request.

+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + +
+
+ + + + +
+ +
+ + + + + + + + + + \ No newline at end of file diff --git a/sdk/adaptive-proxy/docs/TOTPService.html b/sdk/adaptive-proxy/docs/TOTPService.html new file mode 100644 index 0000000..7a98da7 --- /dev/null +++ b/sdk/adaptive-proxy/docs/TOTPService.html @@ -0,0 +1,1135 @@ + + + + + + + + + TOTPService - Documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + +
+ +

+ TOTPService +

+ + + + +
+
+ +

+ + TOTPService + +

+ + +
+

A class for making TOTP related requests to OIDC.

+
+ + +
+ +
+
+ + + + + +

Constructor

+ + + + + + + + +

+ new TOTPService() +

+
+ + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + +
Author:
+
+ +
+ + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + + + + + +
+ + +

Extends

+ + + + + + + + + + + + + + + + + + + + +

Methods

+ + + + + + + + + + + + + +

+ (async) get(path, params) → {Promise.<Object>} +

+
+ + + + + +
+

Send a HTTP GET request.

+
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
path + + + + string + + + + + + + +

The path on the base URL to send the request to.

+ +
params + + + + Object + + + + + + + +

The URL parameters to be sent with the request.

+ +
+ + + + +
Returns:
+ + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + + + Promise.<Object> + + + + + + + +

The response to the HTTP request.

+
+ + + + + +
+ + + + + + +
Inherited From:
+
+ +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ (async) getEnrollments(userId) → {Promise.<Array>} +

+
+ + + + + +
+

Get an email OTP factor enrollment.

+
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
userId + + + + string + + + + + + + +

The identifier of the user for which to retrieve +enrollments.

+ +
+ + + + +
Returns:
+ + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + + + Promise.<Array> + + + + + + + +

The array of enrollments for the given user.

+
+ + + + + +
+ + + + + + +
Inherited From:
+
+ +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ (async) post(path, data, params) → {Promise.<Object>} +

+
+ + + + + +
+

Send a HTTP POST request.

+
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
path + + + + string + + + + + + + +

The path on the base URL to send the request to.

+ +
data + + + + Object + + + + + + + +

The POST body to send with the request.

+ +
params + + + + Object + + + + + + + +

The URL parameters to send with the request.

+ +
+ + + + +
Returns:
+ + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + + + Promise.<Object> + + + + + + + +

The response to the HTTP request.

+
+ + + + + +
+ + + + + + +
Inherited From:
+
+ +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ (async) verify(enrollmentId, otp) → {Promise.<string>} +

+
+ + + + + +
+

Attempt to complete a TOTP multi-factor verification.

+
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
enrollmentId + + + + string + + + + + + + +

The identifier of the TOTP enrollment.

+ +
otp + + + + string + + + + + + + +

The OTP to attempt verification with.

+ +
+ + + + +
Returns:
+ + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + + + Promise.<string> + + + + + + + +

The HTTP response body of the request.

+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + +
+
+ + + + +
+ +
+ + + + + + + + + + \ No newline at end of file diff --git a/sdk/adaptive-proxy/docs/TokenError.html b/sdk/adaptive-proxy/docs/TokenError.html new file mode 100644 index 0000000..dc08e1b --- /dev/null +++ b/sdk/adaptive-proxy/docs/TokenError.html @@ -0,0 +1,300 @@ + + + + + + + + + TokenError - Documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + +
+ +

+ TokenError +

+ + + + +
+
+ +

+ + TokenError + +

+ + +
+

Indicate that a token is invalid, or a token related operation (e.g. token +introspection) has failed.

+
+ + +
+ +
+
+ + + + + +

Constructor

+ + + + + + + + +

+ new TokenError(message) +

+
+ + + + + +
+

Create a TokenError object with a custom error message.

+
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
message + + + + string + + + + + + + +

The error message.

+ +
+ + + + + + + +
+ + + + + + + + + + + + + + + + +
Author:
+
+ +
+ + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + +
+
+ + + + +
+ +
+ + + + + + + + + + \ No newline at end of file diff --git a/sdk/adaptive-proxy/docs/TokenService.html b/sdk/adaptive-proxy/docs/TokenService.html new file mode 100644 index 0000000..43f07d8 --- /dev/null +++ b/sdk/adaptive-proxy/docs/TokenService.html @@ -0,0 +1,1532 @@ + + + + + + + + + TokenService - Documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + +
+ +

+ TokenService +

+ + + + +
+
+ +

+ + TokenService + +

+ + +
+

A class for making token related requests to OIDC.

+
+ + +
+ +
+
+ + + + + +

Constructor

+ + + + + + + + +

+ new TokenService(auth, baseURL, context) +

+
+ + + + + +
+

Create a new TokenService object.

+
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
auth + + + + Object + + + + + + + +

The credentials to authenticate to OIDC.

+ +
baseURL + + + + string + + + + + + + +

The base URL for the OIDC API.

+ +
context + + + + Object + + + + + + + +

The context to send for assessment.

+ +
Properties
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
sessionId + + + + string + + + + + + + +

The session ID generated by the +user-agent, using an Adaptive client SDK.

+ +
userAgent + + + + string + + + + + + + +

The user-agent, typically obtained form +the User-Agent HTTP header.

+ +
ipAddress + + + + string + + + + + + + +

The IP address of the user-agent.

+ +
+ + +
+ + + + + + + +
+ + + + + + + + + + + + + + + + +
Author:
+
+ +
+ + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + + + + + +
+ + +

Extends

+ + + + + + + + + + + + + + + + + + + + +

Methods

+ + + + + + + + + + + + + +

+ (async) get(path, params) → {Promise.<Object>} +

+
+ + + + + +
+

Send a HTTP GET request.

+
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
path + + + + string + + + + + + + +

The path on the base URL to send the request to.

+ +
params + + + + Object + + + + + + + +

The URL parameters to be sent with the request.

+ +
+ + + + +
Returns:
+ + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + + + Promise.<Object> + + + + + + + +

The response to the HTTP request.

+
+ + + + + +
+ + + + + + + + +
Overrides:
+
+ +
+ + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ (async) introspectToken(token, tokenTypeHintopt) → {Promise.<Object>} +

+
+ + + + + +
+

Introspect an access or refresh token.

+
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDescription
token + + + + string + + + + + + + + + + + + + +

The access or refresh token to introspect.

+ +
tokenTypeHint + + + + string + + + + + + + + + <optional>
+ + + + + +
+

The token type. This attribute is an +optional hint about the token that is being introspected. Possible values +are access_token and refresh_token.

+ +
+ + + + +
Returns:
+ + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + + + Promise.<Object> + + + + + + + +

The HTTP response body for the token introspect +request, which is an object containing an "active" property +indicating whether the introspected token is valid or invalid. Other +properties are also included in the introspection result when the +"active" status is true.

+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ (async) post(path, data, params) → {Promise.<Object>} +

+
+ + + + + +
+

Send a HTTP POST request.

+
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
path + + + + string + + + + + + + +

The path on the base URL to send the request to.

+ +
data + + + + Object + + + + + + + +

The POST body to send with the request.

+ +
params + + + + Object + + + + + + + +

The URL parameters to send with the request.

+ +
+ + + + +
Returns:
+ + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + + + Promise.<Object> + + + + + + + +

The response to the HTTP request.

+
+ + + + + +
+ + + + + + + + +
Overrides:
+
+ +
+ + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ (async) refreshAccessToken(refreshToken) → {Promise.<Object>} +

+
+ + + + + +
+

Refresh an access token.

+
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
refreshToken + + + + string + + + + + + + +

The refresh token to refresh with.

+ +
+ + + + +
Returns:
+ + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + + + Promise.<Object> + + + + + + + +

The HTTP response body for the refresh token +request, containing the new access and refresh tokens.

+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ (async) revokeAccessToken(accessToken) +

+
+ + + + + +
+

Revoke an access token.

+
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
accessToken + + + + string + + + + + + + +

The access token to revoke.

+ +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + +
+
+ + + + +
+ +
+ + + + + + + + + + \ No newline at end of file diff --git a/sdk/adaptive-proxy/docs/TransactionError.html b/sdk/adaptive-proxy/docs/TransactionError.html new file mode 100644 index 0000000..4009737 --- /dev/null +++ b/sdk/adaptive-proxy/docs/TransactionError.html @@ -0,0 +1,300 @@ + + + + + + + + + TransactionError - Documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + +
+ +

+ TransactionError +

+ + + + +
+
+ +

+ + TransactionError + +

+ + +
+

Indicate that a transaction associated to the provided transaction ID does +not exist, or the transaction does not contain a required property.

+
+ + +
+ +
+
+ + + + + +

Constructor

+ + + + + + + + +

+ new TransactionError(message) +

+
+ + + + + +
+

Create a TransactionError object with a custom error message.

+
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
message + + + + string + + + + + + + +

The error message.

+ +
+ + + + + + + +
+ + + + + + + + + + + + + + + + +
Author:
+
+ +
+ + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + +
+
+ + + + +
+ +
+ + + + + + + + + + \ No newline at end of file diff --git a/sdk/adaptive-proxy/docs/VoiceOTPService.html b/sdk/adaptive-proxy/docs/VoiceOTPService.html new file mode 100644 index 0000000..7fda2cb --- /dev/null +++ b/sdk/adaptive-proxy/docs/VoiceOTPService.html @@ -0,0 +1,1349 @@ + + + + + + + + + VoiceOTPService - Documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + +
+ +

+ VoiceOTPService +

+ + + + +
+
+ +

+ + VoiceOTPService + +

+ + +
+

A class for making Voice OTP related requests to OIDC.

+
+ + +
+ +
+
+ + + + + +

Constructor

+ + + + + + + + +

+ new VoiceOTPService() +

+
+ + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + +
Author:
+
+ +
+ + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + + + + + +
+ + +

Extends

+ + + + + + + + + + + + + + + + + + + + +

Methods

+ + + + + + + + + + + + + +

+ (async) generate(enrollmentId) → {Promise.<Object>} +

+
+ + + + + +
+

Request an Voice OTP multi-factor verification for this enrollment.

+
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
enrollmentId + + + + string + + + + + + + +

The identifier of the Voice OTP enrollment.

+ +
+ + + + +
Returns:
+ + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + + + Promise.<Object> + + + + + + + +

The Voice OTP verification.

+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ (async) get(path, params) → {Promise.<Object>} +

+
+ + + + + +
+

Send a HTTP GET request.

+
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
path + + + + string + + + + + + + +

The path on the base URL to send the request to.

+ +
params + + + + Object + + + + + + + +

The URL parameters to be sent with the request.

+ +
+ + + + +
Returns:
+ + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + + + Promise.<Object> + + + + + + + +

The response to the HTTP request.

+
+ + + + + +
+ + + + + + +
Inherited From:
+
+ +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ (async) getEnrollments(userId) → {Promise.<Array>} +

+
+ + + + + +
+

Get an email OTP factor enrollment.

+
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
userId + + + + string + + + + + + + +

The identifier of the user for which to retrieve +enrollments.

+ +
+ + + + +
Returns:
+ + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + + + Promise.<Array> + + + + + + + +

The array of enrollments for the given user.

+
+ + + + + +
+ + + + + + +
Inherited From:
+
+ +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ (async) post(path, data, params) → {Promise.<Object>} +

+
+ + + + + +
+

Send a HTTP POST request.

+
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
path + + + + string + + + + + + + +

The path on the base URL to send the request to.

+ +
data + + + + Object + + + + + + + +

The POST body to send with the request.

+ +
params + + + + Object + + + + + + + +

The URL parameters to send with the request.

+ +
+ + + + +
Returns:
+ + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + + + Promise.<Object> + + + + + + + +

The response to the HTTP request.

+
+ + + + + +
+ + + + + + +
Inherited From:
+
+ +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ (async) verify(verificationId, enrollmentId, otp) → {Promise.<string>} +

+
+ + + + + +
+

Attempt to complete an Voice OTP multi-factor verification.

+
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
verificationId + + + + string + + + + + + + +

The identifier of the Voice OTP verification +received in VoiceOTPService#generate.

+ +
enrollmentId + + + + string + + + + + + + +

The identifier of the Voice OTP enrollment.

+ +
otp + + + + string + + + + + + + +

The OTP to attempt verification with.

+ +
+ + + + +
Returns:
+ + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + + + Promise.<string> + + + + + + + +

The HTTP response body of the request.

+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + +
+
+ + + + +
+ +
+ + + + + + + + + + \ No newline at end of file diff --git a/sdk/adaptive-proxy/docs/adaptive.js.html b/sdk/adaptive-proxy/docs/adaptive.js.html new file mode 100644 index 0000000..2bd7f8e --- /dev/null +++ b/sdk/adaptive-proxy/docs/adaptive.js.html @@ -0,0 +1,1729 @@ + + + + + + + + + + + adaptive.js - Documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + +
+ +

+ adaptive.js +

+ + + + + +
+
+
// Copyright contributors to the IBM Security Verify Adaptive Proxy SDK
+// for JavaScript project
+
+
+const LRU = require('lru-cache');
+
+const transactionUtils = require('./utils/transactionUtils');
+const ConfigurationError = require('./errors/configurationError');
+const TransactionError = require('./errors/transactionError');
+const TokenError = require('./errors/tokenError');
+const PolicyService = require('./services/oidc/policyService');
+const FIDOService = require('./services/factors/fidoService');
+const PasswordService = require(
+    './services/factors/passwordService');
+const QRService = require('./services/factors/qrService');
+const TOTPService = require('./services/factors/totpService');
+const EmailOTPService = require('./services/factors/emailOTPService');
+const SMSOTPService = require('./services/factors/smsOTPService');
+const VoiceOTPService = require('./services/factors/voiceOTPService');
+const QuestionsService = require('./services/factors/questionsService');
+const PushService = require('./services/factors/pushService');
+const FactorService = require('./services/factors/factorService');
+const TokenService = require('./services/oidc/tokenService');
+
+
+/**
+ * Class representing the PDA (Policy Driven Authentication) SDK. Used to
+ * perform and validate first- and second-factor verifications on CI (Cloud
+ * Identity).
+ * @author Adam Dorogi-Kaposi <adam.dorogi-kaposi@ibm.com>
+ */
+class Adaptive {
+  /**
+   * Create a new {@link Adaptive} object.
+   * @param {Object} config The configuration settings used for CI requests.
+   * @param {string} config.clientId The identifier of the client application.
+   * @param {string} config.clientSecret The client application secret.
+   * @param {string} config.tenantUrl The URL of the tenant.
+   * @param {Object} [transactionFunctions] An object containing transaction
+   * operation functions. This parameter is optional, in case the
+   * developer would like to handle the storing, retrieving, updating, and
+   * deleting of transactions created during the A2 flow in an external
+   * database. Otherwise, a default in-memory option is used for handling
+   * transactions. If specified, this object must contain four parameters:
+   * <code>createTransaction</code>, <code>getTransaction</code>,
+   * <code>updateTransaction</code>, and <code>deleteTransaction</code>, each
+   * being the appropriate function to store, retrieve, update, and delete
+   * transactions respectively. The custom storage mechanism should ideally have
+   * a time-to-live for the transactions (e.g. 1 hour), to prevent accumulating
+   * unused/unfinished transactions.
+   * @param {Function} [transactionFunctions.createTransaction] The function
+   * used to create (store) a transaction. This function should take one
+   * parameter; a transaction <code>Object</code>. It should store the object in
+   * a database of choice, indexed by a randomly generated v4 UUID (the
+   * transaction ID). After storing the transaction object associated to a
+   * transaction ID, the function should return the transaction ID as a
+   * <code>string</code>.
+   * @param {Function} [transactionFunctions.getTransaction] The function used
+   * to retrieve stored transactions. This function should take one parameter;
+   * a transaction ID <code>string</code>. It should return the transaction
+   * <code>Object</code> associated to the given transaction ID.
+   * @param {Function} [transactionFunctions.updateTransaction] The function
+   * used to update (i.e. add additional properties to) an existing transaction.
+   * This function should take two parameters (in order); a transaction ID
+   * <code>string</code> of the transaction to update, and an
+   * <code>Object</code> of additional properties to add to the
+   * transaction. For example, if the existing transaction is <code>{"userId":
+   * "123456"}</code>, and the object passed into this function is
+   * <code>{"name": "John"}</code>, the updated transaction should be
+   * <code>{"userId": "123456", "name": "John"}</code>. This function shouldn't
+   * return anything.
+   * @param {Function} [transactionFunctions.deleteTransaction] The function
+   * used to delete an existing transaction. This function should take one
+   * parameter; a transaction ID <code>string</code>. The function should remove
+   * the transaction associated with the given transaction ID from the database
+   * storage. This function shouldn't return anything.
+   * @throws {ConfigurationError} The configuration object doesn't contain the
+   * required properties.
+   * @throws {TransactionError} The <code>createTransaction</code>,
+   * <code>getTransaction</code>, <code>updateTransaction</code>, or
+   * <code>deleteTransaction</code> functions are missing from the transaction
+   * functions object.
+   */
+  constructor(config, transactionFunctions={
+    createTransaction: transactionUtils.createTransaction,
+    getTransaction: transactionUtils.getTransaction,
+    updateTransaction: transactionUtils.updateTransaction,
+    deleteTransaction: transactionUtils.deleteTransaction}) {
+    if (!config.clientId) {
+      throw new ConfigurationError(
+          `Cannot find property 'clientId' in configuration settings.`);
+    } else if (!config.clientSecret) {
+      throw new ConfigurationError(
+          `Cannot find property 'clientSecret' in configuration settings.`);
+    } else if (!config.tenantUrl) {
+      throw new ConfigurationError(
+          `Cannot find property 'tenantUrl' in configuration settings.`);
+    }
+
+    if (!transactionFunctions.createTransaction) {
+      throw new TransactionError(
+          `Cannot find function 'createTransaction' in transaction functions.`);
+    } else if (!transactionFunctions.getTransaction) {
+      throw new TransactionError(
+          `Cannot find function 'getTransaction' in transaction functions.`);
+    } else if (!transactionFunctions.updateTransaction) {
+      throw new TransactionError(
+          `Cannot find function 'updateTransaction' in transaction functions.`);
+    } else if (!transactionFunctions.deleteTransaction) {
+      throw new TransactionError(
+          `Cannot find function 'deleteTransaction' in transaction functions.`);
+    }
+
+    this._config = config;
+    this._transactionFunctions = transactionFunctions;
+
+    console.log(`[${Adaptive.name}:constructor(config, transactionFunctions)]`,
+        'clientId:', this._config.clientId);
+    console.log(`[${Adaptive.name}:constructor(config, transactionFunctions)]`,
+        'clientSecret:', '****');
+    console.log(`[${Adaptive.name}:constructor(config, transactionFunctions)]`,
+        'tenantUrl:', this._config.tenantUrl);
+
+    console.log(`[${Adaptive.name}:constructor(config, transactionFunctions)]`,
+        'createTransaction:', this._transactionFunctions.createTransaction);
+    console.log(`[${Adaptive.name}:constructor(config, transactionFunctions)]`,
+        'getTransaction:', this._transactionFunctions.getTransaction);
+    console.log(`[${Adaptive.name}:constructor(config, transactionFunctions)]`,
+        'updateTransaction:', this._transactionFunctions.updateTransaction);
+    console.log(`[${Adaptive.name}:constructor(config, transactionFunctions)]`,
+        'deleteTransaction:', this._transactionFunctions.deleteTransaction);
+  }
+
+  /**
+   * Perform an initial grant request.
+   *
+   * The initial grant request uses the <code>policyauth</code> grant-type to
+   * evaluate the policy attached to the client application on OIDC with the
+   * risk engine.
+   *
+   * An in-memory transaction is also created to associate subsequent requests
+   * to a session or "transaction".
+   * @param {Object} context The context to send for assessment.
+   * @param {string} context.sessionId The session ID generated by the
+   * user-agent, using an Adaptive client SDK.
+   * @param {string} context.userAgent The user-agent, typically obtained form
+   * the User-Agent HTTP header.
+   * @param {string} context.ipAddress The IP address of the user-agent.
+   * @param {string} [context.evaluationContext="login"] The stage in the
+   * user-agent for which to perform an evaluation. (Used for continuous
+   * assessment throughout the user-agent.) Different "stages" or "contexts"
+   * will result in different evaluation results, as configured in the
+   * sub-policies of the tenant application's policy. Possible options are
+   * "login" (default), "landing", "profile", "resume", "highassurance",
+   * "other".
+   * @return {Promise<Object>} The policy evaluation result object. The result
+   * object has a <code>status</code> property of either <code>deny</code>, or
+   * <code>requires</code>. If <code>deny</code>, only the <code>status</code>
+   * property is included in the result object. If <code>requires</code>, a
+   * transaction is created, and the <code>transactionId</code> and an array of
+   * <code>allowedFactors</code> is also included in the result object,
+   * indicating that further first-factor authentication is required.
+   * @example <caption><code>deny</code> result object</caption>
+   * {
+   *   status: 'deny'
+   * }
+   * @example <caption><code>requires</code> result object</caption>
+   * {
+   *   status: 'requires',
+   *   transactionId: '36a101c7-7426-4f45-ab3c-55f8dc075c6e',
+   *   allowedFactors: ['qr', 'fido', 'password']
+   * }
+   */
+  async assessPolicy({sessionId, userAgent, ipAddress,
+    evaluationContext='login'}) {
+    const context = {sessionId, userAgent, ipAddress, evaluationContext};
+    const policyService = new PolicyService({clientId: this._config.clientId,
+      clientSecret: this._config.clientSecret}, this._config.tenantUrl,
+    context);
+
+    try {
+      // Get a `policyauth` access token from OIDC.
+      const assessment = await policyService.assess();
+      console.log(`[${Adaptive.name}:assessPolicy(context)]`, 'assessment:',
+          assessment);
+
+      if (assessment.scope === 'openid') {
+        return {status: 'allow', token: assessment};
+      }
+
+      // If no error is thrown by this point, further authentication is required
+      // (i.e. we received a `requires` response).
+
+      // Create transaction and store in memory cache.
+      const transaction = {assessment};
+      const transactionId = this._transactionFunctions
+          .createTransaction(transaction);
+
+      const allowedFactors = assessment.allowedFactors.map((factor) => {
+        return {type: factor};
+      });
+      return {status: 'requires', allowedFactors, transactionId};
+    } catch (error) {
+      // Policy evaluation is denied.
+      console.log(`[${Adaptive.name}:assessPolicy(context)]`, 'error:', error);
+      const jsonResp = {status: 'deny'};
+      if (error.response.data) {
+        jsonResp.detail = error.response.data;
+      }
+      return jsonResp;
+    }
+  }
+
+  /**
+   * Initiate a FIDO first-factor verification to be completed by the
+   * user-agent.
+   * @param {Object} context The context to send for assessment.
+   * @param {string} context.sessionId The session ID generated by the
+   * user-agent, using an Adaptive client SDK.
+   * @param {string} context.userAgent The user-agent, typically obtained form
+   * the User-Agent HTTP header.
+   * @param {string} context.ipAddress The IP address of the user-agent.
+   * @param {string} [context.evaluationContext="login"] The stage in the
+   * user-agent for which to perform an evaluation. (Used for continuous
+   * assessment throughout the user-agent.) Different "stages" or "contexts"
+   * will result in different evaluation results, as configured in the
+   * sub-policies of the tenant application's policy. Possible options are
+   * "login" (default), "landing", "profile", "resume", "highassurance",
+   * "other".
+   * @param {string} transactionId The identifier of the transaction received in
+   * {@link Adaptive#assessPolicy}.
+   * @param {string} relyingPartyId The identifier of relying party associated
+   * with the FIDO registration.
+   * @param {string} userId The identifier of the OIDC user for which to
+   * initiate a FIDO verification.
+   * @return {Promise<Object>} A FIDO challenge to be completed by the
+   * user-agent.
+   * @example <caption>FIDO challenge return value</caption>
+   * {
+   *   "transactionId": "36a101c7-7426-4f45-ab3c-55f8dc075c6e",
+   *   "fido": {
+   *     "rpId": "fido.verify.ibm.com",
+   *     "challenge": "Q29uZ3JhdHVsYXRpb25zIFlvdSBmb3VuZCBpdAo",
+   *     "userVerification": "preferred",
+   *     "timeout": 30000,
+   *     "allowCredentials": [
+   *       {
+   *         "type": "public-key",
+   *         "id": "SSBhbSBhIGNyZWRlbnRpYWwK"
+   *       }
+   *     ]
+   *   }
+   * }
+   */
+  async generateFIDO({sessionId, userAgent, ipAddress,
+    evaluationContext='login'}, transactionId, relyingPartyId, userId) {
+    const context = {sessionId, userAgent, ipAddress, evaluationContext};
+    const transaction = this._transactionFunctions
+        .getTransaction(transactionId);
+
+    const fidoService = new FIDOService(
+        {accessToken: transaction.assessment.access_token},
+        this._config.tenantUrl, context);
+
+    const verification = await fidoService.generate(relyingPartyId, userId);
+    console.log(`[${Adaptive.name}:generateFIDO(context, transactionId, ` +
+        `relyingPartyId, userId)]`, 'verification:', verification);
+
+    // Update transaction in memory cache.
+    this._transactionFunctions
+        .updateTransaction(transactionId, {fido: verification});
+    this._transactionFunctions
+        .updateTransaction(transactionId, {userId});
+
+    return {transactionId, fido: verification};
+  }
+
+  /**
+   * Complete a FIDO first-factor verification and validate the resulting JWT.
+   * @param {Object} context The context to send for assessment.
+   * @param {string} context.sessionId The session ID generated by the
+   * user-agent, using an Adaptive client SDK.
+   * @param {string} context.userAgent The user-agent, typically obtained form
+   * the User-Agent HTTP header.
+   * @param {string} context.ipAddress The IP address of the user-agent.
+   * @param {string} [context.evaluationContext="login"] The stage in the
+   * user-agent for which to perform an evaluation. (Used for continuous
+   * assessment throughout the user-agent.) Different "stages" or "contexts"
+   * will result in different evaluation results, as configured in the
+   * sub-policies of the tenant application's policy. Possible options are
+   * "login" (default), "landing", "profile", "resume", "highassurance",
+   * "other".
+   * @param {string} transactionId The identifier of the transaction received in
+   * {@link Adaptive#assessPolicy}.
+   * @param {string} relyingPartyId The identifier of relying party associated
+   * with the FIDO registration.
+   * @param {string} authenticatorData The information about the authentication
+   * that was produced by the user-agent authenticator and verified by the
+   * signature.
+   * @param {string} userHandle The identifier for the user who owns this
+   * authenticator.
+   * @param {string} signature The signature of the challenge data that was
+   * produced by the user-agent authenticator.
+   * @param {string} clientDataJSON The base64 encoded client data JSON object.
+   * @return {Promise<Object>} The JWT validation result object. The result
+   * object has a <code>status</code> property of either <code>allow</code>,
+   * <code>deny</code>, or <code>requires</code>.
+   * If <code>allow</code>, a <code>token</code> object is also included in the
+   * result object.
+   * If <code>deny</code>, a <code>details</code> object is returned if an
+   * error message was returned from the token endpoint.
+   * If <code>requires</code>, the allowed second-factor enrollments are
+   * retrieved and included in the result object, indicating that further
+   * second-factor authentication is required.
+   * @example <caption><code>allow</code> result object</caption>
+   * {
+   *   status: 'allow',
+   *   token: {
+   *     access_token: 'zscmjBdvIjudOPLhpbmJi6nBRJg7cZ6WY0Udw1nC',
+   *     refresh_token: 'wFTjurPxTvRD1cW09itgQM83XwCm1UKwsxhVFb1H7HJh8JkwZz',
+   *     scope: 'openid',
+   *     grant_id: 'a0b440b6-fefb-46ea-a603-e1040534cd28',
+   *     id_token: 'eyJhbGciOiJSUzI1NiIsInR5cC...5j_rMn7H3ZpE4axt0WvsYu4jbA',
+   *     token_type: 'Bearer',
+   *     expires_in: 7120
+   *   }
+   * }
+   * @example <caption><code>deny</code> result object</caption>
+   * {
+   *   status: 'deny',
+   *   detail: {
+   *     error: 'adaptive_more_info_required',
+   *     error_description: 'CSIAQ0298E Adaptive access...'
+   *   }
+   * }
+   * @example <caption><code>requires</code> result object</caption>
+   * {
+   *   status: 'requires',
+   *   transactionId: '36a101c7-7426-4f45-ab3c-55f8dc075c6e',
+   *   enrolledFactors: [
+   *     {
+   *       id: '61e39f0a-836b-48fa-b4c9-cface6a3ef5a',
+   *       userId: '60300035KP',
+   *       type: 'emailotp',
+   *       created: '2020-06-15T02:51:49.131Z',
+   *       updated: '2020-06-15T03:15:18.896Z',
+   *       attempted: '2020-07-16T04:30:14.066Z',
+   *       enabled: true,
+   *       validated: true,
+   *       attributes: {
+   *         emailAddress: 'email@email.com'
+   *       }
+   *     }
+   *   ]
+   * }
+   */
+  async evaluateFIDO({sessionId, userAgent, ipAddress,
+    evaluationContext='login'}, transactionId, relyingPartyId,
+  authenticatorData, userHandle, signature, clientDataJSON) {
+    const context = {sessionId, userAgent, ipAddress, evaluationContext};
+    const transaction = this._transactionFunctions
+        .getTransaction(transactionId);
+    if (!transaction.fido) {
+      throw new TransactionError(
+          'This transaction has not initiated a FIDO verification.');
+    }
+
+    // TODO: Handle multiple allowCredentials
+    const credentialId = transaction.fido.allowCredentials[0].id;
+    console.log(`[${Adaptive.name}:evaluateFIDO(context, transactionId, ` +
+        `relyingPartyId, authenticatorData, userHandle, signature, ` +
+        `clientDataJSON)]`, 'credentialId:', credentialId);
+
+    const fidoService = new FIDOService(
+        {accessToken: transaction.assessment.access_token},
+        this._config.tenantUrl, context);
+
+    // Complete FIDO verification.
+    const verification = await fidoService.evaluate(relyingPartyId,
+        credentialId, clientDataJSON, authenticatorData, userHandle,
+        signature);
+    console.log(`[${Adaptive.name}:evaluateFIDO(context, transactionId, ` +
+        `relyingPartyId, authenticatorData, userHandle, signature, ` +
+        `clientDataJSON)]`, 'verification:', verification);
+
+    return this._validateAssertion(transactionId, context,
+        verification.assertion, transaction.userId);
+  }
+
+  /**
+   * Lookup Identity Sources by name.  If name not defined then
+   * return all password-capable sources.
+   *
+   * Complete a FIDO first-factor verification and validate the resulting JWT.
+   * @param {Object} context The context to send for assessment.
+   * @param {string} context.sessionId The session ID generated by the
+   * user-agent, using an Adaptive client SDK.
+   * @param {string} context.userAgent The user-agent, typically obtained form
+   * the User-Agent HTTP header.
+   * @param {string} context.ipAddress The IP address of the user-agent.
+   * @param {string} [context.evaluationContext="login"] The stage in the
+   * user-agent for which to perform an evaluation. (Used for continuous
+   * assessment throughout the user-agent.) Different "stages" or "contexts"
+   * will result in different evaluation results, as configured in the
+   * sub-policies of the tenant application's policy. Possible options are
+   * "login" (default), "landing", "profile", "resume", "highassurance",
+   * "other".
+   * @param {string} transactionId The identifier of the transaction received in
+   * {@link Adaptive#assessPolicy}.
+   * @param {string} [sourceName] The source name to look up.
+   * @return {Promise<Object>} The result object. The result
+   * object contains an array of identity sources for this user.
+   * @example <caption>Result object</caption>
+   * [
+   *   {
+   *     "name": "Cloud Directory",
+   *     "location": "https://<tenant_url>/v1.0/authnmethods/password/11111111-2222-3333-4444-555555555555",
+   *     "id": "11111111-2222-3333-4444-555555555555",
+   *     "type": "ibmldap"
+   *   }
+   * ]
+   */
+  async lookupIdentitySources({sessionId, userAgent, ipAddress,
+    evaluationContext='login'}, transactionId, sourceName) {
+    const context = {sessionId, userAgent, ipAddress, evaluationContext};
+    const transaction = this._transactionFunctions
+        .getTransaction(transactionId);
+
+    const passwordService = new PasswordService(
+        {accessToken: transaction.assessment.access_token},
+        this._config.tenantUrl, context);
+
+    const sources = await passwordService.lookupIdentitySources(sourceName);
+
+    console.log(`[${Adaptive.name}:lookupIdentitySources(context, ` +
+        `transactionId, sourceName)]`, 'sources:', sources);
+
+    return sources;
+  }
+
+  /**
+   * Complete a password first-factor verification.
+   *
+   * Complete a password first-factor verification, validate the resulting JWT,
+   * and gather second-factor enrollments if needed.
+   * @param {Object} context The context to send for assessment.
+   * @param {string} context.sessionId The session ID generated by the
+   * user-agent, using an Adaptive client SDK.
+   * @param {string} context.userAgent The user-agent, typically obtained form
+   * the User-Agent HTTP header.
+   * @param {string} context.ipAddress The IP address of the user-agent.
+   * @param {string} [context.evaluationContext="login"] The stage in the
+   * user-agent for which to perform an evaluation. (Used for continuous
+   * assessment throughout the user-agent.) Different "stages" or "contexts"
+   * will result in different evaluation results, as configured in the
+   * sub-policies of the tenant application's policy. Possible options are
+   * "login" (default), "landing", "profile", "resume", "highassurance",
+   * "other".
+   * @param {string} transactionId The identifier of the transaction received in
+   * {@link Adaptive#assessPolicy}.
+   * @param {string} identitySourceId The identifier of the identity source
+   * associated with the password registration.
+   * @param {string} username The username to authenticate as.
+   * @param {string} password The password to authenticate with.
+   * @return {Promise<Object>} The JWT evaluation result object. The result
+   * object has a <code>status</code> property of either <code>allow</code>,
+   * <code>deny</code>, or <code>requires</code>.
+   * If <code>allow</code>, a <code>token</code> object is also included in the
+   * result object.
+   * If <code>deny</code>, a <code>details</code> object is returned if an
+   * error message was returned from the token endpoint.
+   * If <code>requires</code>, the allowed second-factor enrollments are
+   * retrieved and included in the result object, indicating that further
+   * second-factor authentication is required.
+   * @example <caption><code>allow</code> result object</caption>
+   * {
+   *   status: 'allow',
+   *   token: {
+   *     access_token: 'zscmjBdvIjudOPLhpbmJi6nBRJg7cZ6WY0Udw1nC',
+   *     refresh_token: 'wFTjurPxTvRD1cW09itgQM83XwCm1UKwsxhVFb1H7HJh8JkwZz',
+   *     scope: 'openid',
+   *     grant_id: 'a0b440b6-fefb-46ea-a603-e1040534cd28',
+   *     id_token: 'eyJhbGciOiJSUzI1NiIsInR5cC...5j_rMn7H3ZpE4axt0WvsYu4jbA',
+   *     token_type: 'Bearer',
+   *     expires_in: 7120
+   *   }
+   * }
+   * @example <caption><code>deny</code> result object</caption>
+   * {
+   *   status: 'deny',
+   *   detail: {
+   *     error: 'adaptive_more_info_required',
+   *     error_description: 'CSIAQ0298E Adaptive access...'
+   *   }
+   * }
+   * @example <caption><code>requires</code> result object</caption>
+   * {
+   *   status: 'requires',
+   *   transactionId: '36a101c7-7426-4f45-ab3c-55f8dc075c6e',
+   *   enrolledFactors: [
+   *     {
+   *       id: '61e39f0a-836b-48fa-b4c9-cface6a3ef5a',
+   *       userId: '60300035KP',
+   *       type: 'emailotp',
+   *       created: '2020-06-15T02:51:49.131Z',
+   *       updated: '2020-06-15T03:15:18.896Z',
+   *       attempted: '2020-07-16T04:30:14.066Z',
+   *       enabled: true,
+   *       validated: true,
+   *       attributes: {
+   *         emailAddress: 'email@email.com'
+   *       }
+   *     }
+   *   ]
+   * }
+   */
+  async evaluatePassword({sessionId, userAgent, ipAddress,
+    evaluationContext='login'}, transactionId, identitySourceId, username,
+  password) {
+    const context = {sessionId, userAgent, ipAddress, evaluationContext};
+    const transaction = this._transactionFunctions
+        .getTransaction(transactionId);
+
+    const passwordService = new PasswordService(
+        {accessToken: transaction.assessment.access_token},
+        this._config.tenantUrl, context);
+
+    const authentication = await passwordService.authenticate(identitySourceId,
+        username, password);
+
+    console.log(`[${Adaptive.name}:evaluatePassword(context, transactionId, ` +
+        `identitySourceId, username, password)]`, 'authentication:',
+    authentication);
+
+    // Store user ID in transaction
+    this._transactionFunctions
+        .updateTransaction(transactionId, {userId: authentication.id});
+
+    return this._validateAssertion(transactionId, context,
+        authentication.assertion, authentication.id);
+  }
+
+  /**
+   * @private
+   * Validate a JWT assertion received after a first- or second-factor
+   * authentication. If a <code>requires</code> status is received, get the
+   * allowed enrollment options for the user.
+   * @param {string} transactionId The identifier of the transaction received in
+   * {@link Adaptive#assessPolicy}.
+   * @param {Object} context The context to send for assessment.
+   * @param {string} context.sessionId The session ID generated by the
+   * user-agent, using an Adaptive client SDK.
+   * @param {string} context.userAgent The user-agent, typically obtained form
+   * the User-Agent HTTP header.
+   * @param {string} context.ipAddress The IP address of the user-agent.
+   * @param {string} [context.evaluationContext="login"] The stage in the
+   * user-agent for which to perform an evaluation. (Used for continuous
+   * assessment throughout the user-agent.) Different "stages" or "contexts"
+   * will result in different evaluation results, as configured in the
+   * sub-policies of the tenant application's policy. Possible options are
+   * "login" (default), "landing", "profile", "resume", "highassurance",
+   * "other".
+   * @param {string} assertion The JWT assertion to validate.
+   * @param {string} userId The user ID for which to retrieve enrollments on a
+   * <code>requires</code> response.
+   */
+  async _validateAssertion(transactionId, context, assertion, userId) {
+    const policyService = new PolicyService({clientId: this._config.clientId,
+      clientSecret: this._config.clientSecret},
+    this._config.tenantUrl,
+    context);
+
+    try {
+      const assessment = await policyService.validate(assertion);
+      console.log(`[${Adaptive.name}:_validateAssertion(transactionId, ` +
+          `context, assertion, userId)]`, 'assessment:', assessment);
+
+      if (assessment.scope === 'openid') {
+        // No 2FA required, return token.
+        this._transactionFunctions.deleteTransaction(transactionId);
+        return {status: 'allow', token: assessment};
+      }
+
+      // Further 2FA is required.
+
+      // Update the assessment in the transaction.
+      this._transactionFunctions.updateTransaction(transactionId, {assessment});
+
+      const factorService = new FactorService(
+          {accessToken: assessment.access_token},
+          this._config.tenantUrl, context);
+
+      // Get Factors enrollments for the current user.
+      const enrollments = await factorService.getEnrollments(userId);
+      console.log(`[${Adaptive.name}:_validateAssertion(transactionId, ` +
+            `context, assertion, userId)]`, 'enrollments:', enrollments);
+
+      // Filter the user's enrollment options based on the assessment's
+      // `allowedFactors`, if available.
+      let enrolledFactors = enrollments.factors;
+      if (assessment.allowedFactors) {
+        enrolledFactors = enrolledFactors.filter((enrollment) =>
+          assessment.allowedFactors.includes(enrollment.type) ||
+          (assessment.allowedFactors.includes('signatures') &&
+          enrollment.type === 'signature'));
+      }
+
+      console.log(`[${Adaptive.name}:_validateAssertion(transactionId, ` +
+      `context, assertion, userId)]`, 'enrolledFactors:', enrolledFactors);
+
+      return {status: 'requires', enrolledFactors, transactionId};
+    } catch (error) {
+      // Deny assessment.
+      console.log(`[${Adaptive.name}:_validateAssertion(transactionId, ` +
+          `context, assertion, userId)]`, 'error:', error);
+      const jsonResp = {status: 'deny'};
+      if (error.response.data) {
+        jsonResp.detail = error.response.data;
+      }
+      return jsonResp;
+    }
+  }
+
+  /**
+   * Initiate a QR login first-factor verification.
+   * @param {Object} context The context to send for assessment.
+   * @param {string} context.sessionId The session ID generated by the
+   * user-agent, using an Adaptive client SDK.
+   * @param {string} context.userAgent The user-agent, typically obtained form
+   * the User-Agent HTTP header.
+   * @param {string} context.ipAddress The IP address of the user-agent.
+   * @param {string} [context.evaluationContext="login"] The stage in the
+   * user-agent for which to perform an evaluation. (Used for continuous
+   * assessment throughout the user-agent.) Different "stages" or "contexts"
+   * will result in different evaluation results, as configured in the
+   * sub-policies of the tenant application's policy. Possible options are
+   * "login" (default), "landing", "profile", "resume", "highassurance",
+   * "other".
+   * @param {string} transactionId The identifier of the transaction received in
+   * {@link Adaptive#assessPolicy}.
+   * @param {string} profileId The identifier of an IBM Verify registration
+   * profile. Can be retrieved from <code>/v1.0/authenticators/clients</code>.
+   * @return {Promise<Object>} The QR code login verification.
+   * @example <caption>QR code return value</caption>
+   * {
+   *   transactionId: '36a101c7-7426-4f45-ab3c-55f8dc075c6e',
+   *   qr: {
+   *     code: 'iVBORw0KGgoAAAANSUhEUgAAASwAAAEsAQAAAABR...'
+   *   }
+   * }
+   */
+  async generateQR({sessionId, userAgent, ipAddress, evaluationContext='login'},
+      transactionId, profileId) {
+    const context = {sessionId, userAgent, ipAddress, evaluationContext};
+    const transaction = this._transactionFunctions
+        .getTransaction(transactionId);
+
+    const qrService = new QRService(
+        {accessToken: transaction.assessment.access_token},
+        this._config.tenantUrl, context);
+
+    // Initiate a QR login.
+    const verification = await qrService.generate(profileId);
+    console.log(`[${Adaptive.name}:generateQR(context, transactionId, ` +
+        `profileId)]`, 'verification:', verification);
+
+    // Update transaction in memory cache.
+    this._transactionFunctions
+        .updateTransaction(transactionId, {qr: verification});
+
+    return {transactionId, qr: {code: verification.qrCode}};
+  }
+
+  /**
+   * Evaluate a QR login first-factor verification.
+   * @param {Object} context The context to send for assessment.
+   * @param {string} context.sessionId The session ID generated by the
+   * user-agent, using an Adaptive client SDK.
+   * @param {string} context.userAgent The user-agent, typically obtained form
+   * the User-Agent HTTP header.
+   * @param {string} context.ipAddress The IP address of the user-agent.
+   * @param {string} [context.evaluationContext="login"] The stage in the
+   * user-agent for which to perform an evaluation. (Used for continuous
+   * assessment throughout the user-agent.) Different "stages" or "contexts"
+   * will result in different evaluation results, as configured in the
+   * sub-policies of the tenant application's policy. Possible options are
+   * "login" (default), "landing", "profile", "resume", "highassurance",
+   * "other".
+   * @param {string} transactionId The identifier of the transaction received in
+   * {@link Adaptive#assessPolicy}.
+   * @return {Promise<Object>} Either QR transaction state result object
+   * (if not complete) or the JWT evaluation result object.
+   * If QR transaction not complete, the result object has <code>status</code>
+   * property of <code>pending</code>, <code>timeout</code>,
+   * or <code>error</code>.
+   * If QR transaction is complete, the result object has a <code>status</code>
+   * property of either <code>allow</code>, <code>deny</code>,
+   * or <code>requires</code>.
+   * If <code>allow</code>, a <code>token</code> object is also included in the
+   * result object.
+   * If <code>deny</code>, a <code>details</code> object is returned if an
+   * error message was returned from the token endpoint.
+   * If <code>requires</code>, the allowed second-factor enrollments are
+   * retrieved and included in the result object, indicating that further
+   * second-factor authentication is required.
+   * @example <caption><code>pending</code> result object</caption>
+   * {
+   *   status: 'pending',
+   *   expiry: '2021-04-26T12:06:06.501Z'
+   * }
+   * @example <caption><code>pending</code> result object</caption>
+   * {
+   *   status: 'timeout',
+   *   expiry: '2021-04-26T12:06:06.501Z'
+   * }
+   * @example <caption><code>error</code> result object</caption>
+   * {
+   *   status: 'error'
+   * }
+   * @example <caption><code>allow</code> result object</caption>
+   * {
+   *   status: 'allow',
+   *   token: {
+   *     access_token: 'zscmjBdvIjudOPLhpbmJi6nBRJg7cZ6WY0Udw1nC',
+   *     refresh_token: 'wFTjurPxTvRD1cW09itgQM83XwCm1UKwsxhVFb1H7HJh8JkwZz',
+   *     scope: 'openid',
+   *     grant_id: 'a0b440b6-fefb-46ea-a603-e1040534cd28',
+   *     id_token: 'eyJhbGciOiJSUzI1NiIsInR5cC...5j_rMn7H3ZpE4axt0WvsYu4jbA',
+   *     token_type: 'Bearer',
+   *     expires_in: 7120
+   *   }
+   * }
+   * @example <caption><code>deny</code> result object</caption>
+   * {
+   *   status: 'deny',
+   *   detail: {
+   *     error: 'adaptive_more_info_required',
+   *     error_description: 'CSIAQ0298E Adaptive access...'
+   *   }
+   * }
+   * @example <caption><code>requires</code> result object</caption>
+   * {
+   *   status: 'requires',
+   *   transactionId: '36a101c7-7426-4f45-ab3c-55f8dc075c6e',
+   *   enrolledFactors: [
+   *     {
+   *       id: '61e39f0a-836b-48fa-b4c9-cface6a3ef5a',
+   *       userId: '60300035KP',
+   *       type: 'emailotp',
+   *       created: '2020-06-15T02:51:49.131Z',
+   *       updated: '2020-06-15T03:15:18.896Z',
+   *       attempted: '2020-07-16T04:30:14.066Z',
+   *       enabled: true,
+   *       validated: true,
+   *       attributes: {
+   *         emailAddress: 'email@email.com'
+   *       }
+   *     }
+   *   ]
+   * }
+   */
+  async evaluateQR({sessionId, userAgent, ipAddress, evaluationContext='login'},
+      transactionId) {
+    const context = {sessionId, userAgent, ipAddress, evaluationContext};
+    const transaction = this._transactionFunctions
+        .getTransaction(transactionId);
+    if (!transaction.qr) {
+      throw new TransactionError(
+          'This transaction has not initiated a QR login verification.');
+    }
+    const qrService =
+             new QRService({accessToken: transaction.assessment.access_token},
+                 this._config.tenantUrl,
+                 context);
+
+    const verification = await qrService.verify(transaction.qr.id,
+        transaction.qr.dsi);
+    console.log(`[${Adaptive.name}:evaluateQR(context, transactionId)]`,
+        'verification:', verification);
+
+    if (verification.state === 'SUCCESS') {
+      return this._validateAssertion(transactionId, context,
+          verification.assertion, verification.userId);
+    }
+
+    if (verification.state) {
+      return {
+        status: verification.state.toLowerCase(),
+        expiry: verification.expiry,
+      };
+    } else {
+      return {status: 'error'};
+    }
+  }
+
+  /**
+   * Get Access Token for a transaction.
+   * @param {string} transactionId The identifier of the transaction received in
+   * {@link Adaptive#assessPolicy}.
+   * @return {string} The Access Token associated with the transaction.
+   */
+  getToken(transactionId) {
+    const transaction = this._transactionFunctions
+        .getTransaction(transactionId);
+
+    return transaction.assessment.access_token;
+  }
+
+  /**
+   * Complete a TOTP second-factor verification and validate the resulting JWT.
+   * @param {Object} context The context to send for assessment.
+   * @param {string} context.sessionId The session ID generated by the
+   * user-agent, using an Adaptive client SDK.
+   * @param {string} context.userAgent The user-agent, typically obtained form
+   * the User-Agent HTTP header.
+   * @param {string} context.ipAddress The IP address of the user-agent.
+   * @param {string} [context.evaluationContext="login"] The stage in the
+   * user-agent for which to perform an evaluation. (Used for continuous
+   * assessment throughout the user-agent.) Different "stages" or "contexts"
+   * will result in different evaluation results, as configured in the
+   * sub-policies of the tenant application's policy. Possible options are
+   * "login" (default), "landing", "profile", "resume", "highassurance",
+   * "other".
+   * @param {string} transactionId The identifier of the transaction received in
+   * {@link Adaptive#assessPolicy}.
+   * @param {string} enrollmentId The identifier of the enrollment to perform
+   * second-factor verification with.
+   * @param {string} otp The OTP to attempt verification with.
+   * @return {Promise<Object>} The access and refresh tokens which should have
+   * been received from the JWT validation, along with the <code>status</code>
+   * property of <code>allow</code>.
+   */
+  async evaluateTOTP({sessionId, userAgent, ipAddress,
+    evaluationContext='login'}, transactionId, enrollmentId, otp) {
+    const context = {sessionId, userAgent, ipAddress, evaluationContext};
+    const transaction = this._transactionFunctions
+        .getTransaction(transactionId);
+
+    const totpService = new TOTPService(
+        {accessToken: transaction.assessment.access_token},
+        this._config.tenantUrl, context);
+
+    const verification = await totpService.verify(enrollmentId, otp);
+    console.log(`[${Adaptive.name}:evaluateTOTP(context, transactionId, ` +
+        `enrollmentId, otp)]`, 'verification:', verification);
+
+    return this._validateAssertion(transactionId, context,
+        verification.assertion, verification.userId);
+  }
+
+  /**
+   * Request an email OTP.
+   * @param {Object} context The context to send for assessment.
+   * @param {string} context.sessionId The session ID generated by the
+   * user-agent, using an Adaptive client SDK.
+   * @param {string} context.userAgent The user-agent, typically obtained form
+   * the User-Agent HTTP header.
+   * @param {string} context.ipAddress The IP address of the user-agent.
+   * @param {string} [context.evaluationContext="login"] The stage in the
+   * user-agent for which to perform an evaluation. (Used for continuous
+   * assessment throughout the user-agent.) Different "stages" or "contexts"
+   * will result in different evaluation results, as configured in the
+   * sub-policies of the tenant application's policy. Possible options are
+   * "login" (default), "landing", "profile", "resume", "highassurance",
+   * "other".
+   * @param {string} transactionId The identifier of the transaction received in
+   * @param {string} enrollmentId The identifier of the enrollment to perform
+   * second-factor verification with.
+   * @return {Promise<Object>} The a four-digit correlation associated with the
+   * verification. It will be prefixed to the one-time password in the Email to
+   * be sent.
+   */
+  async generateEmailOTP({sessionId, userAgent, ipAddress,
+    evaluationContext='login'}, transactionId, enrollmentId) {
+    const context = {sessionId, userAgent, ipAddress, evaluationContext};
+    const transaction = this._transactionFunctions
+        .getTransaction(transactionId);
+
+    const emailOTPService = new EmailOTPService(
+        {accessToken: transaction.assessment.access_token},
+        this._config.tenantUrl, context);
+
+    const verification = await emailOTPService.generate(enrollmentId);
+    console.log(`[${Adaptive.name}:generateEmailOTP(context, transactionId, ` +
+        `enrollmentId)]`, 'verification:', verification);
+
+    // Update transaction in memory cache.
+    this._transactionFunctions.updateTransaction(transactionId,
+        {emailotp: {enrollmentId, verification}});
+
+    return {correlation: verification.correlation};
+  }
+
+  /**
+   * Complete an email OTP second-factor verification and validate the resulting
+   * JWT.
+   * @param {Object} context The context to send for assessment.
+   * @param {string} context.sessionId The session ID generated by the
+   * user-agent, using an Adaptive client SDK.
+   * @param {string} context.userAgent The user-agent, typically obtained form
+   * the User-Agent HTTP header.
+   * @param {string} context.ipAddress The IP address of the user-agent.
+   * @param {string} [context.evaluationContext="login"] The stage in the
+   * user-agent for which to perform an evaluation. (Used for continuous
+   * assessment throughout the user-agent.) Different "stages" or "contexts"
+   * will result in different evaluation results, as configured in the
+   * sub-policies of the tenant application's policy. Possible options are
+   * "login" (default), "landing", "profile", "resume", "highassurance",
+   * "other".
+   * @param {string} transactionId The identifier of the transaction received in
+   * {@link Adaptive#assessPolicy}.
+   * @param {string} otp The email OTP received in the email after the email OTP
+   * request in {@link Adaptive#generateEmailOTP}. This OTP shouldn't include
+   * the correlation prefix (the four digits before the dash).
+   * @return {Promise<Object>} The access and refresh tokens which should have
+   * been received from the JWT validation, along with the <code>status</code>
+   * property of <code>allow</code>.
+   */
+  async evaluateEmailOTP({sessionId, userAgent, ipAddress,
+    evaluationContext='login'}, transactionId, otp) {
+    const context = {sessionId, userAgent, ipAddress, evaluationContext};
+    const transaction = this._transactionFunctions
+        .getTransaction(transactionId);
+    if (!transaction.emailotp) {
+      throw new TransactionError(
+          'This transaction has not initiated an email OTP verification.');
+    }
+
+    const emailOTPService = new EmailOTPService(
+        {accessToken: transaction.assessment.access_token},
+        this._config.tenantUrl, context);
+
+    const verification = await emailOTPService.verify(
+        transaction.emailotp.verification.id, transaction.emailotp.enrollmentId,
+        otp);
+    console.log(`[${Adaptive.name}:evaluateEmailOTP(context, transactionId, ` +
+        `otp)]`, 'verification:', verification);
+
+    return this._validateAssertion(transactionId, context,
+        verification.assertion, verification.userId);
+  }
+
+  /**
+   * Request an SMS OTP.
+   * @param {Object} context The context to send for assessment.
+   * @param {string} context.sessionId The session ID generated by the
+   * user-agent, using an Adaptive client SDK.
+   * @param {string} context.userAgent The user-agent, typically obtained form
+   * the User-Agent HTTP header.
+   * @param {string} context.ipAddress The IP address of the user-agent.
+   * @param {string} [context.evaluationContext="login"] The stage in the
+   * user-agent for which to perform an evaluation. (Used for continuous
+   * assessment throughout the user-agent.) Different "stages" or "contexts"
+   * will result in different evaluation results, as configured in the
+   * sub-policies of the tenant application's policy. Possible options are
+   * "login" (default), "landing", "profile", "resume", "highassurance",
+   * "other".
+   * @param {string} transactionId The identifier of the transaction received in
+   * @param {string} enrollmentId The identifier of the enrollment to perform
+   * second-factor verification with.
+   * @return {Promise<Object>} The a four-digit correlation associated with the
+   * verification. It will be prefixed to the one-time password in the SMS to be
+   * sent.
+   */
+  async generateSMSOTP({sessionId, userAgent, ipAddress,
+    evaluationContext='login'}, transactionId, enrollmentId) {
+    const context = {sessionId, userAgent, ipAddress, evaluationContext};
+    const transaction = this._transactionFunctions
+        .getTransaction(transactionId);
+
+    const smsOTPService = new SMSOTPService(
+        {accessToken: transaction.assessment.access_token},
+        this._config.tenantUrl, context);
+
+    const verification = await smsOTPService.generate(enrollmentId);
+    console.log(`[${Adaptive.name}:generateSMSOTP(context, transactionId, ` +
+        `enrollmentId)]`, 'verification:', verification);
+
+    // Update transaction in memory cache.
+    this._transactionFunctions.updateTransaction(transactionId,
+        {smsotp: {enrollmentId, verification}});
+
+    return {correlation: verification.correlation};
+  }
+
+  /**
+   * Complete an SMS OTP second-factor verification and validate the resulting
+   * JWT.
+   * @param {Object} context The context to send for assessment.
+   * @param {string} context.sessionId The session ID generated by the
+   * user-agent, using an Adaptive client SDK.
+   * @param {string} context.userAgent The user-agent, typically obtained form
+   * the User-Agent HTTP header.
+   * @param {string} context.ipAddress The IP address of the user-agent.
+   * @param {string} [context.evaluationContext="login"] The stage in the
+   * user-agent for which to perform an evaluation. (Used for continuous
+   * assessment throughout the user-agent.) Different "stages" or "contexts"
+   * will result in different evaluation results, as configured in the
+   * sub-policies of the tenant application's policy. Possible options are
+   * "login" (default), "landing", "profile", "resume", "highassurance",
+   * "other".
+   * @param {string} transactionId The identifier of the transaction received in
+   * {@link Adaptive#assessPolicy}.
+   * @param {string} otp The SMS OTP received on the phone after the SMS OTP
+   * request in {@link Adaptive#generateSMSOTP}. This OTP shouldn't include the
+   * correlation prefix (the four digits before the dash).
+   * @return {Promise<Object>} The access and refresh tokens which should have
+   * been received from the JWT validation, along with the <code>status</code>
+   * property of <code>allow</code>.
+   */
+  async evaluateSMSOTP({sessionId, userAgent, ipAddress,
+    evaluationContext='login'}, transactionId, otp) {
+    const context = {sessionId, userAgent, ipAddress, evaluationContext};
+    const transaction = this._transactionFunctions
+        .getTransaction(transactionId);
+    if (!transaction.smsotp) {
+      throw new TransactionError(
+          'This transaction has not initiated an SMS OTP verification.');
+    }
+
+    const smsOTPService = new SMSOTPService(
+        {accessToken: transaction.assessment.access_token},
+        this._config.tenantUrl, context);
+
+    const verification = await smsOTPService.verify(
+        transaction.smsotp.verification.id, transaction.smsotp.enrollmentId,
+        otp);
+    console.log(`[${Adaptive.name}:evaluateSMSOTP(context, transactionId, ` +
+        `otp)]`, 'verification:', verification);
+
+    return this._validateAssertion(transactionId, context,
+        verification.assertion, verification.userId);
+  }
+
+  /**
+   * Request an Voice OTP.
+   * @param {Object} context The context to send for assessment.
+   * @param {string} context.sessionId The session ID generated by the
+   * user-agent, using an Adaptive client SDK.
+   * @param {string} context.userAgent The user-agent, typically obtained form
+   * the User-Agent HTTP header.
+   * @param {string} context.ipAddress The IP address of the user-agent.
+   * @param {string} [context.evaluationContext="login"] The stage in the
+   * user-agent for which to perform an evaluation. (Used for continuous
+   * assessment throughout the user-agent.) Different "stages" or "contexts"
+   * will result in different evaluation results, as configured in the
+   * sub-policies of the tenant application's policy. Possible options are
+   * "login" (default), "landing", "profile", "resume", "highassurance",
+   * "other".
+   * @param {string} transactionId The identifier of the transaction received in
+   * @param {string} enrollmentId The identifier of the enrollment to perform
+   * second-factor verification with.
+   * @return {Promise<Object>} The a four-digit correlation associated with the
+   * verification.  This is not used by default in a Voice OTP call.
+   */
+  async generateVoiceOTP({sessionId, userAgent, ipAddress,
+    evaluationContext='login'}, transactionId, enrollmentId) {
+    const context = {sessionId, userAgent, ipAddress, evaluationContext};
+    const transaction = this._transactionFunctions
+        .getTransaction(transactionId);
+
+    const voiceOTPService = new VoiceOTPService(
+        {accessToken: transaction.assessment.access_token},
+        this._config.tenantUrl, context);
+
+    const verification = await voiceOTPService.generate(enrollmentId);
+    console.log(`[${Adaptive.name}:generateVoiceOTP(context, transactionId, ` +
+        `enrollmentId)]`, 'verification:', verification);
+
+    // Update transaction in memory cache.
+    this._transactionFunctions.updateTransaction(transactionId,
+        {voiceotp: {enrollmentId, verification}});
+
+    return {correlation: verification.correlation};
+  }
+
+  /**
+   * Complete an Voice OTP second-factor verification and validate the resulting
+   * JWT.
+   * @param {Object} context The context to send for assessment.
+   * @param {string} context.sessionId The session ID generated by the
+   * user-agent, using an Adaptive client SDK.
+   * @param {string} context.userAgent The user-agent, typically obtained form
+   * the User-Agent HTTP header.
+   * @param {string} context.ipAddress The IP address of the user-agent.
+   * @param {string} [context.evaluationContext="login"] The stage in the
+   * user-agent for which to perform an evaluation. (Used for continuous
+   * assessment throughout the user-agent.) Different "stages" or "contexts"
+   * will result in different evaluation results, as configured in the
+   * sub-policies of the tenant application's policy. Possible options are
+   * "login" (default), "landing", "profile", "resume", "highassurance",
+   * "other".
+   * @param {string} transactionId The identifier of the transaction received in
+   * {@link Adaptive#assessPolicy}.
+   * @param {string} otp The Voice OTP received on the phone after the Voice OTP
+   * request in {@link Adaptive#generateVoiceOTP}. This OTP shouldn't include
+   * the correlation prefix (the four digits before the dash).
+   * @return {Promise<Object>} The access and refresh tokens which should have
+   * been received from the JWT validation, along with the <code>status</code>
+   * property of <code>allow</code>.
+   */
+  async evaluateVoiceOTP({sessionId, userAgent, ipAddress,
+    evaluationContext='login'}, transactionId, otp) {
+    const context = {sessionId, userAgent, ipAddress, evaluationContext};
+    const transaction = this._transactionFunctions
+        .getTransaction(transactionId);
+    if (!transaction.voiceotp) {
+      throw new TransactionError(
+          'This transaction has not initiated an Voice OTP verification.');
+    }
+
+    const voiceOTPService = new VoiceOTPService(
+        {accessToken: transaction.assessment.access_token},
+        this._config.tenantUrl, context);
+
+    const verification = await voiceOTPService.verify(
+        transaction.voiceotp.verification.id, transaction.voiceotp.enrollmentId,
+        otp);
+    console.log(`[${Adaptive.name}:evaluateVoiceOTP(context, transactionId, ` +
+        `otp)]`, 'verification:', verification);
+
+    return this._validateAssertion(transactionId, context,
+        verification.assertion, verification.userId);
+  }
+
+  /**
+   * Request knowledge questions.
+   * @param {Object} context The context to send for assessment.
+   * @param {string} context.sessionId The session ID generated by the
+   * user-agent, using an Adaptive client SDK.
+   * @param {string} context.userAgent The user-agent, typically obtained form
+   * the User-Agent HTTP header.
+   * @param {string} context.ipAddress The IP address of the user-agent.
+   * @param {string} [context.evaluationContext="login"] The stage in the
+   * user-agent for which to perform an evaluation. (Used for continuous
+   * assessment throughout the user-agent.) Different "stages" or "contexts"
+   * will result in different evaluation results, as configured in the
+   * sub-policies of the tenant application's policy. Possible options are
+   * "login" (default), "landing", "profile", "resume", "highassurance",
+   * "other".
+   * @param {string} transactionId The identifier of the transaction received in
+   * {@link Adaptive#assessPolicy}.
+   * @param {string} enrollmentId The identifier of the enrollment to perform
+   * second-factor verification with.
+   * @return {Promise<Object>} The knowledge questions to be answered.
+   * @example <caption>Questions generation return value</caption>
+   * {
+   *   transactionId: '36a101c7-7426-4f45-ab3c-55f8dc075c6e',
+   *   questions: [
+   *     {
+   *       questionKey: 'firstHouseStreet',
+   *       question: 'What was the street name of the first house you lived in?'
+   *     },
+   *     {
+   *       questionKey: 'bestFriend',
+   *       question: 'What is the first name of your best friend?'
+   *     },
+   *     {
+   *       questionKey: 'mothersMaidenName',
+   *       question: 'What is your mothers maiden name?'
+   *     }
+   *   ]
+   * }
+   */
+  async generateQuestions({sessionId, userAgent, ipAddress,
+    evaluationContext='login'}, transactionId, enrollmentId) {
+    const context = {sessionId, userAgent, ipAddress, evaluationContext};
+    const transaction = this._transactionFunctions
+        .getTransaction(transactionId);
+
+    const questionsService = new QuestionsService(
+        {accessToken: transaction.assessment.access_token},
+        this._config.tenantUrl, context);
+
+    const verification = await questionsService.generate(enrollmentId);
+    console.log(`[${Adaptive.name}:generateQuestions(context, transactionId, ` +
+        `enrollmentId)]`, 'verification:', verification);
+
+    // Update transaction in memory cache.
+    this._transactionFunctions.updateTransaction(transactionId, {questions:
+      {enrollmentId, verification}});
+
+    // Return questions to be answered.
+    return {transactionId, questions: verification.questions};
+  }
+
+  /**
+   * Complete a knowledge questions second-factor verification and validate the
+   * resulting JWT.
+   * @param {Object} context The context to send for assessment.
+   * @param {string} context.sessionId The session ID generated by the
+   * user-agent, using an Adaptive client SDK.
+   * @param {string} context.userAgent The user-agent, typically obtained form
+   * the User-Agent HTTP header.
+   * @param {string} context.ipAddress The IP address of the user-agent.
+   * @param {string} [context.evaluationContext="login"] The stage in the
+   * user-agent for which to perform an evaluation. (Used for continuous
+   * assessment throughout the user-agent.) Different "stages" or "contexts"
+   * will result in different evaluation results, as configured in the
+   * sub-policies of the tenant application's policy. Possible options are
+   * "login" (default), "landing", "profile", "resume", "highassurance",
+   * "other".
+   * @param {string} transactionId The identifier of the transaction received in
+   * {@link Adaptive#assessPolicy}.
+   * @param {Object[]} questions The array of question keys and corresponding
+   * answers to attempt verification with.
+   * @param {string} questions[].questionKey The identifier of the question.
+   * @param {string} questions[].answer The answer to the question.
+   * @return {Promise<Object>} The result of the JWT validation. The result
+   * object has a <code>status</code> property of <code>allow</code>, and
+   * returns an access and a refresh token. There is no <code>requires</code>
+   * status, since this is the last required verification step.
+   * @throws {TransactionError} The transaction ID hasn't requested a knowledge
+   * questions verification in {@link Adaptive#generateQuestions}.
+   * @example <caption><code>allow</code> return value</caption>
+   * {
+   *   status: 'allow',
+   *   token: {
+   *     issued_at: 1420262924658,
+   *     scope: 'READ',
+   *     application_name: 'ce1e94a2-9c3e-42fa-a2c6-1ee01815476b',
+   *     refresh_token_issued_at: 1420262924658,
+   *     expires_in: 1799,
+   *     token_type: 'BearerToken',
+   *     refresh_token: 'fYACGW7OCPtCNDEnRSnqFlEgogboFPMm',
+   *     client_id: '5jUAdGv9pBouF0wOH5keAVI35GBtx3dT',
+   *     access_token: '2l4IQtZXbn5WBJdL6EF7uenOWRsi',
+   *     organization_name: 'My Happy Place',
+   *     refresh_token_expires_in: 86399
+   *   }
+   * }
+   */
+  async evaluateQuestions({sessionId, userAgent, ipAddress,
+    evaluationContext='login'}, transactionId, questions) {
+    const context = {sessionId, userAgent, ipAddress, evaluationContext};
+    const transaction = this._transactionFunctions
+        .getTransaction(transactionId);
+    if (!transaction.questions) {
+      throw new TransactionError(
+          'This transaction has not initiated a knowledge questions ' +
+          'verification.');
+    }
+
+    const questionsService = new QuestionsService(
+        {accessToken: transaction.assessment.access_token},
+        this._config.tenantUrl, context);
+
+    const verification = await questionsService.verify(
+        transaction.questions.verification.id,
+        transaction.questions.enrollmentId, questions);
+    console.log(`[${Adaptive.name}:evaluateQuestions(context, transactionId, ` +
+        `questions)]`, 'verification:', verification);
+
+    return this._validateAssertion(transactionId, context,
+        verification.assertion, verification.userId);
+  }
+
+  /**
+   * Request a push notification verification.
+   * @param {Object} context The context to send for assessment.
+   * @param {string} context.sessionId The session ID generated by the
+   * user-agent, using an Adaptive client SDK.
+   * @param {string} context.userAgent The user-agent, typically obtained form
+   * the User-Agent HTTP header.
+   * @param {string} context.ipAddress The IP address of the user-agent.
+   * @param {string} [context.evaluationContext="login"] The stage in the
+   * user-agent for which to perform an evaluation. (Used for continuous
+   * assessment throughout the user-agent.) Different "stages" or "contexts"
+   * will result in different evaluation results, as configured in the
+   * sub-policies of the tenant application's policy. Possible options are
+   * "login" (default), "landing", "profile", "resume", "highassurance",
+   * "other".
+   * @param {string} transactionId The identifier of the transaction received in
+   * {@link Adaptive#assessPolicy}.
+   * @param {string} enrollmentId The identifier of the signature enrollment to
+   * perform second-factor verification with.
+   * @param {string} authenticatorId The identifier of the authenticator
+   * belonging to the signature.
+   * @param {string} message The verification message to be displayed in-app.
+   * @param {string} pushNotificationTitle The title to be displayed
+   * in the  push notification banner.
+   * @param {string} pushNotificationMessage The message to be displayed
+   * in the push notification banner.
+   * @param {Object[]} additionalData An array of objects containing
+   * <code>"name"</code> and <code>"value"</code> attributes to be displayed
+   * in-app.
+   * @return {Promise<Object>} <code>correlation</code> will contain
+   * the confirmation number associated with the transaction.  This can be
+   * displayed in the user agent to link transaction to verification request
+   * in authenticator app.
+   */
+  async generatePush({sessionId, userAgent, ipAddress,
+    evaluationContext='login'}, transactionId, enrollmentId, authenticatorId,
+  message, pushNotificationTitle, pushNotificationMessage, additionalData) {
+    const context = {sessionId, userAgent, ipAddress, evaluationContext};
+    const transaction = this._transactionFunctions
+        .getTransaction(transactionId);
+
+    const pushService = new PushService(
+        {accessToken: transaction.assessment.access_token},
+        this._config.tenantUrl, context);
+
+    const verification = await pushService.generate(enrollmentId,
+        authenticatorId, message, context.ipAddress, context.userAgent,
+        pushNotificationTitle, pushNotificationMessage, additionalData);
+    console.log(`[${Adaptive.name}:generatePush(context, transactionId, ` +
+        `enrollmentId, authenticatorId, message, pushNotificationTitle, ` +
+        `pushNotificationMessage, additionalData)]`,
+    'verification:', verification);
+
+    // Update transaction in memory cache.
+    this._transactionFunctions
+        .updateTransaction(transactionId, {push: verification});
+
+    return {correlation: verification.id.substr(0, 8)};
+  }
+
+  /**
+   * Attempt a push notification verification.
+   * @param {Object} context The context to send for assessment.
+   * @param {string} context.sessionId The session ID generated by the
+   * user-agent, using an Adaptive client SDK.
+   * @param {string} context.userAgent The user-agent, typically obtained form
+   * the User-Agent HTTP header.
+   * @param {string} context.ipAddress The IP address of the user-agent.
+   * @param {string} [context.evaluationContext="login"] The stage in the
+   * user-agent for which to perform an evaluation. (Used for continuous
+   * assessment throughout the user-agent.) Different "stages" or "contexts"
+   * will result in different evaluation results, as configured in the
+   * sub-policies of the tenant application's policy. Possible options are
+   * "login" (default), "landing", "profile", "resume", "highassurance",
+   * "other".
+   * @param {string} transactionId The identifier of the transaction received in
+   * {@link Adaptive#assessPolicy}.
+   * @return {Promise<Object>} The access and refresh tokens which should have
+   * been received from the JWT validation, along with the <code>status</code>
+   * property of <code>allow</code>.
+   */
+  async evaluatePush({sessionId, userAgent, ipAddress,
+    evaluationContext='login'}, transactionId) {
+    const context = {sessionId, userAgent, ipAddress, evaluationContext};
+    const transaction = this._transactionFunctions
+        .getTransaction(transactionId);
+    if (!transaction.push) {
+      throw new TransactionError(
+          'This transaction has not initiated a push verification.');
+    }
+
+    const authenticatorId = transaction.push.authenticatorId;
+    console.log(`[${Adaptive.name}:evaluatePush(transactionId)]`,
+        'authenticatorId:', authenticatorId);
+
+    const verificationId = transaction.push.id;
+    console.log(`[${Adaptive.name}:evaluatePush(transactionId)]`,
+        'verificationId:', verificationId);
+
+    const pushService = new PushService(
+        {accessToken: transaction.assessment.access_token},
+        this._config.tenantUrl,
+        context);
+
+    const verification = await pushService.evaluate(authenticatorId,
+        verificationId);
+    console.log(`[${Adaptive.name}:evaluatePush(context, transactionId)]`,
+        'verification:', verification);
+
+    if (verification.state === 'VERIFY_SUCCESS') {
+      return this._validateAssertion(transactionId, context,
+          verification.assertion, verification.userId);
+    }
+
+    if (verification.state) {
+      return {
+        status: verification.state.toLowerCase(),
+        expiry: verification.expiryTime,
+        pushState: verification.pushNotification.sendState,
+      };
+    } else {
+      return {status: 'error'};
+    }
+  }
+
+  /**
+   * Revoke the access token from OIDC.
+   * @param {string} accessToken The access token to revoke from OIDC.
+   */
+  async logout(accessToken) {
+    const tokenService = new TokenService({clientId: this._config.clientId,
+      clientSecret: this._config.clientSecret}, this._config.tenantUrl, {});
+
+    await tokenService.revokeAccessToken(accessToken);
+  }
+
+  /**
+   * Initiate an OAuth Refresh flow to obtain updated tokens.
+   * @param {Object} context The context to send for assessment.
+   * @param {string} context.sessionId The session ID generated by the
+   * user-agent, using an Adaptive client SDK.
+   * @param {string} context.userAgent The user-agent, typically obtained form
+   * the User-Agent HTTP header.
+   * @param {string} context.ipAddress The IP address of the user-agent.
+   * @param {string} [context.evaluationContext="login"] The stage in the
+   * user-agent for which to perform an evaluation. (Used for continuous
+   * assessment throughout the user-agent.) Different "stages" or "contexts"
+   * will result in different evaluation results, as configured in the
+   * sub-policies of the tenant application's policy. Possible options are
+   * "login" (default), "landing", "profile", "resume", "highassurance",
+   * "other".
+   * @param {string} refreshToken The refresh token to refresh the access token
+   * with.
+   * @return {Promise<Object>} The policy evaluation result object. The result
+   * object has a <code>status</code> property of either <code>allow</code>,
+   * <code>deny</code>, or <code>requires</code>.
+   * If <code>allow</code>, then <code>token</code> object contains refresh
+   * response.
+   * If <code>deny</code>, a <code>details</code> object is returned if an
+   * error message was returned from the token endpoint.
+   * If <code>requires</code>, a transaction is created, and the
+   * <code>transactionId</code> and an array of <code>allowedFactors</code>
+   * is also included in the result object, indicating that further
+   * authentication is required.
+   * @example <caption><code>allow</code> result object</caption>
+   * {
+   *   status: 'allow',
+   *   token: {
+   *     access_token: 'zscmjBdvIjudOPLhpbmJi6nBRJg7cZ6WY0Udw1nC',
+   *     refresh_token: 'wFTjurPxTvRD1cW09itgQM83XwCm1UKwsxhVFb1H7HJh8JkwZz',
+   *     scope: 'openid',
+   *     grant_id: 'a0b440b6-fefb-46ea-a603-e1040534cd28',
+   *     id_token: 'eyJhbGciOiJSUzI1NiIsInR5cC...5j_rMn7H3ZpE4axt0WvsYu4jbA',
+   *     token_type: 'Bearer',
+   *     expires_in: 7120
+   *   }
+   * }
+   * @example <caption><code>deny</code> result object</caption>
+   * {
+   *   status: 'deny',
+   *   detail: {
+   *     error_description: 'CSIAQ0158E The ... is invalid.',
+   *     error: 'invalid_token'
+   *   }
+   * }
+   * @example <caption><code>requires</code> result object</caption>
+   * {
+   *   status: 'requires',
+   *   transactionId: '36a101c7-7426-4f45-ab3c-55f8dc075c6e',
+   *   enrolledFactors: [
+   *     {
+   *       id: '61e39f0a-836b-48fa-b4c9-cface6a3ef5a',
+   *       userId: '60300035KP',
+   *       type: 'emailotp',
+   *       created: '2020-06-15T02:51:49.131Z',
+   *       updated: '2020-06-15T03:15:18.896Z',
+   *       attempted: '2020-07-16T04:30:14.066Z',
+   *       enabled: true,
+   *       validated: true,
+   *       attributes: {
+   *         emailAddress: 'email@email.com'
+   *       }
+   *     }
+   *   ]
+   * }
+   */
+  async refresh({sessionId, userAgent, ipAddress, evaluationContext='login'},
+      refreshToken) {
+    const context = {sessionId, userAgent, ipAddress, evaluationContext};
+    let assessment;
+    try {
+      const tokenService = new TokenService({clientId: this._config.clientId,
+        clientSecret: this._config.clientSecret}, this._config.tenantUrl,
+      context);
+      assessment = await tokenService.refreshAccessToken(refreshToken);
+
+      console.log(`[${Adaptive.name}:refresh(refreshToken, ` +
+           `context)]`, 'assessment:', assessment);
+
+      if (!assessment.allowedFactors) {
+        // No 2FA required, return token.
+        return {status: 'allow', token: assessment};
+      }
+    } catch (error) {
+      // Deny assessment.
+      console.log(`[${Adaptive.name}:refresh(refreshToken, context)]`,
+          'error:', error);
+      const jsonResp = {status: 'deny'};
+      if (error.response.data) {
+        jsonResp.detail = error.response.data;
+      }
+      return jsonResp;
+    }
+    // Further 2FA is required.
+
+    // Create transaction and store in memory cache.
+    const transaction = {assessment};
+    const transactionId = this._transactionFunctions
+        .createTransaction(transaction);
+
+    const factorService = new FactorService(
+        {accessToken: assessment.access_token},
+        this._config.tenantUrl, context);
+
+    // Get Factors enrollments for the current user.
+    const enrollments = await factorService.getEnrollments();
+    console.log(`[${Adaptive.name}:refresh(refreshToken, context)]`,
+        'enrollments:', enrollments);
+
+    // Filter the user's enrollment options based on the assessment's
+    // `allowedFactors`.
+    const enrolledFactors = enrollments.factors.filter((enrollment) =>
+      assessment.allowedFactors.includes(enrollment.type));
+    console.log(`[${Adaptive.name}:refresh(refreshToken, context)]`,
+        'enrolledFactors:', enrolledFactors);
+
+    return {status: 'requires', enrolledFactors, transactionId};
+  }
+
+  /**
+   * Introspect a refresh or access token on OIDC.
+   * @param {string} token The refresh or access token to introspect.
+   * @param {string} [tokenTypeHint] The token type. This attribute is an
+   * optional hint about the token that is being introspected. Possible values
+   * are <code>access_token</code> and <code>refresh_token</code>.
+   * @return {Promise<Object>} An object containing an <code>"active"</code>
+   * property indicating whether the introspected token is valid or invalid.
+   * Other properties are also included in the introspection result when the
+   * <code>"active"</code> status is <code>true</code>.
+   */
+  async introspect(token, tokenTypeHint) {
+    const tokenService = new TokenService({clientId: this._config.clientId,
+      clientSecret: this._config.clientSecret}, this._config.tenantUrl, {});
+
+    return tokenService.introspectToken(token, tokenTypeHint);
+  }
+
+  /**
+   * Return an Express middleware to introspect an access token on OIDC. The
+   * access token to introspect should be in the 'Authorization' header of the
+   * request.
+   * @param {Object} [config] The configuration settings used for the token
+   * introspection middleware.
+   * @param {number} [config.cacheMaxSize=0] The maximum size of the cache, i.e.
+   * the maximum number of successful token introspection responses to cache. If
+   * the cache becomes full, the least-recently-used introspection result will
+   * be removed. A value of 0 means no maximum size, i.e. infinity. This value
+   * is ignored after first initialisation (i.e. after first call to function).
+   * @param {number} [config.cacheTTL=0] The time (in seconds) to cache a
+   * successful introspection result for. If a successful token introspection
+   * is done, the result will be cached for the period of time provided, to save
+   * expensive introspection calls on each subsequent request. A value of 0 will
+   * cache the introspect response for the lifetime of the token as provided in
+   * the <code>exp</code> property of the introspect response.
+   * @param {boolean} [config.denyMFAChallenge=true] A flag indicating
+   * whether an introspected token response with a <code>scope</code> of
+   * <code>'mfa_challenge'</code> should be denied. If <code>true</code>, tokens
+   * with <code>scope</code> of <code>'mfa_challenge'</code> will be rejected.
+   * If <code>false</code>, the <code>scope</code> of tokens will be
+   * disregarded.
+   * @return {Function} The Express middleware function.
+   */
+  introspectMiddleware(config={cacheMaxSize: 0, cacheTTL: 0,
+    denyMFAChallenge: true}) {
+    return async (req, res, next) => {
+      try {
+        if (config.cacheMaxSize === undefined) {
+          throw new ConfigurationError(
+              `Cannot find property 'cacheMaxSize' in configuration settings.`);
+        } else if (config.cacheTTL === undefined) {
+          throw new ConfigurationError(
+              `Cannot find property 'cacheTTL' in configuration settings.`);
+        } else if (config.denyMFAChallenge === undefined) {
+          throw new ConfigurationError(`Cannot find property ` +
+              `'denyMFAChallenge' in configuration settings.`);
+        }
+
+        console.log(`[${Adaptive.name}:introspectMiddleware([config])]`,
+            'config.cacheMaxSize:', config.cacheMaxSize);
+        console.log(`[${Adaptive.name}:introspectMiddleware([config])]`,
+            'config.cacheTTL:', config.cacheTTL);
+        console.log(`[${Adaptive.name}:introspectMiddleware([config])]`,
+            'config.denyMFAChallenge:', config.denyMFAChallenge);
+
+        // Initialise a cache for storing introspection results, if not
+        // initialised already.
+        if (!this._introspectCache) {
+          this._introspectCache = new LRU(config.cacheMaxSize);
+        }
+
+        const authorizationHeader = req.headers['authorization'].split(' ');
+        const accessToken = authorizationHeader[1];
+        if (authorizationHeader[0].toLowerCase() === 'bearer' && accessToken) {
+          const cachedIntrospectResponse = this._introspectCache
+              .get(accessToken);
+          const introspectResponse = cachedIntrospectResponse ||
+              await this.introspect(accessToken, 'access_token');
+          console.log(`[${Adaptive.name}:introspectMiddleware([config])]`,
+              'introspectResponse:', introspectResponse);
+          if (introspectResponse && introspectResponse.active &&
+            (introspectResponse.scope !== 'mfa_challenge' ||
+            !config.denyMFAChallenge)) {
+            // Successful introspection.
+            // Cache introspection if not cached already.
+            if (!cachedIntrospectResponse) {
+              const expiresIn = introspectResponse.exp * 1000 - Date.now();
+              const cacheTTLMilliseconds =
+                  (config.cacheTTL === 0 ? expiresIn : config.cacheTTL * 1000);
+              console.log(`[${Adaptive.name}:introspectMiddleware([config])]`,
+                  'cacheTTLMilliseconds:', cacheTTLMilliseconds);
+              this._introspectCache.set(accessToken, introspectResponse,
+                  cacheTTLMilliseconds);
+            }
+            next();
+            return;
+          }
+        }
+
+        throw new TokenError('Token introspection failed.');
+      } catch (error) {
+        next(error);
+      }
+    };
+  }
+}
+
+module.exports = Adaptive;
+
+
+
+ + + + +
+ +
+ + + + + + + + + + diff --git a/sdk/adaptive-proxy/docs/errors_configurationError.js.html b/sdk/adaptive-proxy/docs/errors_configurationError.js.html new file mode 100644 index 0000000..3171926 --- /dev/null +++ b/sdk/adaptive-proxy/docs/errors_configurationError.js.html @@ -0,0 +1,125 @@ + + + + + + + + + + + errors/configurationError.js - Documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + +
+ +

+ errors/configurationError.js +

+ + + + + +
+
+
// Copyright contributors to the IBM Security Verify Adaptive Proxy SDK
+// for JavaScript project
+
+/**
+ * Indicate that a provided configuration does not contain the
+ * <code>tenantUrl</code>, <code>clientId</code>, or <code>clientSecret</code>
+ * properties.
+ * @author Adam Dorogi-Kaposi <adam.dorogi-kaposi@ibm.com>
+ */
+class ConfigurationError extends Error {
+  /**
+   * Create a {@link ConfigurationError} object with a custom error message.
+   * @param {string} message The error message.
+   */
+  constructor(message) {
+    super(message);
+  }
+}
+
+module.exports = ConfigurationError;
+
+
+
+ + + + +
+ +
+ + + + + + + + + + diff --git a/sdk/adaptive-proxy/docs/errors_tokenError.js.html b/sdk/adaptive-proxy/docs/errors_tokenError.js.html new file mode 100644 index 0000000..208200a --- /dev/null +++ b/sdk/adaptive-proxy/docs/errors_tokenError.js.html @@ -0,0 +1,124 @@ + + + + + + + + + + + errors/tokenError.js - Documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + +
+ +

+ errors/tokenError.js +

+ + + + + +
+
+
// Copyright contributors to the IBM Security Verify Adaptive Proxy SDK
+// for JavaScript project
+
+/**
+ * Indicate that a token is invalid, or a token related operation (e.g. token
+ * introspection) has failed.
+ * @author Adam Dorogi-Kaposi <adam.dorogi-kaposi@ibm.com>
+ */
+class TokenError extends Error {
+  /**
+   * Create a {@link TokenError} object with a custom error message.
+   * @param {string} message The error message.
+   */
+  constructor(message) {
+    super(message);
+  }
+}
+
+module.exports = TokenError;
+
+
+
+ + + + +
+ +
+ + + + + + + + + + diff --git a/sdk/adaptive-proxy/docs/errors_transactionError.js.html b/sdk/adaptive-proxy/docs/errors_transactionError.js.html new file mode 100644 index 0000000..d35c2a8 --- /dev/null +++ b/sdk/adaptive-proxy/docs/errors_transactionError.js.html @@ -0,0 +1,124 @@ + + + + + + + + + + + errors/transactionError.js - Documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + +
+ +

+ errors/transactionError.js +

+ + + + + +
+
+
// Copyright contributors to the IBM Security Verify Adaptive Proxy SDK
+// for JavaScript project
+
+/**
+ * Indicate that a transaction associated to the provided transaction ID does
+ * not exist, or the transaction does not contain a required property.
+ * @author Adam Dorogi-Kaposi <adam.dorogi-kaposi@ibm.com>
+ */
+class TransactionError extends Error {
+  /**
+   * Create a {@link TransactionError} object with a custom error message.
+   * @param {string} message The error message.
+   */
+  constructor(message) {
+    super(message);
+  }
+}
+
+module.exports = TransactionError;
+
+
+
+ + + + +
+ +
+ + + + + + + + + + diff --git a/sdk/adaptive-proxy/docs/fonts/OpenSans-Bold-webfont.eot b/sdk/adaptive-proxy/docs/fonts/OpenSans-Bold-webfont.eot new file mode 100644 index 0000000..5d20d91 Binary files /dev/null and b/sdk/adaptive-proxy/docs/fonts/OpenSans-Bold-webfont.eot differ diff --git a/sdk/adaptive-proxy/docs/fonts/OpenSans-Bold-webfont.svg b/sdk/adaptive-proxy/docs/fonts/OpenSans-Bold-webfont.svg new file mode 100644 index 0000000..3ed7be4 --- /dev/null +++ b/sdk/adaptive-proxy/docs/fonts/OpenSans-Bold-webfont.svg @@ -0,0 +1,1830 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/sdk/adaptive-proxy/docs/fonts/OpenSans-Bold-webfont.woff b/sdk/adaptive-proxy/docs/fonts/OpenSans-Bold-webfont.woff new file mode 100644 index 0000000..1205787 Binary files /dev/null and b/sdk/adaptive-proxy/docs/fonts/OpenSans-Bold-webfont.woff differ diff --git a/sdk/adaptive-proxy/docs/fonts/OpenSans-BoldItalic-webfont.eot b/sdk/adaptive-proxy/docs/fonts/OpenSans-BoldItalic-webfont.eot new file mode 100644 index 0000000..1f639a1 Binary files /dev/null and b/sdk/adaptive-proxy/docs/fonts/OpenSans-BoldItalic-webfont.eot differ diff --git a/sdk/adaptive-proxy/docs/fonts/OpenSans-BoldItalic-webfont.svg b/sdk/adaptive-proxy/docs/fonts/OpenSans-BoldItalic-webfont.svg new file mode 100644 index 0000000..6a2607b --- /dev/null +++ b/sdk/adaptive-proxy/docs/fonts/OpenSans-BoldItalic-webfont.svg @@ -0,0 +1,1830 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/sdk/adaptive-proxy/docs/fonts/OpenSans-BoldItalic-webfont.woff b/sdk/adaptive-proxy/docs/fonts/OpenSans-BoldItalic-webfont.woff new file mode 100644 index 0000000..ed760c0 Binary files /dev/null and b/sdk/adaptive-proxy/docs/fonts/OpenSans-BoldItalic-webfont.woff differ diff --git a/sdk/adaptive-proxy/docs/fonts/OpenSans-Italic-webfont.eot b/sdk/adaptive-proxy/docs/fonts/OpenSans-Italic-webfont.eot new file mode 100644 index 0000000..0c8a0ae Binary files /dev/null and b/sdk/adaptive-proxy/docs/fonts/OpenSans-Italic-webfont.eot differ diff --git a/sdk/adaptive-proxy/docs/fonts/OpenSans-Italic-webfont.svg b/sdk/adaptive-proxy/docs/fonts/OpenSans-Italic-webfont.svg new file mode 100644 index 0000000..e1075dc --- /dev/null +++ b/sdk/adaptive-proxy/docs/fonts/OpenSans-Italic-webfont.svg @@ -0,0 +1,1830 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/sdk/adaptive-proxy/docs/fonts/OpenSans-Italic-webfont.woff b/sdk/adaptive-proxy/docs/fonts/OpenSans-Italic-webfont.woff new file mode 100644 index 0000000..ff652e6 Binary files /dev/null and b/sdk/adaptive-proxy/docs/fonts/OpenSans-Italic-webfont.woff differ diff --git a/sdk/adaptive-proxy/docs/fonts/OpenSans-Light-webfont.eot b/sdk/adaptive-proxy/docs/fonts/OpenSans-Light-webfont.eot new file mode 100644 index 0000000..1486840 Binary files /dev/null and b/sdk/adaptive-proxy/docs/fonts/OpenSans-Light-webfont.eot differ diff --git a/sdk/adaptive-proxy/docs/fonts/OpenSans-Light-webfont.svg b/sdk/adaptive-proxy/docs/fonts/OpenSans-Light-webfont.svg new file mode 100644 index 0000000..11a472c --- /dev/null +++ b/sdk/adaptive-proxy/docs/fonts/OpenSans-Light-webfont.svg @@ -0,0 +1,1831 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/sdk/adaptive-proxy/docs/fonts/OpenSans-Light-webfont.woff b/sdk/adaptive-proxy/docs/fonts/OpenSans-Light-webfont.woff new file mode 100644 index 0000000..e786074 Binary files /dev/null and b/sdk/adaptive-proxy/docs/fonts/OpenSans-Light-webfont.woff differ diff --git a/sdk/adaptive-proxy/docs/fonts/OpenSans-LightItalic-webfont.eot b/sdk/adaptive-proxy/docs/fonts/OpenSans-LightItalic-webfont.eot new file mode 100644 index 0000000..8f44592 Binary files /dev/null and b/sdk/adaptive-proxy/docs/fonts/OpenSans-LightItalic-webfont.eot differ diff --git a/sdk/adaptive-proxy/docs/fonts/OpenSans-LightItalic-webfont.svg b/sdk/adaptive-proxy/docs/fonts/OpenSans-LightItalic-webfont.svg new file mode 100644 index 0000000..431d7e3 --- /dev/null +++ b/sdk/adaptive-proxy/docs/fonts/OpenSans-LightItalic-webfont.svg @@ -0,0 +1,1835 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/sdk/adaptive-proxy/docs/fonts/OpenSans-LightItalic-webfont.woff b/sdk/adaptive-proxy/docs/fonts/OpenSans-LightItalic-webfont.woff new file mode 100644 index 0000000..43e8b9e Binary files /dev/null and b/sdk/adaptive-proxy/docs/fonts/OpenSans-LightItalic-webfont.woff differ diff --git a/sdk/adaptive-proxy/docs/fonts/OpenSans-Regular-webfont.eot b/sdk/adaptive-proxy/docs/fonts/OpenSans-Regular-webfont.eot new file mode 100644 index 0000000..6bbc3cf Binary files /dev/null and b/sdk/adaptive-proxy/docs/fonts/OpenSans-Regular-webfont.eot differ diff --git a/sdk/adaptive-proxy/docs/fonts/OpenSans-Regular-webfont.svg b/sdk/adaptive-proxy/docs/fonts/OpenSans-Regular-webfont.svg new file mode 100644 index 0000000..25a3952 --- /dev/null +++ b/sdk/adaptive-proxy/docs/fonts/OpenSans-Regular-webfont.svg @@ -0,0 +1,1831 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/sdk/adaptive-proxy/docs/fonts/OpenSans-Regular-webfont.woff b/sdk/adaptive-proxy/docs/fonts/OpenSans-Regular-webfont.woff new file mode 100644 index 0000000..e231183 Binary files /dev/null and b/sdk/adaptive-proxy/docs/fonts/OpenSans-Regular-webfont.woff differ diff --git a/sdk/adaptive-proxy/docs/fonts/OpenSans-Semibold-webfont.eot b/sdk/adaptive-proxy/docs/fonts/OpenSans-Semibold-webfont.eot new file mode 100755 index 0000000..d8375dd Binary files /dev/null and b/sdk/adaptive-proxy/docs/fonts/OpenSans-Semibold-webfont.eot differ diff --git a/sdk/adaptive-proxy/docs/fonts/OpenSans-Semibold-webfont.svg b/sdk/adaptive-proxy/docs/fonts/OpenSans-Semibold-webfont.svg new file mode 100755 index 0000000..eec4db8 --- /dev/null +++ b/sdk/adaptive-proxy/docs/fonts/OpenSans-Semibold-webfont.svg @@ -0,0 +1,1830 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/sdk/adaptive-proxy/docs/fonts/OpenSans-Semibold-webfont.ttf b/sdk/adaptive-proxy/docs/fonts/OpenSans-Semibold-webfont.ttf new file mode 100755 index 0000000..b329084 Binary files /dev/null and b/sdk/adaptive-proxy/docs/fonts/OpenSans-Semibold-webfont.ttf differ diff --git a/sdk/adaptive-proxy/docs/fonts/OpenSans-Semibold-webfont.woff b/sdk/adaptive-proxy/docs/fonts/OpenSans-Semibold-webfont.woff new file mode 100755 index 0000000..28d6ade Binary files /dev/null and b/sdk/adaptive-proxy/docs/fonts/OpenSans-Semibold-webfont.woff differ diff --git a/sdk/adaptive-proxy/docs/fonts/OpenSans-SemiboldItalic-webfont.eot b/sdk/adaptive-proxy/docs/fonts/OpenSans-SemiboldItalic-webfont.eot new file mode 100755 index 0000000..0ab1db2 Binary files /dev/null and b/sdk/adaptive-proxy/docs/fonts/OpenSans-SemiboldItalic-webfont.eot differ diff --git a/sdk/adaptive-proxy/docs/fonts/OpenSans-SemiboldItalic-webfont.svg b/sdk/adaptive-proxy/docs/fonts/OpenSans-SemiboldItalic-webfont.svg new file mode 100755 index 0000000..7166ec1 --- /dev/null +++ b/sdk/adaptive-proxy/docs/fonts/OpenSans-SemiboldItalic-webfont.svg @@ -0,0 +1,1830 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/sdk/adaptive-proxy/docs/fonts/OpenSans-SemiboldItalic-webfont.ttf b/sdk/adaptive-proxy/docs/fonts/OpenSans-SemiboldItalic-webfont.ttf new file mode 100755 index 0000000..d2d6318 Binary files /dev/null and b/sdk/adaptive-proxy/docs/fonts/OpenSans-SemiboldItalic-webfont.ttf differ diff --git a/sdk/adaptive-proxy/docs/fonts/OpenSans-SemiboldItalic-webfont.woff b/sdk/adaptive-proxy/docs/fonts/OpenSans-SemiboldItalic-webfont.woff new file mode 100755 index 0000000..d4dfca4 Binary files /dev/null and b/sdk/adaptive-proxy/docs/fonts/OpenSans-SemiboldItalic-webfont.woff differ diff --git a/sdk/adaptive-proxy/docs/global.html b/sdk/adaptive-proxy/docs/global.html new file mode 100644 index 0000000..2effd86 --- /dev/null +++ b/sdk/adaptive-proxy/docs/global.html @@ -0,0 +1,1549 @@ + + + + + + + + + Global - Documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + +
+ +

+ Global +

+ + + + +
+
+ +

+ + + +

+ + + +
+ +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + +
+ + + + + + + + + + + + + + +

Methods

+ + + + + + + + + + + + + +

+ base64UrlEncodeObject(object) → {string} +

+
+ + + + + +
+

Base64url encode the JSON string representation of an object.

+
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
object + + + + Object + + + + + + + +

The object to encode.

+ +
+ + + + +
Returns:
+ + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + + + string + + + + + + + +

The base64url encoded JSON string.

+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ base64UrlEncodeString(string) → {string} +

+
+ + + + + +
+

Base64url encode a string.

+
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
string + + + + string + + + + + + + +

The string to encode.

+ +
+ + + + +
Returns:
+ + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + + + string + + + + + + + +

The base64url encoded string.

+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ createTransaction(object) → {string} +

+
+ + + + + +
+

Create a stored transaction. Associate the given object with a random UUID in +the cache.

+
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
object + + + + Object + + + + + + + +

The object to store as a transaction.

+ +
+ + + + +
Returns:
+ + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + + + string + + + + + + + +

The randomly generated UUID associated to the new +transaction.

+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + +
Throws:
+ + + +
+
+
+

The transaction cannot be stored.

+
+
+
+
+
+
Type
+
+ + + TransactionError + + + + + +
+
+
+
+
+ + + + + + + + + + + + + + + + + + +

+ deleteTransaction(transactionId) +

+
+ + + + + +
+

Delete a stored transaction.

+
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
transactionId + + + + string + + + + + + + +

The identifier of the transaction to delete.

+ +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + +
Throws:
+ + + +
+
+
+

The transaction ID doesn't exist.

+
+
+
+
+
+
Type
+
+ + + TransactionError + + + + + +
+
+
+
+
+ + + + + + + + + + + + + + + + + + +

+ getTransaction(transactionId) → {Object} +

+
+ + + + + +
+

Get a stored transaction.

+
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
transactionId + + + + string + + + + + + + +

The identifier of the transaction.

+ +
+ + + + +
Returns:
+ + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + + + Object + + + + + + + +

The transaction object associated with the identifier.

+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + +
Throws:
+ + + +
+
+
+

The transaction ID doesn't exist.

+
+
+
+
+
+
Type
+
+ + + TransactionError + + + + + +
+
+
+
+
+ + + + + + + + + + + + + + + + + + +

+ maskObject(object) → {Object} +

+
+ + + + + +
+

Mask sensitive properties of an object.

+
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
object + + + + Object + + + + + + + +

The object whose sensitive properties to mask.

+ +
+ + + + +
Returns:
+ + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + + + Object + + + + + + + +

The masked object.

+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ updateTransaction(transactionId, properties) +

+
+ + + + + +
+

Add the given properties to a stored transaction.

+
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
transactionId + + + + string + + + + + + + +

The identifier of the transaction to update.

+ +
properties + + + + Object + + + + + + + +

The properties to add to the transaction.

+ +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + +
Throws:
+ + + +
+
+
+

The transaction ID doesn't exist.

+
+
+
+
+
+
Type
+
+ + + TransactionError + + + + + +
+
+
+
+
+ + + + + + + + + + + + +
+
+ + + + +
+ +
+ + + + + + + + + + \ No newline at end of file diff --git a/sdk/adaptive-proxy/docs/icons/home.svg b/sdk/adaptive-proxy/docs/icons/home.svg new file mode 100644 index 0000000..676d2d3 --- /dev/null +++ b/sdk/adaptive-proxy/docs/icons/home.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/sdk/adaptive-proxy/docs/icons/search.svg b/sdk/adaptive-proxy/docs/icons/search.svg new file mode 100644 index 0000000..ccc84b6 --- /dev/null +++ b/sdk/adaptive-proxy/docs/icons/search.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/sdk/adaptive-proxy/docs/index.html b/sdk/adaptive-proxy/docs/index.html new file mode 100644 index 0000000..10aa034 --- /dev/null +++ b/sdk/adaptive-proxy/docs/index.html @@ -0,0 +1,1788 @@ + + + + + + + + + Home - Documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + +
+ + + + + + + + + + + + +
+
+

IBM Security Verify Adaptive Proxy SDK for JavaScript

+

The Proxy SDK for server-side JavaScript (Node). +The purpose of this library is to provide an interface for device +authentication, authorization, and risk assessment using IBM Security Verify.

+

Installation

+

Use npm to install the Proxy SDK:

+
npm install @ibm-verify/adaptive-proxy
+
+

Configuration Settings

+

To use the Proxy SDK, you will need to initialise an Adaptive object with a +configuration object. The configuration object should contian the following +parameters:

+ + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterTypeDescription
tenantUrlstringThe base URL of your IBM Security Verify Tenant
clientIdstringThe identifier of your Security Verify application
clientSecretstringThe secret for your Security Verify application
+

See Initialise an Adaptive object for an +example.

+

Context Object

+

A call to each function in this SDK requires a context object as a +parameter. This context object contains information about the +user-agent attempting the request, such as a session identifier. +This device-related information will be used to assess risk during +each request.

+

The context object should contain the following parameters:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterTypeDescription
sessionIdstringThe session ID generated by the user-agent, using an Adaptive client SDK.
userAgentstringThe user-agent, typically obtained from the User-Agent HTTP header.
ipAddressstringThe IP address of the user-agent.
[evaluationContext="login"]stringThe stage in the user-agent for which to perform an evaluation. (Used for continuous assessment throughout the user-agent.) Different "stages" or "contexts" will result in different evaluation results, as configured in the sub-policies of the tenant application's policy. Possible options are "login" (default), "landing", "profile", "resume", "highassurance", "other".
+

Overview

+

class Adaptive(config, [transactionFunctions])

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FunctionAsyncReturn
assessPolicy(context)Promise<Object>
lookupIdentitySources(context, transactionId, [sourceName]Promise<Object>
evaluatePassword(context, transactionId, identitySourceId, username, password)Promise<Object>
generateFIDO(context, transactionId, relyingPartyId, userId)Promise<Object>
evaluateFIDO(context, transactionId, relyingPartyId, authenticatorData, userHandle, signature, clientDataJSON)Promise<Object>
generateQR(context, transactionId, profileId)Promise<Object>
evaluateQR(context, transactionId)Promise<Object>
generateEmailOTP(context, transactionId, enrollmentId)Promise<Object>
generateSMSOTP(context, transactionId, enrollmentId)Promise<Object>
generateVoiceOTP(context, transactionId, enrollmentId)Promise<Object>
evaluateTOTP(context, transactionId, enrollmentId, otp)Promise<Object>
evaluateEmailOTP(context, transactionId, otp)Promise<Object>
evaluateSMSOTP(context, transactionId, otp)Promise<Object>
evaluateVoiceOTP(context, transactionId, otp)Promise<Object>
generateQuestions(context, transactionId, enrollmentId)Promise<Object>
evaluateQuestions(context, transactionId, questions)Promise<Object>
generatePush(context, transactionId, enrollmentId, authenticatorId, message, pushNotificationTitle, pushNotificationMessage, additionalData)Promise<Object>
evaluatePush(context, transactionId)Promise<Object>
getToken(transactionId)String
logout(accessToken)undefined
refresh(context, refreshToken)Promise<Object>
introspect(token, [tokenTypeHint])Promise<Object>
introspectMiddleware([config])Function
+

Usage

+

Import the Proxy SDK

+
const Adaptive = require('@ibm-verify/adaptive-proxy');
+
+

Initialise an Adaptive object

+
const config = {
+  tenantUrl: 'https://mytenant.ibmcloudsecurity.com',
+  clientId: 'e957e707-c032-4076-98cc-3dcf24db8aed',
+  clientSecret: '05UXCBaJgL',
+};
+
+const adaptive = new Adaptive(config);
+
+

Custom transaction storage

+

You may also pass in a transactionFunctions object to the Adaptive initialisation, as shown below.

+
const config = {
+  tenantUrl: 'https://mytenant.ibmcloudsecurity.com',
+  clientId: 'e957e707-c032-4076-98cc-3dcf24db8aed',
+  clientSecret: '05UXCBaJgL',
+};
+
+const transactionFunctions = {
+  createTransaction: myCreateTransactionFunction,
+  getTransaction: myGetTransactionFunction,
+  updateTransaction: myUpdateTransactionFunction,
+  deleteTransaction: myDeleteTransactionFunction
+};
+
+const adaptive = new Adaptive(config, transactionFunctions);
+
+

This parameter is optional, in case you would like to handle the storing, retrieving, updating, and deleting of transactions created during the A2 flow in an external database. Otherwise, a default in-memory option is used for handling transactions.

+

If specified, this object must contain four parameters:

+
    +
  • createTransaction +
      +
    • The function used to create (store) a transaction. This function should take one parameter; a transaction Object. It should store the object in a database of choice, indexed by a randomly generated v4 UUID (i.e. the transaction ID). After storing the transaction object associated to a transaction ID, the function should return the transaction ID as a string.
    • +
    +
  • +
  • getTransaction +
      +
    • The function used to retrieve stored transactions. This function should take one parameter; a transaction ID string. It should return the transaction Object associated to the given transaction ID.
    • +
    +
  • +
  • updateTransaction +
      +
    • The function used to update (i.e. add additional properties to) an existing transaction. This function should take two parameters (in order); a transaction ID string of the transaction to update, and an Object of additional properties to add to the transaction. This function shouldn't return anything.
    • +
    • For example, if the existing transaction is
      {
      +  "userId": "123456"
      +}
      +
      +, and the object passed into this function is
      {
      +  "name": "John"
      +}
      +
      +, the updated transaction should result in
      {
      +  "userId": "123456",
      +  "name": "John"
      +}
      +
      +
    • +
    +
  • +
  • deleteTransaction +
      +
    • The function used to delete an existing transaction. This function should take one parameter; a transaction ID string. The function should remove the transaction associated with the given transaction ID from the database storage. This function shouldn't return anything.
    • +
    +
  • +
+

Your storage mechanism of choice should ideally have a time-to-live for the transactions (e.g. 1 hour), to prevent accumulating unused/unfinished transactions.

+

Assess a policy

+

Performs the initial grant request to OIDC. This will perform risk assessment on the policy, which will result in either a deny, or requires response.

+

assessPolicy(context)

+ + + + + + + + + + + + + + + +
ParameterTypeDescription
contextObjectSee Context Object.
+

Responses

+
    +
  • +

    A deny response is received when the policy assessment fails.

    +
    {
    +  "status": "deny"
    +}
    +
    +
  • +
  • +

    A requires response will contain an array of allowed factors, indicating that +further verification is required (i.e. first-factor verification must be +performed) to receive a token. The possible first factor options are "qr", +"fido", and "password". You can use the +generateQR, +generateFIDO, and +evaluatePassword +functions respectively to initiate these first factors. A transaction ID will also be returned, which will be used to associate subsequent requests to this initial grant.

    +
    {
    +  "status": "requires",
    +  "transactionId": "36a101c7-7426-4f45-ab3c-55f8dc075c6e",
    +  "allowedFactors": ["qr", "fido", "password"]
    +}
    +
    +
  • +
+

Example Usage

+
adaptive.assessPolicy(context)
+    .then((result) => {
+      res.send(result);
+    }).catch((error) => {
+      console.log(error);
+      res.status(404).send({error: error.message});
+    });
+
+

Lookup Identity Sources

+

Lookup identity sources by name. If name not defined then return all password-capable sources.

+

lookupIdentitySources(context, transactionId, [sourceName])

+ + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterTypeDescription
contextObjectSee Context Object.
transactionIdstringThe transaction ID received in assessPolicy.
[sourceName]string(Optional) name of identity source. e.g. "Cloud Directory".
+

Response

+
    +
  • A response containing an array of identity source objects:
     [
    +   {
    +     "name": "Cloud Directory",
    +     "location": "https://<tenant_url>/v1.0/authnmethods/password/11111111-2222-3333-4444-555555555555",
    +     "id": "11111111-2222-3333-4444-555555555555",
    +     "type": "ibmldap"
    +   }
    + ]
    +
    +
  • +
+

Example Usage

+
let identitySourceId
+adaptive.lookupIdentitySources(context, transactionId, "Cloud Directory")
+    .then((result) => {
+      identitySourceId = result[0].id;
+    }).catch((error) => {
+      console.log(error);
+      res.status(404).send({error: error.message});
+    });
+
+

Evaluate a password verification

+

Attempt to complete a password first-factor verification after +receiving a requires status from assessPolicy. This will result in either an allow, deny, or requires response.

+

evaluatePassword(context, transactionId, identitySourceId, username, password)

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterTypeDescription
contextObjectSee Context Object.
transactionIdstringThe transaction ID received in assessPolicy.
identitySourceIdstringThe identifier of the identity source associated with the password registration.
usernamestringThe username to authenticate as.
passwordstringThe password to authenticate with.
+

Responses

+
    +
  • +

    An allow response will contain a token to access the API with.

    +
    {
    +  "status": "allow",
    +  "token": {
    +    "access_token": "zscmjBdvIjudOPLhpbmJi6nBRJg7cZ6WY0Udw1nC",
    +    "refresh_token": "wFTjurPxTvRD1cW09itgQM83XwCm1UKwsxhVFb1H7HJh8JkwZz",
    +    "scope": "openid",
    +    "grant_id": "a0b440b6-fefb-46ea-a603-e1040534cd28",
    +    "id_token": "eyJhbGciOiJSUzI1NiIsInR5cC...5j_rMn7H3ZpE4axt0WvsYu4jbA",
    +    "token_type": "Bearer",
    +    "expires_in": 7120
    +  }
    +}
    +
    +
  • +
  • +

    A deny response is received when the policy denies access or policy evaluation fails. If error information is available, it will be returned in a details attribute.

    +
    {
    +  "status": "deny"
    +  "detail": {
    +     "error": "adaptive_more_info_required",
    +     "error_description": "CSIAQ0298E Adaptive access..."
    +  }
    +}
    +
    +
  • +
  • +

    A requires response will contain an array of allowed authentication +enrollments, indicating that further verification is required (i.e. second-factor +verification must be performed) to receive a token. The possible multi-factor +enrollments are "emailotp", "smsotp", "voiceotp", "totp", "questions", "push" and "fido". +You can use the +generateEmailOTP, +generateSMSOTP, +generateVoiceOTP, +evaluateTOTP, +generateQuestions, generatePush, +and generateFIDO functions respectively to +perform these 2FA verifications. You can use any of the returned enrollments to perform the second-factor authentication. Your initial transaction ID will also be +returned.

    +
    {
    +  "status": "requires",
    +  "transactionId": "36a101c7-7426-4f45-ab3c-55f8dc075c6e",
    +  "enrolledFactors": [
    +    {
    +      "id": "61e39f0a-836b-48fa-b4c9-cface6a3ef5a",
    +      "userId": "60300035KP",
    +      "type": "emailotp",
    +      "created": "2020-06-15T02:51:49.131Z",
    +      "updated": "2020-06-15T03:15:18.896Z",
    +      "attempted": "2020-07-16T04:30:14.066Z",
    +      "enabled": true,
    +      "validated": true,
    +      "attributes": {
    +        "emailAddress": "email@email.com"
    +      }
    +    }
    +  ]
    +}
    +
    +
  • +
+

Example Usage

+
adaptive.evaluatePassword(context, transactionId, identitySourceId, username, password)
+    .then((result) => {
+      res.send(result);
+    }).catch((error) => {
+      console.log(error);
+      res.status(404).send({error: error.message});
+    });
+
+

Generate a FIDO verification

+

Initiate a FIDO first-factor verification after receiving a requires status +from assessPolicy, or a FIDO second-factor verification after +receiving a requires status from a first-factor completion +(evaluateQR, +evaluatePassword, or +evaluateFIDO). This will return a FIDO +challenge to be sent back to the user for signing.

+

generateFIDO(context, transactionId, relyingPartyId, userId)

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterTypeDescription
contextObjectSee Context Object.
transactionIdstringThe transaction ID received in assessPolicy.
relyingPartyIdstringThe identifier of the relying party associated with the FIDO registration.
userIdstringThe identifier of the OIDC user for which to initiate a FIDO verification.
+

Response

+
    +
  • The response will contain a FIDO challenge to be signed by your authenticator, +then sent to evaluateFIDO for +completion. Your initial transaction ID will also be returned.
    {
    +  "transactionId": "36a101c7-7426-4f45-ab3c-55f8dc075c6e",
    +  "fido": {
    +    "rpId": "fido.verify.ibm.com",
    +    "challenge": "Q29uZ3JhdHVsYXRpb25zIFlvdSBmb3VuZCBpdAo",
    +    "userVerification": "preferred",
    +    "timeout": 30000,
    +    "allowCredentials": [
    +      {
    +        "type": "public-key",
    +        "id": "SSBhbSBhIGNyZWRlbnRpYWwK"
    +      }
    +    ]
    +  }
    +}
    +
    +
  • +
+

Example Usage

+
adaptive.generateFIDO(context, transactionId, relyingPartyId, userId)
+    .then((result) => {
+      res.send(result);
+    }).catch((error) => {
+      console.log(error);
+      res.status(404).send({error: error.message});
+    });
+
+

Evaluate a FIDO verification

+

Complete a FIDO verification after receiving and signing a FIDO +challenge from generateFIDO. This +will result in either an allow, deny, or requires response.

+

evaluateFIDO(context, transactionId, relyingPartyId, authenticatorData, userHandle, signature, clientDataJSON)

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterTypeDescription
contextObjectSee Context Object.
transactionIdstringThe transaction ID received in assessPolicy.
relyingPartyIdstringThe identifier of the relying party associated with the FIDO registration.
authenticatorDatastringThe information about the authentication produced by the authenticator.
userHandlestringThe identifier for the user who owns this authenticator.
signaturestringThe received and signed FIDO challenge from generateFIDO.
clientDataJSONstringThe base64 encoded client data JSON object.
+

Responses

+
    +
  • +

    An allow response will contain a token to access the API with.

    +
    {
    +  "status": "allow",
    +  "token": {
    +    "access_token": "zscmjBdvIjudOPLhpbmJi6nBRJg7cZ6WY0Udw1nC",
    +    "refresh_token": "wFTjurPxTvRD1cW09itgQM83XwCm1UKwsxhVFb1H7HJh8JkwZz",
    +    "scope": "openid",
    +    "grant_id": "a0b440b6-fefb-46ea-a603-e1040534cd28",
    +    "id_token": "eyJhbGciOiJSUzI1NiIsInR5cC...5j_rMn7H3ZpE4axt0WvsYu4jbA",
    +    "token_type": "Bearer",
    +    "expires_in": 7120
    +  }
    +}
    +
    +
  • +
  • +

    A deny response is received when the policy denies access or policy evaluation fails. If error information is available, it will be returned in a details attribute.

    +
    {
    +  "status": "deny"
    +  "detail": {
    +     "error": "adaptive_more_info_required",
    +     "error_description": "CSIAQ0298E Adaptive access..."
    +  }
    +}
    +
    +
  • +
  • +

    A requires response can only be received during first factor verification. In that case, the response will contain an array of allowed authentication +enrollments, indicating that further verification is required (i.e. second-factor +verification must be performed) to receive a token. The possible multi-factor +enrollments are "emailotp", "smsotp", "voiceotp", "totp", "questions", "push" and "fido". +You can use the +generateEmailOTP, +generateSMSOTP, +generateVoiceOTP, +evaluateTOTP, +generateQuestions, generatePush, +and generateFIDO functions respectively to +perform these 2FA verifications. You can use any of the returned enrollments to perform the second-factor authentication. Your initial transaction ID will also be +returned.

    +
    {
    +  "status": "requires",
    +  "transactionId": "36a101c7-7426-4f45-ab3c-55f8dc075c6e",
    +  "enrolledFactors": [
    +    {
    +      "id": "61e39f0a-836b-48fa-b4c9-cface6a3ef5a",
    +      "userId": "60300035KP",
    +      "type": "emailotp",
    +      "created": "2020-06-15T02:51:49.131Z",
    +      "updated": "2020-06-15T03:15:18.896Z",
    +      "attempted": "2020-07-16T04:30:14.066Z",
    +      "enabled": true,
    +      "validated": true,
    +      "attributes": {
    +        "emailAddress": "email@email.com"
    +      }
    +    }
    +  ]
    +}
    +
    +
  • +
+

Example Usage

+
adaptive.evaluateFIDO(context, transactionId, relyingPartyId, authenticatorData, userHandle, signature, clientDataJSON)
+    .then((result) => {
+      res.send(result);
+    }).catch((error) => {
+      console.log(error);
+      res.status(404).send({error: error.message});
+    });
+
+

Generate a QR login verification

+

Initiate a QR login first-factor verification after receiving a requires +status from assessPolicy. This will return a QR login +code to be sent back to the user for scanning.

+

generateQR(context, transactionId, profileId)

+ + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterTypeDescription
contextObjectSee Context Object.
transactionIdstringThe transaction ID received in assessPolicy.
profileIdstringThe identifier of an IBM Verify registration profile.
+

Response

+
    +
  • The response will contain a QR login code to be scanned by your authenticator. Upon scanning, the authenticator should send a request to evaluateQR for +completion. Your initial transaction ID will also be returned.
    {
    +  "transactionId": "36a101c7-7426-4f45-ab3c-55f8dc075c6e",
    +  "qr": {
    +    "code": "iVBORw0KGgoAAAANSUhEUgAAASwAAAEsAQAAAABR..."
    +  }
    +}
    +
    +
  • +
+

Example Usage

+
adaptive.generateQR(context, transactionId, profileId)
+    .then((result) => {
+      res.send(result);
+    }).catch((error) => {
+      console.log(error);
+      res.status(404).send({error: error.message});
+    });
+
+

Evaluate a QR login verification

+

Complete a QR login first-factor verification after receiving and scanning a QR +login code from generateQR. +This will result in either a pending, timeout, error, allow, deny, or requires response.

+

evaluateQR(context, transactionId)

+ + + + + + + + + + + + + + + + + + + + +
ParameterTypeDescription
contextObjectSee Context Object.
transactionIdstringThe transaction ID received in assessPolicy.
+

Responses

+
    +
  • +

    A pending response indicates the QR code transaction has not yet been completed.

    +
    {
    +  "status": "pending",
    +  "expiry": "2021-04-26T12:06:06.501Z"
    +}
    +
    +
  • +
  • +

    A timeout response indicates the QR code transaction has timed out.

    +
    {
    +  "status": "timeout",
    +  "expiry": "2021-04-26T12:06:06.501Z"
    +}
    +
    +
  • +
  • +

    An error response indicates an error querying the QR code transaction.

    +
    {
    +  "status": "error"
    +}
    +
    +
  • +
  • +

    An allow response will contain a token to access the API with.

    +
    {
    +  "status": "allow",
    +  "token": {
    +    "access_token": "zscmjBdvIjudOPLhpbmJi6nBRJg7cZ6WY0Udw1nC",
    +    "refresh_token": "wFTjurPxTvRD1cW09itgQM83XwCm1UKwsxhVFb1H7HJh8JkwZz",
    +    "scope": "openid",
    +    "grant_id": "a0b440b6-fefb-46ea-a603-e1040534cd28",
    +    "id_token": "eyJhbGciOiJSUzI1NiIsInR5cC...5j_rMn7H3ZpE4axt0WvsYu4jbA",
    +    "token_type": "Bearer",
    +    "expires_in": 7120
    +  }
    +}
    +
    +
  • +
  • +

    A deny response is received when the policy denies access or policy evaluation fails. If error information is available, it will be returned in a details attribute.

    +
    {
    +  "status": "deny"
    +  "detail": {
    +     "error": "adaptive_more_info_required",
    +     "error_description": "CSIAQ0298E Adaptive access..."
    +  }
    +}
    +
    +
  • +
  • +

    A requires response will contain an array of allowed authentication +enrollments, indicating that further verification is required (i.e. second-factor +verification must be performed) to receive a token. The possible multi-factor +enrollments are "emailotp", "smsotp", "voiceotp", "totp", "questions", "push" and "fido". +You can use the +generateEmailOTP, +generateSMSOTP, +generateVoiceOTP, +evaluateTOTP, +generateQuestions, generatePush, +and generateFIDO functions respectively to +perform these 2FA verifications. You can use any of the returned enrollments to perform the second-factor authentication. Your initial transaction ID will also be +returned.

    +
    {
    +  "status": "requires",
    +  "transactionId": "36a101c7-7426-4f45-ab3c-55f8dc075c6e",
    +  "enrolledFactors": [
    +    {
    +      "id": "61e39f0a-836b-48fa-b4c9-cface6a3ef5a",
    +      "userId": "60300035KP",
    +      "type": "emailotp",
    +      "created": "2020-06-15T02:51:49.131Z",
    +      "updated": "2020-06-15T03:15:18.896Z",
    +      "attempted": "2020-07-16T04:30:14.066Z",
    +      "enabled": true,
    +      "validated": true,
    +      "attributes": {
    +        "emailAddress": "email@email.com"
    +      }
    +    }
    +  ]
    +}
    +
    +
  • +
+

Example Usage

+
adaptive.evaluateQR(context, transactionId)
+    .then((result) => {
+      res.send(result);
+    }).catch((error) => {
+      console.log(error);
+      res.status(404).send({error: error.message});
+    });
+
+

Generate an email OTP verification

+

Request an email OTP multi-factor verification after receiving a requires +status from a first factor completion +(evaluateQR, +evaluatePassword, or +evaluateFIDO). This will send an +OTP to the enroled email address of the user, and return a four-digit +correlation associated with the verification. This correlation will be prefixed +to the one-time password in the SMS to be sent.

+

generateEmailOTP(context, transactionId, enrollmentId)

+ + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterTypeDescription
contextObjectSee Context Object.
transactionIdstringThe transaction ID received in evaluatePolicy.
enrollmentIdstringThe identifier of the email OTP enrollment, received in a requires response after a first-factor attempt.
+

Example Usage

+
adaptive.generateEmailOTP(context, transactionId, enrollmentId)
+    .then((result) =>{
+      res.send(result);
+    }).catch((error) => {
+      console.log(error);
+      res.status(404).send({error: error.message});
+    });
+
+

Generate an SMS OTP verification

+

Request an SMS OTP multi-factor verification after receiving a requires status +from a first factor completion +(evaluateQR, +evaluatePassword, or +evaluateFIDO). This will send an +OTP to the phone number of the user, and return a four-digit correlation +associated with the verification. This correlation will be prefixed to the +one-time password in the SMS to be sent.

+

generateSMSOTP(context, transactionId, enrollmentId)

+ + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterTypeDescription
contextObjectSee Context Object.
transactionIdstringThe transaction ID received in assess.
enrollmentIdstringThe identifier of the SMS OTP enrollment, received in a requires response after a first-factor attempt.
+

Example Usage

+
adaptive.generateSMSOTP(context, transactionId, enrollmentId)
+    .then((result) =>{
+      res.send(result);
+    }).catch((error) => {
+      console.log(error);
+      res.status(404).send({error: error.message});
+    });
+
+

Evaluate a TOTP verification

+

Verify a TOTP second-factor verification after receiving a +requires status after a first-factor attempt +(evaluateQR, +evaluatePassword, or +evaluateFIDO). On successful verification, this will result in an allow response.

+

evaluateTOTP(context, transactionId, enrollmentId, otp)

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterTypeDescription
contextObjectSee Context Object.
transactionIdstringThe transaction ID received in assessPolicy.
enrollmentIdstringThe identifier of the TOTP enrollment, received in a requires response after a first-factor attempt.
otpstringThe TOTP to verify with.
+

Responses

+
    +
  • An allow response will contain a token to access the API with.
    {
    +  "status": "allow",
    +  "token": {
    +    "access_token": "zscmjBdvIjudOPLhpbmJi6nBRJg7cZ6WY0Udw1nC",
    +    "refresh_token": "wFTjurPxTvRD1cW09itgQM83XwCm1UKwsxhVFb1H7HJh8JkwZz",
    +    "scope": "openid",
    +    "grant_id": "a0b440b6-fefb-46ea-a603-e1040534cd28",
    +    "id_token": "eyJhbGciOiJSUzI1NiIsInR5cC...5j_rMn7H3ZpE4axt0WvsYu4jbA",
    +    "token_type": "Bearer",
    +    "expires_in": 7120
    +  }
    +}
    +
    +
  • +
+

Example Usage

+
adaptive.evaluateTOTP(context, transactionId, enrollmentId, otp)
+    .then((result) => {
+      res.send(result);
+    }).catch((error) => {
+      console.log(error);
+      res.status(404).send({error: error.message});
+    });
+
+

Evaluate an email OTP verification

+

Verify an email OTP second-factor verification after receiving an email OTP from generateEmailOTP. On successful verification, this will result in an allow response.

+

evaluateEmailOTP(context, transactionId, otp)

+ + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterTypeDescription
contextObjectSee Context Object.
transactionIdstringThe transaction ID received in assessPolicy.
otpstringThe email OTP to verify with. This OTP shouldn't include the correlation prefix (the four digits before the dash).
+

Responses

+
    +
  • An allow response will contain a token to access the API with.
    {
    +  "status": "allow",
    +  "token": {
    +    "access_token": "zscmjBdvIjudOPLhpbmJi6nBRJg7cZ6WY0Udw1nC",
    +    "refresh_token": "wFTjurPxTvRD1cW09itgQM83XwCm1UKwsxhVFb1H7HJh8JkwZz",
    +    "scope": "openid",
    +    "grant_id": "a0b440b6-fefb-46ea-a603-e1040534cd28",
    +    "id_token": "eyJhbGciOiJSUzI1NiIsInR5cC...5j_rMn7H3ZpE4axt0WvsYu4jbA",
    +    "token_type": "Bearer",
    +    "expires_in": 7120
    +  }
    +}
    +
    +
  • +
+

Example Usage

+
adaptive.evaluateEmailOTP(context, transactionId, otp)
+    .then((result) => {
+      res.send(result);
+    }).catch((error) => {
+      console.log(error);
+      res.status(404).send({error: error.message});
+    });
+
+

Evaluate an SMS OTP verification

+

Verify an SMS OTP second-factor verification after receiving an SMS OTP from generateSMSOTP. On successful verification, this will result in an allow response.

+

evaluateSMSOTP(transactionId, otp)

+ + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterTypeDescription
contextObjectSee Context Object.
transactionIdstringThe transaction ID received in assessPolicy.
otpstringThe SMS OTP to verify with. This OTP shouldn't include the correlation prefix (the four digits before the dash).
+

Responses

+
    +
  • An allow response will contain a token to access the API with.
    {
    +  "status": "allow",
    +  "token": {
    +    "access_token": "zscmjBdvIjudOPLhpbmJi6nBRJg7cZ6WY0Udw1nC",
    +    "refresh_token": "wFTjurPxTvRD1cW09itgQM83XwCm1UKwsxhVFb1H7HJh8JkwZz",
    +    "scope": "openid",
    +    "grant_id": "a0b440b6-fefb-46ea-a603-e1040534cd28",
    +    "id_token": "eyJhbGciOiJSUzI1NiIsInR5cC...5j_rMn7H3ZpE4axt0WvsYu4jbA",
    +    "token_type": "Bearer",
    +    "expires_in": 7120
    +  }
    +}
    +
    +
  • +
+

Example Usage

+
adaptive.evaluateSMSOTP(context, transactionId, otp)
+    .then((result) => {
+      res.send(result);
+    }).catch((error) => {
+      console.log(error);
+      res.status(404).send({error: error.message});
+    });
+
+

Generate a knowledge questions verification

+

Request a knowledge questions second-factor verification after receiving a +requires status from a first-factor completion +(evaluateQR, +evaluatePassword, or +evaluateFIDO). This will return a +set of the user's knowledge questions to answer.

+

generateQuestions(context, transactionId, enrollmentId)

+ + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterTypeDescription
contextObjectSee Context Object.
transactionIdstringThe transaction ID received in assessPolicy.
enrollmentIdstringThe identifier of the knowledge questions enrollment, received in a requires response after a first-factor attempt.
+

Response

+
    +
  • The response will contain a set of knowledge questions to be answered by the +user, then sent to +evaluateQuestions for +completion. Your initial transaction ID will also be returned.
    {
    +  "transactionId": "36a101c7-7426-4f45-ab3c-55f8dc075c6e",
    +  "questions": [
    +    {
    +      "questionKey": "firstHouseStreet",
    +      "question": "What was the street name of the first house you ever lived in?"
    +    },
    +    {
    +      "questionKey": "bestFriend",
    +      "question": "What is the first name of your best friend?"
    +    },
    +    {
    +      "questionKey": "mothersMaidenName",
    +      "question": "What is your mothers maiden name?"
    +    }
    +  ]
    +}
    +
    +
  • +
+

Example Usage

+
adaptive.generateQuestions(context, transactionId, enrollmentId)
+    .then((result) => {
+      res.send(result);
+    }).catch((error) => {
+      console.log(error);
+      res.status(404).send({error: error.message});
+    });
+
+

Evaluate a knowledge questions verification

+

Verify a knowledge questions second-factor verification after receiving and +answering a set of knowledge questions from +generateQuestions. +On successful verification, this will result in an allow response.

+

evaluateQuestions(context, transactionId, questions)

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterTypeDescription
contextObjectSee Context Object.
transactionIdstringThe transaction ID received in assessPolicy.
questionsObject[]The array of objects with a question key (received from generateQuestions) and corresponding answer to verify with.
questions[].questionKeystringThe identifier of the question received from generateQuestions.
questions[].answerstringThe answer to the question.
+

Responses

+
    +
  • An allow response will contain a token to access the API with.
    {
    +  "status": "allow",
    +  "token": {
    +    "access_token": "zscmjBdvIjudOPLhpbmJi6nBRJg7cZ6WY0Udw1nC",
    +    "refresh_token": "wFTjurPxTvRD1cW09itgQM83XwCm1UKwsxhVFb1H7HJh8JkwZz",
    +    "scope": "openid",
    +    "grant_id": "a0b440b6-fefb-46ea-a603-e1040534cd28",
    +    "id_token": "eyJhbGciOiJSUzI1NiIsInR5cC...5j_rMn7H3ZpE4axt0WvsYu4jbA",
    +    "token_type": "Bearer",
    +    "expires_in": 7120
    +  }
    +}
    +
    +
  • +
+

Example Usage

+
adaptive.evaluateQuestions(context, transactionId, questions)
+    .then((result) => {
+      res.send(result);
+    }).catch((error) => {
+      console.log(error);
+      res.status(404).send({error: error.message});
+    });
+
+

Generate a push notification verification

+

Request a push notification second-factor verification after receiving a +requires status from a first-factor completion +(evaluateQR, +evaluatePassword, or +evaluateFIDO). This will return a correlation code associated with the verification transaction.

+

generatePush(context, transactionId, enrollmentId, authenticatorId, message, pushNotificationTitle, pushNotificationMessage, additionalData)

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterTypeDescription
contextObjectSee Context Object.
transactionIdstringThe transaction ID received in assessPolicy.
enrollmentIdstringThe identifier of the signature enrollment to perform second-factor verification with.
authenticatorIdstringThe identifier of the authenticator belonging to the signature.
messagestringThe verification message to be displayed in-app.
pushNotificationTitlestringThe title to be displayed in the push notification banner.
pushNotificationMessagestringThe message to be displayed in the push notification banner.
additionalDataObject[]An array of objects containing "name" and "value" attributes to be displayed in-app.
+

Example Usage

+
adaptive.generatePush(context, transactionId, enrollmentId, authenticatorId, message, pushNotificationMessage, pushNotificationMessage, additionalData)
+    .then((result) => {
+      res.send(result);
+    }).catch((error) => {
+      console.log(error);
+      res.status(404).send({error: error.message});
+    });
+
+

Evaluate a push notification verification

+

Verify a push notification second-factor verification after receiving a push notification generatePush. On successful verification, this will result in an allow response.

+

evaluatePush(context, transactionId)

+ + + + + + + + + + + + + + + + + + + + +
ParameterTypeDescription
contextObjectSee Context Object.
transactionIdstringThe transaction ID received in assessPolicy.
+

Responses

+
    +
  • +

    A pending response indicates the transaction has not yet been completed.

    +
    {
    +  "status": "pending",
    +  "expiry": "2021-04-26T12:06:06.501Z",
    +  "pushState": "SUCCESS"
    +}
    +
    +
  • +
  • +

    A timeout response indicates the transaction has timed out.

    +
    {
    +  "status": "timeout",
    +  "expiry": "2021-04-26T12:06:06.501Z",
    +  "pushState": "SUCCESS"
    +}
    +
    +
  • +
  • +

    An error response indicates an error querying transaction.

    +
    {
    +  "status": "error"
    +}
    +
    +
  • +
  • +

    An allow response will contain a token to access the API with.

    +
    {
    +  "status": "allow",
    +  "token": {
    +    "access_token": "zscmjBdvIjudOPLhpbmJi6nBRJg7cZ6WY0Udw1nC",
    +    "refresh_token": "wFTjurPxTvRD1cW09itgQM83XwCm1UKwsxhVFb1H7HJh8JkwZz",
    +    "scope": "openid",
    +    "grant_id": "a0b440b6-fefb-46ea-a603-e1040534cd28",
    +    "id_token": "eyJhbGciOiJSUzI1NiIsInR5cC...5j_rMn7H3ZpE4axt0WvsYu4jbA",
    +    "token_type": "Bearer",
    +    "expires_in": 7120
    +  }
    +}
    +
    +
  • +
+

Example Usage

+
adaptive.evaluatePush(context, transactionId)
+    .then((result) => {
+      res.send(result);
+    }).catch((error) => {
+      console.log(error);
+      res.status(404).send({error: error.message});
+    });
+
+

Get Access Token for a transaction

+

Get the Access Token associated with the in-progress transaction.

+

getToken(transactionId)

+ + + + + + + + + + + + + + + +
ParameterTypeDescription
transactionIdstringThe transaction ID received in assessPolicy.
+

Response

+

A String is returned containing the Access Token associated with the transaction.

+

Example Usage

+
var txnAccessToken = adaptive.getToken(transactionId);
+
+

Logout

+

End the user's session.

+

logout(accessToken)

+ + + + + + + + + + + + + + + +
ParameterTypeDescription
accessTokenstringThe access token to revoke, received after a successful second-factor attempt.
+

Example Usage

+
adaptive.logout(accessToken)
+    .then(() =>{
+      res.send(); // Nothing to return
+    }).catch((error) => {
+      console.log(error);
+      res.status(404).send({error: error.message});
+    });
+
+

Refresh

+

Initiate an OAuth Refresh flow to obtain updated tokens.

+

refresh(context, refreshToken)

+ + + + + + + + + + + + + + + + + + + + +
ParameterTypeDescription
contextObjectSee Context Object.
refreshTokenstringThe refresh token to refresh the access token with.
+

Responses

+
    +
  • +

    An allow response will contain a token to access the API with, along with a new refresh token.

    +
    {
    +  "status": "allow",
    +  "token": {
    +    "access_token": "zscmjBdvIjudOPLhpbmJi6nBRJg7cZ6WY0Udw1nC",
    +    "refresh_token": "wFTjurPxTvRD1cW09itgQM83XwCm1UKwsxhVFb1H7HJh8JkwZz",
    +    "scope": "openid",
    +    "grant_id": "a0b440b6-fefb-46ea-a603-e1040534cd28",
    +    "id_token": "eyJhbGciOiJSUzI1NiIsInR5cC...5j_rMn7H3ZpE4axt0WvsYu4jbA",
    +    "token_type": "Bearer",
    +    "expires_in": 7120
    +  }
    +}
    +
    +
  • +
  • +

    A deny response is received when the policy denies access or policy evaluation fails. If error information is available, it will be returned in a details attribute.

    +
    {
    +  "status": "deny"
    +  "detail": {
    +     "error": "adaptive_more_info_required",
    +     "error_description": "CSIAQ0298E Adaptive access..."
    +  }
    +}
    +
    +
  • +
  • +

    A requires response will contain an array of allowed authentication +enrollments, indicating that further verification is required (i.e. second-factor +verification must be performed) to receive a token. The possible multi-factor +enrollments are "emailotp", "smsotp", "voiceotp", "totp", "questions", "push" and "fido". +You can use the +generateEmailOTP, +generateSMSOTP, +generateVoiceOTP, +evaluateTOTP, +generateQuestions, generatePush, +and generateFIDO functions respectively to +perform these 2FA verifications. You can use any of the returned enrollments to perform the second-factor authentication. Your initial transaction ID will also be +returned.

    +
    {
    +  "status": "requires",
    +  "transactionId": "36a101c7-7426-4f45-ab3c-55f8dc075c6e",
    +  "enrolledFactors": [
    +    {
    +      "id": "61e39f0a-836b-48fa-b4c9-cface6a3ef5a",
    +      "userId": "60300035KP",
    +      "type": "emailotp",
    +      "created": "2020-06-15T02:51:49.131Z",
    +      "updated": "2020-06-15T03:15:18.896Z",
    +      "attempted": "2020-07-16T04:30:14.066Z",
    +      "enabled": true,
    +      "validated": true,
    +      "attributes": {
    +        "emailAddress": "email@email.com"
    +      }
    +    }
    +  ]
    +}
    +
    +
  • +
+

Example Usage

+
adaptive.refresh(context, refreshToken)
+    .then((result) => {
+      res.send(result);
+    }).catch((error) => {
+      console.log(error);
+      res.status(404).send({error: error.message});
+    });
+
+

Introspect

+

Introspect a refresh or access token.

+

introspect(token, [tokenTypeHint])

+ + + + + + + + + + + + + + + + + + + + +
ParameterTypeDescription
tokenstringThe refresh or access token to introspect.
[tokenTypeHint]stringThe token type. This attribute is an optional hint about the token that is being introspected. Possible values are access_token and refresh_token.
+

Responses

+
    +
  • The response will contain an active property which indicates whether the introspected token is valid or invalid. Other properties will also be included when the active status is true.
    {
    +  "at_hash": "SivVIXwh1lUxzFHqPAMxJQ",
    +  "ext": {
    +    "tenantId": "..."
    +  },
    +  "sub": "6040004OML",
    +  "realmName": "cloudIdentityRealm",
    +  "entitlements" : [
    +  ...
    +  ]
    +  "amr": [
    +    "emailotp",
    +    "password"
    +  ],
    +  "uniqueSecurityName": "6040004OML",
    +  "iss": "https://.../oidc/endpoint/default",
    +  "active": true,
    +  "preferred_username": "name",
    +  "token_type": "Bearer",
    +  "client_id": "57bd5573-73cf-48e5-a42c-656bd2d2ad06",
    +  "aud": "57bd5573-73cf-48e5-a42c-656bd2d2ad06",
    +  "acr": "urn:ibm:security:policy:id:331844",
    +  "grant_type": "urn:ietf:params:oauth:grant-type:jwt-bearer",
    +  "restrictEntitlements": false,
    +  "scope": "openid",
    +  "grant_id": "393168ec-eb53-46b8-9957-64158719f075",
    +  "userType": "regular",
    +  "category": "application",
    +  "exp": 1598346175,
    +  "app_id": "2624486582876118578",
    +  "iat": 1598338975
    +}
    +
    +
  • +
+

Example Usage

+
adaptive.introspect(token, tokenTypeHint)
+    .then((result) => {
+      res.send(result);
+    }).catch((error) => {
+      console.log(error);
+      res.status(404).send({error: error.message});
+    });
+
+

Introspect Middleware

+

This function returns an Express middleware function, which has a signature of (req, res, next) => (). This middleware will call the introspect function under the hood, and perform additional checks based on the configuration object. If token introspection succeeds, the next middleware will be called in the stack. If an error occurs during token introspection, the error will be passed to the next() function. You may write your custom error handler middleware to catch the error, and handle it accordingly.

+

A successful introspection result is cached to save on expensive introspection calls for subsequent requests.

+

introspectMiddleware([config])

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterTypeDescription
[config]ObjectThe configuration settings used for the token introspection middleware.
[config.cacheMaxSize=0]numberThe maximum size of the cache, i.e. the maximum number of successful token introspection responses to cache. If the cache becomes full, the least-recently-used introspection result will be removed. A value of 0 means no maximum size, i.e. infinity. This value is ignored after first initialisation (i.e. after first call to function). Default value is 0.
[config.cacheTTL=0]numberThe time (in seconds) to cache a successful introspection result for. If a successful token introspection is done, the result will be cached for the period of time provided, to save expensive introspection calls on each subsequent request. A value of 0 will cache the introspect response for the lifetime of the token as provided in the exp property of the introspect response. Default value is 0.
[config.denyMFAChallenge=true]booleanA flag indicating whether an introspected token response with a scope of 'mfa_challenge' should be denied. If true, tokens with scope of 'mfa_challenge' will be rejected. If false, the scope of tokens will be disregarded.
+

Example Usage

+
// Add the middleware so it's called at every request to a protected endpoint.
+// Cache at most 50 successful introspection responses for 15 minutes each.
+app.use('/protected', adaptive.introspectMiddleware({cacheMaxSize: 50, cacheTTL: 900, denyMFAChallenge: true}));
+
+// Optionally define a custom error handler, so any errors thrown by previous middleware can be handled.
+app.use((err, req, res, next) => {
+  console.log(err.message);
+  res.sendStatus(403);
+});
+
+

Demo

+

A demo Node.js application using the Proxy SDK can be found in the +demo folder.

+

Documentation

+

Full HTML documentation for the Proxy SDK can be found in the docs +folder.

+
+
+ + + + + +
+ +
+ + + + + + + + + + \ No newline at end of file diff --git a/sdk/adaptive-proxy/docs/scripts/linenumber.js b/sdk/adaptive-proxy/docs/scripts/linenumber.js new file mode 100644 index 0000000..8071068 --- /dev/null +++ b/sdk/adaptive-proxy/docs/scripts/linenumber.js @@ -0,0 +1,23 @@ +'use strict'; + +(function () { + let lineId, lines, totalLines, anchorHash; + const source = document.getElementsByClassName('prettyprint source linenums'); + let i = 0; + let lineNumber = 0; + + if (source && source[0]) { + anchorHash = document.location.hash.substring(1); + lines = source[0].getElementsByTagName('li'); + totalLines = lines.length; + + for (; i < totalLines; i++) { + lineNumber++; + lineId = 'line' + lineNumber; + lines[i].id = lineId; + if (lineId === anchorHash) { + lines[i].className += ' selected'; + } + } + } +})(); diff --git a/sdk/adaptive-proxy/docs/scripts/pagelocation.js b/sdk/adaptive-proxy/docs/scripts/pagelocation.js new file mode 100644 index 0000000..22e2cc7 --- /dev/null +++ b/sdk/adaptive-proxy/docs/scripts/pagelocation.js @@ -0,0 +1,104 @@ +'use strict'; + +const $ = window.$; + +$(document).ready(() => { + // If an anchor hash is in the URL highlight the menu item + highlightActiveHash(); + // If a specific page section is in the URL highlight the menu item + highlightActiveSection(); + + // If a specific page section is in the URL scroll that section up to the top + const currentSectionNav = $('#' + getCurrentSectionName() + '-nav'); + + if (currentSectionNav.position()) { + $('nav').scrollTop(currentSectionNav.position().top); + } + + // function to scroll to anchor when clicking an anchor linl + $('a[href*="#"]:not([href="#"])').click(function () { + /* eslint-disable no-invalid-this */ + if ( + window.location.pathname.replace(/^\//, '') === + this.pathname.replace(/^\//, '') && + window.location.hostname === this.hostname + ) { + let target = $(this.hash); + target = target.length ? target : $('[name=' + this.hash.slice(1) + ']'); + if (target.length) { + $('html, body').animate( + { + scrollTop: target.offset().top, + }, + 1000 + ); + } + } + /* eslint-enable no-invalid-this */ + }); +}); + +// If a new anchor section is selected, change the hightlighted menu item +$(window).bind('hashchange', event => { + highlightActiveHash(event); +}); + +function highlightActiveHash(event) { + let oldUrl, oldSubSectionElement; + + // check for and remove old hash active state + if (event && event.originalEvent.oldURL) { + oldUrl = event.originalEvent.oldURL; + + if (oldUrl.indexOf('#') > -1) { + oldSubSectionElement = $( + '#' + + getCurrentSectionName() + + '-' + + oldUrl.substring(oldUrl.indexOf('#') + 1) + + '-nav' + ); + + if (oldSubSectionElement) { + oldSubSectionElement.removeClass('active'); + } + } + } + + if (getCurrentHashName()) { + $( + '#' + getCurrentSectionName() + '-' + getCurrentHashName() + '-nav' + ).addClass('active'); + } +} + +function highlightActiveSection() { + const pageId = getCurrentSectionName(); + + $('#' + pageId + '-nav').addClass('active'); +} + +function getCurrentSectionName() { + const path = window.location.pathname; + const pageUrl = path.split('/').pop(); + + let sectionName = pageUrl.substring(0, pageUrl.indexOf('.')); + + // remove the wodr module- if its in the url + sectionName = sectionName.replace('module-', ''); + + return sectionName; +} + +function getCurrentHashName() { + let pageSubSectionId; + const pageSubSectionHash = window.location.hash; + + if (pageSubSectionHash) { + pageSubSectionId = pageSubSectionHash.substring(1).replace('.', ''); + + return pageSubSectionId; + } + + return false; +} diff --git a/sdk/adaptive-proxy/docs/services_factors_emailOTPService.js.html b/sdk/adaptive-proxy/docs/services_factors_emailOTPService.js.html new file mode 100644 index 0000000..dcf4766 --- /dev/null +++ b/sdk/adaptive-proxy/docs/services_factors_emailOTPService.js.html @@ -0,0 +1,145 @@ + + + + + + + + + + + services/factors/emailOTPService.js - Documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + +
+ +

+ services/factors/emailOTPService.js +

+ + + + + +
+
+
// Copyright contributors to the IBM Security Verify Adaptive Proxy SDK
+// for JavaScript project
+
+const FactorService = require('../factors/factorService');
+
+
+/**
+ * A class for making email OTP related requests to OIDC.
+ * @extends FactorService
+ * @author Adam Dorogi-Kaposi <adam.dorogi-kaposi@ibm.com>
+ */
+class EmailOTPService extends FactorService {
+  /**
+   * Request an email OTP multi-factor verification for this enrollment.
+   * @param {string} enrollmentId The identifier of the email OTP enrollment.
+   * @return {Promise<Object>} The email OTP verification.
+   */
+  async generate(enrollmentId) {
+    const response = await this.post(
+        `/v2.0/factors/emailotp/${enrollmentId}/verifications`);
+    return response.data;
+  }
+
+  /**
+   * Attempt to complete an email OTP multi-factor verification.
+   * @param {string} verificationId The identifier of the email OTP verification
+   * received in {@link EmailOTPService#generate}.
+   * @param {string} enrollmentId The identifier of the email OTP enrollment.
+   * @param {string} otp The OTP to attempt verification with.
+   * @return {Promise<string>} The HTTP response body of the request.
+   */
+  async verify(verificationId, enrollmentId, otp) {
+    const response = await this.post(`/v2.0/factors/emailotp/` +
+      `${enrollmentId}/verifications/${verificationId}`, {otp},
+    {returnJwt: true});
+    return response.data;
+  }
+}
+
+module.exports = EmailOTPService;
+
+
+
+ + + + +
+ +
+ + + + + + + + + + diff --git a/sdk/adaptive-proxy/docs/services_factors_factorService.js.html b/sdk/adaptive-proxy/docs/services_factors_factorService.js.html new file mode 100644 index 0000000..f2dd3dc --- /dev/null +++ b/sdk/adaptive-proxy/docs/services_factors_factorService.js.html @@ -0,0 +1,137 @@ + + + + + + + + + + + services/factors/factorService.js - Documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + +
+ +

+ services/factors/factorService.js +

+ + + + + +
+
+
// Copyright contributors to the IBM Security Verify Adaptive Proxy SDK
+// for JavaScript project
+
+const Service = require('../service');
+
+
+/**
+ * A class for making Factors requests.
+ * @extends Service
+ * @author Adam Dorogi-Kaposi <adam.dorogi-kaposi@ibm.com>
+ */
+class FactorService extends Service {
+  /**
+   * Get an email OTP factor enrollment.
+   * @param {string} userId The identifier of the user for which to retrieve
+   * enrollments.
+   * @return {Promise<Array>} The array of enrollments for the given user.
+   */
+  async getEnrollments(userId=undefined) {
+    let response;
+    if (userId) {
+      response = await this.get('/v2.0/factors',
+          {search: `userId="${userId}"&enabled=true`});
+    } else {
+      response = await this.get('/v2.0/factors',
+          {search: `enabled=true`});
+    }
+    return response.data;
+  }
+}
+
+module.exports = FactorService;
+
+
+
+ + + + +
+ +
+ + + + + + + + + + diff --git a/sdk/adaptive-proxy/docs/services_factors_fidoService.js.html b/sdk/adaptive-proxy/docs/services_factors_fidoService.js.html new file mode 100644 index 0000000..c971236 --- /dev/null +++ b/sdk/adaptive-proxy/docs/services_factors_fidoService.js.html @@ -0,0 +1,174 @@ + + + + + + + + + + + services/factors/fidoService.js - Documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + +
+ +

+ services/factors/fidoService.js +

+ + + + + +
+
+
// Copyright contributors to the IBM Security Verify Adaptive Proxy SDK
+// for JavaScript project
+
+
+const FactorService = require('../factors/factorService');
+
+
+/**
+ * A class for making FIDO related requests to OIDC. These include initiating
+ * and completing a FIDO verification.
+ * @extends FactorService
+ * @author Adam Dorogi-Kaposi <adam.dorogi-kaposi@ibm.com>
+ */
+class FIDOService extends FactorService {
+  /**
+   * Initiate a FIDO verification.
+   * @param {string} relyingPartyId The identifier of a relying party resolved
+   * in {@link FIDOService#resolveRelyingParty}.
+   * @param {string} userId The identifier of the OIDC user for which to
+   * initiate FIDO verification.
+   * @return {Promise<Object>} The assertion options, containing FIDO
+   * credentials.
+   */
+  async generate(relyingPartyId, userId) {
+    const response = await this.post(`/v2.0/factors/fido2/relyingparties/` +
+        `${relyingPartyId}/assertion/options`, {userVerification: 'preferred',
+      userId});
+    return response.data;
+  }
+
+  /**
+   * Complete a FIDO verification.
+   * @param {string} relyingPartyId The identifier of a relying party resolved
+   * in {@link FIDOService#resolveRelyingParty}.
+   * @param {string} credentialId The identifier of a FIDO credential received
+   * in the assertion options in {@link FIDOService#generate}.
+   * @param {string} clientDataJSON The assertion options received in
+   * {@link FIDOService#generate}, in Base64 URL encoded format.
+   * @param {string} authenticatorData The information about the authenticator
+   * used for the FIDO verification, verified by the signature.
+   * @param {string} [userHandle] The identifier of the user who owns the
+   * authenticator used for the FIDO verification.
+   * @param {string} signature The challenge received in
+   * {@link FIDOService#generate}, signed by the authenticator used
+   * for the FIDO verification, in Base64 URL encoded format.
+   * @return {Promise<string>} The JWT to be validated by OIDC in
+   * {@link PolicyService#validate}.
+   */
+  async evaluate(relyingPartyId, credentialId, clientDataJSON,
+      authenticatorData, userHandle, signature) {
+    const response = await this.post(
+        `/v2.0/factors/fido2/relyingparties/${relyingPartyId}/assertion/result`,
+        {
+          type: 'public-key',
+          rawId: credentialId,
+          response: {
+            clientDataJSON,
+            authenticatorData,
+            userHandle,
+            signature,
+          },
+          id: credentialId,
+          getClientExtensionResults: {},
+        }, {returnJwt: true});
+    return response.data;
+  }
+}
+
+module.exports = FIDOService;
+
+
+
+ + + + +
+ +
+ + + + + + + + + + diff --git a/sdk/adaptive-proxy/docs/services_factors_passwordService.js.html b/sdk/adaptive-proxy/docs/services_factors_passwordService.js.html new file mode 100644 index 0000000..5769e62 --- /dev/null +++ b/sdk/adaptive-proxy/docs/services_factors_passwordService.js.html @@ -0,0 +1,154 @@ + + + + + + + + + + + services/factors/passwordService.js - Documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + +
+ +

+ services/factors/passwordService.js +

+ + + + + +
+
+
// Copyright contributors to the IBM Security Verify Adaptive Proxy SDK
+// for JavaScript project
+
+
+const FactorService = require('../factors/factorService');
+
+
+/**
+ * A class for making password related requests to OIDC.
+ * @extends FactorService
+ * @author Adam Dorogi-Kaposi <adam.dorogi-kaposi@ibm.com>
+ */
+class PasswordService extends FactorService {
+  /**
+   * Lookup identity sources by sourceName (or all password-capable
+   * sources if sourceName not defined)
+   * @param {string} sourceName The name of the Identity Source.
+   * @return {Promise<Object>} The array of sources returned.
+   */
+  async lookupIdentitySources(sourceName) {
+    let response;
+    if (sourceName) {
+      response = await this.get(
+          `/v1.0/authnmethods/password?search=name = "${sourceName}"`);
+    } else {
+      response = await this.get('/v1.0/authnmethods/password');
+    }
+    return response.data.password;
+  }
+
+  /**
+   * Attempt password authentication with an identity source.
+   * @param {string} identitySourceId The identifier of an identity source
+   * resolved in {@link PasswordService#resolveIdentitySource}.
+   * @param {string} username The username to authenticate as.
+   * @param {string} password The password to authenticate with.
+   * @return {Promise<Object>} The HTTP response body of the authentication.
+   * This response body also includes the JWT to be validated by OIDC in
+   * {@link PolicyService#validate}.
+   */
+  async authenticate(identitySourceId, username, password) {
+    const response = await this.post(
+        `/v1.0/authnmethods/password/${identitySourceId}`,
+        {username, password}, {returnJwt: true});
+    return response.data;
+  }
+}
+
+module.exports = PasswordService;
+
+
+
+ + + + +
+ +
+ + + + + + + + + + diff --git a/sdk/adaptive-proxy/docs/services_factors_pushService.js.html b/sdk/adaptive-proxy/docs/services_factors_pushService.js.html new file mode 100644 index 0000000..d54be3b --- /dev/null +++ b/sdk/adaptive-proxy/docs/services_factors_pushService.js.html @@ -0,0 +1,185 @@ + + + + + + + + + + + services/factors/pushService.js - Documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + +
+ +

+ services/factors/pushService.js +

+ + + + + +
+
+
// Copyright contributors to the IBM Security Verify Adaptive Proxy SDK
+// for JavaScript project
+
+
+const FactorService = require('../factors/factorService');
+
+
+/**
+ * A class for making push notification related requests to OIDC. These include
+ * initiating and attempting a push notification verification.
+ * @extends FactorService
+ * @author Adam Dorogi-Kaposi <adam.dorogi-kaposi@ibm.com>
+ */
+class PushService extends FactorService {
+  /**
+   * Request a push notification verification.
+   * @param {string} signatureId The identifier of the signature enrollment to
+   * perform second-factor verification with.
+   * @param {string} authenticatorId The identifier of the authenticator
+   * belonging to the signature.
+   * @param {string} message The verification message to be displayed in-app.
+   * @param {string} originIpAddress The IP address from which the
+   * authentication is attempted.
+   * @param {string} originUserAgent The user agent from which the
+   * authentication is attempted.
+   * @param {string} pushNotificationTitle The title to be displayed
+   * in the push notification notification banner.
+   * @param {string} pushNotificationMessage The message to be displayed
+   * in the push notification banner.
+   * @param {Object[]} additionalData An array of objects containing
+   * <code>"name"</code> and <code>"value"</code> attributes to be displayed
+   * in-app.
+   * @return {Promise<string>} The HTTP response body of the request.
+   */
+  async generate(signatureId, authenticatorId, message, originIpAddress,
+      originUserAgent, pushNotificationTitle, pushNotificationMessage,
+      additionalData) {
+    const response = await this.post(`/v1.0/authenticators/` +
+      `${authenticatorId}/verifications`,
+    {
+      transactionData: {
+        message,
+        originIpAddress,
+        originUserAgent,
+        additionalData,
+      },
+      pushNotification: {
+        title: pushNotificationTitle,
+        message: pushNotificationMessage,
+        send: true,
+      },
+      authenticationMethods: [
+        {
+          id: signatureId,
+          methodType: 'signature',
+        },
+      ],
+      logic: 'OR',
+      expiresIn: 120,
+    });
+    return response.data;
+  }
+
+  /**
+   * Check status of a push notification verification.
+   * @param {string} authenticatorId The identifier of the authenticator
+   * belonging to the signature.
+   * @param {string} verificationId The identifier of the verification initiated
+   * in {@link PushService#generate}.
+   * @return {Promise<string>} The HTTP response body of the request.
+   */
+  async evaluate(authenticatorId, verificationId) {
+    const response = await this.get(`/v1.0/authenticators/` +
+        `${authenticatorId}/verifications/${verificationId}`,
+    {returnJwt: true});
+    return response.data;
+  }
+}
+
+module.exports = PushService;
+
+
+
+ + + + +
+ +
+ + + + + + + + + + diff --git a/sdk/adaptive-proxy/docs/services_factors_qrService.js.html b/sdk/adaptive-proxy/docs/services_factors_qrService.js.html new file mode 100644 index 0000000..97bb88b --- /dev/null +++ b/sdk/adaptive-proxy/docs/services_factors_qrService.js.html @@ -0,0 +1,147 @@ + + + + + + + + + + + services/factors/qrService.js - Documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + +
+ +

+ services/factors/qrService.js +

+ + + + + +
+
+
// Copyright contributors to the IBM Security Verify Adaptive Proxy SDK
+// for JavaScript project
+
+
+const FactorService = require('../factors/factorService');
+
+
+/**
+ * A class for making QR login related requests to OIDC.
+ * @extends FactorService
+ * @author Adam Dorogi-Kaposi <adam.dorogi-kaposi@ibm.com>
+ */
+class QRService extends FactorService {
+  /**
+   * Initiate a QR login verification.
+   * @param {string} profileId The identifier of an IBM Verify registration
+   * profile.
+   * @return {Promise<Object>} The QR code login verification.
+   */
+  async generate(profileId) {
+    const response = await this.get('/v2.0/factors/qr/authenticate',
+        {profileId});
+    return response.data;
+  }
+
+  /**
+   * Complete a QR login verification.
+   * @param {string} verificationId The identifier of the QR login verification
+   * received in {@link QRService#generate}.
+   * @param {string} dsi The DSI of the QR login verification received in
+   * {@link QRService#generate}.
+   * @return {Promise<string>} The HTTP response body of the request.
+   */
+  async verify(verificationId, dsi) {
+    const response = await this.get(
+        `/v2.0/factors/qr/authenticate/${verificationId}`,
+        {dsi: dsi, returnJwt: true});
+    return response.data;
+  }
+}
+
+module.exports = QRService;
+
+
+
+ + + + +
+ +
+ + + + + + + + + + diff --git a/sdk/adaptive-proxy/docs/services_factors_questionsService.js.html b/sdk/adaptive-proxy/docs/services_factors_questionsService.js.html new file mode 100644 index 0000000..5fe07a9 --- /dev/null +++ b/sdk/adaptive-proxy/docs/services_factors_questionsService.js.html @@ -0,0 +1,150 @@ + + + + + + + + + + + services/factors/questionsService.js - Documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + +
+ +

+ services/factors/questionsService.js +

+ + + + + +
+
+
// Copyright contributors to the IBM Security Verify Adaptive Proxy SDK
+// for JavaScript project
+
+
+const FactorService = require('../factors/factorService');
+
+
+/**
+ * A class for making knowledge questions related requests to OIDC.
+ * @extends FactorService
+ * @author Adam Dorogi-Kaposi <adam.dorogi-kaposi@ibm.com>
+ */
+class QuestionsService extends FactorService {
+  /**
+   * Request a knowledge questions multi-factor verification for this
+   * enrollment.
+   * @param {string} enrollmentId The identifier of the knowledge questions
+   * enrollment.
+   * @return {Promise<Object>} The knowledge questions verification.
+   */
+  async generate(enrollmentId) {
+    const response = await this.post(
+        `/v2.0/factors/questions/${enrollmentId}/verifications`);
+    return response.data;
+  }
+
+  /**
+   * Attempt to complete a knowledge questions multi-factor verification.
+   * @param {string} verificationId The identifier of the knowledge questions
+   * verification received in {@link QuestionsService#generate}.
+   * @param {string} enrollmentId The identifier of the knowledge questions
+   * enrollment.
+   * @param {Object[]} questions The array of question keys and corresponding
+   * answers to attempt verification with.
+   * @return {Promise<string>} The HTTP response body of the request.
+   */
+  async verify(verificationId, enrollmentId, questions) {
+    const response = await this.post(`/v2.0/factors/questions/` +
+        `${enrollmentId}/verifications/${verificationId}`, {questions},
+    {returnJwt: true});
+    return response.data;
+  }
+}
+
+module.exports = QuestionsService;
+
+
+
+ + + + +
+ +
+ + + + + + + + + + diff --git a/sdk/adaptive-proxy/docs/services_factors_smsOTPService.js.html b/sdk/adaptive-proxy/docs/services_factors_smsOTPService.js.html new file mode 100644 index 0000000..2742d01 --- /dev/null +++ b/sdk/adaptive-proxy/docs/services_factors_smsOTPService.js.html @@ -0,0 +1,146 @@ + + + + + + + + + + + services/factors/smsOTPService.js - Documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + +
+ +

+ services/factors/smsOTPService.js +

+ + + + + +
+
+
// Copyright contributors to the IBM Security Verify Adaptive Proxy SDK
+// for JavaScript project
+
+
+const FactorService = require('../factors/factorService');
+
+
+/**
+ * A class for making SMS OTP related requests to OIDC.
+ * @extends FactorService
+ * @author Adam Dorogi-Kaposi <adam.dorogi-kaposi@ibm.com>
+ */
+class SMSOTPService extends FactorService {
+  /**
+   * Request an SMS OTP multi-factor verification for this enrollment.
+   * @param {string} enrollmentId The identifier of the SMS OTP enrollment.
+   * @return {Promise<Object>} The SMS OTP verification.
+   */
+  async generate(enrollmentId) {
+    const response = await this.post(
+        `/v2.0/factors/smsotp/${enrollmentId}/verifications`);
+    return response.data;
+  }
+
+  /**
+   * Attempt to complete an SMS OTP multi-factor verification.
+   * @param {string} verificationId The identifier of the SMS OTP verification
+   * received in {@link SMSOTPService#generate}.
+   * @param {string} enrollmentId The identifier of the SMS OTP enrollment.
+   * @param {string} otp The OTP to attempt verification with.
+   * @return {Promise<string>} The HTTP response body of the request.
+   */
+  async verify(verificationId, enrollmentId, otp) {
+    const response = await this.post(`/v2.0/factors/smsotp/` +
+      `${enrollmentId}/verifications/${verificationId}`, {otp},
+    {returnJwt: true});
+    return response.data;
+  }
+}
+
+module.exports = SMSOTPService;
+
+
+
+ + + + +
+ +
+ + + + + + + + + + diff --git a/sdk/adaptive-proxy/docs/services_factors_totpService.js.html b/sdk/adaptive-proxy/docs/services_factors_totpService.js.html new file mode 100644 index 0000000..51bbea0 --- /dev/null +++ b/sdk/adaptive-proxy/docs/services_factors_totpService.js.html @@ -0,0 +1,132 @@ + + + + + + + + + + + services/factors/totpService.js - Documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + +
+ +

+ services/factors/totpService.js +

+ + + + + +
+
+
// Copyright contributors to the IBM Security Verify Adaptive Proxy SDK
+// for JavaScript project
+
+
+const FactorService = require('../factors/factorService');
+
+
+/**
+ * A class for making TOTP related requests to OIDC.
+ * @extends FactorService
+ * @author Adam Dorogi-Kaposi <adam.dorogi-kaposi@ibm.com>
+ */
+class TOTPService extends FactorService {
+  /**
+   * Attempt to complete a TOTP multi-factor verification.
+   * @param {string} enrollmentId The identifier of the TOTP enrollment.
+   * @param {string} otp The OTP to attempt verification with.
+   * @return {Promise<string>} The HTTP response body of the request.
+   */
+  async verify(enrollmentId, otp) {
+    const response = await this.post(
+        `/v2.0/factors/totp/${enrollmentId}`, {otp}, {returnJwt: true});
+    return response.data;
+  }
+}
+
+module.exports = TOTPService;
+
+
+
+ + + + +
+ +
+ + + + + + + + + + diff --git a/sdk/adaptive-proxy/docs/services_factors_voiceOTPService.js.html b/sdk/adaptive-proxy/docs/services_factors_voiceOTPService.js.html new file mode 100644 index 0000000..7fe16b8 --- /dev/null +++ b/sdk/adaptive-proxy/docs/services_factors_voiceOTPService.js.html @@ -0,0 +1,146 @@ + + + + + + + + + + + services/factors/voiceOTPService.js - Documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + +
+ +

+ services/factors/voiceOTPService.js +

+ + + + + +
+
+
// Copyright contributors to the IBM Security Verify Adaptive Proxy SDK
+// for JavaScript project
+
+
+const FactorService = require('../factors/factorService');
+
+
+/**
+ * A class for making Voice OTP related requests to OIDC.
+ * @extends FactorService
+ * @author Adam Dorogi-Kaposi <adam.dorogi-kaposi@ibm.com>
+ */
+class VoiceOTPService extends FactorService {
+  /**
+   * Request an Voice OTP multi-factor verification for this enrollment.
+   * @param {string} enrollmentId The identifier of the Voice OTP enrollment.
+   * @return {Promise<Object>} The Voice OTP verification.
+   */
+  async generate(enrollmentId) {
+    const response = await this.post(
+        `/v2.0/factors/voiceotp/${enrollmentId}/verifications`);
+    return response.data;
+  }
+
+  /**
+   * Attempt to complete an Voice OTP multi-factor verification.
+   * @param {string} verificationId The identifier of the Voice OTP verification
+   * received in {@link VoiceOTPService#generate}.
+   * @param {string} enrollmentId The identifier of the Voice OTP enrollment.
+   * @param {string} otp The OTP to attempt verification with.
+   * @return {Promise<string>} The HTTP response body of the request.
+   */
+  async verify(verificationId, enrollmentId, otp) {
+    const response = await this.post(`/v2.0/factors/voiceotp/` +
+      `${enrollmentId}/verifications/${verificationId}`, {otp},
+    {returnJwt: true});
+    return response.data;
+  }
+}
+
+module.exports = VoiceOTPService;
+
+
+
+ + + + +
+ +
+ + + + + + + + + + diff --git a/sdk/adaptive-proxy/docs/services_oidc_policyService.js.html b/sdk/adaptive-proxy/docs/services_oidc_policyService.js.html new file mode 100644 index 0000000..acdbf95 --- /dev/null +++ b/sdk/adaptive-proxy/docs/services_oidc_policyService.js.html @@ -0,0 +1,178 @@ + + + + + + + + + + + services/oidc/policyService.js - Documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + +
+ +

+ services/oidc/policyService.js +

+ + + + + +
+
+
// Copyright contributors to the IBM Security Verify Adaptive Proxy SDK
+// for JavaScript project
+
+
+const Service = require('../service');
+
+
+/**
+ * A class for making policy related requests to OIDC. These include the initial
+ * grant request, as well as validating received JWT assertions.
+ * @extends Service
+ * @author Adam Dorogi-Kaposi <adam.dorogi-kaposi@ibm.com>
+ */
+class PolicyService extends Service {
+  /**
+   * Create a new {@link PolicyService} object.
+   * @param {Object} auth The credentials to authenticate to OIDC.
+   * @param {string} baseURL The base URL for the OIDC API.
+   * @param {Object} context The context to send for assessment.
+   * @param {string} context.sessionId The session ID generated by the
+   * user-agent, using an Adaptive client SDK.
+   * @param {string} context.userAgent The user-agent, typically obtained form
+   * the User-Agent HTTP header.
+   * @param {string} context.ipAddress The IP address of the user-agent.
+   */
+  constructor(auth, baseURL, context) {
+    super(auth, baseURL, context, 'x-www-form-urlencoded');
+  }
+
+  /**
+   * Evaluate the policy attached to the client application.
+   *
+   * Request an access token from OIDC with the <code>policyauth</code>
+   * grant-type. OIDC will in turn evaluate the policy attached to the client
+   * application, and will respond depending on the outocme of the evaluation.
+   * The response from OIDC will be one of two statuses: <code>deny</code>, or
+   * <code>requires</code>. A deny response is indicated by a 401 status code.
+   * A 200 HTTP status code indicates a <code>requires</code> response.
+   * @return {Promise<Object>} The HTTP response body for a
+   * <code>requires</code> response from OIDC.
+   * @throws {Error} A <code>deny</code> response is received.
+   */
+  async assess() {
+    const response = await this.post('/v1.0/endpoint/default/token',
+        {grant_type: 'policyauth', scope: 'openid',
+          context: this._context});
+    return response.data;
+  }
+
+  /**
+   * Validate a JWT assertion received from a first- or second-factor
+   * verification on OIDC.
+   *
+   * The response from OIDC will be one of three statuses: <code>allow</code>,
+   * <code>deny</code>, or <code>requires</code>. A deny response is indicated
+   * by a 401 status code. A 200 HTTP status code indicates an
+   * <code>allow</code> or <code>requires</code> response.
+   * @param {string} jwt The JWT assertion to validate.
+   * @return {Promise<Object>} The HTTP response body for an <code>allow</code>
+   * or <code>requires</code> response from OIDC.
+   * @throws {Error} A <code>deny</code> response is received.
+   */
+  async validate(jwt) {
+    const response = await this.post('/v1.0/endpoint/default/token',
+        {grant_type: 'urn:ietf:params:oauth:grant-type:jwt-bearer',
+          scope: 'openid',
+          context: this._context,
+          assertion: jwt});
+    return response.data;
+  }
+}
+
+module.exports = PolicyService;
+
+
+
+ + + + +
+ +
+ + + + + + + + + + diff --git a/sdk/adaptive-proxy/docs/services_oidc_tokenService.js.html b/sdk/adaptive-proxy/docs/services_oidc_tokenService.js.html new file mode 100644 index 0000000..0d0f9b1 --- /dev/null +++ b/sdk/adaptive-proxy/docs/services_oidc_tokenService.js.html @@ -0,0 +1,176 @@ + + + + + + + + + + + services/oidc/tokenService.js - Documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + +
+ +

+ services/oidc/tokenService.js +

+ + + + + +
+
+
// Copyright contributors to the IBM Security Verify Adaptive Proxy SDK
+// for JavaScript project
+
+
+const Service = require('../service');
+
+
+/**
+ * A class for making token related requests to OIDC.
+ * @extends Service
+ * @author Adam Dorogi-Kaposi <adam.dorogi-kaposi@ibm.com>
+ */
+class TokenService extends Service {
+  /**
+   * Create a new {@link TokenService} object.
+   * @param {Object} auth The credentials to authenticate to OIDC.
+   * @param {string} baseURL The base URL for the OIDC API.
+   * @param {Object} context The context to send for assessment.
+   * @param {string} context.sessionId The session ID generated by the
+   * user-agent, using an Adaptive client SDK.
+   * @param {string} context.userAgent The user-agent, typically obtained form
+   * the User-Agent HTTP header.
+   * @param {string} context.ipAddress The IP address of the user-agent.
+   */
+  constructor(auth, baseURL, context) {
+    super(auth, baseURL, context, 'x-www-form-urlencoded');
+  }
+
+  /**
+   * Revoke an access token.
+   * @param {string} accessToken The access token to revoke.
+   */
+  async revokeAccessToken(accessToken) {
+    await this.post('/v1.0/endpoint/default/revoke',
+        {token: accessToken});
+  }
+
+  /**
+   * Refresh an access token.
+   * @param {string} refreshToken The refresh token to refresh with.
+   * @return {Promise<Object>} The HTTP response body for the refresh token
+   * request, containing the new access and refresh tokens.
+   */
+  async refreshAccessToken(refreshToken) {
+    const response = await this.post('/v1.0/endpoint/default/token',
+        {grant_type: 'refresh_token', scope: 'openid',
+          refresh_token: refreshToken,
+          context: this._context});
+    return response.data;
+  }
+
+  /**
+   * Introspect an access or refresh token.
+   * @param {string} token The access or refresh token to introspect.
+   * @param {string} [tokenTypeHint] The token type. This attribute is an
+   * optional hint about the token that is being introspected. Possible values
+   * are <code>access_token</code> and <code>refresh_token</code>.
+   * @return {Promise<Object>} The HTTP response body for the token introspect
+   * request, which is an object containing an <code>"active"</code> property
+   * indicating whether the introspected token is valid or invalid. Other
+   * properties are also included in the introspection result when the
+   * <code>"active"</code> status is <code>true</code>.
+   */
+  async introspectToken(token, tokenTypeHint) {
+    const response = await this.post('/v1.0/endpoint/default/introspect',
+        {token, token_type_hint: tokenTypeHint});
+    return response.data;
+  }
+}
+
+module.exports = TokenService;
+
+
+
+ + + + +
+ +
+ + + + + + + + + + diff --git a/sdk/adaptive-proxy/docs/services_service.js.html b/sdk/adaptive-proxy/docs/services_service.js.html new file mode 100644 index 0000000..825e523 --- /dev/null +++ b/sdk/adaptive-proxy/docs/services_service.js.html @@ -0,0 +1,242 @@ + + + + + + + + + + + services/service.js - Documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + +
+ +

+ services/service.js +

+ + + + + +
+
+
// Copyright contributors to the IBM Security Verify Adaptive Proxy SDK
+// for JavaScript project
+
+
+const base64Utils = require('../utils/base64Utils');
+const securityUtils = require('../utils/securityUtils');
+
+const axios = require('axios');
+const querystring = require('querystring');
+
+
+/**
+ * A class for making HTTP requests to OIDC.
+ * @author Adam Dorogi-Kaposi <adam.dorogi-kaposi@ibm.com>
+ */
+class Service {
+  /**
+   * Create a new {@link Service} object.
+   * @param {Object} auth The credentials to authenticate to Factors or OIDC.
+   * Either an <code>accessToken</code>, or a <code>clientId</code> and
+   * <code>clientSecret</code> may be used for authentication. If an
+   * <code>accessToken</code>, set this object's
+   * <code>_authorizationHeader</code> property to <code>Authorization: Bearer
+   * ${accessToken}</code>. If a <code>clientId</code> and
+   * <code>clientSecret</code>, Base64 encode the <code>clientId</code> and
+   * <code>clientSecret</code>, and set this object's
+   * <code>_authorizationHeader</code> property to <code>Authorization: Basic
+   * ${Base64(clientId:clientSecret)}</code>.
+   * @param {string} [auth.accessToken] The access token to authenticate to
+   * Factors or OIDC.
+   * @param {string} [auth.clientId] The identifier of the client to
+   * authenticate to Factors or OIDC.
+   * @param {string} [auth.clientSecret] The client secret to authenticate to
+   * Factors or OIDC.
+   * @param {string} baseURL The base URL for the API, normally the tenant URL.
+   * @param {Object} context The context to send for assessment.
+   * @param {string} context.sessionId The session ID generated by the
+   * user-agent, using an Adaptive client SDK.
+   * @param {string} context.userAgent The user-agent, typically obtained form
+   * the User-Agent HTTP header.
+   * @param {string} context.ipAddress The IP address of the user-agent.
+   * @param {string} [contentTypeHeader='json'] The type of content to send in
+   * the requests. Sets the <code>Content-Type</code> header of the requests
+   * appropriately.
+   * @param {string} [acceptHeader='json'] The type of content to receive in the
+   * response. Sets the <code>Accept</code> header of the requests
+   * appropriately.
+   */
+  constructor(auth, baseURL, context, contentTypeHeader='json',
+      acceptHeader='json') {
+    this._baseURL = baseURL;
+    this._context = base64Utils.base64UrlEncodeObject(context);
+    this._contentTypeHeader = contentTypeHeader;
+    this._acceptHeader = acceptHeader;
+
+    if (auth.accessToken) {
+      this._authorizationHeader = `Bearer ${auth.accessToken}`;
+    } else if (auth.clientId && auth.clientSecret) {
+      const base64EncodedCredentials = base64Utils
+          .base64UrlEncodeString(`${auth.clientId}:${auth.clientSecret}`);
+      this._authorizationHeader = `Basic ${base64EncodedCredentials}`;
+    }
+
+    console.log(`[${Service.name}:constructor(auth, baseURL, context, ` +
+      `contentTypeHeader='json', acceptHeader='json')]`,
+    'baseURL:', this._baseURL);
+    console.log(`[${Service.name}:constructor(auth, baseURL, context, ` +
+      `contentTypeHeader='json', acceptHeader='json')]`,
+    'context:', this._context);
+    console.log(`[${Service.name}:constructor(auth, baseURL, context, ` +
+      `contentTypeHeader='json', acceptHeader='json')]`,
+    'contentTypeHeader:', this._contentTypeHeader);
+    console.log(`[${Service.name}:constructor(auth, baseURL, context, ` +
+      `contentTypeHeader='json', acceptHeader='json')]`,
+    'acceptHeader:', this._acceptHeader);
+    console.log(`[${Service.name}:constructor(auth, baseURL, context, ` +
+      `contentTypeHeader='json', acceptHeader='json')]`,
+    'authorizationHeader:', '****');
+  }
+
+  /**
+   * Send a HTTP GET request.
+   * @param {string} path The path on the base URL to send the request to.
+   * @param {Object} params The URL parameters to be sent with the request.
+   * @return {Promise<Object>} The response to the HTTP request.
+   */
+  async get(path, params={}) {
+    const headers = {
+      'Accept': `application/${this._acceptHeader}`,
+      'Authorization': this._authorizationHeader,
+    };
+
+    console.log(`[${Service.name}:get(path, params={})]`,
+        'path:', path);
+    console.log(`[${Service.name}:get(path, params={})]`,
+        'params:', securityUtils.maskObject(params));
+    console.log(`[${Service.name}:get(path, params={})]`,
+        'headers:', securityUtils.maskObject(headers));
+
+    return await axios.get(this._baseURL + path, {params, headers});
+  }
+
+  /**
+   * Send a HTTP POST request.
+   * @param {string} path The path on the base URL to send the request to.
+   * @param {Object} data The POST body to send with the request.
+   * @param {Object} params The URL parameters to send with the request.
+   * @return {Promise<Object>} The response to the HTTP request.
+   */
+  async post(path, data={}, params={}) {
+    const headers = {
+      'Accept': `application/${this._acceptHeader}`,
+      'Content-Type': `application/${this._contentTypeHeader}`,
+      'Authorization': this._authorizationHeader,
+    };
+
+    let dataMasked = securityUtils.maskObject(data);
+
+    if (this._contentTypeHeader === 'x-www-form-urlencoded') {
+      data = querystring.stringify(data);
+      dataMasked = querystring.stringify(dataMasked);
+    }
+
+    console.log(`[${Service.name}:post(path, data={}, params={})]`,
+        'path:', path);
+    console.log(`[${Service.name}:post(path, data={}, params={})]`,
+        'data:', dataMasked);
+    console.log(`[${Service.name}:post(path, data={}, params={})]`,
+        'params:', securityUtils.maskObject(params));
+    console.log(`[${Service.name}:post(path, data={}, params={})]`,
+        'headers:', securityUtils.maskObject(headers));
+
+    return await axios.post(this._baseURL + path, data, {params, headers});
+  }
+}
+
+module.exports = Service;
+
+
+
+ + + + +
+ +
+ + + + + + + + + + diff --git a/sdk/adaptive-proxy/docs/styles/collapse.css b/sdk/adaptive-proxy/docs/styles/collapse.css new file mode 100644 index 0000000..4dc4121 --- /dev/null +++ b/sdk/adaptive-proxy/docs/styles/collapse.css @@ -0,0 +1,27 @@ +@media only screen and (min-width: 681px) { + nav > ul > li:hover .methods, + .active .methods { + display: block; + } + + .methods { + display: none; + } + + nav > ul > li { + padding: 20px 0; + } + + nav > ul > li > a { + padding: 0; + } + + nav > ul > li.active a { + margin-bottom: 10px; + } + + nav > ul > li:hover > a, + nav > ul > li.active > a { + margin-bottom: 15px; + } +} diff --git a/sdk/adaptive-proxy/docs/styles/jsdoc-default.css b/sdk/adaptive-proxy/docs/styles/jsdoc-default.css new file mode 100644 index 0000000..bfa773d --- /dev/null +++ b/sdk/adaptive-proxy/docs/styles/jsdoc-default.css @@ -0,0 +1,900 @@ +* { + box-sizing: border-box +} + +html, body { + height: 100%; + width: 100%; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + color: #3e3c42; + text-rendering: optimizeLegibility; + margin: 0; +} + +body { + color: #3e3c42; + background-color: #f3f3f3; + width: 100%; + font: 16px/1.875 "Avenir Next W01", "Avenir Next", "Helvetica Neue", Helvetica, sans-serif; + font-size: 16px; + line-height: 160%; +} + +a, a:active { + color: #0095dd; + text-decoration: none; +} + +a:hover { + text-decoration: underline +} + +p, ul, ol, blockquote { + margin-bottom: 1em; +} + +p { + max-width: 800px; +} + +h1, h2, h3, h4, h5, h6 { + color: #706d77; + font-weight: 500; + margin: 0; + line-height: 1; +} + +h1 { + color: #4b484f; + font-weight: 500; + font-size: 40px; + display: block; +} + +h1 span { + color: #999; + font-size: 32px; + display: block; + line-height: 1.5; +} + +h1.page-title { + border-bottom: 1px dashed #ccc; + margin-bottom: 20px; + padding-bottom: 30px; +} + +h2 { + font-size: 30px; + margin: 1.5em 0 0; +} + +h3 { + font-size: 20px; + margin: 1.5em 0 0; + text-transform: uppercase; +} + +h3.reference-title { + display: block; + font-weight: 400; + margin-top: 2em; + max-width: 200px; +} + +h3.reference-title small { + display: inline-block; + color: #0095dd; + margin-left: 5px; + font-weight: 500; +} + +h3.subsection-title { + border-bottom: 1px solid #ececec; + padding-bottom: 20px; + margin-top: 3em; + margin-bottom: 1em; +} + +h4 { + font-size: 16px; + margin: 1em 0 0; + font-weight: bold; +} + +h4.name { + font-size: 20px; + margin-top: 0; + font-weight: 500; +} + +h5 { + margin: 2em 0 0.5em 0; + font-size: 14px; + font-weight: 500; + text-transform: uppercase; +} + +.container-overview .subsection-title { + font-size: 14px; + text-transform: uppercase; + margin: 8px 0 15px 0; + font-weight: bold; + color: #4D4E53; + padding-top: 10px; +} + +h6 { + font-size: 100%; + letter-spacing: -0.01em; + margin: 6px 0 3px 0; + font-style: italic; + text-transform: uppercase; + font-weight: 500; +} + +tt, code, kbd, samp { + font-family: "Source Code Pro", monospace; + background: #f4f4f4; + padding: 1px 5px; + border-radius: 5px; +} + +.class-description { + margin-bottom: 1em; + margin-top: 1em; + padding: 10px 20px; + background-color: rgba(26, 159, 224, 0.1); +} + +.class-description:empty { + margin: 0 +} + +#main { + background-color: white; + float: right; + min-width: 360px; + width: calc(100% - 300px); + padding: 30px; + z-index: 100; +} + +header { + display: block; + max-width: 1400px; +} + +section { + display: block; + max-width: 1400px; + background-color: #fff; +} + +.variation { + display: none +} + +.signature-attributes { + font-size: 60%; + color: #aaa; + font-style: italic; + font-weight: lighter; +} + +.rule { + width: 100%; + margin-top: 20px; + display: block; + border-top: 1px solid #ccc; +} + +ul { + list-style-type: none; + padding-left: 0; +} + +ul li a { + font-weight: 500; +} + +ul ul { + padding-top: 5px; +} + +ul li ul { + padding-left: 20px; +} + +ul li ul li a { + font-weight: normal; +} + +nav { + float: left; + display: block; + width: 300px; + background: #f7f7f7; + overflow-x: visible; + overflow-y: auto; + height: 100%; + padding: 0px 30px 100px 30px; + height: 100%; + position: fixed; + transition: left 0.2s; + z-index: 998; + margin-top: 0px; + top: 43px; +} + +.navicon-button { + display: inline-block; + position: fixed; + bottom: 1.5em; + right: 1.5em; + z-index: 2; +} + +nav h3 { + font-size: 13px; + text-transform: uppercase; + letter-spacing: 1px; + font-weight: bold; + line-height: 24px; + margin: 40px 0 10px 0; + padding: 0; +} + +nav ul { + font-size: 100%; + line-height: 17px; + padding: 0; + margin: 0; + list-style-type: none; + border: none; + padding-left: 0; +} + +nav ul a { + font-size: 16px; +} + +nav ul a, nav ul a:active { + display: block; +} + +nav ul a:hover, nav ul a:active { + color: hsl(200, 100%, 43%); + text-decoration: none; +} + +nav>ul { + padding: 0 10px; +} + +nav>ul li:first-child { + padding-top: 0; +} + +nav ul li ul { + padding-left: 0; +} + +nav>ul>li { + border-bottom: 1px solid #e2e2e2; + padding: 10px 0 20px 0; +} + +nav>ul>li.active ul { + border-left: 3px solid #0095dd; + padding-left: 15px; +} + +nav>ul>li.active ul li.active a { + font-weight: bold; +} + +nav>ul>li.active a { + color: #0095dd; +} + +nav>ul>li>a { + color: #706d77; + padding: 20px 0; + font-size: 18px; +} + +nav ul ul { + margin-bottom: 10px; + padding-left: 0; +} + +nav ul ul a { + color: #5f5c63; +} + +nav ul ul a, nav ul ul a:active { + font-family: 'bt_mono', monospace; + font-size: 14px; + padding-left: 20px; + padding-top: 3px; + padding-bottom: 9px; +} + +nav h2 { + font-size: 12px; + margin: 0; + padding: 0; +} + +nav>h2>a { + color: hsl(202, 71%, 50%); + border-bottom: 1px solid hsl(202, 71%, 50%); + padding-bottom: 5px; +} + +nav>h2>a:hover { + font-weight: 500; + text-decoration: none; +} + +footer { + background-color: #fff; + color: hsl(0, 0%, 28%); + margin-left: 300px; + display: block; + font-style: italic; + font-size: 12px; + padding: 30px; + text-align: center; +} + +.ancestors { + color: #999; +} + +.ancestors a { + color: #999 !important; + text-decoration: none; +} + +.clear { + clear: both; +} + +.important { + font-weight: bold; + color: #950B02; +} + +.yes-def { + text-indent: -1000px; +} + +.type-signature { + color: #aaa; +} + +.name, .signature { + font-family: 'bt_mono', monospace; + word-wrap: break-word; +} + +.details { + margin-top: 14px; + font-size: 13px; + text-align: right; + background: #ffffff; + /* Old browsers */ + background: -moz-linear-gradient(left, #ffffff 0%, #fafafa 100%); + /* FF3.6-15 */ + background: -webkit-linear-gradient(left, #ffffff 0%, #fafafa 100%); + /* Chrome10-25,Safari5.1-6 */ + background: linear-gradient(to right, #ffffff 0%, #fafafa 100%); + /* W3C, IE10+, FF16+, Chrome26+, Opera12+, Safari7+ */ + filter: progid: DXImageTransform.Microsoft.gradient( startColorstr='#ffffff', endColorstr='#fafafa', GradientType=1); + padding-right: 5px; +} + +.details dt { + display: inline-block; +} + +.details dd { + display: inline-block; + margin: 0; +} + +.details dd a { + font-style: italic; + font-weight: normal; + line-height: 1; +} + +.details ul { + list-style-type: none; + margin: 0; +} + +.details pre.prettyprint { + margin: 0 +} + +.details .object-value { + padding-top: 0 +} + +.description { + margin-bottom: 1em; + margin-top: 1em; +} + +.code-caption { + font-style: italic; + margin: 0; + font-size: 16px; + color: #545454; +} + +.prettyprint { + font-size: 13px; + border: 1px solid #ddd; + border-radius: 3px; + overflow: auto; + background-color: #fbfbfb; +} + +.prettyprint.source { + width: inherit; +} + +.prettyprint code { + font-size: 100%; + line-height: 18px; + display: block; + margin: 0 30px; + background-color: #fbfbfb; + color: #4D4E53; +} + +.prettyprint>code { + padding: 30px 15px; +} + +.prettyprint .linenums code { + padding: 0 15px; +} + +.prettyprint .linenums li:first-of-type code { + padding-top: 15px; +} + +.prettyprint code span.line { + display: inline-block; +} + +.prettyprint.linenums { + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.prettyprint.linenums ol { + padding-left: 0 +} + +.prettyprint.linenums li { + border-left: 3px #ddd solid +} + +.prettyprint.linenums li.selected, .prettyprint.linenums li.selected * { + background-color: lightyellow +} + +.prettyprint.linenums li * { + -webkit-user-select: text; + -moz-user-select: text; + -ms-user-select: text; + user-select: text; +} + +.readme .prettyprint { + max-width: 800px; +} + +.params, .returns, .props { + border-spacing: 0; + border: 1px solid #ddd; + border-radius: 3px; + width: 100%; + font-size: 14px; +} + +.params .name, .props .name, .name code { + color: #4D4E53; + font-family: 'bt_mono', monospace; + font-size: 100%; +} + +.params td, .params th,.returns td, .returns th, .props td, .props th { + margin: 0px; + text-align: left; + vertical-align: top; + padding: 10px; + display: table-cell; +} + +.params td, .returns td { + border-top: 1px solid #eee; +} + +.params thead tr, .returns thead tr,.props thead tr { + background-color: #fff; + font-weight: bold; +} + +.params .params thead tr, .returns .returns thead tr, .props .props thead tr { + background-color: #fff; + font-weight: bold; +} + +.params td.description>p:first-child, .returns td.description>p:first-child, .props td.description>p:first-child { + margin-top: 0; + padding-top: 0; +} + +.params td.description>p:last-child, .returns td.description>p:last-child, .props td.description>p:last-child { + margin-bottom: 0; + padding-bottom: 0; +} + +dl.param-type { + margin-top: 5px; +} + +.param-type dt, .param-type dd { + display: inline-block +} + +.param-type dd { + font-family: Consolas, Monaco, 'Andale Mono', monospace +} + +.disabled { + color: #454545 +} + + +/* tag source style */ + +.tag-deprecated { + padding-right: 5px; +} + +.tag-source { + border-bottom: 1px solid rgba(28, 160, 224, 0.35); +} + +.tag-source:first-child { + border-bottom: 1px solid rgba(28, 160, 224, 1); +} + + +/* navicon button */ + +.navicon-button { + position: relative; + transition: 0.25s; + cursor: pointer; + user-select: none; + opacity: .8; + background-color: white; + border-radius: 100%; + width: 50px; + height: 50px; + -webkit-box-shadow: 0px 2px 9px 0px rgba(0, 0, 0, 0.31); + -moz-box-shadow: 0px 2px 9px 0px rgba(0, 0, 0, 0.31); + box-shadow: 0px 2px 9px 0px rgba(0, 0, 0, 0.31); +} + +.navicon-button .navicon:before, .navicon-button .navicon:after { + transition: 0.25s; +} + +.navicon-button:hover { + transition: 0.5s; + opacity: 1; +} + +.navicon-button:hover .navicon:before, .navicon-button:hover .navicon:after { + transition: 0.25s; +} + +.navicon-button:hover .navicon:before { + top: .425rem; +} + +.navicon-button:hover .navicon:after { + top: -.425rem; +} + + +/* navicon */ + +.navicon { + position: relative; + width: 1.5em; + height: .195rem; + background: #000; + top: calc(50% - .09rem); + left: calc(50% - .75rem); + transition: 0.3s; + border-radius: 5px; +} + +.navicon:before, .navicon:after { + display: block; + content: ""; + height: .195rem; + width: 1.5rem; + background: #000; + position: absolute; + z-index: -1; + transition: 0.3s 0.25s; +} + +.navicon:before { + top: 0.425rem; + height: .195rem; + border-radius: 5px; +} + +.navicon:after { + top: -0.425rem; + border-radius: 5px; +} + + +/* open */ + +.nav-trigger:checked+label:not(.steps) .navicon:before, .nav-trigger:checked+label:not(.steps) .navicon:after { + top: 0 !important; +} + +.nav-trigger:checked+label .navicon:before, .nav-trigger:checked+label .navicon:after { + transition: 0.5s; +} + + +/* Minus */ + +.nav-trigger:checked+label { + transform: scale(0.75); +} + + +/* × and + */ + +.nav-trigger:checked+label.plus .navicon, .nav-trigger:checked+label.x .navicon { + background: transparent; +} + +.nav-trigger:checked+label.plus .navicon:before, .nav-trigger:checked+label.x .navicon:before { + transform: rotate(-45deg); + background: #000; +} + +.nav-trigger:checked+label.plus .navicon:after, .nav-trigger:checked+label.x .navicon:after { + transform: rotate(45deg); + background: #000; +} + +.nav-trigger:checked+label.plus { + transform: scale(0.75) rotate(45deg); +} + +.nav-trigger:checked~nav { + left: 0 !important; +} + +.nav-trigger:checked~.overlay { + display: block; +} + +.nav-trigger { + position: fixed; + top: 0; + clip: rect(0, 0, 0, 0); +} + +.overlay { + display: none; + position: fixed; + top: 0; + bottom: 0; + left: 0; + right: 0; + width: 100%; + height: 100%; + background: hsla(0, 0%, 0%, 0.5); + z-index: 1; +} + +table { + border-collapse: separate; + ; + display: block; + overflow-x: auto; + /*table-layout:fixed;*/ +} + +table tbody td { + border-top: 1px solid hsl(207, 10%, 86%); + border-right: 1px solid #eee; + padding: 5px; + /*word-wrap: break-word;*/ +} + +td table.params, td table.returns, td table.props { + border: 0; +} + +@media only screen and (min-width: 320px) and (max-width: 680px) { + body { + overflow-x: hidden; + } + #main { + padding: 30px 30px; + width: 100%; + min-width: 360px; + } + nav { + background: #FFF; + width: 300px; + height: 100%; + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: -300px; + z-index: 3; + padding: 0 10px; + transition: left 0.2s; + margin-top: 0; + } + .navicon-button { + display: inline-block; + position: fixed; + bottom: 1.5em; + right: 20px; + z-index: 1000; + } + .top-nav-wrapper { + display: none; + } + #main h1.page-title { + margin: 0.5em 0; + } + footer { + margin-left: 0; + margin-bottom: 30px; + } +} + +.top-nav-wrapper { + background-color: #ececec; + position: fixed; + top: 0px; + left: 0px; + padding: 10px 10px 0 10px; + z-index: 999; + width: 300px; +} + +.top-nav-wrapper ul { + margin: 0; +} + +.top-nav-wrapper ul li { + display: inline-block; + padding: 0 10px; + vertical-align: top; +} + +.top-nav-wrapper ul li.active { + border-bottom: 2px solid rgba(28, 160, 224, 1); +} + +.search-wrapper { + display: inline-block; + position: relative; +} + +.search-wrapper svg { + position: absolute; + left: 0px; +} + +input.search-input { + background: transparent; + box-shadow: 0; + border: 0; + border-bottom: 1px solid #c7c7c7; + padding: 7px 15px 12px 35px; + margin: 0 auto; +} + + +/* Smooth outline with box-shadow: */ + +input.search-input:focus { + border-bottom: 2px solid rgba(28, 160, 224, 1); + outline: none; +} + + +/* Hightlight JS Paradiso Light Theme */ + +.hljs-comment, .hljs-quote { + color: #776e71 +} + +.hljs-variable, .hljs-template-variable, .hljs-tag, .hljs-name, .hljs-selector-id, .hljs-selector-class, .hljs-regexp, .hljs-link, .hljs-meta { + color: #ef6155 +} + +.hljs-number, .hljs-built_in, .hljs-builtin-name, .hljs-literal, .hljs-type, .hljs-params, .hljs-deletion { + color: #f99b15 +} + +.hljs-title, .hljs-section, .hljs-attribute { + color: #fec418 +} + +.hljs-string, .hljs-symbol, .hljs-bullet, .hljs-addition { + color: #48b685 +} + +.hljs-keyword, .hljs-selector-tag { + color: #815ba4 +} + +.hljs { + display: block; + overflow-x: auto; + background: #e7e9db; + color: #4f424c; + padding: 0.5em +} + +.hljs-emphasis { + font-style: italic +} + +.hljs-strong { + font-weight: bold +} + +.link-icon { + opacity: 0; + position: absolute; + margin-left: -25px; + padding-right: 5px; + padding-top: 2px; +} + +.example-container .link-icon { + margin-top: -6px; +} + +.example-container:hover .link-icon, +.name-container:hover .link-icon { + opacity: .5; +} + +.name-container { + display: flex; + padding-top: 1em; +} diff --git a/sdk/adaptive-proxy/docs/styles/prettify-jsdoc.css b/sdk/adaptive-proxy/docs/styles/prettify-jsdoc.css new file mode 100644 index 0000000..834a866 --- /dev/null +++ b/sdk/adaptive-proxy/docs/styles/prettify-jsdoc.css @@ -0,0 +1,111 @@ +/* JSDoc prettify.js theme */ + +/* plain text */ +.pln { + color: #000000; + font-weight: normal; + font-style: normal; +} + +/* string content */ +.str { + color: hsl(104, 100%, 24%); + font-weight: normal; + font-style: normal; +} + +/* a keyword */ +.kwd { + color: #000000; + font-weight: bold; + font-style: normal; +} + +/* a comment */ +.com { + font-weight: normal; + font-style: italic; +} + +/* a type name */ +.typ { + color: #000000; + font-weight: normal; + font-style: normal; +} + +/* a literal value */ +.lit { + color: #006400; + font-weight: normal; + font-style: normal; +} + +/* punctuation */ +.pun { + color: #000000; + font-weight: bold; + font-style: normal; +} + +/* lisp open bracket */ +.opn { + color: #000000; + font-weight: bold; + font-style: normal; +} + +/* lisp close bracket */ +.clo { + color: #000000; + font-weight: bold; + font-style: normal; +} + +/* a markup tag name */ +.tag { + color: #006400; + font-weight: normal; + font-style: normal; +} + +/* a markup attribute name */ +.atn { + color: #006400; + font-weight: normal; + font-style: normal; +} + +/* a markup attribute value */ +.atv { + color: #006400; + font-weight: normal; + font-style: normal; +} + +/* a declaration */ +.dec { + color: #000000; + font-weight: bold; + font-style: normal; +} + +/* a variable name */ +.var { + color: #000000; + font-weight: normal; + font-style: normal; +} + +/* a function name */ +.fun { + color: #000000; + font-weight: bold; + font-style: normal; +} + +/* Specify class=linenums on a pre to get line numbering */ +ol.linenums { + margin-top: 0; + margin-bottom: 0; +} diff --git a/sdk/adaptive-proxy/docs/styles/prettify-tomorrow.css b/sdk/adaptive-proxy/docs/styles/prettify-tomorrow.css new file mode 100644 index 0000000..eaf1251 --- /dev/null +++ b/sdk/adaptive-proxy/docs/styles/prettify-tomorrow.css @@ -0,0 +1,138 @@ +/* Tomorrow Theme */ +/* Original theme - https://github.com/chriskempson/tomorrow-theme */ +/* Pretty printing styles. Used with prettify.js. */ +/* SPAN elements with the classes below are added by prettyprint. */ +/* plain text */ +.pln { + color: #4d4d4c; } + +@media screen { + /* string content */ + .str { + color: hsl(104, 100%, 24%); } + + /* a keyword */ + .kwd { + color: hsl(240, 100%, 50%); } + + /* a comment */ + .com { + color: hsl(0, 0%, 60%); } + + /* a type name */ + .typ { + color: hsl(240, 100%, 32%); } + + /* a literal value */ + .lit { + color: hsl(240, 100%, 40%); } + + /* punctuation */ + .pun { + color: #000000; } + + /* lisp open bracket */ + .opn { + color: #000000; } + + /* lisp close bracket */ + .clo { + color: #000000; } + + /* a markup tag name */ + .tag { + color: #c82829; } + + /* a markup attribute name */ + .atn { + color: #f5871f; } + + /* a markup attribute value */ + .atv { + color: #3e999f; } + + /* a declaration */ + .dec { + color: #f5871f; } + + /* a variable name */ + .var { + color: #c82829; } + + /* a function name */ + .fun { + color: #4271ae; } } +/* Use higher contrast and text-weight for printable form. */ +@media print, projection { + .str { + color: #060; } + + .kwd { + color: #006; + font-weight: bold; } + + .com { + color: #600; + font-style: italic; } + + .typ { + color: #404; + font-weight: bold; } + + .lit { + color: #044; } + + .pun, .opn, .clo { + color: #440; } + + .tag { + color: #006; + font-weight: bold; } + + .atn { + color: #404; } + + .atv { + color: #060; } } +/* Style */ +/* +pre.prettyprint { + background: white; + font-family: Consolas, Monaco, 'Andale Mono', monospace; + font-size: 12px; + line-height: 1.5; + border: 1px solid #ccc; + padding: 10px; } +*/ + +/* Get LI elements to show when they are in the main article */ +article ul li { + list-style-type: circle; + margin-left: 25px; +} + +/* Specify class=linenums on a pre to get line numbering */ +ol.linenums { + margin-top: 0; + margin-bottom: 0; } + +/* IE indents via margin-left */ +li.L0, +li.L1, +li.L2, +li.L3, +li.L4, +li.L5, +li.L6, +li.L7, +li.L8, +li.L9 { + /* */ } + +/* Alternate shading for lines */ +li.L1, +li.L3, +li.L5, +li.L7, +li.L9 { + /* */ } diff --git a/sdk/adaptive-proxy/docs/utils_base64Utils.js.html b/sdk/adaptive-proxy/docs/utils_base64Utils.js.html new file mode 100644 index 0000000..ff6743b --- /dev/null +++ b/sdk/adaptive-proxy/docs/utils_base64Utils.js.html @@ -0,0 +1,132 @@ + + + + + + + + + + + utils/base64Utils.js - Documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + +
+ +

+ utils/base64Utils.js +

+ + + + + +
+
+
// Copyright contributors to the IBM Security Verify Adaptive Proxy SDK
+// for JavaScript project
+
+
+/**
+ * Base64url encode a string.
+ * @param {string} string The string to encode.
+ * @return {string} The base64url encoded string.
+ */
+function base64UrlEncodeString(string) {
+  return Buffer.from(string).toString('base64')
+      // For URL safe base64 (base64url)
+      .replace(/\+/g, '-')
+      .replace(/\//g, '_')
+      .replace(/=+$/g, '');
+}
+
+/**
+ * Base64url encode the JSON string representation of an object.
+ * @param {Object} object The object to encode.
+* @return {string} The base64url encoded JSON string.
+ */
+function base64UrlEncodeObject(object) {
+  return base64UrlEncodeString(JSON.stringify(object));
+}
+
+module.exports = {base64UrlEncodeObject, base64UrlEncodeString};
+
+
+
+ + + + +
+ +
+ + + + + + + + + + diff --git a/sdk/adaptive-proxy/docs/utils_securityUtils.js.html b/sdk/adaptive-proxy/docs/utils_securityUtils.js.html new file mode 100644 index 0000000..2066628 --- /dev/null +++ b/sdk/adaptive-proxy/docs/utils_securityUtils.js.html @@ -0,0 +1,129 @@ + + + + + + + + + + + utils/securityUtils.js - Documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + +
+ +

+ utils/securityUtils.js +

+ + + + + +
+
+
// Copyright contributors to the IBM Security Verify Adaptive Proxy SDK
+// for JavaScript project
+
+
+/**
+ * Mask sensitive properties of an object.
+ * @param {Object} object The object whose sensitive properties to mask.
+ * @return {Object} The masked object.
+ */
+function maskObject(object) {
+  const sensitiveProperties = ['password', 'otp', 'Authorization', 'assertion',
+    'token', 'access_token', 'refresh_token'];
+
+  const clone = {...object};
+  for (sensitiveProperty of sensitiveProperties) {
+    if (clone[sensitiveProperty]) {
+      clone[sensitiveProperty] = '****';
+    }
+  }
+
+  return clone;
+}
+
+module.exports = {maskObject};
+
+
+
+ + + + +
+ +
+ + + + + + + + + + diff --git a/sdk/adaptive-proxy/docs/utils_transactionUtils.js.html b/sdk/adaptive-proxy/docs/utils_transactionUtils.js.html new file mode 100644 index 0000000..2448d83 --- /dev/null +++ b/sdk/adaptive-proxy/docs/utils_transactionUtils.js.html @@ -0,0 +1,200 @@ + + + + + + + + + + + utils/transactionUtils.js - Documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + +
+ +

+ utils/transactionUtils.js +

+ + + + + +
+
+
// Copyright contributors to the IBM Security Verify Adaptive Proxy SDK
+// for JavaScript project
+
+
+const TransactionError = require('../errors/transactionError');
+
+const NodeCache = require('node-cache');
+const {v4: uuid} = require('uuid');
+
+
+// Initialise a cache with 10-minute storage.
+const cache = new NodeCache({stdTTL: 600});
+
+/**
+ * Create a stored transaction. Associate the given object with a random UUID in
+ * the cache.
+ * @param {Object} object The object to store as a transaction.
+ * @return {string} The randomly generated UUID associated to the new
+ * transaction.
+ * @throws {TransactionError} The transaction cannot be stored.
+ */
+function createTransaction(object) {
+  const transactionId = uuid();
+  if (!cache.set(transactionId, object)) {
+    throw new TransactionError(
+        `Could not create transaction with ID ${transactionId}.`);
+  }
+
+  console.log(`[transactionUtils:createTransaction(object)]`,
+      'transactionId:', transactionId);
+  console.log(`[transactionUtils:createTransaction(object)]`,
+      'transaction:', object);
+
+  return transactionId;
+}
+
+/**
+ * Get a stored transaction.
+ * @param {string} transactionId The identifier of the transaction.
+ * @return {Object} The transaction object associated with the identifier.
+ * @throws {TransactionError} The transaction ID doesn't exist.
+ */
+function getTransaction(transactionId) {
+  const transaction = cache.get(transactionId);
+  if (!transaction) {
+    throw new TransactionError('Invalid transaction ID provided.');
+  }
+
+  console.log(`[transactionUtils:getTransaction(transactionId)]`,
+      'transactionId:', transactionId);
+  console.log(`[transactionUtils:getTransaction(transactionId)]`,
+      'transaction:', transaction);
+
+  return transaction;
+}
+
+/**
+ * Add the given properties to a stored transaction.
+ * @param {string} transactionId The identifier of the transaction to update.
+ * @param {Object} properties The properties to add to the transaction.
+ * @throws {TransactionError} The transaction ID doesn't exist.
+ */
+function updateTransaction(transactionId, properties) {
+  const oldTransaction = cache.get(transactionId);
+  if (!oldTransaction) {
+    throw new TransactionError('Invalid transaction ID provided.');
+  }
+  const newTransaction = {...oldTransaction, ...properties};
+
+  console.log(`[transactionUtils:updateTransaction(transactionId, properties)]`,
+      'transactionId:', transactionId);
+  console.log(`[transactionUtils:updateTransaction(transactionId, properties)]`,
+      'oldTransaction:', oldTransaction);
+  console.log(`[transactionUtils:updateTransaction(transactionId, properties)]`,
+      'newTransaction:', newTransaction);
+
+  cache.set(transactionId, newTransaction);
+}
+
+/**
+ * Delete a stored transaction.
+ * @param {string} transactionId The identifier of the transaction to delete.
+ * @throws {TransactionError} The transaction ID doesn't exist.
+ */
+function deleteTransaction(transactionId) {
+  if (cache.del(transactionId) !== 1) {
+    throw new TransactionError('Invalid transaction ID provided.');
+  }
+
+  console.log(`[transactionUtils:deleteTransaction(transactionId)]`,
+      'transactionId:', transactionId);
+}
+
+module.exports = {createTransaction, updateTransaction, getTransaction,
+  deleteTransaction};
+
+
+
+ + + + +
+ +
+ + + + + + + + + + diff --git a/sdk/adaptive-proxy/lib/adaptive.js b/sdk/adaptive-proxy/lib/adaptive.js new file mode 100644 index 0000000..12ac641 --- /dev/null +++ b/sdk/adaptive-proxy/lib/adaptive.js @@ -0,0 +1,1624 @@ +// Copyright contributors to the IBM Security Verify Adaptive Proxy SDK +// for JavaScript project + + +const LRU = require('lru-cache'); + +const transactionUtils = require('./utils/transactionUtils'); +const ConfigurationError = require('./errors/configurationError'); +const TransactionError = require('./errors/transactionError'); +const TokenError = require('./errors/tokenError'); +const PolicyService = require('./services/oidc/policyService'); +const FIDOService = require('./services/factors/fidoService'); +const PasswordService = require( + './services/factors/passwordService'); +const QRService = require('./services/factors/qrService'); +const TOTPService = require('./services/factors/totpService'); +const EmailOTPService = require('./services/factors/emailOTPService'); +const SMSOTPService = require('./services/factors/smsOTPService'); +const VoiceOTPService = require('./services/factors/voiceOTPService'); +const QuestionsService = require('./services/factors/questionsService'); +const PushService = require('./services/factors/pushService'); +const FactorService = require('./services/factors/factorService'); +const TokenService = require('./services/oidc/tokenService'); + + +/** + * Class representing the PDA (Policy Driven Authentication) SDK. Used to + * perform and validate first- and second-factor verifications on CI (Cloud + * Identity). + * @author Adam Dorogi-Kaposi + */ +class Adaptive { + /** + * Create a new {@link Adaptive} object. + * @param {Object} config The configuration settings used for CI requests. + * @param {string} config.clientId The identifier of the client application. + * @param {string} config.clientSecret The client application secret. + * @param {string} config.tenantUrl The URL of the tenant. + * @param {Object} [transactionFunctions] An object containing transaction + * operation functions. This parameter is optional, in case the + * developer would like to handle the storing, retrieving, updating, and + * deleting of transactions created during the A2 flow in an external + * database. Otherwise, a default in-memory option is used for handling + * transactions. If specified, this object must contain four parameters: + * createTransaction, getTransaction, + * updateTransaction, and deleteTransaction, each + * being the appropriate function to store, retrieve, update, and delete + * transactions respectively. The custom storage mechanism should ideally have + * a time-to-live for the transactions (e.g. 1 hour), to prevent accumulating + * unused/unfinished transactions. + * @param {Function} [transactionFunctions.createTransaction] The function + * used to create (store) a transaction. This function should take one + * parameter; a transaction Object. It should store the object in + * a database of choice, indexed by a randomly generated v4 UUID (the + * transaction ID). After storing the transaction object associated to a + * transaction ID, the function should return the transaction ID as a + * string. + * @param {Function} [transactionFunctions.getTransaction] The function used + * to retrieve stored transactions. This function should take one parameter; + * a transaction ID string. It should return the transaction + * Object associated to the given transaction ID. + * @param {Function} [transactionFunctions.updateTransaction] The function + * used to update (i.e. add additional properties to) an existing transaction. + * This function should take two parameters (in order); a transaction ID + * string of the transaction to update, and an + * Object of additional properties to add to the + * transaction. For example, if the existing transaction is {"userId": + * "123456"}, and the object passed into this function is + * {"name": "John"}, the updated transaction should be + * {"userId": "123456", "name": "John"}. This function shouldn't + * return anything. + * @param {Function} [transactionFunctions.deleteTransaction] The function + * used to delete an existing transaction. This function should take one + * parameter; a transaction ID string. The function should remove + * the transaction associated with the given transaction ID from the database + * storage. This function shouldn't return anything. + * @throws {ConfigurationError} The configuration object doesn't contain the + * required properties. + * @throws {TransactionError} The createTransaction, + * getTransaction, updateTransaction, or + * deleteTransaction functions are missing from the transaction + * functions object. + */ + constructor(config, transactionFunctions={ + createTransaction: transactionUtils.createTransaction, + getTransaction: transactionUtils.getTransaction, + updateTransaction: transactionUtils.updateTransaction, + deleteTransaction: transactionUtils.deleteTransaction}) { + if (!config.clientId) { + throw new ConfigurationError( + `Cannot find property 'clientId' in configuration settings.`); + } else if (!config.clientSecret) { + throw new ConfigurationError( + `Cannot find property 'clientSecret' in configuration settings.`); + } else if (!config.tenantUrl) { + throw new ConfigurationError( + `Cannot find property 'tenantUrl' in configuration settings.`); + } + + if (!transactionFunctions.createTransaction) { + throw new TransactionError( + `Cannot find function 'createTransaction' in transaction functions.`); + } else if (!transactionFunctions.getTransaction) { + throw new TransactionError( + `Cannot find function 'getTransaction' in transaction functions.`); + } else if (!transactionFunctions.updateTransaction) { + throw new TransactionError( + `Cannot find function 'updateTransaction' in transaction functions.`); + } else if (!transactionFunctions.deleteTransaction) { + throw new TransactionError( + `Cannot find function 'deleteTransaction' in transaction functions.`); + } + + this._config = config; + this._transactionFunctions = transactionFunctions; + + console.log(`[${Adaptive.name}:constructor(config, transactionFunctions)]`, + 'clientId:', this._config.clientId); + console.log(`[${Adaptive.name}:constructor(config, transactionFunctions)]`, + 'clientSecret:', '****'); + console.log(`[${Adaptive.name}:constructor(config, transactionFunctions)]`, + 'tenantUrl:', this._config.tenantUrl); + + console.log(`[${Adaptive.name}:constructor(config, transactionFunctions)]`, + 'createTransaction:', this._transactionFunctions.createTransaction); + console.log(`[${Adaptive.name}:constructor(config, transactionFunctions)]`, + 'getTransaction:', this._transactionFunctions.getTransaction); + console.log(`[${Adaptive.name}:constructor(config, transactionFunctions)]`, + 'updateTransaction:', this._transactionFunctions.updateTransaction); + console.log(`[${Adaptive.name}:constructor(config, transactionFunctions)]`, + 'deleteTransaction:', this._transactionFunctions.deleteTransaction); + } + + /** + * Perform an initial grant request. + * + * The initial grant request uses the policyauth grant-type to + * evaluate the policy attached to the client application on OIDC with the + * risk engine. + * + * An in-memory transaction is also created to associate subsequent requests + * to a session or "transaction". + * @param {Object} context The context to send for assessment. + * @param {string} context.sessionId The session ID generated by the + * user-agent, using an Adaptive client SDK. + * @param {string} context.userAgent The user-agent, typically obtained form + * the User-Agent HTTP header. + * @param {string} context.ipAddress The IP address of the user-agent. + * @param {string} [context.evaluationContext="login"] The stage in the + * user-agent for which to perform an evaluation. (Used for continuous + * assessment throughout the user-agent.) Different "stages" or "contexts" + * will result in different evaluation results, as configured in the + * sub-policies of the tenant application's policy. Possible options are + * "login" (default), "landing", "profile", "resume", "highassurance", + * "other". + * @return {Promise} The policy evaluation result object. The result + * object has a status property of either deny, or + * requires. If deny, only the status + * property is included in the result object. If requires, a + * transaction is created, and the transactionId and an array of + * allowedFactors is also included in the result object, + * indicating that further first-factor authentication is required. + * @example deny result object + * { + * status: 'deny' + * } + * @example requires result object + * { + * status: 'requires', + * transactionId: '36a101c7-7426-4f45-ab3c-55f8dc075c6e', + * allowedFactors: ['qr', 'fido', 'password'] + * } + */ + async assessPolicy({sessionId, userAgent, ipAddress, + evaluationContext='login'}) { + const context = {sessionId, userAgent, ipAddress, evaluationContext}; + const policyService = new PolicyService({clientId: this._config.clientId, + clientSecret: this._config.clientSecret}, this._config.tenantUrl, + context); + + try { + // Get a `policyauth` access token from OIDC. + const assessment = await policyService.assess(); + console.log(`[${Adaptive.name}:assessPolicy(context)]`, 'assessment:', + assessment); + + if (assessment.scope === 'openid') { + return {status: 'allow', token: assessment}; + } + + // If no error is thrown by this point, further authentication is required + // (i.e. we received a `requires` response). + + // Create transaction and store in memory cache. + const transaction = {assessment}; + const transactionId = this._transactionFunctions + .createTransaction(transaction); + + const allowedFactors = assessment.allowedFactors.map((factor) => { + return {type: factor}; + }); + return {status: 'requires', allowedFactors, transactionId}; + } catch (error) { + // Policy evaluation is denied. + console.log(`[${Adaptive.name}:assessPolicy(context)]`, 'error:', error); + const jsonResp = {status: 'deny'}; + if (error.response.data) { + jsonResp.detail = error.response.data; + } + return jsonResp; + } + } + + /** + * Initiate a FIDO first-factor verification to be completed by the + * user-agent. + * @param {Object} context The context to send for assessment. + * @param {string} context.sessionId The session ID generated by the + * user-agent, using an Adaptive client SDK. + * @param {string} context.userAgent The user-agent, typically obtained form + * the User-Agent HTTP header. + * @param {string} context.ipAddress The IP address of the user-agent. + * @param {string} [context.evaluationContext="login"] The stage in the + * user-agent for which to perform an evaluation. (Used for continuous + * assessment throughout the user-agent.) Different "stages" or "contexts" + * will result in different evaluation results, as configured in the + * sub-policies of the tenant application's policy. Possible options are + * "login" (default), "landing", "profile", "resume", "highassurance", + * "other". + * @param {string} transactionId The identifier of the transaction received in + * {@link Adaptive#assessPolicy}. + * @param {string} relyingPartyId The identifier of relying party associated + * with the FIDO registration. + * @param {string} userId The identifier of the OIDC user for which to + * initiate a FIDO verification. + * @return {Promise} A FIDO challenge to be completed by the + * user-agent. + * @example FIDO challenge return value + * { + * "transactionId": "36a101c7-7426-4f45-ab3c-55f8dc075c6e", + * "fido": { + * "rpId": "fido.verify.ibm.com", + * "challenge": "Q29uZ3JhdHVsYXRpb25zIFlvdSBmb3VuZCBpdAo", + * "userVerification": "preferred", + * "timeout": 30000, + * "allowCredentials": [ + * { + * "type": "public-key", + * "id": "SSBhbSBhIGNyZWRlbnRpYWwK" + * } + * ] + * } + * } + */ + async generateFIDO({sessionId, userAgent, ipAddress, + evaluationContext='login'}, transactionId, relyingPartyId, userId) { + const context = {sessionId, userAgent, ipAddress, evaluationContext}; + const transaction = this._transactionFunctions + .getTransaction(transactionId); + + const fidoService = new FIDOService( + {accessToken: transaction.assessment.access_token}, + this._config.tenantUrl, context); + + const verification = await fidoService.generate(relyingPartyId, userId); + console.log(`[${Adaptive.name}:generateFIDO(context, transactionId, ` + + `relyingPartyId, userId)]`, 'verification:', verification); + + // Update transaction in memory cache. + this._transactionFunctions + .updateTransaction(transactionId, {fido: verification}); + this._transactionFunctions + .updateTransaction(transactionId, {userId}); + + return {transactionId, fido: verification}; + } + + /** + * Complete a FIDO first-factor verification and validate the resulting JWT. + * @param {Object} context The context to send for assessment. + * @param {string} context.sessionId The session ID generated by the + * user-agent, using an Adaptive client SDK. + * @param {string} context.userAgent The user-agent, typically obtained form + * the User-Agent HTTP header. + * @param {string} context.ipAddress The IP address of the user-agent. + * @param {string} [context.evaluationContext="login"] The stage in the + * user-agent for which to perform an evaluation. (Used for continuous + * assessment throughout the user-agent.) Different "stages" or "contexts" + * will result in different evaluation results, as configured in the + * sub-policies of the tenant application's policy. Possible options are + * "login" (default), "landing", "profile", "resume", "highassurance", + * "other". + * @param {string} transactionId The identifier of the transaction received in + * {@link Adaptive#assessPolicy}. + * @param {string} relyingPartyId The identifier of relying party associated + * with the FIDO registration. + * @param {string} authenticatorData The information about the authentication + * that was produced by the user-agent authenticator and verified by the + * signature. + * @param {string} userHandle The identifier for the user who owns this + * authenticator. + * @param {string} signature The signature of the challenge data that was + * produced by the user-agent authenticator. + * @param {string} clientDataJSON The base64 encoded client data JSON object. + * @return {Promise} The JWT validation result object. The result + * object has a status property of either allow, + * deny, or requires. + * If allow, a token object is also included in the + * result object. + * If deny, a details object is returned if an + * error message was returned from the token endpoint. + * If requires, the allowed second-factor enrollments are + * retrieved and included in the result object, indicating that further + * second-factor authentication is required. + * @example allow result object + * { + * status: 'allow', + * token: { + * access_token: 'zscmjBdvIjudOPLhpbmJi6nBRJg7cZ6WY0Udw1nC', + * refresh_token: 'wFTjurPxTvRD1cW09itgQM83XwCm1UKwsxhVFb1H7HJh8JkwZz', + * scope: 'openid', + * grant_id: 'a0b440b6-fefb-46ea-a603-e1040534cd28', + * id_token: 'eyJhbGciOiJSUzI1NiIsInR5cC...5j_rMn7H3ZpE4axt0WvsYu4jbA', + * token_type: 'Bearer', + * expires_in: 7120 + * } + * } + * @example deny result object + * { + * status: 'deny', + * detail: { + * error: 'adaptive_more_info_required', + * error_description: 'CSIAQ0298E Adaptive access...' + * } + * } + * @example requires result object + * { + * status: 'requires', + * transactionId: '36a101c7-7426-4f45-ab3c-55f8dc075c6e', + * enrolledFactors: [ + * { + * id: '61e39f0a-836b-48fa-b4c9-cface6a3ef5a', + * userId: '60300035KP', + * type: 'emailotp', + * created: '2020-06-15T02:51:49.131Z', + * updated: '2020-06-15T03:15:18.896Z', + * attempted: '2020-07-16T04:30:14.066Z', + * enabled: true, + * validated: true, + * attributes: { + * emailAddress: 'email@email.com' + * } + * } + * ] + * } + */ + async evaluateFIDO({sessionId, userAgent, ipAddress, + evaluationContext='login'}, transactionId, relyingPartyId, + authenticatorData, userHandle, signature, clientDataJSON) { + const context = {sessionId, userAgent, ipAddress, evaluationContext}; + const transaction = this._transactionFunctions + .getTransaction(transactionId); + if (!transaction.fido) { + throw new TransactionError( + 'This transaction has not initiated a FIDO verification.'); + } + + // TODO: Handle multiple allowCredentials + const credentialId = transaction.fido.allowCredentials[0].id; + console.log(`[${Adaptive.name}:evaluateFIDO(context, transactionId, ` + + `relyingPartyId, authenticatorData, userHandle, signature, ` + + `clientDataJSON)]`, 'credentialId:', credentialId); + + const fidoService = new FIDOService( + {accessToken: transaction.assessment.access_token}, + this._config.tenantUrl, context); + + // Complete FIDO verification. + const verification = await fidoService.evaluate(relyingPartyId, + credentialId, clientDataJSON, authenticatorData, userHandle, + signature); + console.log(`[${Adaptive.name}:evaluateFIDO(context, transactionId, ` + + `relyingPartyId, authenticatorData, userHandle, signature, ` + + `clientDataJSON)]`, 'verification:', verification); + + return this._validateAssertion(transactionId, context, + verification.assertion, transaction.userId); + } + + /** + * Lookup Identity Sources by name. If name not defined then + * return all password-capable sources. + * + * Complete a FIDO first-factor verification and validate the resulting JWT. + * @param {Object} context The context to send for assessment. + * @param {string} context.sessionId The session ID generated by the + * user-agent, using an Adaptive client SDK. + * @param {string} context.userAgent The user-agent, typically obtained form + * the User-Agent HTTP header. + * @param {string} context.ipAddress The IP address of the user-agent. + * @param {string} [context.evaluationContext="login"] The stage in the + * user-agent for which to perform an evaluation. (Used for continuous + * assessment throughout the user-agent.) Different "stages" or "contexts" + * will result in different evaluation results, as configured in the + * sub-policies of the tenant application's policy. Possible options are + * "login" (default), "landing", "profile", "resume", "highassurance", + * "other". + * @param {string} transactionId The identifier of the transaction received in + * {@link Adaptive#assessPolicy}. + * @param {string} [sourceName] The source name to look up. + * @return {Promise} The result object. The result + * object contains an array of identity sources for this user. + * @example Result object + * [ + * { + * "name": "Cloud Directory", + * "location": "https:///v1.0/authnmethods/password/11111111-2222-3333-4444-555555555555", + * "id": "11111111-2222-3333-4444-555555555555", + * "type": "ibmldap" + * } + * ] + */ + async lookupIdentitySources({sessionId, userAgent, ipAddress, + evaluationContext='login'}, transactionId, sourceName) { + const context = {sessionId, userAgent, ipAddress, evaluationContext}; + const transaction = this._transactionFunctions + .getTransaction(transactionId); + + const passwordService = new PasswordService( + {accessToken: transaction.assessment.access_token}, + this._config.tenantUrl, context); + + const sources = await passwordService.lookupIdentitySources(sourceName); + + console.log(`[${Adaptive.name}:lookupIdentitySources(context, ` + + `transactionId, sourceName)]`, 'sources:', sources); + + return sources; + } + + /** + * Complete a password first-factor verification. + * + * Complete a password first-factor verification, validate the resulting JWT, + * and gather second-factor enrollments if needed. + * @param {Object} context The context to send for assessment. + * @param {string} context.sessionId The session ID generated by the + * user-agent, using an Adaptive client SDK. + * @param {string} context.userAgent The user-agent, typically obtained form + * the User-Agent HTTP header. + * @param {string} context.ipAddress The IP address of the user-agent. + * @param {string} [context.evaluationContext="login"] The stage in the + * user-agent for which to perform an evaluation. (Used for continuous + * assessment throughout the user-agent.) Different "stages" or "contexts" + * will result in different evaluation results, as configured in the + * sub-policies of the tenant application's policy. Possible options are + * "login" (default), "landing", "profile", "resume", "highassurance", + * "other". + * @param {string} transactionId The identifier of the transaction received in + * {@link Adaptive#assessPolicy}. + * @param {string} identitySourceId The identifier of the identity source + * associated with the password registration. + * @param {string} username The username to authenticate as. + * @param {string} password The password to authenticate with. + * @return {Promise} The JWT evaluation result object. The result + * object has a status property of either allow, + * deny, or requires. + * If allow, a token object is also included in the + * result object. + * If deny, a details object is returned if an + * error message was returned from the token endpoint. + * If requires, the allowed second-factor enrollments are + * retrieved and included in the result object, indicating that further + * second-factor authentication is required. + * @example allow result object + * { + * status: 'allow', + * token: { + * access_token: 'zscmjBdvIjudOPLhpbmJi6nBRJg7cZ6WY0Udw1nC', + * refresh_token: 'wFTjurPxTvRD1cW09itgQM83XwCm1UKwsxhVFb1H7HJh8JkwZz', + * scope: 'openid', + * grant_id: 'a0b440b6-fefb-46ea-a603-e1040534cd28', + * id_token: 'eyJhbGciOiJSUzI1NiIsInR5cC...5j_rMn7H3ZpE4axt0WvsYu4jbA', + * token_type: 'Bearer', + * expires_in: 7120 + * } + * } + * @example deny result object + * { + * status: 'deny', + * detail: { + * error: 'adaptive_more_info_required', + * error_description: 'CSIAQ0298E Adaptive access...' + * } + * } + * @example requires result object + * { + * status: 'requires', + * transactionId: '36a101c7-7426-4f45-ab3c-55f8dc075c6e', + * enrolledFactors: [ + * { + * id: '61e39f0a-836b-48fa-b4c9-cface6a3ef5a', + * userId: '60300035KP', + * type: 'emailotp', + * created: '2020-06-15T02:51:49.131Z', + * updated: '2020-06-15T03:15:18.896Z', + * attempted: '2020-07-16T04:30:14.066Z', + * enabled: true, + * validated: true, + * attributes: { + * emailAddress: 'email@email.com' + * } + * } + * ] + * } + */ + async evaluatePassword({sessionId, userAgent, ipAddress, + evaluationContext='login'}, transactionId, identitySourceId, username, + password) { + const context = {sessionId, userAgent, ipAddress, evaluationContext}; + const transaction = this._transactionFunctions + .getTransaction(transactionId); + + const passwordService = new PasswordService( + {accessToken: transaction.assessment.access_token}, + this._config.tenantUrl, context); + + const authentication = await passwordService.authenticate(identitySourceId, + username, password); + + console.log(`[${Adaptive.name}:evaluatePassword(context, transactionId, ` + + `identitySourceId, username, password)]`, 'authentication:', + authentication); + + // Store user ID in transaction + this._transactionFunctions + .updateTransaction(transactionId, {userId: authentication.id}); + + return this._validateAssertion(transactionId, context, + authentication.assertion, authentication.id); + } + + /** + * @private + * Validate a JWT assertion received after a first- or second-factor + * authentication. If a requires status is received, get the + * allowed enrollment options for the user. + * @param {string} transactionId The identifier of the transaction received in + * {@link Adaptive#assessPolicy}. + * @param {Object} context The context to send for assessment. + * @param {string} context.sessionId The session ID generated by the + * user-agent, using an Adaptive client SDK. + * @param {string} context.userAgent The user-agent, typically obtained form + * the User-Agent HTTP header. + * @param {string} context.ipAddress The IP address of the user-agent. + * @param {string} [context.evaluationContext="login"] The stage in the + * user-agent for which to perform an evaluation. (Used for continuous + * assessment throughout the user-agent.) Different "stages" or "contexts" + * will result in different evaluation results, as configured in the + * sub-policies of the tenant application's policy. Possible options are + * "login" (default), "landing", "profile", "resume", "highassurance", + * "other". + * @param {string} assertion The JWT assertion to validate. + * @param {string} userId The user ID for which to retrieve enrollments on a + * requires response. + */ + async _validateAssertion(transactionId, context, assertion, userId) { + const policyService = new PolicyService({clientId: this._config.clientId, + clientSecret: this._config.clientSecret}, + this._config.tenantUrl, + context); + + try { + const assessment = await policyService.validate(assertion); + console.log(`[${Adaptive.name}:_validateAssertion(transactionId, ` + + `context, assertion, userId)]`, 'assessment:', assessment); + + if (assessment.scope === 'openid') { + // No 2FA required, return token. + this._transactionFunctions.deleteTransaction(transactionId); + return {status: 'allow', token: assessment}; + } + + // Further 2FA is required. + + // Update the assessment in the transaction. + this._transactionFunctions.updateTransaction(transactionId, {assessment}); + + const factorService = new FactorService( + {accessToken: assessment.access_token}, + this._config.tenantUrl, context); + + // Get Factors enrollments for the current user. + const enrollments = await factorService.getEnrollments(userId); + console.log(`[${Adaptive.name}:_validateAssertion(transactionId, ` + + `context, assertion, userId)]`, 'enrollments:', enrollments); + + // Filter the user's enrollment options based on the assessment's + // `allowedFactors`, if available. + let enrolledFactors = enrollments.factors; + if (assessment.allowedFactors) { + enrolledFactors = enrolledFactors.filter((enrollment) => + assessment.allowedFactors.includes(enrollment.type) || + (assessment.allowedFactors.includes('signatures') && + enrollment.type === 'signature')); + } + + console.log(`[${Adaptive.name}:_validateAssertion(transactionId, ` + + `context, assertion, userId)]`, 'enrolledFactors:', enrolledFactors); + + return {status: 'requires', enrolledFactors, transactionId}; + } catch (error) { + // Deny assessment. + console.log(`[${Adaptive.name}:_validateAssertion(transactionId, ` + + `context, assertion, userId)]`, 'error:', error); + const jsonResp = {status: 'deny'}; + if (error.response.data) { + jsonResp.detail = error.response.data; + } + return jsonResp; + } + } + + /** + * Initiate a QR login first-factor verification. + * @param {Object} context The context to send for assessment. + * @param {string} context.sessionId The session ID generated by the + * user-agent, using an Adaptive client SDK. + * @param {string} context.userAgent The user-agent, typically obtained form + * the User-Agent HTTP header. + * @param {string} context.ipAddress The IP address of the user-agent. + * @param {string} [context.evaluationContext="login"] The stage in the + * user-agent for which to perform an evaluation. (Used for continuous + * assessment throughout the user-agent.) Different "stages" or "contexts" + * will result in different evaluation results, as configured in the + * sub-policies of the tenant application's policy. Possible options are + * "login" (default), "landing", "profile", "resume", "highassurance", + * "other". + * @param {string} transactionId The identifier of the transaction received in + * {@link Adaptive#assessPolicy}. + * @param {string} profileId The identifier of an IBM Verify registration + * profile. Can be retrieved from /v1.0/authenticators/clients. + * @return {Promise} The QR code login verification. + * @example QR code return value + * { + * transactionId: '36a101c7-7426-4f45-ab3c-55f8dc075c6e', + * qr: { + * code: 'iVBORw0KGgoAAAANSUhEUgAAASwAAAEsAQAAAABR...' + * } + * } + */ + async generateQR({sessionId, userAgent, ipAddress, evaluationContext='login'}, + transactionId, profileId) { + const context = {sessionId, userAgent, ipAddress, evaluationContext}; + const transaction = this._transactionFunctions + .getTransaction(transactionId); + + const qrService = new QRService( + {accessToken: transaction.assessment.access_token}, + this._config.tenantUrl, context); + + // Initiate a QR login. + const verification = await qrService.generate(profileId); + console.log(`[${Adaptive.name}:generateQR(context, transactionId, ` + + `profileId)]`, 'verification:', verification); + + // Update transaction in memory cache. + this._transactionFunctions + .updateTransaction(transactionId, {qr: verification}); + + return {transactionId, qr: {code: verification.qrCode}}; + } + + /** + * Evaluate a QR login first-factor verification. + * @param {Object} context The context to send for assessment. + * @param {string} context.sessionId The session ID generated by the + * user-agent, using an Adaptive client SDK. + * @param {string} context.userAgent The user-agent, typically obtained form + * the User-Agent HTTP header. + * @param {string} context.ipAddress The IP address of the user-agent. + * @param {string} [context.evaluationContext="login"] The stage in the + * user-agent for which to perform an evaluation. (Used for continuous + * assessment throughout the user-agent.) Different "stages" or "contexts" + * will result in different evaluation results, as configured in the + * sub-policies of the tenant application's policy. Possible options are + * "login" (default), "landing", "profile", "resume", "highassurance", + * "other". + * @param {string} transactionId The identifier of the transaction received in + * {@link Adaptive#assessPolicy}. + * @return {Promise} Either QR transaction state result object + * (if not complete) or the JWT evaluation result object. + * If QR transaction not complete, the result object has status + * property of pending, timeout, + * or error. + * If QR transaction is complete, the result object has a status + * property of either allow, deny, + * or requires. + * If allow, a token object is also included in the + * result object. + * If deny, a details object is returned if an + * error message was returned from the token endpoint. + * If requires, the allowed second-factor enrollments are + * retrieved and included in the result object, indicating that further + * second-factor authentication is required. + * @example pending result object + * { + * status: 'pending', + * expiry: '2021-04-26T12:06:06.501Z' + * } + * @example pending result object + * { + * status: 'timeout', + * expiry: '2021-04-26T12:06:06.501Z' + * } + * @example error result object + * { + * status: 'error' + * } + * @example allow result object + * { + * status: 'allow', + * token: { + * access_token: 'zscmjBdvIjudOPLhpbmJi6nBRJg7cZ6WY0Udw1nC', + * refresh_token: 'wFTjurPxTvRD1cW09itgQM83XwCm1UKwsxhVFb1H7HJh8JkwZz', + * scope: 'openid', + * grant_id: 'a0b440b6-fefb-46ea-a603-e1040534cd28', + * id_token: 'eyJhbGciOiJSUzI1NiIsInR5cC...5j_rMn7H3ZpE4axt0WvsYu4jbA', + * token_type: 'Bearer', + * expires_in: 7120 + * } + * } + * @example deny result object + * { + * status: 'deny', + * detail: { + * error: 'adaptive_more_info_required', + * error_description: 'CSIAQ0298E Adaptive access...' + * } + * } + * @example requires result object + * { + * status: 'requires', + * transactionId: '36a101c7-7426-4f45-ab3c-55f8dc075c6e', + * enrolledFactors: [ + * { + * id: '61e39f0a-836b-48fa-b4c9-cface6a3ef5a', + * userId: '60300035KP', + * type: 'emailotp', + * created: '2020-06-15T02:51:49.131Z', + * updated: '2020-06-15T03:15:18.896Z', + * attempted: '2020-07-16T04:30:14.066Z', + * enabled: true, + * validated: true, + * attributes: { + * emailAddress: 'email@email.com' + * } + * } + * ] + * } + */ + async evaluateQR({sessionId, userAgent, ipAddress, evaluationContext='login'}, + transactionId) { + const context = {sessionId, userAgent, ipAddress, evaluationContext}; + const transaction = this._transactionFunctions + .getTransaction(transactionId); + if (!transaction.qr) { + throw new TransactionError( + 'This transaction has not initiated a QR login verification.'); + } + const qrService = + new QRService({accessToken: transaction.assessment.access_token}, + this._config.tenantUrl, + context); + + const verification = await qrService.verify(transaction.qr.id, + transaction.qr.dsi); + console.log(`[${Adaptive.name}:evaluateQR(context, transactionId)]`, + 'verification:', verification); + + if (verification.state === 'SUCCESS') { + return this._validateAssertion(transactionId, context, + verification.assertion, verification.userId); + } + + if (verification.state) { + return { + status: verification.state.toLowerCase(), + expiry: verification.expiry, + }; + } else { + return {status: 'error'}; + } + } + + /** + * Get Access Token for a transaction. + * @param {string} transactionId The identifier of the transaction received in + * {@link Adaptive#assessPolicy}. + * @return {string} The Access Token associated with the transaction. + */ + getToken(transactionId) { + const transaction = this._transactionFunctions + .getTransaction(transactionId); + + return transaction.assessment.access_token; + } + + /** + * Complete a TOTP second-factor verification and validate the resulting JWT. + * @param {Object} context The context to send for assessment. + * @param {string} context.sessionId The session ID generated by the + * user-agent, using an Adaptive client SDK. + * @param {string} context.userAgent The user-agent, typically obtained form + * the User-Agent HTTP header. + * @param {string} context.ipAddress The IP address of the user-agent. + * @param {string} [context.evaluationContext="login"] The stage in the + * user-agent for which to perform an evaluation. (Used for continuous + * assessment throughout the user-agent.) Different "stages" or "contexts" + * will result in different evaluation results, as configured in the + * sub-policies of the tenant application's policy. Possible options are + * "login" (default), "landing", "profile", "resume", "highassurance", + * "other". + * @param {string} transactionId The identifier of the transaction received in + * {@link Adaptive#assessPolicy}. + * @param {string} enrollmentId The identifier of the enrollment to perform + * second-factor verification with. + * @param {string} otp The OTP to attempt verification with. + * @return {Promise} The access and refresh tokens which should have + * been received from the JWT validation, along with the status + * property of allow. + */ + async evaluateTOTP({sessionId, userAgent, ipAddress, + evaluationContext='login'}, transactionId, enrollmentId, otp) { + const context = {sessionId, userAgent, ipAddress, evaluationContext}; + const transaction = this._transactionFunctions + .getTransaction(transactionId); + + const totpService = new TOTPService( + {accessToken: transaction.assessment.access_token}, + this._config.tenantUrl, context); + + const verification = await totpService.verify(enrollmentId, otp); + console.log(`[${Adaptive.name}:evaluateTOTP(context, transactionId, ` + + `enrollmentId, otp)]`, 'verification:', verification); + + return this._validateAssertion(transactionId, context, + verification.assertion, verification.userId); + } + + /** + * Request an email OTP. + * @param {Object} context The context to send for assessment. + * @param {string} context.sessionId The session ID generated by the + * user-agent, using an Adaptive client SDK. + * @param {string} context.userAgent The user-agent, typically obtained form + * the User-Agent HTTP header. + * @param {string} context.ipAddress The IP address of the user-agent. + * @param {string} [context.evaluationContext="login"] The stage in the + * user-agent for which to perform an evaluation. (Used for continuous + * assessment throughout the user-agent.) Different "stages" or "contexts" + * will result in different evaluation results, as configured in the + * sub-policies of the tenant application's policy. Possible options are + * "login" (default), "landing", "profile", "resume", "highassurance", + * "other". + * @param {string} transactionId The identifier of the transaction received in + * @param {string} enrollmentId The identifier of the enrollment to perform + * second-factor verification with. + * @return {Promise} The a four-digit correlation associated with the + * verification. It will be prefixed to the one-time password in the Email to + * be sent. + */ + async generateEmailOTP({sessionId, userAgent, ipAddress, + evaluationContext='login'}, transactionId, enrollmentId) { + const context = {sessionId, userAgent, ipAddress, evaluationContext}; + const transaction = this._transactionFunctions + .getTransaction(transactionId); + + const emailOTPService = new EmailOTPService( + {accessToken: transaction.assessment.access_token}, + this._config.tenantUrl, context); + + const verification = await emailOTPService.generate(enrollmentId); + console.log(`[${Adaptive.name}:generateEmailOTP(context, transactionId, ` + + `enrollmentId)]`, 'verification:', verification); + + // Update transaction in memory cache. + this._transactionFunctions.updateTransaction(transactionId, + {emailotp: {enrollmentId, verification}}); + + return {correlation: verification.correlation}; + } + + /** + * Complete an email OTP second-factor verification and validate the resulting + * JWT. + * @param {Object} context The context to send for assessment. + * @param {string} context.sessionId The session ID generated by the + * user-agent, using an Adaptive client SDK. + * @param {string} context.userAgent The user-agent, typically obtained form + * the User-Agent HTTP header. + * @param {string} context.ipAddress The IP address of the user-agent. + * @param {string} [context.evaluationContext="login"] The stage in the + * user-agent for which to perform an evaluation. (Used for continuous + * assessment throughout the user-agent.) Different "stages" or "contexts" + * will result in different evaluation results, as configured in the + * sub-policies of the tenant application's policy. Possible options are + * "login" (default), "landing", "profile", "resume", "highassurance", + * "other". + * @param {string} transactionId The identifier of the transaction received in + * {@link Adaptive#assessPolicy}. + * @param {string} otp The email OTP received in the email after the email OTP + * request in {@link Adaptive#generateEmailOTP}. This OTP shouldn't include + * the correlation prefix (the four digits before the dash). + * @return {Promise} The access and refresh tokens which should have + * been received from the JWT validation, along with the status + * property of allow. + */ + async evaluateEmailOTP({sessionId, userAgent, ipAddress, + evaluationContext='login'}, transactionId, otp) { + const context = {sessionId, userAgent, ipAddress, evaluationContext}; + const transaction = this._transactionFunctions + .getTransaction(transactionId); + if (!transaction.emailotp) { + throw new TransactionError( + 'This transaction has not initiated an email OTP verification.'); + } + + const emailOTPService = new EmailOTPService( + {accessToken: transaction.assessment.access_token}, + this._config.tenantUrl, context); + + const verification = await emailOTPService.verify( + transaction.emailotp.verification.id, transaction.emailotp.enrollmentId, + otp); + console.log(`[${Adaptive.name}:evaluateEmailOTP(context, transactionId, ` + + `otp)]`, 'verification:', verification); + + return this._validateAssertion(transactionId, context, + verification.assertion, verification.userId); + } + + /** + * Request an SMS OTP. + * @param {Object} context The context to send for assessment. + * @param {string} context.sessionId The session ID generated by the + * user-agent, using an Adaptive client SDK. + * @param {string} context.userAgent The user-agent, typically obtained form + * the User-Agent HTTP header. + * @param {string} context.ipAddress The IP address of the user-agent. + * @param {string} [context.evaluationContext="login"] The stage in the + * user-agent for which to perform an evaluation. (Used for continuous + * assessment throughout the user-agent.) Different "stages" or "contexts" + * will result in different evaluation results, as configured in the + * sub-policies of the tenant application's policy. Possible options are + * "login" (default), "landing", "profile", "resume", "highassurance", + * "other". + * @param {string} transactionId The identifier of the transaction received in + * @param {string} enrollmentId The identifier of the enrollment to perform + * second-factor verification with. + * @return {Promise} The a four-digit correlation associated with the + * verification. It will be prefixed to the one-time password in the SMS to be + * sent. + */ + async generateSMSOTP({sessionId, userAgent, ipAddress, + evaluationContext='login'}, transactionId, enrollmentId) { + const context = {sessionId, userAgent, ipAddress, evaluationContext}; + const transaction = this._transactionFunctions + .getTransaction(transactionId); + + const smsOTPService = new SMSOTPService( + {accessToken: transaction.assessment.access_token}, + this._config.tenantUrl, context); + + const verification = await smsOTPService.generate(enrollmentId); + console.log(`[${Adaptive.name}:generateSMSOTP(context, transactionId, ` + + `enrollmentId)]`, 'verification:', verification); + + // Update transaction in memory cache. + this._transactionFunctions.updateTransaction(transactionId, + {smsotp: {enrollmentId, verification}}); + + return {correlation: verification.correlation}; + } + + /** + * Complete an SMS OTP second-factor verification and validate the resulting + * JWT. + * @param {Object} context The context to send for assessment. + * @param {string} context.sessionId The session ID generated by the + * user-agent, using an Adaptive client SDK. + * @param {string} context.userAgent The user-agent, typically obtained form + * the User-Agent HTTP header. + * @param {string} context.ipAddress The IP address of the user-agent. + * @param {string} [context.evaluationContext="login"] The stage in the + * user-agent for which to perform an evaluation. (Used for continuous + * assessment throughout the user-agent.) Different "stages" or "contexts" + * will result in different evaluation results, as configured in the + * sub-policies of the tenant application's policy. Possible options are + * "login" (default), "landing", "profile", "resume", "highassurance", + * "other". + * @param {string} transactionId The identifier of the transaction received in + * {@link Adaptive#assessPolicy}. + * @param {string} otp The SMS OTP received on the phone after the SMS OTP + * request in {@link Adaptive#generateSMSOTP}. This OTP shouldn't include the + * correlation prefix (the four digits before the dash). + * @return {Promise} The access and refresh tokens which should have + * been received from the JWT validation, along with the status + * property of allow. + */ + async evaluateSMSOTP({sessionId, userAgent, ipAddress, + evaluationContext='login'}, transactionId, otp) { + const context = {sessionId, userAgent, ipAddress, evaluationContext}; + const transaction = this._transactionFunctions + .getTransaction(transactionId); + if (!transaction.smsotp) { + throw new TransactionError( + 'This transaction has not initiated an SMS OTP verification.'); + } + + const smsOTPService = new SMSOTPService( + {accessToken: transaction.assessment.access_token}, + this._config.tenantUrl, context); + + const verification = await smsOTPService.verify( + transaction.smsotp.verification.id, transaction.smsotp.enrollmentId, + otp); + console.log(`[${Adaptive.name}:evaluateSMSOTP(context, transactionId, ` + + `otp)]`, 'verification:', verification); + + return this._validateAssertion(transactionId, context, + verification.assertion, verification.userId); + } + + /** + * Request an Voice OTP. + * @param {Object} context The context to send for assessment. + * @param {string} context.sessionId The session ID generated by the + * user-agent, using an Adaptive client SDK. + * @param {string} context.userAgent The user-agent, typically obtained form + * the User-Agent HTTP header. + * @param {string} context.ipAddress The IP address of the user-agent. + * @param {string} [context.evaluationContext="login"] The stage in the + * user-agent for which to perform an evaluation. (Used for continuous + * assessment throughout the user-agent.) Different "stages" or "contexts" + * will result in different evaluation results, as configured in the + * sub-policies of the tenant application's policy. Possible options are + * "login" (default), "landing", "profile", "resume", "highassurance", + * "other". + * @param {string} transactionId The identifier of the transaction received in + * @param {string} enrollmentId The identifier of the enrollment to perform + * second-factor verification with. + * @return {Promise} The a four-digit correlation associated with the + * verification. This is not used by default in a Voice OTP call. + */ + async generateVoiceOTP({sessionId, userAgent, ipAddress, + evaluationContext='login'}, transactionId, enrollmentId) { + const context = {sessionId, userAgent, ipAddress, evaluationContext}; + const transaction = this._transactionFunctions + .getTransaction(transactionId); + + const voiceOTPService = new VoiceOTPService( + {accessToken: transaction.assessment.access_token}, + this._config.tenantUrl, context); + + const verification = await voiceOTPService.generate(enrollmentId); + console.log(`[${Adaptive.name}:generateVoiceOTP(context, transactionId, ` + + `enrollmentId)]`, 'verification:', verification); + + // Update transaction in memory cache. + this._transactionFunctions.updateTransaction(transactionId, + {voiceotp: {enrollmentId, verification}}); + + return {correlation: verification.correlation}; + } + + /** + * Complete an Voice OTP second-factor verification and validate the resulting + * JWT. + * @param {Object} context The context to send for assessment. + * @param {string} context.sessionId The session ID generated by the + * user-agent, using an Adaptive client SDK. + * @param {string} context.userAgent The user-agent, typically obtained form + * the User-Agent HTTP header. + * @param {string} context.ipAddress The IP address of the user-agent. + * @param {string} [context.evaluationContext="login"] The stage in the + * user-agent for which to perform an evaluation. (Used for continuous + * assessment throughout the user-agent.) Different "stages" or "contexts" + * will result in different evaluation results, as configured in the + * sub-policies of the tenant application's policy. Possible options are + * "login" (default), "landing", "profile", "resume", "highassurance", + * "other". + * @param {string} transactionId The identifier of the transaction received in + * {@link Adaptive#assessPolicy}. + * @param {string} otp The Voice OTP received on the phone after the Voice OTP + * request in {@link Adaptive#generateVoiceOTP}. This OTP shouldn't include + * the correlation prefix (the four digits before the dash). + * @return {Promise} The access and refresh tokens which should have + * been received from the JWT validation, along with the status + * property of allow. + */ + async evaluateVoiceOTP({sessionId, userAgent, ipAddress, + evaluationContext='login'}, transactionId, otp) { + const context = {sessionId, userAgent, ipAddress, evaluationContext}; + const transaction = this._transactionFunctions + .getTransaction(transactionId); + if (!transaction.voiceotp) { + throw new TransactionError( + 'This transaction has not initiated an Voice OTP verification.'); + } + + const voiceOTPService = new VoiceOTPService( + {accessToken: transaction.assessment.access_token}, + this._config.tenantUrl, context); + + const verification = await voiceOTPService.verify( + transaction.voiceotp.verification.id, transaction.voiceotp.enrollmentId, + otp); + console.log(`[${Adaptive.name}:evaluateVoiceOTP(context, transactionId, ` + + `otp)]`, 'verification:', verification); + + return this._validateAssertion(transactionId, context, + verification.assertion, verification.userId); + } + + /** + * Request knowledge questions. + * @param {Object} context The context to send for assessment. + * @param {string} context.sessionId The session ID generated by the + * user-agent, using an Adaptive client SDK. + * @param {string} context.userAgent The user-agent, typically obtained form + * the User-Agent HTTP header. + * @param {string} context.ipAddress The IP address of the user-agent. + * @param {string} [context.evaluationContext="login"] The stage in the + * user-agent for which to perform an evaluation. (Used for continuous + * assessment throughout the user-agent.) Different "stages" or "contexts" + * will result in different evaluation results, as configured in the + * sub-policies of the tenant application's policy. Possible options are + * "login" (default), "landing", "profile", "resume", "highassurance", + * "other". + * @param {string} transactionId The identifier of the transaction received in + * {@link Adaptive#assessPolicy}. + * @param {string} enrollmentId The identifier of the enrollment to perform + * second-factor verification with. + * @return {Promise} The knowledge questions to be answered. + * @example Questions generation return value + * { + * transactionId: '36a101c7-7426-4f45-ab3c-55f8dc075c6e', + * questions: [ + * { + * questionKey: 'firstHouseStreet', + * question: 'What was the street name of the first house you lived in?' + * }, + * { + * questionKey: 'bestFriend', + * question: 'What is the first name of your best friend?' + * }, + * { + * questionKey: 'mothersMaidenName', + * question: 'What is your mothers maiden name?' + * } + * ] + * } + */ + async generateQuestions({sessionId, userAgent, ipAddress, + evaluationContext='login'}, transactionId, enrollmentId) { + const context = {sessionId, userAgent, ipAddress, evaluationContext}; + const transaction = this._transactionFunctions + .getTransaction(transactionId); + + const questionsService = new QuestionsService( + {accessToken: transaction.assessment.access_token}, + this._config.tenantUrl, context); + + const verification = await questionsService.generate(enrollmentId); + console.log(`[${Adaptive.name}:generateQuestions(context, transactionId, ` + + `enrollmentId)]`, 'verification:', verification); + + // Update transaction in memory cache. + this._transactionFunctions.updateTransaction(transactionId, {questions: + {enrollmentId, verification}}); + + // Return questions to be answered. + return {transactionId, questions: verification.questions}; + } + + /** + * Complete a knowledge questions second-factor verification and validate the + * resulting JWT. + * @param {Object} context The context to send for assessment. + * @param {string} context.sessionId The session ID generated by the + * user-agent, using an Adaptive client SDK. + * @param {string} context.userAgent The user-agent, typically obtained form + * the User-Agent HTTP header. + * @param {string} context.ipAddress The IP address of the user-agent. + * @param {string} [context.evaluationContext="login"] The stage in the + * user-agent for which to perform an evaluation. (Used for continuous + * assessment throughout the user-agent.) Different "stages" or "contexts" + * will result in different evaluation results, as configured in the + * sub-policies of the tenant application's policy. Possible options are + * "login" (default), "landing", "profile", "resume", "highassurance", + * "other". + * @param {string} transactionId The identifier of the transaction received in + * {@link Adaptive#assessPolicy}. + * @param {Object[]} questions The array of question keys and corresponding + * answers to attempt verification with. + * @param {string} questions[].questionKey The identifier of the question. + * @param {string} questions[].answer The answer to the question. + * @return {Promise} The result of the JWT validation. The result + * object has a status property of allow, and + * returns an access and a refresh token. There is no requires + * status, since this is the last required verification step. + * @throws {TransactionError} The transaction ID hasn't requested a knowledge + * questions verification in {@link Adaptive#generateQuestions}. + * @example allow return value + * { + * status: 'allow', + * token: { + * issued_at: 1420262924658, + * scope: 'READ', + * application_name: 'ce1e94a2-9c3e-42fa-a2c6-1ee01815476b', + * refresh_token_issued_at: 1420262924658, + * expires_in: 1799, + * token_type: 'BearerToken', + * refresh_token: 'fYACGW7OCPtCNDEnRSnqFlEgogboFPMm', + * client_id: '5jUAdGv9pBouF0wOH5keAVI35GBtx3dT', + * access_token: '2l4IQtZXbn5WBJdL6EF7uenOWRsi', + * organization_name: 'My Happy Place', + * refresh_token_expires_in: 86399 + * } + * } + */ + async evaluateQuestions({sessionId, userAgent, ipAddress, + evaluationContext='login'}, transactionId, questions) { + const context = {sessionId, userAgent, ipAddress, evaluationContext}; + const transaction = this._transactionFunctions + .getTransaction(transactionId); + if (!transaction.questions) { + throw new TransactionError( + 'This transaction has not initiated a knowledge questions ' + + 'verification.'); + } + + const questionsService = new QuestionsService( + {accessToken: transaction.assessment.access_token}, + this._config.tenantUrl, context); + + const verification = await questionsService.verify( + transaction.questions.verification.id, + transaction.questions.enrollmentId, questions); + console.log(`[${Adaptive.name}:evaluateQuestions(context, transactionId, ` + + `questions)]`, 'verification:', verification); + + return this._validateAssertion(transactionId, context, + verification.assertion, verification.userId); + } + + /** + * Request a push notification verification. + * @param {Object} context The context to send for assessment. + * @param {string} context.sessionId The session ID generated by the + * user-agent, using an Adaptive client SDK. + * @param {string} context.userAgent The user-agent, typically obtained form + * the User-Agent HTTP header. + * @param {string} context.ipAddress The IP address of the user-agent. + * @param {string} [context.evaluationContext="login"] The stage in the + * user-agent for which to perform an evaluation. (Used for continuous + * assessment throughout the user-agent.) Different "stages" or "contexts" + * will result in different evaluation results, as configured in the + * sub-policies of the tenant application's policy. Possible options are + * "login" (default), "landing", "profile", "resume", "highassurance", + * "other". + * @param {string} transactionId The identifier of the transaction received in + * {@link Adaptive#assessPolicy}. + * @param {string} enrollmentId The identifier of the signature enrollment to + * perform second-factor verification with. + * @param {string} authenticatorId The identifier of the authenticator + * belonging to the signature. + * @param {string} message The verification message to be displayed in-app. + * @param {string} pushNotificationTitle The title to be displayed + * in the push notification banner. + * @param {string} pushNotificationMessage The message to be displayed + * in the push notification banner. + * @param {Object[]} additionalData An array of objects containing + * "name" and "value" attributes to be displayed + * in-app. + * @return {Promise} correlation will contain + * the confirmation number associated with the transaction. This can be + * displayed in the user agent to link transaction to verification request + * in authenticator app. + */ + async generatePush({sessionId, userAgent, ipAddress, + evaluationContext='login'}, transactionId, enrollmentId, authenticatorId, + message, pushNotificationTitle, pushNotificationMessage, additionalData) { + const context = {sessionId, userAgent, ipAddress, evaluationContext}; + const transaction = this._transactionFunctions + .getTransaction(transactionId); + + const pushService = new PushService( + {accessToken: transaction.assessment.access_token}, + this._config.tenantUrl, context); + + const verification = await pushService.generate(enrollmentId, + authenticatorId, message, context.ipAddress, context.userAgent, + pushNotificationTitle, pushNotificationMessage, additionalData); + console.log(`[${Adaptive.name}:generatePush(context, transactionId, ` + + `enrollmentId, authenticatorId, message, pushNotificationTitle, ` + + `pushNotificationMessage, additionalData)]`, + 'verification:', verification); + + // Update transaction in memory cache. + this._transactionFunctions + .updateTransaction(transactionId, {push: verification}); + + return {correlation: verification.id.substr(0, 8)}; + } + + /** + * Attempt a push notification verification. + * @param {Object} context The context to send for assessment. + * @param {string} context.sessionId The session ID generated by the + * user-agent, using an Adaptive client SDK. + * @param {string} context.userAgent The user-agent, typically obtained form + * the User-Agent HTTP header. + * @param {string} context.ipAddress The IP address of the user-agent. + * @param {string} [context.evaluationContext="login"] The stage in the + * user-agent for which to perform an evaluation. (Used for continuous + * assessment throughout the user-agent.) Different "stages" or "contexts" + * will result in different evaluation results, as configured in the + * sub-policies of the tenant application's policy. Possible options are + * "login" (default), "landing", "profile", "resume", "highassurance", + * "other". + * @param {string} transactionId The identifier of the transaction received in + * {@link Adaptive#assessPolicy}. + * @return {Promise} The access and refresh tokens which should have + * been received from the JWT validation, along with the status + * property of allow. + */ + async evaluatePush({sessionId, userAgent, ipAddress, + evaluationContext='login'}, transactionId) { + const context = {sessionId, userAgent, ipAddress, evaluationContext}; + const transaction = this._transactionFunctions + .getTransaction(transactionId); + if (!transaction.push) { + throw new TransactionError( + 'This transaction has not initiated a push verification.'); + } + + const authenticatorId = transaction.push.authenticatorId; + console.log(`[${Adaptive.name}:evaluatePush(transactionId)]`, + 'authenticatorId:', authenticatorId); + + const verificationId = transaction.push.id; + console.log(`[${Adaptive.name}:evaluatePush(transactionId)]`, + 'verificationId:', verificationId); + + const pushService = new PushService( + {accessToken: transaction.assessment.access_token}, + this._config.tenantUrl, + context); + + const verification = await pushService.evaluate(authenticatorId, + verificationId); + console.log(`[${Adaptive.name}:evaluatePush(context, transactionId)]`, + 'verification:', verification); + + if (verification.state === 'VERIFY_SUCCESS') { + return this._validateAssertion(transactionId, context, + verification.assertion, verification.userId); + } + + if (verification.state) { + return { + status: verification.state.toLowerCase(), + expiry: verification.expiryTime, + pushState: verification.pushNotification.sendState, + }; + } else { + return {status: 'error'}; + } + } + + /** + * Revoke the access token from OIDC. + * @param {string} accessToken The access token to revoke from OIDC. + */ + async logout(accessToken) { + const tokenService = new TokenService({clientId: this._config.clientId, + clientSecret: this._config.clientSecret}, this._config.tenantUrl, {}); + + await tokenService.revokeAccessToken(accessToken); + } + + /** + * Initiate an OAuth Refresh flow to obtain updated tokens. + * @param {Object} context The context to send for assessment. + * @param {string} context.sessionId The session ID generated by the + * user-agent, using an Adaptive client SDK. + * @param {string} context.userAgent The user-agent, typically obtained form + * the User-Agent HTTP header. + * @param {string} context.ipAddress The IP address of the user-agent. + * @param {string} [context.evaluationContext="login"] The stage in the + * user-agent for which to perform an evaluation. (Used for continuous + * assessment throughout the user-agent.) Different "stages" or "contexts" + * will result in different evaluation results, as configured in the + * sub-policies of the tenant application's policy. Possible options are + * "login" (default), "landing", "profile", "resume", "highassurance", + * "other". + * @param {string} refreshToken The refresh token to refresh the access token + * with. + * @return {Promise} The policy evaluation result object. The result + * object has a status property of either allow, + * deny, or requires. + * If allow, then token object contains refresh + * response. + * If deny, a details object is returned if an + * error message was returned from the token endpoint. + * If requires, a transaction is created, and the + * transactionId and an array of allowedFactors + * is also included in the result object, indicating that further + * authentication is required. + * @example allow result object + * { + * status: 'allow', + * token: { + * access_token: 'zscmjBdvIjudOPLhpbmJi6nBRJg7cZ6WY0Udw1nC', + * refresh_token: 'wFTjurPxTvRD1cW09itgQM83XwCm1UKwsxhVFb1H7HJh8JkwZz', + * scope: 'openid', + * grant_id: 'a0b440b6-fefb-46ea-a603-e1040534cd28', + * id_token: 'eyJhbGciOiJSUzI1NiIsInR5cC...5j_rMn7H3ZpE4axt0WvsYu4jbA', + * token_type: 'Bearer', + * expires_in: 7120 + * } + * } + * @example deny result object + * { + * status: 'deny', + * detail: { + * error_description: 'CSIAQ0158E The ... is invalid.', + * error: 'invalid_token' + * } + * } + * @example requires result object + * { + * status: 'requires', + * transactionId: '36a101c7-7426-4f45-ab3c-55f8dc075c6e', + * enrolledFactors: [ + * { + * id: '61e39f0a-836b-48fa-b4c9-cface6a3ef5a', + * userId: '60300035KP', + * type: 'emailotp', + * created: '2020-06-15T02:51:49.131Z', + * updated: '2020-06-15T03:15:18.896Z', + * attempted: '2020-07-16T04:30:14.066Z', + * enabled: true, + * validated: true, + * attributes: { + * emailAddress: 'email@email.com' + * } + * } + * ] + * } + */ + async refresh({sessionId, userAgent, ipAddress, evaluationContext='login'}, + refreshToken) { + const context = {sessionId, userAgent, ipAddress, evaluationContext}; + let assessment; + try { + const tokenService = new TokenService({clientId: this._config.clientId, + clientSecret: this._config.clientSecret}, this._config.tenantUrl, + context); + assessment = await tokenService.refreshAccessToken(refreshToken); + + console.log(`[${Adaptive.name}:refresh(refreshToken, ` + + `context)]`, 'assessment:', assessment); + + if (!assessment.allowedFactors) { + // No 2FA required, return token. + return {status: 'allow', token: assessment}; + } + } catch (error) { + // Deny assessment. + console.log(`[${Adaptive.name}:refresh(refreshToken, context)]`, + 'error:', error); + const jsonResp = {status: 'deny'}; + if (error.response.data) { + jsonResp.detail = error.response.data; + } + return jsonResp; + } + // Further 2FA is required. + + // Create transaction and store in memory cache. + const transaction = {assessment}; + const transactionId = this._transactionFunctions + .createTransaction(transaction); + + const factorService = new FactorService( + {accessToken: assessment.access_token}, + this._config.tenantUrl, context); + + // Get Factors enrollments for the current user. + const enrollments = await factorService.getEnrollments(); + console.log(`[${Adaptive.name}:refresh(refreshToken, context)]`, + 'enrollments:', enrollments); + + // Filter the user's enrollment options based on the assessment's + // `allowedFactors`. + const enrolledFactors = enrollments.factors.filter((enrollment) => + assessment.allowedFactors.includes(enrollment.type)); + console.log(`[${Adaptive.name}:refresh(refreshToken, context)]`, + 'enrolledFactors:', enrolledFactors); + + return {status: 'requires', enrolledFactors, transactionId}; + } + + /** + * Introspect a refresh or access token on OIDC. + * @param {string} token The refresh or access token to introspect. + * @param {string} [tokenTypeHint] The token type. This attribute is an + * optional hint about the token that is being introspected. Possible values + * are access_token and refresh_token. + * @return {Promise} An object containing an "active" + * property indicating whether the introspected token is valid or invalid. + * Other properties are also included in the introspection result when the + * "active" status is true. + */ + async introspect(token, tokenTypeHint) { + const tokenService = new TokenService({clientId: this._config.clientId, + clientSecret: this._config.clientSecret}, this._config.tenantUrl, {}); + + return tokenService.introspectToken(token, tokenTypeHint); + } + + /** + * Return an Express middleware to introspect an access token on OIDC. The + * access token to introspect should be in the 'Authorization' header of the + * request. + * @param {Object} [config] The configuration settings used for the token + * introspection middleware. + * @param {number} [config.cacheMaxSize=0] The maximum size of the cache, i.e. + * the maximum number of successful token introspection responses to cache. If + * the cache becomes full, the least-recently-used introspection result will + * be removed. A value of 0 means no maximum size, i.e. infinity. This value + * is ignored after first initialisation (i.e. after first call to function). + * @param {number} [config.cacheTTL=0] The time (in seconds) to cache a + * successful introspection result for. If a successful token introspection + * is done, the result will be cached for the period of time provided, to save + * expensive introspection calls on each subsequent request. A value of 0 will + * cache the introspect response for the lifetime of the token as provided in + * the exp property of the introspect response. + * @param {boolean} [config.denyMFAChallenge=true] A flag indicating + * whether an introspected token response with a scope of + * 'mfa_challenge' should be denied. If true, tokens + * with scope of 'mfa_challenge' will be rejected. + * If false, the scope of tokens will be + * disregarded. + * @return {Function} The Express middleware function. + */ + introspectMiddleware(config={cacheMaxSize: 0, cacheTTL: 0, + denyMFAChallenge: true}) { + return async (req, res, next) => { + try { + if (config.cacheMaxSize === undefined) { + throw new ConfigurationError( + `Cannot find property 'cacheMaxSize' in configuration settings.`); + } else if (config.cacheTTL === undefined) { + throw new ConfigurationError( + `Cannot find property 'cacheTTL' in configuration settings.`); + } else if (config.denyMFAChallenge === undefined) { + throw new ConfigurationError(`Cannot find property ` + + `'denyMFAChallenge' in configuration settings.`); + } + + console.log(`[${Adaptive.name}:introspectMiddleware([config])]`, + 'config.cacheMaxSize:', config.cacheMaxSize); + console.log(`[${Adaptive.name}:introspectMiddleware([config])]`, + 'config.cacheTTL:', config.cacheTTL); + console.log(`[${Adaptive.name}:introspectMiddleware([config])]`, + 'config.denyMFAChallenge:', config.denyMFAChallenge); + + // Initialise a cache for storing introspection results, if not + // initialised already. + if (!this._introspectCache) { + this._introspectCache = new LRU(config.cacheMaxSize); + } + + const authorizationHeader = req.headers['authorization'].split(' '); + const accessToken = authorizationHeader[1]; + if (authorizationHeader[0].toLowerCase() === 'bearer' && accessToken) { + const cachedIntrospectResponse = this._introspectCache + .get(accessToken); + const introspectResponse = cachedIntrospectResponse || + await this.introspect(accessToken, 'access_token'); + console.log(`[${Adaptive.name}:introspectMiddleware([config])]`, + 'introspectResponse:', introspectResponse); + if (introspectResponse && introspectResponse.active && + (introspectResponse.scope !== 'mfa_challenge' || + !config.denyMFAChallenge)) { + // Successful introspection. + // Cache introspection if not cached already. + if (!cachedIntrospectResponse) { + const expiresIn = introspectResponse.exp * 1000 - Date.now(); + const cacheTTLMilliseconds = + (config.cacheTTL === 0 ? expiresIn : config.cacheTTL * 1000); + console.log(`[${Adaptive.name}:introspectMiddleware([config])]`, + 'cacheTTLMilliseconds:', cacheTTLMilliseconds); + this._introspectCache.set(accessToken, introspectResponse, + cacheTTLMilliseconds); + } + next(); + return; + } + } + + throw new TokenError('Token introspection failed.'); + } catch (error) { + next(error); + } + }; + } +} + +module.exports = Adaptive; diff --git a/sdk/adaptive-proxy/lib/errors/configurationError.js b/sdk/adaptive-proxy/lib/errors/configurationError.js new file mode 100644 index 0000000..979c6b4 --- /dev/null +++ b/sdk/adaptive-proxy/lib/errors/configurationError.js @@ -0,0 +1,20 @@ +// Copyright contributors to the IBM Security Verify Adaptive Proxy SDK +// for JavaScript project + +/** + * Indicate that a provided configuration does not contain the + * tenantUrl, clientId, or clientSecret + * properties. + * @author Adam Dorogi-Kaposi + */ +class ConfigurationError extends Error { + /** + * Create a {@link ConfigurationError} object with a custom error message. + * @param {string} message The error message. + */ + constructor(message) { + super(message); + } +} + +module.exports = ConfigurationError; diff --git a/sdk/adaptive-proxy/lib/errors/tokenError.js b/sdk/adaptive-proxy/lib/errors/tokenError.js new file mode 100644 index 0000000..766af64 --- /dev/null +++ b/sdk/adaptive-proxy/lib/errors/tokenError.js @@ -0,0 +1,19 @@ +// Copyright contributors to the IBM Security Verify Adaptive Proxy SDK +// for JavaScript project + +/** + * Indicate that a token is invalid, or a token related operation (e.g. token + * introspection) has failed. + * @author Adam Dorogi-Kaposi + */ +class TokenError extends Error { + /** + * Create a {@link TokenError} object with a custom error message. + * @param {string} message The error message. + */ + constructor(message) { + super(message); + } +} + +module.exports = TokenError; diff --git a/sdk/adaptive-proxy/lib/errors/transactionError.js b/sdk/adaptive-proxy/lib/errors/transactionError.js new file mode 100644 index 0000000..4fde540 --- /dev/null +++ b/sdk/adaptive-proxy/lib/errors/transactionError.js @@ -0,0 +1,19 @@ +// Copyright contributors to the IBM Security Verify Adaptive Proxy SDK +// for JavaScript project + +/** + * Indicate that a transaction associated to the provided transaction ID does + * not exist, or the transaction does not contain a required property. + * @author Adam Dorogi-Kaposi + */ +class TransactionError extends Error { + /** + * Create a {@link TransactionError} object with a custom error message. + * @param {string} message The error message. + */ + constructor(message) { + super(message); + } +} + +module.exports = TransactionError; diff --git a/sdk/adaptive-proxy/lib/index.js b/sdk/adaptive-proxy/lib/index.js new file mode 100644 index 0000000..e5b171e --- /dev/null +++ b/sdk/adaptive-proxy/lib/index.js @@ -0,0 +1,5 @@ +// Copyright contributors to the IBM Security Verify Adaptive Proxy SDK +// for JavaScript project + + +module.exports = require('./adaptive'); diff --git a/sdk/adaptive-proxy/lib/services/factors/emailOTPService.js b/sdk/adaptive-proxy/lib/services/factors/emailOTPService.js new file mode 100644 index 0000000..53b689b --- /dev/null +++ b/sdk/adaptive-proxy/lib/services/factors/emailOTPService.js @@ -0,0 +1,40 @@ +// Copyright contributors to the IBM Security Verify Adaptive Proxy SDK +// for JavaScript project + +const FactorService = require('../factors/factorService'); + + +/** + * A class for making email OTP related requests to OIDC. + * @extends FactorService + * @author Adam Dorogi-Kaposi + */ +class EmailOTPService extends FactorService { + /** + * Request an email OTP multi-factor verification for this enrollment. + * @param {string} enrollmentId The identifier of the email OTP enrollment. + * @return {Promise} The email OTP verification. + */ + async generate(enrollmentId) { + const response = await this.post( + `/v2.0/factors/emailotp/${enrollmentId}/verifications`); + return response.data; + } + + /** + * Attempt to complete an email OTP multi-factor verification. + * @param {string} verificationId The identifier of the email OTP verification + * received in {@link EmailOTPService#generate}. + * @param {string} enrollmentId The identifier of the email OTP enrollment. + * @param {string} otp The OTP to attempt verification with. + * @return {Promise} The HTTP response body of the request. + */ + async verify(verificationId, enrollmentId, otp) { + const response = await this.post(`/v2.0/factors/emailotp/` + + `${enrollmentId}/verifications/${verificationId}`, {otp}, + {returnJwt: true}); + return response.data; + } +} + +module.exports = EmailOTPService; diff --git a/sdk/adaptive-proxy/lib/services/factors/factorService.js b/sdk/adaptive-proxy/lib/services/factors/factorService.js new file mode 100644 index 0000000..e905dce --- /dev/null +++ b/sdk/adaptive-proxy/lib/services/factors/factorService.js @@ -0,0 +1,32 @@ +// Copyright contributors to the IBM Security Verify Adaptive Proxy SDK +// for JavaScript project + +const Service = require('../service'); + + +/** + * A class for making Factors requests. + * @extends Service + * @author Adam Dorogi-Kaposi + */ +class FactorService extends Service { + /** + * Get an email OTP factor enrollment. + * @param {string} userId The identifier of the user for which to retrieve + * enrollments. + * @return {Promise} The array of enrollments for the given user. + */ + async getEnrollments(userId=undefined) { + let response; + if (userId) { + response = await this.get('/v2.0/factors', + {search: `userId="${userId}"&enabled=true`}); + } else { + response = await this.get('/v2.0/factors', + {search: `enabled=true`}); + } + return response.data; + } +} + +module.exports = FactorService; diff --git a/sdk/adaptive-proxy/lib/services/factors/fidoService.js b/sdk/adaptive-proxy/lib/services/factors/fidoService.js new file mode 100644 index 0000000..5173327 --- /dev/null +++ b/sdk/adaptive-proxy/lib/services/factors/fidoService.js @@ -0,0 +1,69 @@ +// Copyright contributors to the IBM Security Verify Adaptive Proxy SDK +// for JavaScript project + + +const FactorService = require('../factors/factorService'); + + +/** + * A class for making FIDO related requests to OIDC. These include initiating + * and completing a FIDO verification. + * @extends FactorService + * @author Adam Dorogi-Kaposi + */ +class FIDOService extends FactorService { + /** + * Initiate a FIDO verification. + * @param {string} relyingPartyId The identifier of a relying party resolved + * in {@link FIDOService#resolveRelyingParty}. + * @param {string} userId The identifier of the OIDC user for which to + * initiate FIDO verification. + * @return {Promise} The assertion options, containing FIDO + * credentials. + */ + async generate(relyingPartyId, userId) { + const response = await this.post(`/v2.0/factors/fido2/relyingparties/` + + `${relyingPartyId}/assertion/options`, {userVerification: 'preferred', + userId}); + return response.data; + } + + /** + * Complete a FIDO verification. + * @param {string} relyingPartyId The identifier of a relying party resolved + * in {@link FIDOService#resolveRelyingParty}. + * @param {string} credentialId The identifier of a FIDO credential received + * in the assertion options in {@link FIDOService#generate}. + * @param {string} clientDataJSON The assertion options received in + * {@link FIDOService#generate}, in Base64 URL encoded format. + * @param {string} authenticatorData The information about the authenticator + * used for the FIDO verification, verified by the signature. + * @param {string} [userHandle] The identifier of the user who owns the + * authenticator used for the FIDO verification. + * @param {string} signature The challenge received in + * {@link FIDOService#generate}, signed by the authenticator used + * for the FIDO verification, in Base64 URL encoded format. + * @return {Promise} The JWT to be validated by OIDC in + * {@link PolicyService#validate}. + */ + async evaluate(relyingPartyId, credentialId, clientDataJSON, + authenticatorData, userHandle, signature) { + const response = await this.post( + `/v2.0/factors/fido2/relyingparties/${relyingPartyId}/assertion/result`, + { + type: 'public-key', + rawId: credentialId, + response: { + clientDataJSON, + authenticatorData, + userHandle, + signature, + }, + id: credentialId, + getClientExtensionResults: {}, + }, {returnJwt: true}); + return response.data; + } +} + +module.exports = FIDOService; diff --git a/sdk/adaptive-proxy/lib/services/factors/passwordService.js b/sdk/adaptive-proxy/lib/services/factors/passwordService.js new file mode 100644 index 0000000..62b6664 --- /dev/null +++ b/sdk/adaptive-proxy/lib/services/factors/passwordService.js @@ -0,0 +1,49 @@ +// Copyright contributors to the IBM Security Verify Adaptive Proxy SDK +// for JavaScript project + + +const FactorService = require('../factors/factorService'); + + +/** + * A class for making password related requests to OIDC. + * @extends FactorService + * @author Adam Dorogi-Kaposi + */ +class PasswordService extends FactorService { + /** + * Lookup identity sources by sourceName (or all password-capable + * sources if sourceName not defined) + * @param {string} sourceName The name of the Identity Source. + * @return {Promise} The array of sources returned. + */ + async lookupIdentitySources(sourceName) { + let response; + if (sourceName) { + response = await this.get( + `/v1.0/authnmethods/password?search=name = "${sourceName}"`); + } else { + response = await this.get('/v1.0/authnmethods/password'); + } + return response.data.password; + } + + /** + * Attempt password authentication with an identity source. + * @param {string} identitySourceId The identifier of an identity source + * resolved in {@link PasswordService#resolveIdentitySource}. + * @param {string} username The username to authenticate as. + * @param {string} password The password to authenticate with. + * @return {Promise} The HTTP response body of the authentication. + * This response body also includes the JWT to be validated by OIDC in + * {@link PolicyService#validate}. + */ + async authenticate(identitySourceId, username, password) { + const response = await this.post( + `/v1.0/authnmethods/password/${identitySourceId}`, + {username, password}, {returnJwt: true}); + return response.data; + } +} + +module.exports = PasswordService; diff --git a/sdk/adaptive-proxy/lib/services/factors/pushService.js b/sdk/adaptive-proxy/lib/services/factors/pushService.js new file mode 100644 index 0000000..39c11b2 --- /dev/null +++ b/sdk/adaptive-proxy/lib/services/factors/pushService.js @@ -0,0 +1,80 @@ +// Copyright contributors to the IBM Security Verify Adaptive Proxy SDK +// for JavaScript project + + +const FactorService = require('../factors/factorService'); + + +/** + * A class for making push notification related requests to OIDC. These include + * initiating and attempting a push notification verification. + * @extends FactorService + * @author Adam Dorogi-Kaposi + */ +class PushService extends FactorService { + /** + * Request a push notification verification. + * @param {string} signatureId The identifier of the signature enrollment to + * perform second-factor verification with. + * @param {string} authenticatorId The identifier of the authenticator + * belonging to the signature. + * @param {string} message The verification message to be displayed in-app. + * @param {string} originIpAddress The IP address from which the + * authentication is attempted. + * @param {string} originUserAgent The user agent from which the + * authentication is attempted. + * @param {string} pushNotificationTitle The title to be displayed + * in the push notification notification banner. + * @param {string} pushNotificationMessage The message to be displayed + * in the push notification banner. + * @param {Object[]} additionalData An array of objects containing + * "name" and "value" attributes to be displayed + * in-app. + * @return {Promise} The HTTP response body of the request. + */ + async generate(signatureId, authenticatorId, message, originIpAddress, + originUserAgent, pushNotificationTitle, pushNotificationMessage, + additionalData) { + const response = await this.post(`/v1.0/authenticators/` + + `${authenticatorId}/verifications`, + { + transactionData: { + message, + originIpAddress, + originUserAgent, + additionalData, + }, + pushNotification: { + title: pushNotificationTitle, + message: pushNotificationMessage, + send: true, + }, + authenticationMethods: [ + { + id: signatureId, + methodType: 'signature', + }, + ], + logic: 'OR', + expiresIn: 120, + }); + return response.data; + } + + /** + * Check status of a push notification verification. + * @param {string} authenticatorId The identifier of the authenticator + * belonging to the signature. + * @param {string} verificationId The identifier of the verification initiated + * in {@link PushService#generate}. + * @return {Promise} The HTTP response body of the request. + */ + async evaluate(authenticatorId, verificationId) { + const response = await this.get(`/v1.0/authenticators/` + + `${authenticatorId}/verifications/${verificationId}`, + {returnJwt: true}); + return response.data; + } +} + +module.exports = PushService; diff --git a/sdk/adaptive-proxy/lib/services/factors/qrService.js b/sdk/adaptive-proxy/lib/services/factors/qrService.js new file mode 100644 index 0000000..b7bd4f1 --- /dev/null +++ b/sdk/adaptive-proxy/lib/services/factors/qrService.js @@ -0,0 +1,42 @@ +// Copyright contributors to the IBM Security Verify Adaptive Proxy SDK +// for JavaScript project + + +const FactorService = require('../factors/factorService'); + + +/** + * A class for making QR login related requests to OIDC. + * @extends FactorService + * @author Adam Dorogi-Kaposi + */ +class QRService extends FactorService { + /** + * Initiate a QR login verification. + * @param {string} profileId The identifier of an IBM Verify registration + * profile. + * @return {Promise} The QR code login verification. + */ + async generate(profileId) { + const response = await this.get('/v2.0/factors/qr/authenticate', + {profileId}); + return response.data; + } + + /** + * Complete a QR login verification. + * @param {string} verificationId The identifier of the QR login verification + * received in {@link QRService#generate}. + * @param {string} dsi The DSI of the QR login verification received in + * {@link QRService#generate}. + * @return {Promise} The HTTP response body of the request. + */ + async verify(verificationId, dsi) { + const response = await this.get( + `/v2.0/factors/qr/authenticate/${verificationId}`, + {dsi: dsi, returnJwt: true}); + return response.data; + } +} + +module.exports = QRService; diff --git a/sdk/adaptive-proxy/lib/services/factors/questionsService.js b/sdk/adaptive-proxy/lib/services/factors/questionsService.js new file mode 100644 index 0000000..e4a2cac --- /dev/null +++ b/sdk/adaptive-proxy/lib/services/factors/questionsService.js @@ -0,0 +1,45 @@ +// Copyright contributors to the IBM Security Verify Adaptive Proxy SDK +// for JavaScript project + + +const FactorService = require('../factors/factorService'); + + +/** + * A class for making knowledge questions related requests to OIDC. + * @extends FactorService + * @author Adam Dorogi-Kaposi + */ +class QuestionsService extends FactorService { + /** + * Request a knowledge questions multi-factor verification for this + * enrollment. + * @param {string} enrollmentId The identifier of the knowledge questions + * enrollment. + * @return {Promise} The knowledge questions verification. + */ + async generate(enrollmentId) { + const response = await this.post( + `/v2.0/factors/questions/${enrollmentId}/verifications`); + return response.data; + } + + /** + * Attempt to complete a knowledge questions multi-factor verification. + * @param {string} verificationId The identifier of the knowledge questions + * verification received in {@link QuestionsService#generate}. + * @param {string} enrollmentId The identifier of the knowledge questions + * enrollment. + * @param {Object[]} questions The array of question keys and corresponding + * answers to attempt verification with. + * @return {Promise} The HTTP response body of the request. + */ + async verify(verificationId, enrollmentId, questions) { + const response = await this.post(`/v2.0/factors/questions/` + + `${enrollmentId}/verifications/${verificationId}`, {questions}, + {returnJwt: true}); + return response.data; + } +} + +module.exports = QuestionsService; diff --git a/sdk/adaptive-proxy/lib/services/factors/smsOTPService.js b/sdk/adaptive-proxy/lib/services/factors/smsOTPService.js new file mode 100644 index 0000000..9e7cbea --- /dev/null +++ b/sdk/adaptive-proxy/lib/services/factors/smsOTPService.js @@ -0,0 +1,41 @@ +// Copyright contributors to the IBM Security Verify Adaptive Proxy SDK +// for JavaScript project + + +const FactorService = require('../factors/factorService'); + + +/** + * A class for making SMS OTP related requests to OIDC. + * @extends FactorService + * @author Adam Dorogi-Kaposi + */ +class SMSOTPService extends FactorService { + /** + * Request an SMS OTP multi-factor verification for this enrollment. + * @param {string} enrollmentId The identifier of the SMS OTP enrollment. + * @return {Promise} The SMS OTP verification. + */ + async generate(enrollmentId) { + const response = await this.post( + `/v2.0/factors/smsotp/${enrollmentId}/verifications`); + return response.data; + } + + /** + * Attempt to complete an SMS OTP multi-factor verification. + * @param {string} verificationId The identifier of the SMS OTP verification + * received in {@link SMSOTPService#generate}. + * @param {string} enrollmentId The identifier of the SMS OTP enrollment. + * @param {string} otp The OTP to attempt verification with. + * @return {Promise} The HTTP response body of the request. + */ + async verify(verificationId, enrollmentId, otp) { + const response = await this.post(`/v2.0/factors/smsotp/` + + `${enrollmentId}/verifications/${verificationId}`, {otp}, + {returnJwt: true}); + return response.data; + } +} + +module.exports = SMSOTPService; diff --git a/sdk/adaptive-proxy/lib/services/factors/totpService.js b/sdk/adaptive-proxy/lib/services/factors/totpService.js new file mode 100644 index 0000000..bc1aa9d --- /dev/null +++ b/sdk/adaptive-proxy/lib/services/factors/totpService.js @@ -0,0 +1,27 @@ +// Copyright contributors to the IBM Security Verify Adaptive Proxy SDK +// for JavaScript project + + +const FactorService = require('../factors/factorService'); + + +/** + * A class for making TOTP related requests to OIDC. + * @extends FactorService + * @author Adam Dorogi-Kaposi + */ +class TOTPService extends FactorService { + /** + * Attempt to complete a TOTP multi-factor verification. + * @param {string} enrollmentId The identifier of the TOTP enrollment. + * @param {string} otp The OTP to attempt verification with. + * @return {Promise} The HTTP response body of the request. + */ + async verify(enrollmentId, otp) { + const response = await this.post( + `/v2.0/factors/totp/${enrollmentId}`, {otp}, {returnJwt: true}); + return response.data; + } +} + +module.exports = TOTPService; diff --git a/sdk/adaptive-proxy/lib/services/factors/voiceOTPService.js b/sdk/adaptive-proxy/lib/services/factors/voiceOTPService.js new file mode 100644 index 0000000..a20ab17 --- /dev/null +++ b/sdk/adaptive-proxy/lib/services/factors/voiceOTPService.js @@ -0,0 +1,41 @@ +// Copyright contributors to the IBM Security Verify Adaptive Proxy SDK +// for JavaScript project + + +const FactorService = require('../factors/factorService'); + + +/** + * A class for making Voice OTP related requests to OIDC. + * @extends FactorService + * @author Adam Dorogi-Kaposi + */ +class VoiceOTPService extends FactorService { + /** + * Request an Voice OTP multi-factor verification for this enrollment. + * @param {string} enrollmentId The identifier of the Voice OTP enrollment. + * @return {Promise} The Voice OTP verification. + */ + async generate(enrollmentId) { + const response = await this.post( + `/v2.0/factors/voiceotp/${enrollmentId}/verifications`); + return response.data; + } + + /** + * Attempt to complete an Voice OTP multi-factor verification. + * @param {string} verificationId The identifier of the Voice OTP verification + * received in {@link VoiceOTPService#generate}. + * @param {string} enrollmentId The identifier of the Voice OTP enrollment. + * @param {string} otp The OTP to attempt verification with. + * @return {Promise} The HTTP response body of the request. + */ + async verify(verificationId, enrollmentId, otp) { + const response = await this.post(`/v2.0/factors/voiceotp/` + + `${enrollmentId}/verifications/${verificationId}`, {otp}, + {returnJwt: true}); + return response.data; + } +} + +module.exports = VoiceOTPService; diff --git a/sdk/adaptive-proxy/lib/services/oidc/policyService.js b/sdk/adaptive-proxy/lib/services/oidc/policyService.js new file mode 100644 index 0000000..bd5db94 --- /dev/null +++ b/sdk/adaptive-proxy/lib/services/oidc/policyService.js @@ -0,0 +1,73 @@ +// Copyright contributors to the IBM Security Verify Adaptive Proxy SDK +// for JavaScript project + + +const Service = require('../service'); + + +/** + * A class for making policy related requests to OIDC. These include the initial + * grant request, as well as validating received JWT assertions. + * @extends Service + * @author Adam Dorogi-Kaposi + */ +class PolicyService extends Service { + /** + * Create a new {@link PolicyService} object. + * @param {Object} auth The credentials to authenticate to OIDC. + * @param {string} baseURL The base URL for the OIDC API. + * @param {Object} context The context to send for assessment. + * @param {string} context.sessionId The session ID generated by the + * user-agent, using an Adaptive client SDK. + * @param {string} context.userAgent The user-agent, typically obtained form + * the User-Agent HTTP header. + * @param {string} context.ipAddress The IP address of the user-agent. + */ + constructor(auth, baseURL, context) { + super(auth, baseURL, context, 'x-www-form-urlencoded'); + } + + /** + * Evaluate the policy attached to the client application. + * + * Request an access token from OIDC with the policyauth + * grant-type. OIDC will in turn evaluate the policy attached to the client + * application, and will respond depending on the outocme of the evaluation. + * The response from OIDC will be one of two statuses: deny, or + * requires. A deny response is indicated by a 401 status code. + * A 200 HTTP status code indicates a requires response. + * @return {Promise} The HTTP response body for a + * requires response from OIDC. + * @throws {Error} A deny response is received. + */ + async assess() { + const response = await this.post('/v1.0/endpoint/default/token', + {grant_type: 'policyauth', scope: 'openid', + context: this._context}); + return response.data; + } + + /** + * Validate a JWT assertion received from a first- or second-factor + * verification on OIDC. + * + * The response from OIDC will be one of three statuses: allow, + * deny, or requires. A deny response is indicated + * by a 401 status code. A 200 HTTP status code indicates an + * allow or requires response. + * @param {string} jwt The JWT assertion to validate. + * @return {Promise} The HTTP response body for an allow + * or requires response from OIDC. + * @throws {Error} A deny response is received. + */ + async validate(jwt) { + const response = await this.post('/v1.0/endpoint/default/token', + {grant_type: 'urn:ietf:params:oauth:grant-type:jwt-bearer', + scope: 'openid', + context: this._context, + assertion: jwt}); + return response.data; + } +} + +module.exports = PolicyService; diff --git a/sdk/adaptive-proxy/lib/services/oidc/tokenService.js b/sdk/adaptive-proxy/lib/services/oidc/tokenService.js new file mode 100644 index 0000000..db23176 --- /dev/null +++ b/sdk/adaptive-proxy/lib/services/oidc/tokenService.js @@ -0,0 +1,71 @@ +// Copyright contributors to the IBM Security Verify Adaptive Proxy SDK +// for JavaScript project + + +const Service = require('../service'); + + +/** + * A class for making token related requests to OIDC. + * @extends Service + * @author Adam Dorogi-Kaposi + */ +class TokenService extends Service { + /** + * Create a new {@link TokenService} object. + * @param {Object} auth The credentials to authenticate to OIDC. + * @param {string} baseURL The base URL for the OIDC API. + * @param {Object} context The context to send for assessment. + * @param {string} context.sessionId The session ID generated by the + * user-agent, using an Adaptive client SDK. + * @param {string} context.userAgent The user-agent, typically obtained form + * the User-Agent HTTP header. + * @param {string} context.ipAddress The IP address of the user-agent. + */ + constructor(auth, baseURL, context) { + super(auth, baseURL, context, 'x-www-form-urlencoded'); + } + + /** + * Revoke an access token. + * @param {string} accessToken The access token to revoke. + */ + async revokeAccessToken(accessToken) { + await this.post('/v1.0/endpoint/default/revoke', + {token: accessToken}); + } + + /** + * Refresh an access token. + * @param {string} refreshToken The refresh token to refresh with. + * @return {Promise} The HTTP response body for the refresh token + * request, containing the new access and refresh tokens. + */ + async refreshAccessToken(refreshToken) { + const response = await this.post('/v1.0/endpoint/default/token', + {grant_type: 'refresh_token', scope: 'openid', + refresh_token: refreshToken, + context: this._context}); + return response.data; + } + + /** + * Introspect an access or refresh token. + * @param {string} token The access or refresh token to introspect. + * @param {string} [tokenTypeHint] The token type. This attribute is an + * optional hint about the token that is being introspected. Possible values + * are access_token and refresh_token. + * @return {Promise} The HTTP response body for the token introspect + * request, which is an object containing an "active" property + * indicating whether the introspected token is valid or invalid. Other + * properties are also included in the introspection result when the + * "active" status is true. + */ + async introspectToken(token, tokenTypeHint) { + const response = await this.post('/v1.0/endpoint/default/introspect', + {token, token_type_hint: tokenTypeHint}); + return response.data; + } +} + +module.exports = TokenService; diff --git a/sdk/adaptive-proxy/lib/services/service.js b/sdk/adaptive-proxy/lib/services/service.js new file mode 100644 index 0000000..a76acc8 --- /dev/null +++ b/sdk/adaptive-proxy/lib/services/service.js @@ -0,0 +1,137 @@ +// Copyright contributors to the IBM Security Verify Adaptive Proxy SDK +// for JavaScript project + + +const base64Utils = require('../utils/base64Utils'); +const securityUtils = require('../utils/securityUtils'); + +const axios = require('axios'); +const querystring = require('querystring'); + + +/** + * A class for making HTTP requests to OIDC. + * @author Adam Dorogi-Kaposi + */ +class Service { + /** + * Create a new {@link Service} object. + * @param {Object} auth The credentials to authenticate to Factors or OIDC. + * Either an accessToken, or a clientId and + * clientSecret may be used for authentication. If an + * accessToken, set this object's + * _authorizationHeader property to Authorization: Bearer + * ${accessToken}. If a clientId and + * clientSecret, Base64 encode the clientId and + * clientSecret, and set this object's + * _authorizationHeader property to Authorization: Basic + * ${Base64(clientId:clientSecret)}. + * @param {string} [auth.accessToken] The access token to authenticate to + * Factors or OIDC. + * @param {string} [auth.clientId] The identifier of the client to + * authenticate to Factors or OIDC. + * @param {string} [auth.clientSecret] The client secret to authenticate to + * Factors or OIDC. + * @param {string} baseURL The base URL for the API, normally the tenant URL. + * @param {Object} context The context to send for assessment. + * @param {string} context.sessionId The session ID generated by the + * user-agent, using an Adaptive client SDK. + * @param {string} context.userAgent The user-agent, typically obtained form + * the User-Agent HTTP header. + * @param {string} context.ipAddress The IP address of the user-agent. + * @param {string} [contentTypeHeader='json'] The type of content to send in + * the requests. Sets the Content-Type header of the requests + * appropriately. + * @param {string} [acceptHeader='json'] The type of content to receive in the + * response. Sets the Accept header of the requests + * appropriately. + */ + constructor(auth, baseURL, context, contentTypeHeader='json', + acceptHeader='json') { + this._baseURL = baseURL; + this._context = base64Utils.base64UrlEncodeObject(context); + this._contentTypeHeader = contentTypeHeader; + this._acceptHeader = acceptHeader; + + if (auth.accessToken) { + this._authorizationHeader = `Bearer ${auth.accessToken}`; + } else if (auth.clientId && auth.clientSecret) { + const base64EncodedCredentials = base64Utils + .base64UrlEncodeString(`${auth.clientId}:${auth.clientSecret}`); + this._authorizationHeader = `Basic ${base64EncodedCredentials}`; + } + + console.log(`[${Service.name}:constructor(auth, baseURL, context, ` + + `contentTypeHeader='json', acceptHeader='json')]`, + 'baseURL:', this._baseURL); + console.log(`[${Service.name}:constructor(auth, baseURL, context, ` + + `contentTypeHeader='json', acceptHeader='json')]`, + 'context:', this._context); + console.log(`[${Service.name}:constructor(auth, baseURL, context, ` + + `contentTypeHeader='json', acceptHeader='json')]`, + 'contentTypeHeader:', this._contentTypeHeader); + console.log(`[${Service.name}:constructor(auth, baseURL, context, ` + + `contentTypeHeader='json', acceptHeader='json')]`, + 'acceptHeader:', this._acceptHeader); + console.log(`[${Service.name}:constructor(auth, baseURL, context, ` + + `contentTypeHeader='json', acceptHeader='json')]`, + 'authorizationHeader:', '****'); + } + + /** + * Send a HTTP GET request. + * @param {string} path The path on the base URL to send the request to. + * @param {Object} params The URL parameters to be sent with the request. + * @return {Promise} The response to the HTTP request. + */ + async get(path, params={}) { + const headers = { + 'Accept': `application/${this._acceptHeader}`, + 'Authorization': this._authorizationHeader, + }; + + console.log(`[${Service.name}:get(path, params={})]`, + 'path:', path); + console.log(`[${Service.name}:get(path, params={})]`, + 'params:', securityUtils.maskObject(params)); + console.log(`[${Service.name}:get(path, params={})]`, + 'headers:', securityUtils.maskObject(headers)); + + return await axios.get(this._baseURL + path, {params, headers}); + } + + /** + * Send a HTTP POST request. + * @param {string} path The path on the base URL to send the request to. + * @param {Object} data The POST body to send with the request. + * @param {Object} params The URL parameters to send with the request. + * @return {Promise} The response to the HTTP request. + */ + async post(path, data={}, params={}) { + const headers = { + 'Accept': `application/${this._acceptHeader}`, + 'Content-Type': `application/${this._contentTypeHeader}`, + 'Authorization': this._authorizationHeader, + }; + + let dataMasked = securityUtils.maskObject(data); + + if (this._contentTypeHeader === 'x-www-form-urlencoded') { + data = querystring.stringify(data); + dataMasked = querystring.stringify(dataMasked); + } + + console.log(`[${Service.name}:post(path, data={}, params={})]`, + 'path:', path); + console.log(`[${Service.name}:post(path, data={}, params={})]`, + 'data:', dataMasked); + console.log(`[${Service.name}:post(path, data={}, params={})]`, + 'params:', securityUtils.maskObject(params)); + console.log(`[${Service.name}:post(path, data={}, params={})]`, + 'headers:', securityUtils.maskObject(headers)); + + return await axios.post(this._baseURL + path, data, {params, headers}); + } +} + +module.exports = Service; diff --git a/sdk/adaptive-proxy/lib/utils/base64Utils.js b/sdk/adaptive-proxy/lib/utils/base64Utils.js new file mode 100644 index 0000000..898d5b4 --- /dev/null +++ b/sdk/adaptive-proxy/lib/utils/base64Utils.js @@ -0,0 +1,27 @@ +// Copyright contributors to the IBM Security Verify Adaptive Proxy SDK +// for JavaScript project + + +/** + * Base64url encode a string. + * @param {string} string The string to encode. + * @return {string} The base64url encoded string. + */ +function base64UrlEncodeString(string) { + return Buffer.from(string).toString('base64') + // For URL safe base64 (base64url) + .replace(/\+/g, '-') + .replace(/\//g, '_') + .replace(/=+$/g, ''); +} + +/** + * Base64url encode the JSON string representation of an object. + * @param {Object} object The object to encode. +* @return {string} The base64url encoded JSON string. + */ +function base64UrlEncodeObject(object) { + return base64UrlEncodeString(JSON.stringify(object)); +} + +module.exports = {base64UrlEncodeObject, base64UrlEncodeString}; diff --git a/sdk/adaptive-proxy/lib/utils/securityUtils.js b/sdk/adaptive-proxy/lib/utils/securityUtils.js new file mode 100644 index 0000000..5cb1e38 --- /dev/null +++ b/sdk/adaptive-proxy/lib/utils/securityUtils.js @@ -0,0 +1,24 @@ +// Copyright contributors to the IBM Security Verify Adaptive Proxy SDK +// for JavaScript project + + +/** + * Mask sensitive properties of an object. + * @param {Object} object The object whose sensitive properties to mask. + * @return {Object} The masked object. + */ +function maskObject(object) { + const sensitiveProperties = ['password', 'otp', 'Authorization', 'assertion', + 'token', 'access_token', 'refresh_token']; + + const clone = {...object}; + for (sensitiveProperty of sensitiveProperties) { + if (clone[sensitiveProperty]) { + clone[sensitiveProperty] = '****'; + } + } + + return clone; +} + +module.exports = {maskObject}; diff --git a/sdk/adaptive-proxy/lib/utils/transactionUtils.js b/sdk/adaptive-proxy/lib/utils/transactionUtils.js new file mode 100644 index 0000000..df6296a --- /dev/null +++ b/sdk/adaptive-proxy/lib/utils/transactionUtils.js @@ -0,0 +1,95 @@ +// Copyright contributors to the IBM Security Verify Adaptive Proxy SDK +// for JavaScript project + + +const TransactionError = require('../errors/transactionError'); + +const NodeCache = require('node-cache'); +const {v4: uuid} = require('uuid'); + + +// Initialise a cache with 10-minute storage. +const cache = new NodeCache({stdTTL: 600}); + +/** + * Create a stored transaction. Associate the given object with a random UUID in + * the cache. + * @param {Object} object The object to store as a transaction. + * @return {string} The randomly generated UUID associated to the new + * transaction. + * @throws {TransactionError} The transaction cannot be stored. + */ +function createTransaction(object) { + const transactionId = uuid(); + if (!cache.set(transactionId, object)) { + throw new TransactionError( + `Could not create transaction with ID ${transactionId}.`); + } + + console.log(`[transactionUtils:createTransaction(object)]`, + 'transactionId:', transactionId); + console.log(`[transactionUtils:createTransaction(object)]`, + 'transaction:', object); + + return transactionId; +} + +/** + * Get a stored transaction. + * @param {string} transactionId The identifier of the transaction. + * @return {Object} The transaction object associated with the identifier. + * @throws {TransactionError} The transaction ID doesn't exist. + */ +function getTransaction(transactionId) { + const transaction = cache.get(transactionId); + if (!transaction) { + throw new TransactionError('Invalid transaction ID provided.'); + } + + console.log(`[transactionUtils:getTransaction(transactionId)]`, + 'transactionId:', transactionId); + console.log(`[transactionUtils:getTransaction(transactionId)]`, + 'transaction:', transaction); + + return transaction; +} + +/** + * Add the given properties to a stored transaction. + * @param {string} transactionId The identifier of the transaction to update. + * @param {Object} properties The properties to add to the transaction. + * @throws {TransactionError} The transaction ID doesn't exist. + */ +function updateTransaction(transactionId, properties) { + const oldTransaction = cache.get(transactionId); + if (!oldTransaction) { + throw new TransactionError('Invalid transaction ID provided.'); + } + const newTransaction = {...oldTransaction, ...properties}; + + console.log(`[transactionUtils:updateTransaction(transactionId, properties)]`, + 'transactionId:', transactionId); + console.log(`[transactionUtils:updateTransaction(transactionId, properties)]`, + 'oldTransaction:', oldTransaction); + console.log(`[transactionUtils:updateTransaction(transactionId, properties)]`, + 'newTransaction:', newTransaction); + + cache.set(transactionId, newTransaction); +} + +/** + * Delete a stored transaction. + * @param {string} transactionId The identifier of the transaction to delete. + * @throws {TransactionError} The transaction ID doesn't exist. + */ +function deleteTransaction(transactionId) { + if (cache.del(transactionId) !== 1) { + throw new TransactionError('Invalid transaction ID provided.'); + } + + console.log(`[transactionUtils:deleteTransaction(transactionId)]`, + 'transactionId:', transactionId); +} + +module.exports = {createTransaction, updateTransaction, getTransaction, + deleteTransaction}; diff --git a/sdk/adaptive-proxy/package-lock.json b/sdk/adaptive-proxy/package-lock.json new file mode 100644 index 0000000..01cce39 --- /dev/null +++ b/sdk/adaptive-proxy/package-lock.json @@ -0,0 +1,1604 @@ +{ + "name": "@ibm-verify/adaptive-proxy", + "version": "1.6.1", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@babel/code-frame": { + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", + "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", + "dev": true, + "requires": { + "@babel/highlight": "^7.10.4" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.14.0", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.0.tgz", + "integrity": "sha512-V3ts7zMSu5lfiwWDVWzRDGIN+lnCEUdaXgtVHJgLb1rGaA6jMrtB9EmE7L18foXJIE8Un/A/h6NJfGQp/e1J4A==", + "dev": true + }, + "@babel/highlight": { + "version": "7.14.0", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.0.tgz", + "integrity": "sha512-YSCOwxvTYEIMSGaBQb5kDDsCopDdiUGsqpatp3fOlI4+2HQSkTmEVWnVuySdAC5EWCqSWWTv0ib63RjR7dTBdg==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.14.0", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "@babel/parser": { + "version": "7.14.1", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.14.1.tgz", + "integrity": "sha512-muUGEKu8E/ftMTPlNp+mc6zL3E9zKWmF5sDHZ5MSsoTP9Wyz64AhEf9kD08xYJ7w6Hdcu8H550ircnPyWSIF0Q==", + "dev": true + }, + "@eslint/eslintrc": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.1.tgz", + "integrity": "sha512-5v7TDE9plVhvxQeWLXDTvFvJBdH6pEsdnl2g/dAptmuFEPedQ4Erq5rsDsX+mvAM610IhNaO2W5V1dOOnDKxkQ==", + "dev": true, + "requires": { + "ajv": "^6.12.4", + "debug": "^4.1.1", + "espree": "^7.3.0", + "globals": "^12.1.0", + "ignore": "^4.0.6", + "import-fresh": "^3.2.1", + "js-yaml": "^3.13.1", + "minimatch": "^3.0.4", + "strip-json-comments": "^3.1.1" + }, + "dependencies": { + "globals": { + "version": "12.4.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", + "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", + "dev": true, + "requires": { + "type-fest": "^0.8.1" + } + }, + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true + } + } + }, + "@ungap/promise-all-settled": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz", + "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==", + "dev": true + }, + "acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "dev": true + }, + "acorn-jsx": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.1.tgz", + "integrity": "sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng==", + "dev": true + }, + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true + }, + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "anymatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "dev": true, + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "dev": true + }, + "axios": { + "version": "0.21.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz", + "integrity": "sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==", + "requires": { + "follow-redirects": "^1.10.0" + } + }, + "balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true + }, + "bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", + "dev": true + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true + }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true + }, + "camelcase": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz", + "integrity": "sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==", + "dev": true + }, + "catharsis": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/catharsis/-/catharsis-0.9.0.tgz", + "integrity": "sha512-prMTQVpcns/tzFgFVkVp6ak6RykZyWb3gu8ckUpd6YkTlacOd3DXGJjIpD4Q6zJirizvaiAjSSHlOsA+6sNh2A==", + "dev": true, + "requires": { + "lodash": "^4.17.15" + } + }, + "chalk": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", + "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "chokidar": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.1.tgz", + "integrity": "sha512-9+s+Od+W0VJJzawDma/gvBNQqkTiqYTWLuZoyAsivsI4AaWTCzHG06/TMjsf1cYe9Cb97UCEhjz7HvnPk2p/tw==", + "dev": true, + "requires": { + "anymatch": "~3.1.1", + "braces": "~3.0.2", + "fsevents": "~2.3.1", + "glob-parent": "~5.1.0", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.5.0" + } + }, + "cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "clone": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", + "integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=" + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "debug": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", + "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "decamelize": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", + "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", + "dev": true + }, + "deep-is": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", + "dev": true + }, + "diff": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", + "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", + "dev": true + }, + "doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "enquirer": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", + "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", + "dev": true, + "requires": { + "ansi-colors": "^4.1.1" + } + }, + "entities": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.0.3.tgz", + "integrity": "sha512-MyoZ0jgnLvB2X3Lg5HqpFmn1kybDiIfEQmKzTb5apr51Rb+T3KdmMiqa70T+bhGnyv7bQ6WMj2QMHpGMmlrUYQ==", + "dev": true + }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true + }, + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true + }, + "eslint": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.26.0.tgz", + "integrity": "sha512-4R1ieRf52/izcZE7AlLy56uIHHDLT74Yzz2Iv2l6kDaYvEu9x+wMB5dZArVL8SYGXSYV2YAg70FcW5Y5nGGNIg==", + "dev": true, + "requires": { + "@babel/code-frame": "7.12.11", + "@eslint/eslintrc": "^0.4.1", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "enquirer": "^2.3.5", + "eslint-scope": "^5.1.1", + "eslint-utils": "^2.1.0", + "eslint-visitor-keys": "^2.0.0", + "espree": "^7.3.1", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "file-entry-cache": "^6.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.0.0", + "globals": "^13.6.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash": "^4.17.21", + "minimatch": "^3.0.4", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "progress": "^2.0.0", + "regexpp": "^3.1.0", + "semver": "^7.2.1", + "strip-ansi": "^6.0.0", + "strip-json-comments": "^3.1.0", + "table": "^6.0.4", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + } + }, + "eslint-config-google": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/eslint-config-google/-/eslint-config-google-0.14.0.tgz", + "integrity": "sha512-WsbX4WbjuMvTdeVL6+J3rK1RGhCTqjsFjX7UMSMgZiyxxaNLkoJENbrGExzERFeoTpGw3F3FypTiWAP9ZXzkEw==", + "dev": true + }, + "eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + } + }, + "eslint-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^1.1.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + } + } + }, + "eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true + }, + "espree": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", + "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", + "dev": true, + "requires": { + "acorn": "^7.4.0", + "acorn-jsx": "^5.3.1", + "eslint-visitor-keys": "^1.3.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + } + } + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + }, + "esquery": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", + "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "dev": true, + "requires": { + "estraverse": "^5.1.0" + }, + "dependencies": { + "estraverse": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "dev": true + } + } + }, + "esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "requires": { + "estraverse": "^5.2.0" + }, + "dependencies": { + "estraverse": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "dev": true + } + } + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, + "file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "requires": { + "flat-cache": "^3.0.4" + } + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "requires": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + } + }, + "flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true + }, + "flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dev": true, + "requires": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + } + }, + "flatted": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.1.1.tgz", + "integrity": "sha512-zAoAQiudy+r5SvnSw3KJy5os/oRJYHzrzja/tBDqrZtNhUw8bt6y8OBzMWcjWr+8liV8Eb6yOhw8WZ7VFZ5ZzA==", + "dev": true + }, + "follow-redirects": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.1.tgz", + "integrity": "sha512-HWqDgT7ZEkqRzBvc2s64vSZ/hfOceEol3ac/7tKwzuvEyWx3/4UegXh5oBOIotkGsObyk3xznnSRVADBgWSQVg==" + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "optional": true + }, + "functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "dev": true + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true + }, + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "globals": { + "version": "13.8.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.8.0.tgz", + "integrity": "sha512-rHtdA6+PDBIjeEvA91rpqzEvk/k3/i7EeNQiryiWuJH0Hw9cpyJMAt2jtbAwUaRdhD+573X4vWw6IcjKPasi9Q==", + "dev": true, + "requires": { + "type-fest": "^0.20.2" + } + }, + "graceful-fs": { + "version": "4.2.6", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", + "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==", + "dev": true + }, + "growl": { + "version": "1.10.5", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", + "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true + }, + "ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true + }, + "import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "requires": { + "binary-extensions": "^2.0.0" + } + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, + "is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "dev": true + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "js2xmlparser": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/js2xmlparser/-/js2xmlparser-4.0.1.tgz", + "integrity": "sha512-KrPTolcw6RocpYjdC7pL7v62e55q7qOMHvLX1UCLc5AAS8qeJ6nukarEJAF2KL2PZxlbGueEbINqZR2bDe/gUw==", + "dev": true, + "requires": { + "xmlcreate": "^2.0.3" + } + }, + "jsdoc": { + "version": "3.6.7", + "resolved": "https://registry.npmjs.org/jsdoc/-/jsdoc-3.6.7.tgz", + "integrity": "sha512-sxKt7h0vzCd+3Y81Ey2qinupL6DpRSZJclS04ugHDNmRUXGzqicMJ6iwayhSA0S0DwwX30c5ozyUthr1QKF6uw==", + "dev": true, + "requires": { + "@babel/parser": "^7.9.4", + "bluebird": "^3.7.2", + "catharsis": "^0.9.0", + "escape-string-regexp": "^2.0.0", + "js2xmlparser": "^4.0.1", + "klaw": "^3.0.0", + "markdown-it": "^10.0.0", + "markdown-it-anchor": "^5.2.7", + "marked": "^2.0.3", + "mkdirp": "^1.0.4", + "requizzle": "^0.2.3", + "strip-json-comments": "^3.1.0", + "taffydb": "2.6.2", + "underscore": "~1.13.1" + }, + "dependencies": { + "escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true + } + } + }, + "jsdoc-fresh": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/jsdoc-fresh/-/jsdoc-fresh-1.1.1.tgz", + "integrity": "sha512-sOHmQlPQ89q1XhUfVH+QgR2vnI80KcD31tKchqp4toaGzcxWIobMOEOOJEivZyQC9JxxcdNebqR1qwjNKg4sfQ==", + "dev": true, + "requires": { + "taffydb": "^2.7.3" + }, + "dependencies": { + "taffydb": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/taffydb/-/taffydb-2.7.3.tgz", + "integrity": "sha1-KtNxaWKUmPylvIQkMJbTzeDsOjQ=", + "dev": true + } + } + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true + }, + "klaw": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/klaw/-/klaw-3.0.0.tgz", + "integrity": "sha512-0Fo5oir+O9jnXu5EefYbVK+mHMBeEVEy2cmctR1O1NECcCkPRreJKrS6Qt/j3KC2C148Dfo9i3pCmCMsdqGr0g==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.9" + } + }, + "levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + } + }, + "linkify-it": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-2.2.0.tgz", + "integrity": "sha512-GnAl/knGn+i1U/wjBz3akz2stz+HrHLsxMwHQGofCDfPvlf+gDKN58UtfmUquTY4/MXeE2x7k19KQmeoZi94Iw==", + "dev": true, + "requires": { + "uc.micro": "^1.0.1" + } + }, + "locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "requires": { + "p-locate": "^5.0.0" + } + }, + "lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "lodash.clonedeep": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=", + "dev": true + }, + "lodash.truncate": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", + "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=", + "dev": true + }, + "log-symbols": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.0.0.tgz", + "integrity": "sha512-FN8JBzLx6CzeMrB0tg6pqlGU1wCrXW+ZXGH481kfsBqer0hToTIiHdjH4Mq8xJUbvATujKCvaREGWpGUionraA==", + "dev": true, + "requires": { + "chalk": "^4.0.0" + } + }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "requires": { + "yallist": "^4.0.0" + } + }, + "markdown-it": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-10.0.0.tgz", + "integrity": "sha512-YWOP1j7UbDNz+TumYP1kpwnP0aEa711cJjrAQrzd0UXlbJfc5aAq0F/PZHjiioqDC1NKgvIMX+o+9Bk7yuM2dg==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "entities": "~2.0.0", + "linkify-it": "^2.0.0", + "mdurl": "^1.0.1", + "uc.micro": "^1.0.5" + } + }, + "markdown-it-anchor": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/markdown-it-anchor/-/markdown-it-anchor-5.3.0.tgz", + "integrity": "sha512-/V1MnLL/rgJ3jkMWo84UR+K+jF1cxNG1a+KwqeXqTIJ+jtA8aWSHuigx8lTzauiIjBDbwF3NcWQMotd0Dm39jA==", + "dev": true + }, + "marked": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/marked/-/marked-2.1.3.tgz", + "integrity": "sha512-/Q+7MGzaETqifOMWYEA7HVMaZb4XbcRfaOzcSsHZEith83KGlvaSG33u0SKu89Mj5h+T8V2hM+8O45Qc5XTgwA==", + "dev": true + }, + "mdurl": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", + "integrity": "sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4=", + "dev": true + }, + "minami": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/minami/-/minami-1.2.3.tgz", + "integrity": "sha1-mbbc37LwpU2hycj3qjoyd4eq+fg=", + "dev": true + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true + }, + "mocha": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-8.4.0.tgz", + "integrity": "sha512-hJaO0mwDXmZS4ghXsvPVriOhsxQ7ofcpQdm8dE+jISUOKopitvnXFQmpRR7jd2K6VBG6E26gU3IAbXXGIbu4sQ==", + "dev": true, + "requires": { + "@ungap/promise-all-settled": "1.1.2", + "ansi-colors": "4.1.1", + "browser-stdout": "1.3.1", + "chokidar": "3.5.1", + "debug": "4.3.1", + "diff": "5.0.0", + "escape-string-regexp": "4.0.0", + "find-up": "5.0.0", + "glob": "7.1.6", + "growl": "1.10.5", + "he": "1.2.0", + "js-yaml": "4.0.0", + "log-symbols": "4.0.0", + "minimatch": "3.0.4", + "ms": "2.1.3", + "nanoid": "3.1.20", + "serialize-javascript": "5.0.1", + "strip-json-comments": "3.1.1", + "supports-color": "8.1.1", + "which": "2.0.2", + "wide-align": "1.1.3", + "workerpool": "6.1.0", + "yargs": "16.2.0", + "yargs-parser": "20.2.4", + "yargs-unparser": "2.0.0" + }, + "dependencies": { + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "js-yaml": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.0.0.tgz", + "integrity": "sha512-pqon0s+4ScYUvX30wxQi3PogGFAlUyH0awepWvwkj4jD4v+ova3RiYw8bmA6x2rDrEaj8i/oWKoRxpVNW+Re8Q==", + "dev": true, + "requires": { + "argparse": "^2.0.1" + } + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "nanoid": { + "version": "3.1.20", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.20.tgz", + "integrity": "sha512-a1cQNyczgKbLX9jwbS/+d7W8fX/RfgYR7lVWwWOGIPNgK2m0MWvrGF6/m4kk6U3QcFMnZf3RIhL0v2Jgh/0Uxw==", + "dev": true + }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, + "node-cache": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/node-cache/-/node-cache-5.1.2.tgz", + "integrity": "sha512-t1QzWwnk4sjLWaQAS8CHgOJ+RAfmHpxFWmc36IWTiWHQfs0w5JDMBS1b1ZxQteo0vVVuWJvIUKHDkkeK7vIGCg==", + "requires": { + "clone": "2.x" + } + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dev": true, + "requires": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + } + }, + "p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "requires": { + "yocto-queue": "^0.1.0" + } + }, + "p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "requires": { + "p-limit": "^3.0.2" + } + }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "requires": { + "callsites": "^3.0.0" + } + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + }, + "picomatch": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.3.tgz", + "integrity": "sha512-KpELjfwcCDUb9PeigTs2mBJzXUPzAuP2oPcA989He8Rte0+YUAjw1JVedDhuTKPkHjSYzMN3npC9luThGYEKdg==", + "dev": true + }, + "prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true + }, + "progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true + }, + "randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "requires": { + "safe-buffer": "^5.1.0" + } + }, + "readdirp": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.5.0.tgz", + "integrity": "sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ==", + "dev": true, + "requires": { + "picomatch": "^2.2.1" + } + }, + "regexpp": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz", + "integrity": "sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==", + "dev": true + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "dev": true + }, + "require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true + }, + "requizzle": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/requizzle/-/requizzle-0.2.3.tgz", + "integrity": "sha512-YanoyJjykPxGHii0fZP0uUPEXpvqfBDxWV7s6GKAiiOsiqhX6vHNyW3Qzdmqp/iq/ExbhaGbVrjB4ruEVSM4GQ==", + "dev": true, + "requires": { + "lodash": "^4.17.14" + } + }, + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true + }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true + }, + "semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "serialize-javascript": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-5.0.1.tgz", + "integrity": "sha512-SaaNal9imEO737H2c05Og0/8LUXG7EnsZyMa8MzkmuHoELfT6txuj0cMqRj6zfPKnmQ1yasR4PCJc8x+M4JSPA==", + "dev": true, + "requires": { + "randombytes": "^2.1.0" + } + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, + "slice-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + } + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "string-width": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", + "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + } + }, + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.0" + } + }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "table": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/table/-/table-6.7.0.tgz", + "integrity": "sha512-SAM+5p6V99gYiiy2gT5ArdzgM1dLDed0nkrWmG6Fry/bUS/m9x83BwpJUOf1Qj/x2qJd+thL6IkIx7qPGRxqBw==", + "dev": true, + "requires": { + "ajv": "^8.0.1", + "lodash.clonedeep": "^4.5.0", + "lodash.truncate": "^4.4.2", + "slice-ansi": "^4.0.0", + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "ajv": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.3.0.tgz", + "integrity": "sha512-RYE7B5An83d7eWnDR8kbdaIFqmKCNsP16ay1hDbJEU+sa0e3H9SebskCt0Uufem6cfAVu7Col6ubcn/W+Sm8/Q==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + } + }, + "json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + } + } + }, + "taffydb": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/taffydb/-/taffydb-2.6.2.tgz", + "integrity": "sha1-fLy2S1oUG2ou/CxdLGe04VCyomg=", + "dev": true + }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + }, + "type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1" + } + }, + "type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true + }, + "uc.micro": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", + "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==", + "dev": true + }, + "underscore": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.1.tgz", + "integrity": "sha512-hzSoAVtJF+3ZtiFX0VgfFPHEDRm7Y/QPjGyNo4TVdnDTdft3tr8hEkD25a1jC+TjTuE7tkHGKkhwCgs9dgBB2g==", + "dev": true + }, + "uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, + "uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" + }, + "v8-compile-cache": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", + "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", + "dev": true + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "wide-align": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", + "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", + "dev": true, + "requires": { + "string-width": "^1.0.2 || 2" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + } + } + }, + "word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true + }, + "workerpool": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.1.0.tgz", + "integrity": "sha512-toV7q9rWNYha963Pl/qyeZ6wG+3nnsyvolaNUS8+R5Wtw6qJPTxIlOP1ZSvcGhEJw+l3HMMmtiNo9Gl61G4GVg==", + "dev": true + }, + "wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "xmlcreate": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/xmlcreate/-/xmlcreate-2.0.3.tgz", + "integrity": "sha512-HgS+X6zAztGa9zIK3Y3LXuJes33Lz9x+YyTxgrkIdabu2vqcGOWwdfCpf1hWLRrd553wd4QCDf6BBO6FfdsRiQ==", + "dev": true + }, + "y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "requires": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + } + }, + "yargs-parser": { + "version": "20.2.4", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", + "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", + "dev": true + }, + "yargs-unparser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", + "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", + "dev": true, + "requires": { + "camelcase": "^6.0.0", + "decamelize": "^4.0.0", + "flat": "^5.0.2", + "is-plain-obj": "^2.1.0" + } + }, + "yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true + } + } +} diff --git a/sdk/adaptive-proxy/package.json b/sdk/adaptive-proxy/package.json new file mode 100644 index 0000000..714df63 --- /dev/null +++ b/sdk/adaptive-proxy/package.json @@ -0,0 +1,42 @@ +{ + "name": "@ibm-verify/adaptive-proxy", + "version": "1.6.1", + "description": "", + "main": "lib/index.js", + "scripts": { + "test": "mocha", + "clean": "rm -r node_modules package-lock.json", + "docs": "rm -r docs 2>/dev/null; npx jsdoc -c ./.jsdoc.json --verbose", + "codecheck": "npx eslint \"**/*.js\"", + "codecheckfix": "npx eslint --fix \"**/*.js\"" + }, + "keywords": [], + "author": "Adam Dorogi-Kaposi ", + "contributors": [ + { + "name": "Lachlan Ashcroft", + "email": "Lachlan.Ashcroft@ibm.com", + "url": "https://github.com/loxstomper" + } + ], + "repository": { + "directory": "sdk/adaptive-proxy", + "type": "git", + "url": "https://github.com/ibm-security-verify/verify-sdk-javascript.git" + }, + "license": "MIT", + "dependencies": { + "axios": "^0.21.1", + "lru-cache": "^6.0.0", + "node-cache": "^5.1.2", + "uuid": "^8.3.2" + }, + "devDependencies": { + "eslint": "^7.20.0", + "eslint-config-google": "^0.14.0", + "jsdoc": "^3.6.6", + "jsdoc-fresh": "^1.1.0", + "minami": "^1.2.3", + "mocha": "^8.3.0" + } +} diff --git a/sdk/adaptive-proxy/test/base64UtilsTest.js b/sdk/adaptive-proxy/test/base64UtilsTest.js new file mode 100644 index 0000000..70bc982 --- /dev/null +++ b/sdk/adaptive-proxy/test/base64UtilsTest.js @@ -0,0 +1,115 @@ +// Copyright contributors to the IBM Security Verify Adaptive Proxy SDK +// for JavaScript project + + +const assert = require('assert'); +const base64Utils = require('../lib/utils/base64Utils'); + + +describe('base64Utils', () => { + describe('#base64UrlEncodeString', () => { + it('should return an empty string when encoding an empty string', () => { + const actual = ''; + const expected = ''; + assert.equal(base64Utils.base64UrlEncodeString(actual), expected); + }); + + it(`should return 'Zg' when encoding 'f'`, () => { + const actual = 'f'; + const expected = 'Zg'; + assert.equal(base64Utils.base64UrlEncodeString(actual), expected); + }); + + it(`should return 'Zm8' when encoding 'fo'`, () => { + const actual = 'fo'; + const expected = 'Zm8'; + assert.equal(base64Utils.base64UrlEncodeString(actual), expected); + }); + + it(`should return 'Zm9v' when encoding 'foo'`, () => { + const actual = 'foo'; + const expected = 'Zm9v'; + assert.equal(base64Utils.base64UrlEncodeString(actual), expected); + }); + + it(`should return 'Zm9vYg' when encoding 'foob'`, () => { + const actual = 'foob'; + const expected = 'Zm9vYg'; + assert.equal(base64Utils.base64UrlEncodeString(actual), expected); + }); + + it(`should return 'Zm9vYmE' when encoding 'fooba'`, () => { + const actual = 'fooba'; + const expected = 'Zm9vYmE'; + assert.equal(base64Utils.base64UrlEncodeString(actual), expected); + }); + + it(`should return 'Zm9vYmFy' when encoding 'foobar'`, () => { + const actual = 'foobar'; + const expected = 'Zm9vYmFy'; + assert.equal(base64Utils.base64UrlEncodeString(actual), expected); + }); + + it(`should return 'eyJ1c2VybmFtZSI6ImFkbWluIiwicGFzc3dvcmQiOiIxMjM0NSJ9' ` + + `when encoding '{"username":"admin","password":"12345"}'`, () => { + const actual = '{"username":"admin","password":"12345"}'; + const expected = 'eyJ1c2VybmFtZSI6ImFkbWluIiwicGFzc3dvcmQiOiIxMjM0NSJ9'; + assert.equal(base64Utils.base64UrlEncodeString(actual), expected); + }); + + it(`should return '8J-YhA' when encoding '😄'`, () => { + const actual = '😄'; + const expected = '8J-YhA'; + assert.equal(base64Utils.base64UrlEncodeString(actual), expected); + }); + }); + + describe('#base64UrlEncodeObject', () => { + it(`should return 'e30' when encoding {}`, () => { + const actual = {}; + const expected = 'e30'; + assert.equal(base64Utils.base64UrlEncodeObject(actual), expected); + }); + + it(`should return 'e30' when encoding {username: undefined}`, () => { + const actual = {username: undefined}; + const expected = 'e30'; + assert.equal(base64Utils.base64UrlEncodeObject(actual), expected); + }); + + it(`should return 'eyJ1c2VybmFtZSI6bnVsbH0' when encoding ` + + `{username: null}`, () => { + const actual = {username: null}; + const expected = 'eyJ1c2VybmFtZSI6bnVsbH0'; + assert.equal(base64Utils.base64UrlEncodeObject(actual), expected); + }); + + it(`should return 'eyJ1c2VybmFtZSI6ImFkbWluIiwicGFzc3dvcmQiOiIxMjM0NSJ9' ` + + `when encoding {username: 'admin', password: '12345'}`, () => { + const actual = {username: 'admin', password: '12345'}; + const expected = 'eyJ1c2VybmFtZSI6ImFkbWluIiwicGFzc3dvcmQiOiIxMjM0NSJ9'; + assert.equal(base64Utils.base64UrlEncodeObject(actual), expected); + }); + + it(`should return 'eyJuYW1lIjoiQWRhbSIsImFnZSI6MjJ9' ` + + `when encoding {name: 'Adam', age: 22}`, () => { + const actual = {name: 'Adam', age: 22}; + const expected = 'eyJuYW1lIjoiQWRhbSIsImFnZSI6MjJ9'; + assert.equal(base64Utils.base64UrlEncodeObject(actual), expected); + }); + + it(`should return 'eyJ1c2VybmFtZSI6Img0eDByXCIsXCJhZG1pblwiOlwidHJ1ZSJ9' ` + + `when encoding {username: 'h4x0r","admin":"true'}`, () => { + const actual = {username: 'h4x0r","admin":"true'}; + const expected = 'eyJ1c2VybmFtZSI6Img0eDByXCIsXCJhZG1pblwiOlwidHJ1ZSJ9'; + assert.equal(base64Utils.base64UrlEncodeObject(actual), expected); + }); + + it(`should return 'eyJlbW9qaSI6IvCfmIQifQ' when encoding ` + + `{emoji: '😄'}`, () => { + const actual = {emoji: '😄'}; + const expected = 'eyJlbW9qaSI6IvCfmIQifQ'; + assert.equal(base64Utils.base64UrlEncodeObject(actual), expected); + }); + }); +}); diff --git a/sdk/adaptive-proxy/test/transactionUtilsTest.js b/sdk/adaptive-proxy/test/transactionUtilsTest.js new file mode 100644 index 0000000..876dc9f --- /dev/null +++ b/sdk/adaptive-proxy/test/transactionUtilsTest.js @@ -0,0 +1,79 @@ +// Copyright contributors to the IBM Security Verify Adaptive Proxy SDK +// for JavaScript project + + +const assert = require('assert'); +const transactionUtils = require('../lib/utils/transactionUtils'); + + +describe('transactionUtils', () => { + describe('#createTransaction', () => { + it('should return a random UUID after creating a transaction', () => { + const transaction = {message: 'Hello, world!'}; + const transactionId = transactionUtils.createTransaction(transaction); + + assert.notEqual(transactionId, undefined); + }); + }); + + describe('#getTransaction', () => { + it('should return a transaction when passed a valid transaction ID', () => { + const transaction = {message: 'Hello, world!'}; + const transactionId = transactionUtils.createTransaction(transaction); + + assert.deepEqual(transactionUtils.getTransaction(transactionId), + transaction); + }); + + it('should throw an error when passed an invalid transaction ID', () => { + const transactionId = '00000000-0000-0000-0000-000000000000'; + + assert.throws(() => transactionUtils.getTransaction(transactionId)); + }); + }); + + describe('#updateTransaction', () => { + it('should add a property to an existing transaction', () => { + const transaction = {message1: 'Hello'}; + const transactionId = transactionUtils.createTransaction(transaction); + + transactionUtils.updateTransaction(transactionId, {message2: 'world!'}); + assert.deepEqual(transactionUtils.getTransaction(transactionId), + {message1: 'Hello', message2: 'world!'}); + }); + + it('should update a property of an existing transaction', () => { + const transaction = {message: 'Hello, world!'}; + const transactionId = transactionUtils.createTransaction(transaction); + + transactionUtils.updateTransaction(transactionId, {message: 'Hello!'}); + assert.deepEqual(transactionUtils.getTransaction(transactionId), + {message: 'Hello!'}); + }); + + it('should throw an error when passed an invalid transaction ID', () => { + const transactionId = '00000000-0000-0000-0000-000000000000'; + + assert.throws(() => transactionUtils.updateTransaction(transactionId, + {message: 'Hello!'})); + }); + }); + + describe('#deleteTransaction', () => { + it('should delete a transaction when passed a valid transaction ID', () => { + const transaction = {message: 'Hello, world!'}; + const transactionId = transactionUtils.createTransaction(transaction); + + assert.deepEqual(transactionUtils.getTransaction(transactionId), + {message: 'Hello, world!'}); + transactionUtils.deleteTransaction(transactionId); + assert.throws(() => transactionUtils.getTransaction(transactionId)); + }); + + it('should throw an error when passed an invalid transaction ID', () => { + const transactionId = '00000000-0000-0000-0000-000000000000'; + + assert.throws(() => transactionUtils.deleteTransaction(transactionId)); + }); + }); +});