diff --git a/src/cli/config-manager/config-manager-pull/config-manager-pull-custom-nodes.ts b/src/cli/config-manager/config-manager-pull/config-manager-pull-custom-nodes.ts new file mode 100644 index 000000000..322aa0a94 --- /dev/null +++ b/src/cli/config-manager/config-manager-pull/config-manager-pull-custom-nodes.ts @@ -0,0 +1,58 @@ +import { frodo } from '@rockcarver/frodo-lib'; +import { Option } from 'commander'; + +import { configManagerExportCustomNodes } from '../../../configManagerOps/FrConfigCustomNodesOps'; +import { getTokens } from '../../../ops/AuthenticateOps'; +import { verboseMessage } from '../../../utils/Console'; +import { FrodoCommand } from '../../FrodoCommand'; + +const { CLOUD_DEPLOYMENT_TYPE_KEY, FORGEOPS_DEPLOYMENT_TYPE_KEY } = + frodo.utils.constants; + +const deploymentTypes = [ + CLOUD_DEPLOYMENT_TYPE_KEY, + FORGEOPS_DEPLOYMENT_TYPE_KEY, +]; + +export default function setup() { + const program = new FrodoCommand( + 'frodo config-manager pull custom-nodes', + [], + deploymentTypes + ); + + program + .description('Export custom nodes.') + .addOption( + new Option( + '-n, --node-name ', + 'Custom node display name. If specified, only one custom node is exported.' + ) + ) + .action(async (host, realm, user, password, options, command) => { + command.handleDefaultArgsAndOpts( + host, + realm, + user, + password, + options, + command + ); + + if (await getTokens(false, true, deploymentTypes)) { + if (options.nodeName) { + verboseMessage( + `Fetching custom node with name '${options.nodeName}'` + ); + } else { + verboseMessage('Fetching custom nodes'); + } + const outcome = await configManagerExportCustomNodes(options.nodeName); + if (!outcome) process.exitCode = 1; + } else { + process.exitCode = 1; + } + }); + + return program; +} diff --git a/src/cli/config-manager/config-manager-pull/config-manager-pull.ts b/src/cli/config-manager/config-manager-pull/config-manager-pull.ts index d27bc80da..fb9327378 100644 --- a/src/cli/config-manager/config-manager-pull/config-manager-pull.ts +++ b/src/cli/config-manager/config-manager-pull/config-manager-pull.ts @@ -10,6 +10,7 @@ import ConnectorMappings from './config-manager-pull-connector-mappings'; import CookieDomains from './config-manager-pull-cookie-domains'; import CORS from './config-manager-pull-cors'; import CSP from './config-manager-pull-csp'; +import CustomNodes from './config-manager-pull-custom-nodes'; import EmailProvider from './config-manager-pull-email-provider'; import EmailTemplates from './config-manager-pull-email-templates'; import Endpoints from './config-manager-pull-endpoints'; @@ -52,6 +53,7 @@ export default function setup() { program.addCommand(CookieDomains().name('cookie-domains')); program.addCommand(CORS().name('cors')); program.addCommand(CSP().name('csp')); + program.addCommand(CustomNodes().name('custom-nodes')); program.addCommand(EmailProvider().name('email-provider')); program.addCommand(EmailTemplates().name('email-templates')); program.addCommand(Endpoints().name('endpoints')); diff --git a/src/configManagerOps/FrConfigCustomNodesOps.ts b/src/configManagerOps/FrConfigCustomNodesOps.ts new file mode 100644 index 000000000..91db0016c --- /dev/null +++ b/src/configManagerOps/FrConfigCustomNodesOps.ts @@ -0,0 +1,47 @@ +import { frodo } from '@rockcarver/frodo-lib'; + +import { printError } from '../utils/Console'; + +const { saveJsonToFile, getFilePath, saveTextToFile } = frodo.utils; +const { readCustomNode, readCustomNodes } = frodo.authn.node; + +/** + * Export all custom nodes to 'custom-nodes/nodes' directory. + * Each custom node will be exported as a JSON file with a reference to its script file. + * The script content will be saved in a separate .js file. + * @param {string} name Optional display name of a custom node to export. If not provided, all custom nodes will be exported. + * @returns {Promise} True if export was successful + */ +export async function configManagerExportCustomNodes( + name?: string +): Promise { + try { + let customNodes; + if (name) { + const customNode = await readCustomNode(undefined, name); + customNodes = [customNode]; + } else { + customNodes = await readCustomNodes(); + } + + for (const node of customNodes) { + const nodeDir = getFilePath( + `custom-nodes/nodes/${node.displayName}/`, + true + ); + const scriptFileName = `${node.displayName}.js`; + const jsonFileName = `${node.displayName}.json`; + + saveTextToFile(`${node.script}`, nodeDir + scriptFileName); + node.script = { file: scriptFileName }; + + const filePath = nodeDir + jsonFileName; + saveJsonToFile(node, filePath, false); + } + + return true; + } catch (error) { + printError(error); + return false; + } +} diff --git a/test/client_cli/en/__snapshots__/config-manager-pull-custom-nodes.test.js.snap b/test/client_cli/en/__snapshots__/config-manager-pull-custom-nodes.test.js.snap new file mode 100644 index 000000000..6c25f6123 --- /dev/null +++ b/test/client_cli/en/__snapshots__/config-manager-pull-custom-nodes.test.js.snap @@ -0,0 +1,30 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`CLI help interface for 'config-manager pull custom-nodes' should be expected english 1`] = ` +"Usage: frodo config-manager pull custom-nodes [options] [host] [realm] [username] [password] + +[Experimental] Export custom nodes. + +Arguments: + host AM base URL, e.g.: + https://cdk.iam.example.com/am. To use a + connection profile, just specify a unique + substring or alias. + realm Realm. Specify realm as '/' for the root realm or + 'realm' or '/parent/child' otherwise. (default: + "alpha" for Identity Cloud tenants, "/" + otherwise.) + username Username to login with. Must be an admin user + with appropriate rights to manage authentication + journeys/trees. + password Password. + +Options: + -n, --node-name Custom node display name. If specified, only one + custom node is exported. + -h, --help Help + -hh, --help-more Help with all options. + -hhh, --help-all Help with all options, environment variables, and + usage examples. +" +`; diff --git a/test/client_cli/en/config-manager-pull-custom-nodes.test.js b/test/client_cli/en/config-manager-pull-custom-nodes.test.js new file mode 100644 index 000000000..a9f4fdaaa --- /dev/null +++ b/test/client_cli/en/config-manager-pull-custom-nodes.test.js @@ -0,0 +1,10 @@ +import cp from 'child_process'; +import { promisify } from 'util'; + +const exec = promisify(cp.exec); +const CMD = 'frodo config-manager pull custom-nodes --help'; +const { stdout } = await exec(CMD); + +test("CLI help interface for 'config-manager pull custom-nodes' should be expected english", async () => { + expect(stdout).toMatchSnapshot(); +}); \ No newline at end of file diff --git a/test/e2e/__snapshots__/config-manager-pull-custom-nodes.e2e.test.js.snap b/test/e2e/__snapshots__/config-manager-pull-custom-nodes.e2e.test.js.snap new file mode 100644 index 000000000..612368810 --- /dev/null +++ b/test/e2e/__snapshots__/config-manager-pull-custom-nodes.e2e.test.js.snap @@ -0,0 +1,1668 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`frodo config-manager pull custom-nodes "frodo config-manager pull custom-nodes -D configManagerPullCustomNodesDir0 -m forgeops": should export all custom-nodes in fr-config manager style. 1`] = `0`; + +exports[`frodo config-manager pull custom-nodes "frodo config-manager pull custom-nodes -D configManagerPullCustomNodesDir0 -m forgeops": should export all custom-nodes in fr-config manager style. 2`] = `""`; + +exports[`frodo config-manager pull custom-nodes "frodo config-manager pull custom-nodes -D configManagerPullCustomNodesDir0 -m forgeops": should export all custom-nodes in fr-config manager style.: configManagerPullCustomNodesDir0/custom-nodes/nodes/ALU/ALU.js 1`] = ` +"var SCRIPT_OUTCOMES = { + SUCCESS: 'Success' +}; + +var OPERATORS = { + ADD: "ADD", + SUBTRACT: "SUBTRACT", + MULTIPLY: "MULTIPLY", + DIVIDE: "DIVIDE" +} + +function main() { + var a = Number(properties.a); + var b = Number(properties.b); + switch (properties.operator) { + case OPERATORS.ADD: + nodeState.putShared("z", a + b); + break; + case OPERATORS.SUBTRACT: + nodeState.putShared("z", a - b); + break; + case OPERATORS.MULTIPLY: + nodeState.putShared("z", a * b); + break; + case OPERATORS.DIVIDE: + if (b == 0) throw new Error("Cannot divide by 0"); + nodeState.putShared("z", a / b); + break; + default: throw new Error("Unknown operator."); + } + action.goTo(SCRIPT_OUTCOMES.SUCCESS); +} + +main(); +" +`; + +exports[`frodo config-manager pull custom-nodes "frodo config-manager pull custom-nodes -D configManagerPullCustomNodesDir0 -m forgeops": should export all custom-nodes in fr-config manager style.: configManagerPullCustomNodesDir0/custom-nodes/nodes/ALU/ALU.json 1`] = ` +{ + "_id": "c6063fb2f5dc42dd9772bedc93898bd8-1", + "description": "Simple ALU that performs basic binary math operations. Expects an "x" and "y" value on the shared state, and will produce a new "z" value on the shared state as output.", + "displayName": "ALU", + "errorOutcome": true, + "inputs": [ + "x", + "y", + ], + "outcomes": [ + "Success", + ], + "outputs": [ + "z", + ], + "properties": { + "operator": { + "defaultValue": "ADD", + "description": "The operation to perform.", + "multivalued": false, + "options": { + "ADD": "+", + "DIVIDE": "/", + "MULTIPLY": "*", + "SUBTRACT": "-", + }, + "required": true, + "title": "Operator", + "type": "STRING", + }, + }, + "script": { + "file": "ALU.js", + }, + "serviceName": "c6063fb2f5dc42dd9772bedc93898bd8", + "tags": [ + "math", + "utilities", + ], +} +`; + +exports[`frodo config-manager pull custom-nodes "frodo config-manager pull custom-nodes -D configManagerPullCustomNodesDir0 -m forgeops": should export all custom-nodes in fr-config manager style.: configManagerPullCustomNodesDir0/custom-nodes/nodes/Display Callback/Display Callback.js 1`] = ` +"var SCRIPT_OUTCOMES = { + OUTCOME: 'outcome' +}; + +var CALLBACKS = { + BOOLEAN_ATTRIBUTE_INPUT_CALLBACK: "BOOLEAN_ATTRIBUTE_INPUT_CALLBACK", + CHOICE_CALLBACK: "CHOICE_CALLBACK", + CONFIRMATION_CALLBACK: "CONFIRMATION_CALLBACK", + CONSENT_MAPPING_CALLBACK: "CONSENT_MAPPING_CALLBACK", + DEVICE_PROFILE_CALLBACK: "DEVICE_PROFILE_CALLBACK", + HIDDEN_VALUE_CALLBACK: "HIDDEN_VALUE_CALLBACK", + HTTP_CALLBACK: "HTTP_CALLBACK", + IDP_CALLBACK: "IDP_CALLBACK", + KBA_CREATE_CALLBACK: "KBA_CREATE_CALLBACK", + LANGUAGE_CALLBACK: "LANGUAGE_CALLBACK", + METADATA_CALLBACK: "METADATA_CALLBACK", + NAME_CALLBACK: "NAME_CALLBACK", + NUMBER_ATTRIBUTE_INPUT_CALLBACK: "NUMBER_ATTRIBUTE_INPUT_CALLBACK", + PASSWORD_CALLBACK: "PASSWORD_CALLBACK", + POLLING_WAIT_CALLBACK: "POLLING_WAIT_CALLBACK", + REDIRECT_CALLBACK: "REDIRECT_CALLBACK", + SCRIPT_TEXT_OUTPUT_CALLBACK: "SCRIPT_TEXT_OUTPUT_CALLBACK", + SELECT_IDP_CALLBACK: "SELECT_IDP_CALLBACK", + STRING_ATTRIBUTE_INPUT_CALLBACK: "STRING_ATTRIBUTE_INPUT_CALLBACK", + SUSPENDED_TEXT_OUTPUT_CALLBACK: "SUSPENDED_TEXT_OUTPUT_CALLBACK", + TERMS_AND_CONDITIONS_CALLBACK: "TERMS_AND_CONDITIONS_CALLBACK", + TEXT_INPUT_CALLBACK: "TEXT_INPUT_CALLBACK", + TEXT_OUTPUT_CALLBACK: "TEXT_OUTPUT_CALLBACK", + VALIDATED_PASSWORD_CALLBACK: "VALIDATED_PASSWORD_CALLBACK", + VALIDATED_USERNAME_CALLBACK: "VALIDATED_USERNAME_CALLBACK", + X509_CERTIFICATE_CALLBACK: "X509_CERTIFICATE_CALLBACK" +} + +function isStringPresent(value) { + return value; +} + +function getString(value) { + return value || ''; +} + +function isArrayPresent(value) { + return value; +} + +function getArray(value) { + return value ? JSON.parse(value) : []; +} + +function isObjectPresent(value) { + return value; +} + +function getObject(value) { + return value ? JSON.parse(value) : {}; +} + +function isIntPresent(value) { + return value; +} + +function getInt(value) { + return value ? parseInt(value) : 0; +} + +function isDoublePresent(value) { + return value; +} + +function getDouble(value) { + return value ? parseFloat(value) : 0.0; +} + +function isBooleanPresent(value) { + return value; +} + +function getBoolean(value) { + return value ? value.toLowerCase() === 'true' : false; +} + +function setProperty(value) { + if (properties.sharedProperty) nodeState.putShared(properties.sharedProperty, value); + if (properties.transientProperty) nodeState.putTransient(properties.transientProperty, value); + if (properties.objectSharedProperty) { + var attributes = {}; + attributes[properties.objectSharedProperty] = value; + nodeState.mergeShared({ + objectAttributes: attributes + }); + } + if (properties.objectTransientProperty) { + var attributes = {}; + attributes[properties.objectTransientProperty] = value; + nodeState.mergeTransient({ + objectAttributes: attributes + }); + } +} + +function booleanAttributeInputCallback() { + var name = getString(properties.options.name); + var prompt = getString(properties.options.prompt); + var value = getBoolean(properties.options.value); + var required = getBoolean(properties.options.required); + var policies = getObject(properties.options.policies); + var validateOnly = getBoolean(properties.options.validateOnly); + var failedPolicies = getArray(properties.options.failedPolicies); + if (isBooleanPresent(properties.options.validateOnly) || isObjectPresent(properties.options.policies)) { + if (isArrayPresent(failedPolicies)) { + callbacksBuilder.booleanAttributeInputCallback(name, prompt, value, required, policies, validateOnly, failedPolicies); + } else { + callbacksBuilder.booleanAttributeInputCallback(name, prompt, value, required, policies, validateOnly); + } + } else if (isArrayPresent(failedPolicies)) { + callbacksBuilder.booleanAttributeInputCallback(name, prompt, value, required, failedPolicies); + } else { + callbacksBuilder.booleanAttributeInputCallback(name, prompt, value, required); + } +} + +function choiceCallback() { + var prompt = getString(properties.options.prompt); + var choices = getArray(properties.options.choices); + var defaultChoice = getInt(properties.options.defaultChoice); + var multipleSelectionsAllowed = getBoolean(properties.options.multipleSelectionsAllowed); + callbacksBuilder.choiceCallback(prompt, choices, defaultChoice, multipleSelectionsAllowed); +} + +function confirmationCallback() { + var prompt = getString(properties.options.prompt); + var messageType = getInt(properties.options.messageType); + var options = getArray(properties.options.options); + var optionType = getInt(properties.options.optionType); + var defaultOption = getInt(properties.options.defaultOption); + if (isStringPresent(properties.options.prompt)) { + if (isIntPresent(properties.options.optionType)) { + callbacksBuilder.confirmationCallback(prompt, messageType, optionType, defaultOption); + } else { + callbacksBuilder.confirmationCallback(prompt, messageType, options, defaultOption); + } + } else { + if (isIntPresent(properties.options.optionType)) { + callbacksBuilder.confirmationCallback(messageType, optionType, defaultOption); + } else { + callbacksBuilder.confirmationCallback(messageType, options, defaultOption); + } + } +} + +function consentMappingCallback() { + var config = getObject(properties.options.config); + var message = getString(properties.options.message); + var isRequired = getBoolean(properties.options.isRequired); + var name = getString(properties.options.name); + var displayName = getString(properties.options.displayName); + var icon = getString(properties.options.icon); + var accessLevel = getString(properties.options.accessLevel); + var titles = getArray(properties.options.titles); + if (isObjectPresent(properties.options.prompt)) { + callbacksBuilder.consentMappingCallback(config, message, isRequired); + } else { + callbacksBuilder.consentMappingCallback(name, displayName, icon, accessLevel, titles, message, isRequired); + } +} + +function deviceProfileCallback() { + var metadata = getBoolean(properties.options.metadata); + var location = getBoolean(properties.options.location); + var message = getString(properties.options.message); + callbacksBuilder.deviceProfileCallback(metadata, location, message); +} + +function hiddenValueCallback() { + var id = getString(properties.options.id); + var value = getString(properties.options.value); + callbacksBuilder.hiddenValueCallback(id, value); +} + +function httpCallback() { + var authorizationHeader = getString(properties.options.authorizationHeader); + var negotiationHeader = getString(properties.options.negotiationHeader); + var authRHeader = getString(properties.options.authRHeader); + var negoName = getString(properties.options.negoName); + var negoValue = getString(properties.options.negoValue); + if (isStringPresent(properties.options.authorizationHeader) || isStringPresent(properties.options.negotiationHeader)) { + var errorCode = getString(properties.options.errorCode); + callbacksBuilder.httpCallback(authorizationHeader, negotiationHeader, errorCode); + } else { + var errorCode = getInt(properties.options.errorCode); + callbacksBuilder.httpCallback(authRHeader, negoName, negoValue, errorCode); + } +} + +function idPCallback() { + var provider = getString(properties.options.provider); + var clientId = getString(properties.options.clientId); + var redirectUri = getString(properties.options.redirectUri); + var scope = getArray(properties.options.scope); + var nonce = getString(properties.options.nonce); + var request = getString(properties.options.request); + var requestUri = getString(properties.options.requestUri); + var acrValues = getArray(properties.options.acrValues); + var requestNativeAppForUserInfo = getBoolean(properties.options.requestNativeAppForUserInfo); + var token = getString(properties.options.token); + var tokenType = getString(properties.options.tokenType); + if (isStringPresent(properties.options.token) || isStringPresent(properties.options.tokenType)) { + callbacksBuilder.idPCallback(provider, clientId, redirectUri, scope, nonce, request, requestUri, acrValues, requestNativeAppForUserInfo, token, tokenType); + } else { + callbacksBuilder.idPCallback(provider, clientId, redirectUri, scope, nonce, request, requestUri, acrValues, requestNativeAppForUserInfo); + } +} + +function kbaCreateCallback() { + var prompt = getString(properties.options.prompt); + var predefinedQuestions = getArray(properties.options.predefinedQuestions); + var allowUserDefinedQuestions = getBoolean(properties.options.allowUserDefinedQuestions); + callbacksBuilder.kbaCreateCallback(prompt, predefinedQuestions, allowUserDefinedQuestions); +} + +function languageCallback() { + var language = getString(properties.options.language); + var country = getString(properties.options.country); + callbacksBuilder.languageCallback(language, country); +} + +function metadataCallback() { + var outputValue = getObject(properties.options.outputValue); + callbacksBuilder.metadataCallback(outputValue); +} + +function nameCallback() { + var prompt = getString(properties.options.prompt); + var defaultName = getString(properties.options.defaultName); + if (isStringPresent(properties.options.defaultName)) { + callbacksBuilder.nameCallback(prompt, defaultName); + } else { + callbacksBuilder.nameCallback(prompt); + } +} + +function numberAttributeInputCallback() { + var name = getString(properties.options.name); + var prompt = getString(properties.options.prompt); + var value = getDouble(properties.options.value); + var required = getBoolean(properties.options.required); + var policies = getObject(properties.options.policies); + var validateOnly = getBoolean(properties.options.validateOnly); + var failedPolicies = getArray(properties.options.failedPolicies); + if (isBooleanPresent(properties.options.validateOnly) || isObjectPresent(properties.options.policies)) { + if (isArrayPresent(failedPolicies)) { + callbacksBuilder.numberAttributeInputCallback(name, prompt, value, required, policies, validateOnly, failedPolicies); + } else { + callbacksBuilder.numberAttributeInputCallback(name, prompt, value, required, policies, validateOnly); + } + } else if (isArrayPresent(failedPolicies)) { + callbacksBuilder.numberAttributeInputCallback(name, prompt, value, required, failedPolicies); + } else { + callbacksBuilder.numberAttributeInputCallback(name, prompt, value, required); + } +} + +function passwordCallback() { + var prompt = getString(properties.options.prompt); + var echoOn = getBoolean(properties.options.echoOn); + callbacksBuilder.passwordCallback(prompt, echoOn); +} + +function pollingWaitCallback() { + var waitTime = getString(properties.options.waitTime); + var message = getString(properties.options.message); + callbacksBuilder.pollingWaitCallback(waitTime, message); +} + +function redirectCallback() { + throw new Error('Not Implemented'); +} + +function scriptTextOutputCallback() { + var message = getString(properties.options.message); + callbacksBuilder.scriptTextOutputCallback(message); +} + +function selectIdPCallback() { + var providers = getObject(properties.options.providers); + callbacksBuilder.selectIdPCallback(providers); +} + +function stringAttributeInputCallback() { + var name = getString(properties.options.name); + var prompt = getString(properties.options.prompt); + var value = getString(properties.options.value); + var required = getBoolean(properties.options.required); + var policies = getObject(properties.options.policies); + var validateOnly = getBoolean(properties.options.validateOnly); + var failedPolicies = getArray(properties.options.failedPolicies); + if (isBooleanPresent(properties.options.validateOnly) || isObjectPresent(properties.options.policies)) { + if (isArrayPresent(failedPolicies)) { + callbacksBuilder.stringAttributeInputCallback(name, prompt, value, required, policies, validateOnly, failedPolicies); + } else { + callbacksBuilder.stringAttributeInputCallback(name, prompt, value, required, policies, validateOnly); + } + } else if (isArrayPresent(failedPolicies)) { + callbacksBuilder.stringAttributeInputCallback(name, prompt, value, required, failedPolicies); + } else { + callbacksBuilder.stringAttributeInputCallback(name, prompt, value, required); + } +} + +function suspendedTextOutputCallback() { + var messageType = getInt(properties.options.messageType); + var message = getString(properties.options.message); + callbacksBuilder.suspendedTextOutputCallback(messageType, message); +} + +function termsAndConditionsCallback() { + var version = getString(properties.options.version); + var terms = getString(properties.options.terms); + var createDate = getString(properties.options.createDate); + callbacksBuilder.termsAndConditionsCallback(version, terms, createDate); +} + +function textInputCallback() { + var prompt = getString(properties.options.prompt); + var defaultText = getString(properties.options.defaultText); + if (isStringPresent(properties.options.defaultText)) { + callbacksBuilder.textInputCallback(prompt, defaultText); + } else { + callbacksBuilder.textInputCallback(prompt); + } +} + +function textOutputCallback() { + var messageType = getString(properties.options.messageType); + var message = getString(properties.options.message); + callbacksBuilder.textOutputCallback(messageType, message); +} + +function validatedPasswordCallback() { + var prompt = getString(properties.options.prompt); + var echoOn = getBoolean(properties.options.echoOn); + var policies = getObject(properties.options.policies); + var validateOnly = getBoolean(properties.options.validateOnly); + var failedPolicies = getArray(properties.options.failedPolicies); + if (isArrayPresent(properties.options.failedPolicies)) { + callbacksBuilder.validatedPasswordCallback(prompt, echoOn, policies, validateOnly, failedPolicies); + } else { + callbacksBuilder.validatedPasswordCallback(prompt, echoOn, policies, validateOnly); + } +} + +function validatedUsernameCallback() { + var prompt = getString(properties.options.prompt); + var policies = getObject(properties.options.policies); + var validateOnly = getBoolean(properties.options.validateOnly); + var failedPolicies = getArray(properties.options.failedPolicies); + if (isArrayPresent(properties.options.failedPolicies)) { + callbacksBuilder.validatedUsernameCallback(prompt, policies, validateOnly, failedPolicies); + } else { + callbacksBuilder.validatedUsernameCallback(prompt, policies, validateOnly); + } +} + +function x509CertificateCallback() { + throw new Error('Not Implemented'); +} + +function getBooleanAttributeInputCallback() { + setProperty(callbacks.getBooleanAttributeInputCallbacks().get(0)); +} + +function getChoiceCallback() { + var multipleSelectionsAllowed = getBoolean(properties.options.multipleSelectionsAllowed); + var selections = callbacks.getChoiceCallbacks().get(0); + setProperty(multipleSelectionsAllowed ? selections : selections[0]); +} + +function getConfirmationCallback() { + setProperty(callbacks.getConfirmationCallbacks().get(0)); +} + +function getConsentMappingCallback() { + setProperty(callbacks.getConsentMappingCallbacks().get(0)); +} + +function getDeviceProfileCallback() { + setProperty(callbacks.getDeviceProfileCallbacks().get(0)); +} + +function getHiddenValueCallback() { + var id = getString(properties.options.id); + setProperty(callbacks.getHiddenValueCallbacks().get(id)); +} + +function getHttpCallback() { + setProperty(callbacks.getHttpCallbacks().get(0)); +} + +function getIdPCallback() { + setProperty(callbacks.getIdpCallbacks().get(0)); +} + +function getKbaCreateCallback() { + setProperty(callbacks.getKbaCreateCallbacks().get(0)); +} + +function getLanguageCallback() { + setProperty(callbacks.getLanguageCallbacks().get(0)); +} + +function getNameCallback() { + setProperty(callbacks.getNameCallbacks().get(0)); +} + +function getNumberAttributeInputCallback() { + setProperty(callbacks.getNumberAttributeInputCallbacks().get(0)); +} + +function getPasswordCallback() { + setProperty(callbacks.getPasswordCallbacks().get(0)); +} + +function getSelectIdPCallback() { + setProperty(callbacks.getSelectIdPCallbacks().get(0)); +} + +function getStringAttributeInputCallback() { + setProperty(callbacks.getStringAttributeInputCallbacks().get(0)); +} + +function getTermsAndConditionsCallback() { + setProperty(callbacks.getTermsAndConditionsCallbacks().get(0)); +} + +function getTextInputCallback() { + setProperty(callbacks.getTextInputCallbacks().get(0)); +} + +function getValidatedPasswordCallback() { + setProperty(callbacks.getValidatedPasswordCallbacks().get(0)); +} + +function getValidatedUsernameCallback() { + setProperty(callbacks.getValidatedUsernameCallbacks().get(0)); +} + +function getX509CertificateCallback() { + setProperty(callbacks.getX509CertificateCallbacks().get(0)); +} + +function main() { + if (!callbacks.isEmpty()) { + switch (properties.callback) { + case CALLBACKS.BOOLEAN_ATTRIBUTE_INPUT_CALLBACK: getBooleanAttributeInputCallback(); break; + case CALLBACKS.CHOICE_CALLBACK: getChoiceCallback(); break; + case CALLBACKS.CONFIRMATION_CALLBACK: getConfirmationCallback(); break; + case CALLBACKS.CONSENT_MAPPING_CALLBACK: getConsentMappingCallback(); break; + case CALLBACKS.DEVICE_PROFILE_CALLBACK: getDeviceProfileCallback(); break; + case CALLBACKS.HIDDEN_VALUE_CALLBACK: getHiddenValueCallback(); break; + case CALLBACKS.HTTP_CALLBACK: getHttpCallback(); break; + case CALLBACKS.IDP_CALLBACK: getIdPCallback(); break; + case CALLBACKS.KBA_CREATE_CALLBACK: getKbaCreateCallback(); break; + case CALLBACKS.LANGUAGE_CALLBACK: getLanguageCallback(); break; + case CALLBACKS.NAME_CALLBACK: getNameCallback(); break; + case CALLBACKS.NUMBER_ATTRIBUTE_INPUT_CALLBACK: getNumberAttributeInputCallback(); break; + case CALLBACKS.PASSWORD_CALLBACK: getPasswordCallback(); break; + case CALLBACKS.SELECT_IDP_CALLBACK: getSelectIdPCallback(); break; + case CALLBACKS.STRING_ATTRIBUTE_INPUT_CALLBACK: getStringAttributeInputCallback(); break; + case CALLBACKS.TERMS_AND_CONDITIONS_CALLBACK: getTermsAndConditionsCallback(); break; + case CALLBACKS.TEXT_INPUT_CALLBACK: getTextInputCallback(); break; + case CALLBACKS.VALIDATED_PASSWORD_CALLBACK: getValidatedPasswordCallback(); break; + case CALLBACKS.VALIDATED_USERNAME_CALLBACK: getValidatedUsernameCallback(); break; + case CALLBACKS.X509_CERTIFICATE_CALLBACK: getX509CertificateCallback(); break; + default: break; + } + action.goTo(SCRIPT_OUTCOMES.OUTCOME); + return; + } + + switch (properties.callback) { + case CALLBACKS.BOOLEAN_ATTRIBUTE_INPUT_CALLBACK: booleanAttributeInputCallback(); break; + case CALLBACKS.CHOICE_CALLBACK: choiceCallback(); break; + case CALLBACKS.CONFIRMATION_CALLBACK: confirmationCallback(); break; + case CALLBACKS.CONSENT_MAPPING_CALLBACK: consentMappingCallback(); break; + case CALLBACKS.DEVICE_PROFILE_CALLBACK: deviceProfileCallback(); break; + case CALLBACKS.HIDDEN_VALUE_CALLBACK: hiddenValueCallback(); break; + case CALLBACKS.HTTP_CALLBACK: httpCallback(); break; + case CALLBACKS.IDP_CALLBACK: idPCallback(); break; + case CALLBACKS.KBA_CREATE_CALLBACK: kbaCreateCallback(); break; + case CALLBACKS.LANGUAGE_CALLBACK: languageCallback(); break; + case CALLBACKS.METADATA_CALLBACK: metadataCallback(); break; + case CALLBACKS.NAME_CALLBACK: nameCallback(); break; + case CALLBACKS.NUMBER_ATTRIBUTE_INPUT_CALLBACK: numberAttributeInputCallback(); break; + case CALLBACKS.PASSWORD_CALLBACK: passwordCallback(); break; + case CALLBACKS.POLLING_WAIT_CALLBACK: pollingWaitCallback(); break; + case CALLBACKS.REDIRECT_CALLBACK: redirectCallback(); break; + case CALLBACKS.SCRIPT_TEXT_OUTPUT_CALLBACK: scriptTextOutputCallback(); break; + case CALLBACKS.SELECT_IDP_CALLBACK: selectIdPCallback(); break; + case CALLBACKS.STRING_ATTRIBUTE_INPUT_CALLBACK: stringAttributeInputCallback(); break; + case CALLBACKS.SUSPENDED_TEXT_OUTPUT_CALLBACK: suspendedTextOutputCallback(); break; + case CALLBACKS.TERMS_AND_CONDITIONS_CALLBACK: termsAndConditionsCallback(); break; + case CALLBACKS.TEXT_INPUT_CALLBACK: textInputCallback(); break; + case CALLBACKS.TEXT_OUTPUT_CALLBACK: textOutputCallback(); break; + case CALLBACKS.VALIDATED_PASSWORD_CALLBACK: validatedPasswordCallback(); break; + case CALLBACKS.VALIDATED_USERNAME_CALLBACK: validatedUsernameCallback(); break; + case CALLBACKS.X509_CERTIFICATE_CALLBACK: x509CertificateCallback(); break; + default: throw new Error('Unknown Callback'); // Should never reach this case + } +} + +main(); +" +`; + +exports[`frodo config-manager pull custom-nodes "frodo config-manager pull custom-nodes -D configManagerPullCustomNodesDir0 -m forgeops": should export all custom-nodes in fr-config manager style.: configManagerPullCustomNodesDir0/custom-nodes/nodes/Display Callback/Display Callback.json 1`] = ` +{ + "_id": "ef81b1a52c914710b3388caebfe7233a-1", + "description": "Displays custom callback to the page", + "displayName": "Display Callback", + "errorOutcome": false, + "inputs": [], + "outcomes": [ + "outcome", + ], + "outputs": [], + "properties": { + "callback": { + "description": "The callback to display", + "multivalued": false, + "options": { + "BOOLEAN_ATTRIBUTE_INPUT_CALLBACK": "booleanAttributeInputCallback", + "CHOICE_CALLBACK": "choiceCallback", + "CONFIRMATION_CALLBACK": "confirmationCallback", + "CONSENT_MAPPING_CALLBACK": "consentMappingCallback", + "DEVICE_PROFILE_CALLBACK": "deviceProfileCallback", + "HIDDEN_VALUE_CALLBACK": "hiddenValueCallback", + "HTTP_CALLBACK": "httpCallback", + "IDP_CALLBACK": "idPCallback", + "KBA_CREATE_CALLBACK": "kbaCreateCallback", + "LANGUAGE_CALLBACK": "languageCallback", + "METADATA_CALLBACK": "metadataCallback", + "NAME_CALLBACK": "nameCallback", + "NUMBER_ATTRIBUTE_INPUT_CALLBACK": "numberAttributeInputCallback", + "PASSWORD_CALLBACK": "passwordCallback", + "POLLING_WAIT_CALLBACK": "pollingWaitCallback", + "REDIRECT_CALLBACK": "redirectCallback", + "SCRIPT_TEXT_OUTPUT_CALLBACK": "scriptTextOutputCallback", + "SELECT_IDP_CALLBACK": "selectIdPCallback", + "STRING_ATTRIBUTE_INPUT_CALLBACK": "stringAttributeInputCallback", + "SUSPENDED_TEXT_OUTPUT_CALLBACK": "suspendedTextOutputCallback", + "TERMS_AND_CONDITIONS_CALLBACK": "termsAndConditionsCallback", + "TEXT_INPUT_CALLBACK": "textInputCallback", + "TEXT_OUTPUT_CALLBACK": "textOutputCallback", + "VALIDATED_PASSWORD_CALLBACK": "validatedPasswordCallback", + "VALIDATED_USERNAME_CALLBACK": "validatedUsernameCallback", + "X509_CERTIFICATE_CALLBACK": "x509CertificateCallback", + }, + "required": true, + "title": "Callback", + "type": "STRING", + }, + "objectSharedProperty": { + "description": "The objectAttributes property on the shared state to put the callback input into (if applicable)", + "multivalued": false, + "required": false, + "title": "Object Attributes Shared Property", + "type": "STRING", + }, + "objectTransientProperty": { + "description": "The objectAttributes property on the transient state to put the callback input into (if applicable)", + "multivalued": false, + "required": false, + "title": "Object Attributes Transient Property", + "type": "STRING", + }, + "options": { + "description": "The options containing the parameters for the callback (see documentation for possible parameters: https://docs.pingidentity.com/pingoneaic/latest/am-scripting/scripting-api-node.html#scripting-api-node-callbacks). + +For example, for textOutputCallback, the options could be: { messageType: 0, message: "Hello World!" }. + +Note that for required parameters that are not specified in the options will use default values based on the type of the parameter ("" for Strings, [] for Arrays, {} for Objects, 0 for Ints, 0.0 for Doubles, and false for Booleans).", + "multivalued": false, + "required": true, + "title": "Options", + "type": "OBJECT", + }, + "sharedProperty": { + "description": "The shared state property to put the callback input into (if applicable)", + "multivalued": false, + "required": false, + "title": "Shared State Property", + "type": "STRING", + }, + "transientProperty": { + "description": "The transient state property to put the callback input into (if applicable)", + "multivalued": false, + "required": false, + "title": "Transient State Property", + "type": "STRING", + }, + }, + "script": { + "file": "Display Callback.js", + }, + "serviceName": "ef81b1a52c914710b3388caebfe7233a", + "tags": [ + "callback", + "utilities", + ], +} +`; + +exports[`frodo config-manager pull custom-nodes "frodo config-manager pull custom-nodes -D configManagerPullCustomNodesDir0 -m forgeops": should export all custom-nodes in fr-config manager style.: configManagerPullCustomNodesDir0/custom-nodes/nodes/Display State/Display State.js 1`] = ` +"var SCRIPT_OUTCOMES = { + OUTCOME: "outcome" +}; + +function main() { + if (!callbacks.isEmpty()) { + action.goTo(SCRIPT_OUTCOMES.OUTCOME); + return; + } + var keySet = nodeState.keys(); // Java Set + var keys = Array.from(keySet); // Make it into JavaScript array + debugState = {}; + for (var i in keys) { + var k = new String(keys[i]); + var item = nodeState.get(k); + if (typeof item === "object") { + debugState[k] = nodeState.getObject(k); + } else { + debugState[k] = nodeState.get(k); + } + } + if (properties.displayFormat === "JSON") { + callbacksBuilder.textOutputCallback(0, \`
\${JSON.stringify(debugState, null, 2)}
\`); + return; + } + callbacksBuilder.textOutputCallback(0, \`\${Array.from(Object.keys(debugState).map(k => \`\`))}
KeyValue
\${k}
\${debugState[k]}
\`); +} + +main(); +" +`; + +exports[`frodo config-manager pull custom-nodes "frodo config-manager pull custom-nodes -D configManagerPullCustomNodesDir0 -m forgeops": should export all custom-nodes in fr-config manager style.: configManagerPullCustomNodesDir0/custom-nodes/nodes/Display State/Display State.json 1`] = ` +{ + "_id": "8ab9f1aad4b4460a9c45d15fb148e221-1", + "description": "Debug node that displays the shared and transient state of the journey for debugging purposes.", + "displayName": "Display State", + "errorOutcome": false, + "inputs": [], + "outcomes": [ + "outcome", + ], + "outputs": [], + "properties": { + "displayFormat": { + "defaultValue": "TABLE", + "description": "The format in which to display the states.", + "multivalued": false, + "options": { + "JSON": "Raw JSON", + "TABLE": "HTML Table", + }, + "required": true, + "title": "Display Format", + "type": "STRING", + }, + }, + "script": { + "file": "Display State.js", + }, + "serviceName": "8ab9f1aad4b4460a9c45d15fb148e221", + "tags": [ + "debug", + "testing", + ], +} +`; + +exports[`frodo config-manager pull custom-nodes "frodo config-manager pull custom-nodes -D configManagerPullCustomNodesDir0 -m forgeops": should export all custom-nodes in fr-config manager style.: configManagerPullCustomNodesDir0/custom-nodes/nodes/Generate JWT/Generate JWT.js 1`] = ` +"var aud = properties.audience; +var iss = properties.issuer; +var validity = properties.validity; +var esv = properties.signingkey; + +var signingkey = systemEnv.getProperty(esv); + +var username = nodeState.get("username"); + +var data = { + jwtType:"SIGNED", + jwsAlgorithm: "HS256", + issuer: iss, + subject: username, + audience: aud, + type: "JWT", + validityMinutes: validity, + signingKey: signingkey +}; + +var jwt = jwtAssertion.generateJwt(data); + +if (jwt !== null && jwt.length > 0) { + nodeState.putShared("assertionJwt" , jwt); + action.goTo("True"); +} else { + action.goTo("False"); +} +" +`; + +exports[`frodo config-manager pull custom-nodes "frodo config-manager pull custom-nodes -D configManagerPullCustomNodesDir0 -m forgeops": should export all custom-nodes in fr-config manager style.: configManagerPullCustomNodesDir0/custom-nodes/nodes/Generate JWT/Generate JWT.json 1`] = ` +{ + "_id": "e5ad0110c8ee4dafaae983003cd05d4a-1", + "description": "Generate a signed JWT using the HMAC SHA-256 algorithm.", + "displayName": "Generate JWT", + "errorOutcome": true, + "inputs": [], + "outcomes": [ + "True", + "False", + ], + "outputs": [], + "properties": { + "audience": { + "description": "The audience (aud) claim", + "multivalued": false, + "required": true, + "title": "Audience", + "type": "STRING", + }, + "issuer": { + "description": "The issuer (iss) claim", + "multivalued": false, + "required": true, + "title": "Issuer", + "type": "STRING", + }, + "signingkey": { + "defaultValue": "esv.signing.key", + "description": "The secret label for the HMAC signing key", + "multivalued": false, + "required": true, + "title": "HMAC Signing Key", + "type": "STRING", + }, + "validity": { + "defaultValue": 5, + "description": "", + "multivalued": false, + "required": true, + "title": "Validity (minutes)", + "type": "NUMBER", + }, + }, + "script": { + "file": "Generate JWT.js", + }, + "serviceName": "e5ad0110c8ee4dafaae983003cd05d4a", + "tags": [ + "Utilities", + "utilities", + ], +} +`; + +exports[`frodo config-manager pull custom-nodes "frodo config-manager pull custom-nodes -D configManagerPullCustomNodesDir0 -m forgeops": should export all custom-nodes in fr-config manager style.: configManagerPullCustomNodesDir0/custom-nodes/nodes/Has Session AM/Has Session AM.js 1`] = ` +"var SCRIPT_OUTCOMES = { + TRUE: 'True', + FALSE: 'False' +} + +function main() { + action.goTo(typeof existingSession === "undefined" ? SCRIPT_OUTCOMES.FALSE : SCRIPT_OUTCOMES.TRUE); +} + +main(); +" +`; + +exports[`frodo config-manager pull custom-nodes "frodo config-manager pull custom-nodes -D configManagerPullCustomNodesDir0 -m forgeops": should export all custom-nodes in fr-config manager style.: configManagerPullCustomNodesDir0/custom-nodes/nodes/Has Session AM/Has Session AM.json 1`] = ` +{ + "_id": "session-1", + "description": "Checks if the user has a current session.", + "displayName": "Has Session AM", + "errorOutcome": false, + "inputs": [], + "outcomes": [ + "True", + "False", + ], + "outputs": [], + "properties": {}, + "script": { + "file": "Has Session AM.js", + }, + "serviceName": "session", + "tags": [ + "utilities", + ], +} +`; + +exports[`frodo config-manager pull custom-nodes "frodo config-manager pull custom-nodes -D configManagerPullCustomNodesDir0 -m forgeops": should export all custom-nodes in fr-config manager style.: configManagerPullCustomNodesDir0/custom-nodes/nodes/Has Session/Has Session.js 1`] = ` +"var SCRIPT_OUTCOMES = { + TRUE: 'True', + FALSE: 'False' +} + +function main() { + action.goTo(typeof existingSession === "undefined" ? SCRIPT_OUTCOMES.FALSE : SCRIPT_OUTCOMES.TRUE); +} + +main(); +" +`; + +exports[`frodo config-manager pull custom-nodes "frodo config-manager pull custom-nodes -D configManagerPullCustomNodesDir0 -m forgeops": should export all custom-nodes in fr-config manager style.: configManagerPullCustomNodesDir0/custom-nodes/nodes/Has Session/Has Session.json 1`] = ` +{ + "_id": "c605506774a848f7877b4d17a453bd39-1", + "description": "Checks if the user has a current session.", + "displayName": "Has Session", + "errorOutcome": false, + "inputs": [], + "outcomes": [ + "True", + "False", + ], + "outputs": [], + "properties": {}, + "script": { + "file": "Has Session.js", + }, + "serviceName": "c605506774a848f7877b4d17a453bd39", + "tags": [ + "utilities", + ], +} +`; + +exports[`frodo config-manager pull custom-nodes "frodo config-manager pull custom-nodes -D configManagerPullCustomNodesDir0 -m forgeops": should export all custom-nodes in fr-config manager style.: configManagerPullCustomNodesDir0/custom-nodes/nodes/Vector ALU/Vector ALU.js 1`] = ` +"var SCRIPT_OUTCOMES = { + SUCCESS: 'Success' +}; + +var OPERATORS = { + ADD: "ADD", + SUBTRACT: "SUBTRACT", + DOT: "DOT", + CROSS: "CROSS" +} + +function add(a, b) { + return a.map((v, i) => v + b[i]); +} + +function subtract(a, b) { + return a.map((v, i) => v - b[i]); +} + +function dot(a, b) { + return a.reduce((sum, v, i) => sum + v * b[i], 0); +} + +function cross(a, b) { + return [ + a[1] * b[2] - a[2] * b[1], + a[2] * b[0] - a[0] * b[2], + a[0] * b[1] - a[1] * b[0] + ]; +} + +function main() { + if (properties.a.length !== properties.b.length) throw new Error("Vectors not the same dimension."); + switch (properties.operator) { + case OPERATORS.ADD: + nodeState.putShared("c", add(properties.a, properties.b)); + break; + case OPERATORS.SUBTRACT: + nodeState.putShared("c", subtract(properties.a, properties.b)); + break; + case OPERATORS.DOT: + nodeState.putShared("c", dot(properties.a, properties.b)); + break; + case OPERATORS.CROSS: + if (properties.a.length !== 3) throw new Error("Vectors not dimension 3 for cross product"); + nodeState.putShared("c", cross(properties.a, properties.b)); + break; + default: throw new Error("Unknown operator."); + } + action.goTo(SCRIPT_OUTCOMES.SUCCESS); +} + +main(); +" +`; + +exports[`frodo config-manager pull custom-nodes "frodo config-manager pull custom-nodes -D configManagerPullCustomNodesDir0 -m forgeops": should export all custom-nodes in fr-config manager style.: configManagerPullCustomNodesDir0/custom-nodes/nodes/Vector ALU/Vector ALU.json 1`] = ` +{ + "_id": "c15e2efb3deb4d4ea338c74a6440b69f-1", + "description": "Simple ALU that performs basic binary vector math operations. Outputs the result onto the shared state with key "c".", + "displayName": "Vector ALU", + "errorOutcome": true, + "inputs": [], + "outcomes": [ + "Success", + ], + "outputs": [ + "c", + ], + "properties": { + "a": { + "defaultValue": [ + 1, + 2, + 3, + ], + "description": "Left vector operand", + "multivalued": true, + "required": true, + "title": "A", + "type": "NUMBER", + }, + "b": { + "defaultValue": [ + 4, + 5, + 6, + ], + "description": "Right vector operand", + "multivalued": true, + "required": true, + "title": "B", + "type": "NUMBER", + }, + "operator": { + "defaultValue": "DOT", + "description": "The binary operation to perform on the vectors.", + "multivalued": false, + "options": { + "ADD": "+", + "CROSS": "X", + "DOT": ".", + "SUBTRACT": "-", + }, + "required": true, + "title": "Operator", + "type": "STRING", + }, + }, + "script": { + "file": "Vector ALU.js", + }, + "serviceName": "c15e2efb3deb4d4ea338c74a6440b69f", + "tags": [ + "math", + "vector", + "utilities", + ], +} +`; + +exports[`frodo config-manager pull custom-nodes "frodo config-manager pull custom-nodes -D configManagerPullCustomNodesDir1 -n 'Display Callback' -m forgeops": should export custom node named: Display Callback 1`] = `0`; + +exports[`frodo config-manager pull custom-nodes "frodo config-manager pull custom-nodes -D configManagerPullCustomNodesDir1 -n 'Display Callback' -m forgeops": should export custom node named: Display Callback 2`] = `""`; + +exports[`frodo config-manager pull custom-nodes "frodo config-manager pull custom-nodes -D configManagerPullCustomNodesDir1 -n 'Display Callback' -m forgeops": should export custom node named: Display Callback: configManagerPullCustomNodesDir1/custom-nodes/nodes/Display Callback/Display Callback.js 1`] = ` +"var SCRIPT_OUTCOMES = { + OUTCOME: 'outcome' +}; + +var CALLBACKS = { + BOOLEAN_ATTRIBUTE_INPUT_CALLBACK: "BOOLEAN_ATTRIBUTE_INPUT_CALLBACK", + CHOICE_CALLBACK: "CHOICE_CALLBACK", + CONFIRMATION_CALLBACK: "CONFIRMATION_CALLBACK", + CONSENT_MAPPING_CALLBACK: "CONSENT_MAPPING_CALLBACK", + DEVICE_PROFILE_CALLBACK: "DEVICE_PROFILE_CALLBACK", + HIDDEN_VALUE_CALLBACK: "HIDDEN_VALUE_CALLBACK", + HTTP_CALLBACK: "HTTP_CALLBACK", + IDP_CALLBACK: "IDP_CALLBACK", + KBA_CREATE_CALLBACK: "KBA_CREATE_CALLBACK", + LANGUAGE_CALLBACK: "LANGUAGE_CALLBACK", + METADATA_CALLBACK: "METADATA_CALLBACK", + NAME_CALLBACK: "NAME_CALLBACK", + NUMBER_ATTRIBUTE_INPUT_CALLBACK: "NUMBER_ATTRIBUTE_INPUT_CALLBACK", + PASSWORD_CALLBACK: "PASSWORD_CALLBACK", + POLLING_WAIT_CALLBACK: "POLLING_WAIT_CALLBACK", + REDIRECT_CALLBACK: "REDIRECT_CALLBACK", + SCRIPT_TEXT_OUTPUT_CALLBACK: "SCRIPT_TEXT_OUTPUT_CALLBACK", + SELECT_IDP_CALLBACK: "SELECT_IDP_CALLBACK", + STRING_ATTRIBUTE_INPUT_CALLBACK: "STRING_ATTRIBUTE_INPUT_CALLBACK", + SUSPENDED_TEXT_OUTPUT_CALLBACK: "SUSPENDED_TEXT_OUTPUT_CALLBACK", + TERMS_AND_CONDITIONS_CALLBACK: "TERMS_AND_CONDITIONS_CALLBACK", + TEXT_INPUT_CALLBACK: "TEXT_INPUT_CALLBACK", + TEXT_OUTPUT_CALLBACK: "TEXT_OUTPUT_CALLBACK", + VALIDATED_PASSWORD_CALLBACK: "VALIDATED_PASSWORD_CALLBACK", + VALIDATED_USERNAME_CALLBACK: "VALIDATED_USERNAME_CALLBACK", + X509_CERTIFICATE_CALLBACK: "X509_CERTIFICATE_CALLBACK" +} + +function isStringPresent(value) { + return value; +} + +function getString(value) { + return value || ''; +} + +function isArrayPresent(value) { + return value; +} + +function getArray(value) { + return value ? JSON.parse(value) : []; +} + +function isObjectPresent(value) { + return value; +} + +function getObject(value) { + return value ? JSON.parse(value) : {}; +} + +function isIntPresent(value) { + return value; +} + +function getInt(value) { + return value ? parseInt(value) : 0; +} + +function isDoublePresent(value) { + return value; +} + +function getDouble(value) { + return value ? parseFloat(value) : 0.0; +} + +function isBooleanPresent(value) { + return value; +} + +function getBoolean(value) { + return value ? value.toLowerCase() === 'true' : false; +} + +function setProperty(value) { + if (properties.sharedProperty) nodeState.putShared(properties.sharedProperty, value); + if (properties.transientProperty) nodeState.putTransient(properties.transientProperty, value); + if (properties.objectSharedProperty) { + var attributes = {}; + attributes[properties.objectSharedProperty] = value; + nodeState.mergeShared({ + objectAttributes: attributes + }); + } + if (properties.objectTransientProperty) { + var attributes = {}; + attributes[properties.objectTransientProperty] = value; + nodeState.mergeTransient({ + objectAttributes: attributes + }); + } +} + +function booleanAttributeInputCallback() { + var name = getString(properties.options.name); + var prompt = getString(properties.options.prompt); + var value = getBoolean(properties.options.value); + var required = getBoolean(properties.options.required); + var policies = getObject(properties.options.policies); + var validateOnly = getBoolean(properties.options.validateOnly); + var failedPolicies = getArray(properties.options.failedPolicies); + if (isBooleanPresent(properties.options.validateOnly) || isObjectPresent(properties.options.policies)) { + if (isArrayPresent(failedPolicies)) { + callbacksBuilder.booleanAttributeInputCallback(name, prompt, value, required, policies, validateOnly, failedPolicies); + } else { + callbacksBuilder.booleanAttributeInputCallback(name, prompt, value, required, policies, validateOnly); + } + } else if (isArrayPresent(failedPolicies)) { + callbacksBuilder.booleanAttributeInputCallback(name, prompt, value, required, failedPolicies); + } else { + callbacksBuilder.booleanAttributeInputCallback(name, prompt, value, required); + } +} + +function choiceCallback() { + var prompt = getString(properties.options.prompt); + var choices = getArray(properties.options.choices); + var defaultChoice = getInt(properties.options.defaultChoice); + var multipleSelectionsAllowed = getBoolean(properties.options.multipleSelectionsAllowed); + callbacksBuilder.choiceCallback(prompt, choices, defaultChoice, multipleSelectionsAllowed); +} + +function confirmationCallback() { + var prompt = getString(properties.options.prompt); + var messageType = getInt(properties.options.messageType); + var options = getArray(properties.options.options); + var optionType = getInt(properties.options.optionType); + var defaultOption = getInt(properties.options.defaultOption); + if (isStringPresent(properties.options.prompt)) { + if (isIntPresent(properties.options.optionType)) { + callbacksBuilder.confirmationCallback(prompt, messageType, optionType, defaultOption); + } else { + callbacksBuilder.confirmationCallback(prompt, messageType, options, defaultOption); + } + } else { + if (isIntPresent(properties.options.optionType)) { + callbacksBuilder.confirmationCallback(messageType, optionType, defaultOption); + } else { + callbacksBuilder.confirmationCallback(messageType, options, defaultOption); + } + } +} + +function consentMappingCallback() { + var config = getObject(properties.options.config); + var message = getString(properties.options.message); + var isRequired = getBoolean(properties.options.isRequired); + var name = getString(properties.options.name); + var displayName = getString(properties.options.displayName); + var icon = getString(properties.options.icon); + var accessLevel = getString(properties.options.accessLevel); + var titles = getArray(properties.options.titles); + if (isObjectPresent(properties.options.prompt)) { + callbacksBuilder.consentMappingCallback(config, message, isRequired); + } else { + callbacksBuilder.consentMappingCallback(name, displayName, icon, accessLevel, titles, message, isRequired); + } +} + +function deviceProfileCallback() { + var metadata = getBoolean(properties.options.metadata); + var location = getBoolean(properties.options.location); + var message = getString(properties.options.message); + callbacksBuilder.deviceProfileCallback(metadata, location, message); +} + +function hiddenValueCallback() { + var id = getString(properties.options.id); + var value = getString(properties.options.value); + callbacksBuilder.hiddenValueCallback(id, value); +} + +function httpCallback() { + var authorizationHeader = getString(properties.options.authorizationHeader); + var negotiationHeader = getString(properties.options.negotiationHeader); + var authRHeader = getString(properties.options.authRHeader); + var negoName = getString(properties.options.negoName); + var negoValue = getString(properties.options.negoValue); + if (isStringPresent(properties.options.authorizationHeader) || isStringPresent(properties.options.negotiationHeader)) { + var errorCode = getString(properties.options.errorCode); + callbacksBuilder.httpCallback(authorizationHeader, negotiationHeader, errorCode); + } else { + var errorCode = getInt(properties.options.errorCode); + callbacksBuilder.httpCallback(authRHeader, negoName, negoValue, errorCode); + } +} + +function idPCallback() { + var provider = getString(properties.options.provider); + var clientId = getString(properties.options.clientId); + var redirectUri = getString(properties.options.redirectUri); + var scope = getArray(properties.options.scope); + var nonce = getString(properties.options.nonce); + var request = getString(properties.options.request); + var requestUri = getString(properties.options.requestUri); + var acrValues = getArray(properties.options.acrValues); + var requestNativeAppForUserInfo = getBoolean(properties.options.requestNativeAppForUserInfo); + var token = getString(properties.options.token); + var tokenType = getString(properties.options.tokenType); + if (isStringPresent(properties.options.token) || isStringPresent(properties.options.tokenType)) { + callbacksBuilder.idPCallback(provider, clientId, redirectUri, scope, nonce, request, requestUri, acrValues, requestNativeAppForUserInfo, token, tokenType); + } else { + callbacksBuilder.idPCallback(provider, clientId, redirectUri, scope, nonce, request, requestUri, acrValues, requestNativeAppForUserInfo); + } +} + +function kbaCreateCallback() { + var prompt = getString(properties.options.prompt); + var predefinedQuestions = getArray(properties.options.predefinedQuestions); + var allowUserDefinedQuestions = getBoolean(properties.options.allowUserDefinedQuestions); + callbacksBuilder.kbaCreateCallback(prompt, predefinedQuestions, allowUserDefinedQuestions); +} + +function languageCallback() { + var language = getString(properties.options.language); + var country = getString(properties.options.country); + callbacksBuilder.languageCallback(language, country); +} + +function metadataCallback() { + var outputValue = getObject(properties.options.outputValue); + callbacksBuilder.metadataCallback(outputValue); +} + +function nameCallback() { + var prompt = getString(properties.options.prompt); + var defaultName = getString(properties.options.defaultName); + if (isStringPresent(properties.options.defaultName)) { + callbacksBuilder.nameCallback(prompt, defaultName); + } else { + callbacksBuilder.nameCallback(prompt); + } +} + +function numberAttributeInputCallback() { + var name = getString(properties.options.name); + var prompt = getString(properties.options.prompt); + var value = getDouble(properties.options.value); + var required = getBoolean(properties.options.required); + var policies = getObject(properties.options.policies); + var validateOnly = getBoolean(properties.options.validateOnly); + var failedPolicies = getArray(properties.options.failedPolicies); + if (isBooleanPresent(properties.options.validateOnly) || isObjectPresent(properties.options.policies)) { + if (isArrayPresent(failedPolicies)) { + callbacksBuilder.numberAttributeInputCallback(name, prompt, value, required, policies, validateOnly, failedPolicies); + } else { + callbacksBuilder.numberAttributeInputCallback(name, prompt, value, required, policies, validateOnly); + } + } else if (isArrayPresent(failedPolicies)) { + callbacksBuilder.numberAttributeInputCallback(name, prompt, value, required, failedPolicies); + } else { + callbacksBuilder.numberAttributeInputCallback(name, prompt, value, required); + } +} + +function passwordCallback() { + var prompt = getString(properties.options.prompt); + var echoOn = getBoolean(properties.options.echoOn); + callbacksBuilder.passwordCallback(prompt, echoOn); +} + +function pollingWaitCallback() { + var waitTime = getString(properties.options.waitTime); + var message = getString(properties.options.message); + callbacksBuilder.pollingWaitCallback(waitTime, message); +} + +function redirectCallback() { + throw new Error('Not Implemented'); +} + +function scriptTextOutputCallback() { + var message = getString(properties.options.message); + callbacksBuilder.scriptTextOutputCallback(message); +} + +function selectIdPCallback() { + var providers = getObject(properties.options.providers); + callbacksBuilder.selectIdPCallback(providers); +} + +function stringAttributeInputCallback() { + var name = getString(properties.options.name); + var prompt = getString(properties.options.prompt); + var value = getString(properties.options.value); + var required = getBoolean(properties.options.required); + var policies = getObject(properties.options.policies); + var validateOnly = getBoolean(properties.options.validateOnly); + var failedPolicies = getArray(properties.options.failedPolicies); + if (isBooleanPresent(properties.options.validateOnly) || isObjectPresent(properties.options.policies)) { + if (isArrayPresent(failedPolicies)) { + callbacksBuilder.stringAttributeInputCallback(name, prompt, value, required, policies, validateOnly, failedPolicies); + } else { + callbacksBuilder.stringAttributeInputCallback(name, prompt, value, required, policies, validateOnly); + } + } else if (isArrayPresent(failedPolicies)) { + callbacksBuilder.stringAttributeInputCallback(name, prompt, value, required, failedPolicies); + } else { + callbacksBuilder.stringAttributeInputCallback(name, prompt, value, required); + } +} + +function suspendedTextOutputCallback() { + var messageType = getInt(properties.options.messageType); + var message = getString(properties.options.message); + callbacksBuilder.suspendedTextOutputCallback(messageType, message); +} + +function termsAndConditionsCallback() { + var version = getString(properties.options.version); + var terms = getString(properties.options.terms); + var createDate = getString(properties.options.createDate); + callbacksBuilder.termsAndConditionsCallback(version, terms, createDate); +} + +function textInputCallback() { + var prompt = getString(properties.options.prompt); + var defaultText = getString(properties.options.defaultText); + if (isStringPresent(properties.options.defaultText)) { + callbacksBuilder.textInputCallback(prompt, defaultText); + } else { + callbacksBuilder.textInputCallback(prompt); + } +} + +function textOutputCallback() { + var messageType = getString(properties.options.messageType); + var message = getString(properties.options.message); + callbacksBuilder.textOutputCallback(messageType, message); +} + +function validatedPasswordCallback() { + var prompt = getString(properties.options.prompt); + var echoOn = getBoolean(properties.options.echoOn); + var policies = getObject(properties.options.policies); + var validateOnly = getBoolean(properties.options.validateOnly); + var failedPolicies = getArray(properties.options.failedPolicies); + if (isArrayPresent(properties.options.failedPolicies)) { + callbacksBuilder.validatedPasswordCallback(prompt, echoOn, policies, validateOnly, failedPolicies); + } else { + callbacksBuilder.validatedPasswordCallback(prompt, echoOn, policies, validateOnly); + } +} + +function validatedUsernameCallback() { + var prompt = getString(properties.options.prompt); + var policies = getObject(properties.options.policies); + var validateOnly = getBoolean(properties.options.validateOnly); + var failedPolicies = getArray(properties.options.failedPolicies); + if (isArrayPresent(properties.options.failedPolicies)) { + callbacksBuilder.validatedUsernameCallback(prompt, policies, validateOnly, failedPolicies); + } else { + callbacksBuilder.validatedUsernameCallback(prompt, policies, validateOnly); + } +} + +function x509CertificateCallback() { + throw new Error('Not Implemented'); +} + +function getBooleanAttributeInputCallback() { + setProperty(callbacks.getBooleanAttributeInputCallbacks().get(0)); +} + +function getChoiceCallback() { + var multipleSelectionsAllowed = getBoolean(properties.options.multipleSelectionsAllowed); + var selections = callbacks.getChoiceCallbacks().get(0); + setProperty(multipleSelectionsAllowed ? selections : selections[0]); +} + +function getConfirmationCallback() { + setProperty(callbacks.getConfirmationCallbacks().get(0)); +} + +function getConsentMappingCallback() { + setProperty(callbacks.getConsentMappingCallbacks().get(0)); +} + +function getDeviceProfileCallback() { + setProperty(callbacks.getDeviceProfileCallbacks().get(0)); +} + +function getHiddenValueCallback() { + var id = getString(properties.options.id); + setProperty(callbacks.getHiddenValueCallbacks().get(id)); +} + +function getHttpCallback() { + setProperty(callbacks.getHttpCallbacks().get(0)); +} + +function getIdPCallback() { + setProperty(callbacks.getIdpCallbacks().get(0)); +} + +function getKbaCreateCallback() { + setProperty(callbacks.getKbaCreateCallbacks().get(0)); +} + +function getLanguageCallback() { + setProperty(callbacks.getLanguageCallbacks().get(0)); +} + +function getNameCallback() { + setProperty(callbacks.getNameCallbacks().get(0)); +} + +function getNumberAttributeInputCallback() { + setProperty(callbacks.getNumberAttributeInputCallbacks().get(0)); +} + +function getPasswordCallback() { + setProperty(callbacks.getPasswordCallbacks().get(0)); +} + +function getSelectIdPCallback() { + setProperty(callbacks.getSelectIdPCallbacks().get(0)); +} + +function getStringAttributeInputCallback() { + setProperty(callbacks.getStringAttributeInputCallbacks().get(0)); +} + +function getTermsAndConditionsCallback() { + setProperty(callbacks.getTermsAndConditionsCallbacks().get(0)); +} + +function getTextInputCallback() { + setProperty(callbacks.getTextInputCallbacks().get(0)); +} + +function getValidatedPasswordCallback() { + setProperty(callbacks.getValidatedPasswordCallbacks().get(0)); +} + +function getValidatedUsernameCallback() { + setProperty(callbacks.getValidatedUsernameCallbacks().get(0)); +} + +function getX509CertificateCallback() { + setProperty(callbacks.getX509CertificateCallbacks().get(0)); +} + +function main() { + if (!callbacks.isEmpty()) { + switch (properties.callback) { + case CALLBACKS.BOOLEAN_ATTRIBUTE_INPUT_CALLBACK: getBooleanAttributeInputCallback(); break; + case CALLBACKS.CHOICE_CALLBACK: getChoiceCallback(); break; + case CALLBACKS.CONFIRMATION_CALLBACK: getConfirmationCallback(); break; + case CALLBACKS.CONSENT_MAPPING_CALLBACK: getConsentMappingCallback(); break; + case CALLBACKS.DEVICE_PROFILE_CALLBACK: getDeviceProfileCallback(); break; + case CALLBACKS.HIDDEN_VALUE_CALLBACK: getHiddenValueCallback(); break; + case CALLBACKS.HTTP_CALLBACK: getHttpCallback(); break; + case CALLBACKS.IDP_CALLBACK: getIdPCallback(); break; + case CALLBACKS.KBA_CREATE_CALLBACK: getKbaCreateCallback(); break; + case CALLBACKS.LANGUAGE_CALLBACK: getLanguageCallback(); break; + case CALLBACKS.NAME_CALLBACK: getNameCallback(); break; + case CALLBACKS.NUMBER_ATTRIBUTE_INPUT_CALLBACK: getNumberAttributeInputCallback(); break; + case CALLBACKS.PASSWORD_CALLBACK: getPasswordCallback(); break; + case CALLBACKS.SELECT_IDP_CALLBACK: getSelectIdPCallback(); break; + case CALLBACKS.STRING_ATTRIBUTE_INPUT_CALLBACK: getStringAttributeInputCallback(); break; + case CALLBACKS.TERMS_AND_CONDITIONS_CALLBACK: getTermsAndConditionsCallback(); break; + case CALLBACKS.TEXT_INPUT_CALLBACK: getTextInputCallback(); break; + case CALLBACKS.VALIDATED_PASSWORD_CALLBACK: getValidatedPasswordCallback(); break; + case CALLBACKS.VALIDATED_USERNAME_CALLBACK: getValidatedUsernameCallback(); break; + case CALLBACKS.X509_CERTIFICATE_CALLBACK: getX509CertificateCallback(); break; + default: break; + } + action.goTo(SCRIPT_OUTCOMES.OUTCOME); + return; + } + + switch (properties.callback) { + case CALLBACKS.BOOLEAN_ATTRIBUTE_INPUT_CALLBACK: booleanAttributeInputCallback(); break; + case CALLBACKS.CHOICE_CALLBACK: choiceCallback(); break; + case CALLBACKS.CONFIRMATION_CALLBACK: confirmationCallback(); break; + case CALLBACKS.CONSENT_MAPPING_CALLBACK: consentMappingCallback(); break; + case CALLBACKS.DEVICE_PROFILE_CALLBACK: deviceProfileCallback(); break; + case CALLBACKS.HIDDEN_VALUE_CALLBACK: hiddenValueCallback(); break; + case CALLBACKS.HTTP_CALLBACK: httpCallback(); break; + case CALLBACKS.IDP_CALLBACK: idPCallback(); break; + case CALLBACKS.KBA_CREATE_CALLBACK: kbaCreateCallback(); break; + case CALLBACKS.LANGUAGE_CALLBACK: languageCallback(); break; + case CALLBACKS.METADATA_CALLBACK: metadataCallback(); break; + case CALLBACKS.NAME_CALLBACK: nameCallback(); break; + case CALLBACKS.NUMBER_ATTRIBUTE_INPUT_CALLBACK: numberAttributeInputCallback(); break; + case CALLBACKS.PASSWORD_CALLBACK: passwordCallback(); break; + case CALLBACKS.POLLING_WAIT_CALLBACK: pollingWaitCallback(); break; + case CALLBACKS.REDIRECT_CALLBACK: redirectCallback(); break; + case CALLBACKS.SCRIPT_TEXT_OUTPUT_CALLBACK: scriptTextOutputCallback(); break; + case CALLBACKS.SELECT_IDP_CALLBACK: selectIdPCallback(); break; + case CALLBACKS.STRING_ATTRIBUTE_INPUT_CALLBACK: stringAttributeInputCallback(); break; + case CALLBACKS.SUSPENDED_TEXT_OUTPUT_CALLBACK: suspendedTextOutputCallback(); break; + case CALLBACKS.TERMS_AND_CONDITIONS_CALLBACK: termsAndConditionsCallback(); break; + case CALLBACKS.TEXT_INPUT_CALLBACK: textInputCallback(); break; + case CALLBACKS.TEXT_OUTPUT_CALLBACK: textOutputCallback(); break; + case CALLBACKS.VALIDATED_PASSWORD_CALLBACK: validatedPasswordCallback(); break; + case CALLBACKS.VALIDATED_USERNAME_CALLBACK: validatedUsernameCallback(); break; + case CALLBACKS.X509_CERTIFICATE_CALLBACK: x509CertificateCallback(); break; + default: throw new Error('Unknown Callback'); // Should never reach this case + } +} + +main(); +" +`; + +exports[`frodo config-manager pull custom-nodes "frodo config-manager pull custom-nodes -D configManagerPullCustomNodesDir1 -n 'Display Callback' -m forgeops": should export custom node named: Display Callback: configManagerPullCustomNodesDir1/custom-nodes/nodes/Display Callback/Display Callback.json 1`] = ` +{ + "_id": "ef81b1a52c914710b3388caebfe7233a-1", + "description": "Displays custom callback to the page", + "displayName": "Display Callback", + "errorOutcome": false, + "inputs": [], + "outcomes": [ + "outcome", + ], + "outputs": [], + "properties": { + "callback": { + "description": "The callback to display", + "multivalued": false, + "options": { + "BOOLEAN_ATTRIBUTE_INPUT_CALLBACK": "booleanAttributeInputCallback", + "CHOICE_CALLBACK": "choiceCallback", + "CONFIRMATION_CALLBACK": "confirmationCallback", + "CONSENT_MAPPING_CALLBACK": "consentMappingCallback", + "DEVICE_PROFILE_CALLBACK": "deviceProfileCallback", + "HIDDEN_VALUE_CALLBACK": "hiddenValueCallback", + "HTTP_CALLBACK": "httpCallback", + "IDP_CALLBACK": "idPCallback", + "KBA_CREATE_CALLBACK": "kbaCreateCallback", + "LANGUAGE_CALLBACK": "languageCallback", + "METADATA_CALLBACK": "metadataCallback", + "NAME_CALLBACK": "nameCallback", + "NUMBER_ATTRIBUTE_INPUT_CALLBACK": "numberAttributeInputCallback", + "PASSWORD_CALLBACK": "passwordCallback", + "POLLING_WAIT_CALLBACK": "pollingWaitCallback", + "REDIRECT_CALLBACK": "redirectCallback", + "SCRIPT_TEXT_OUTPUT_CALLBACK": "scriptTextOutputCallback", + "SELECT_IDP_CALLBACK": "selectIdPCallback", + "STRING_ATTRIBUTE_INPUT_CALLBACK": "stringAttributeInputCallback", + "SUSPENDED_TEXT_OUTPUT_CALLBACK": "suspendedTextOutputCallback", + "TERMS_AND_CONDITIONS_CALLBACK": "termsAndConditionsCallback", + "TEXT_INPUT_CALLBACK": "textInputCallback", + "TEXT_OUTPUT_CALLBACK": "textOutputCallback", + "VALIDATED_PASSWORD_CALLBACK": "validatedPasswordCallback", + "VALIDATED_USERNAME_CALLBACK": "validatedUsernameCallback", + "X509_CERTIFICATE_CALLBACK": "x509CertificateCallback", + }, + "required": true, + "title": "Callback", + "type": "STRING", + }, + "objectSharedProperty": { + "description": "The objectAttributes property on the shared state to put the callback input into (if applicable)", + "multivalued": false, + "required": false, + "title": "Object Attributes Shared Property", + "type": "STRING", + }, + "objectTransientProperty": { + "description": "The objectAttributes property on the transient state to put the callback input into (if applicable)", + "multivalued": false, + "required": false, + "title": "Object Attributes Transient Property", + "type": "STRING", + }, + "options": { + "description": "The options containing the parameters for the callback (see documentation for possible parameters: https://docs.pingidentity.com/pingoneaic/latest/am-scripting/scripting-api-node.html#scripting-api-node-callbacks). + +For example, for textOutputCallback, the options could be: { messageType: 0, message: "Hello World!" }. + +Note that for required parameters that are not specified in the options will use default values based on the type of the parameter ("" for Strings, [] for Arrays, {} for Objects, 0 for Ints, 0.0 for Doubles, and false for Booleans).", + "multivalued": false, + "required": true, + "title": "Options", + "type": "OBJECT", + }, + "sharedProperty": { + "description": "The shared state property to put the callback input into (if applicable)", + "multivalued": false, + "required": false, + "title": "Shared State Property", + "type": "STRING", + }, + "transientProperty": { + "description": "The transient state property to put the callback input into (if applicable)", + "multivalued": false, + "required": false, + "title": "Transient State Property", + "type": "STRING", + }, + }, + "script": { + "file": "Display Callback.js", + }, + "serviceName": "ef81b1a52c914710b3388caebfe7233a", + "tags": [ + "callback", + "utilities", + ], +} +`; diff --git a/test/e2e/config-manager-pull-custom-nodes.e2e.test.js b/test/e2e/config-manager-pull-custom-nodes.e2e.test.js new file mode 100644 index 000000000..9ca8b5329 --- /dev/null +++ b/test/e2e/config-manager-pull-custom-nodes.e2e.test.js @@ -0,0 +1,71 @@ +/** + * Follow this process to write e2e tests for the CLI project: + * + * 1. Test if all the necessary mocks for your tests already exist. + * In mock mode, run the command you want to test with the same arguments + * and parameters exactly as you want to test it, for example: + * + * $ FRODO_MOCK=1 frodo conn save https://openam-frodo-dev.forgeblocks.com/am volker.scheuber@forgerock.com Sup3rS3cr3t! + * + * If your command completes without errors and with the expected results, + * all the required mocks already exist and you are good to write your + * test and skip to step #4. + * + * If, however, your command fails and you see errors like the one below, + * you know you need to record the mock responses first: + * + * [Polly] [adapter:node-http] Recording for the following request is not found and `recordIfMissing` is `false`. + * + * 2. Record mock responses for your exact command. + * In mock record mode, run the command you want to test with the same arguments + * and parameters exactly as you want to test it, for example: + * + * $ FRODO_MOCK=record frodo conn save https://openam-frodo-dev.forgeblocks.com/am volker.scheuber@forgerock.com Sup3rS3cr3t! + * + * Wait until you see all the Polly instances (mock recording adapters) have + * shutdown before you try to run step #1 again. + * Messages like these indicate mock recording adapters shutting down: + * + * Polly instance 'conn/4' stopping in 3s... + * Polly instance 'conn/4' stopping in 2s... + * Polly instance 'conn/save/3' stopping in 3s... + * Polly instance 'conn/4' stopping in 1s... + * Polly instance 'conn/save/3' stopping in 2s... + * Polly instance 'conn/4' stopped. + * Polly instance 'conn/save/3' stopping in 1s... + * Polly instance 'conn/save/3' stopped. + * + * 3. Validate your freshly recorded mock responses are complete and working. + * Re-run the exact command you want to test in mock mode (see step #1). + * + * 4. Write your test. + * Make sure to use the exact command including number of arguments and params. + * + * 5. Commit both your test and your new recordings to the repository. + * Your tests are likely going to reside outside the frodo-lib project but + * the recordings must be committed to the frodo-lib project. + */ + +/* +FRODO_MOCK=record FRODO_NO_CACHE=1 FRODO_HOST=https://nightly.gcp.forgeops.com/am frodo config-manager pull custom-nodes -D configManagerPullCustomNodesDir0 -m forgeops +FRODO_MOCK=record FRODO_NO_CACHE=1 FRODO_HOST=https://nightly.gcp.forgeops.com/am frodo config-manager pull custom-nodes -D configManagerPullCustomNodesDir1 -n 'Display Callback' -m forgeops +*/ + +import { getEnv, testExport } from './utils/TestUtils'; +import { forgeops_connection as fc } from './utils/TestConfig'; + +process.env['FRODO_MOCK'] = '1'; +const env = getEnv(fc); + +describe('frodo config-manager pull custom-nodes', () => { + test(`"frodo config-manager pull custom-nodes -D configManagerPullCustomNodesDir0 -m forgeops": should export all custom-nodes in fr-config manager style.`, async () => { + const dirName = 'configManagerPullCustomNodesDir0'; + const CMD = `frodo config-manager pull custom-nodes -D ${dirName} -m forgeops`; + await testExport(CMD, env, undefined, undefined, dirName, false); + }); + test(`"frodo config-manager pull custom-nodes -D configManagerPullCustomNodesDir1 -n 'Display Callback' -m forgeops": should export custom node named: Display Callback`, async () => { + const dirName = 'configManagerPullCustomNodesDir1'; + const CMD = `frodo config-manager pull custom-nodes -D ${dirName} -n 'Display Callback' -m forgeops`; + await testExport(CMD, env, undefined, undefined, dirName, false); + }); +}); \ No newline at end of file diff --git a/test/e2e/mocks/config-manager_4167095917/pull_2167214206/custom-nodes_3091214966/0_D_m_314327836/am_1076162899/recording.har b/test/e2e/mocks/config-manager_4167095917/pull_2167214206/custom-nodes_3091214966/0_D_m_314327836/am_1076162899/recording.har new file mode 100644 index 000000000..ddcad469b --- /dev/null +++ b/test/e2e/mocks/config-manager_4167095917/pull_2167214206/custom-nodes_3091214966/0_D_m_314327836/am_1076162899/recording.har @@ -0,0 +1,780 @@ +{ + "log": { + "_recordingName": "config-manager/pull/custom-nodes/0_D_m/am", + "creator": { + "comment": "persister:fs", + "name": "Polly.JS", + "version": "6.0.6" + }, + "entries": [ + { + "_id": "ccd7a5defd0fdeaa986a2b54642d911a", + "_order": 0, + "cache": {}, + "request": { + "bodySize": 0, + "cookies": [], + "headers": [ + { + "name": "accept", + "value": "application/json, text/plain, */*" + }, + { + "name": "content-type", + "value": "application/json" + }, + { + "name": "user-agent", + "value": "@rockcarver/frodo-lib/4.0.0-36" + }, + { + "name": "x-forgerock-transactionid", + "value": "frodo-57641519-67ef-4da6-8b71-2538f4143c60" + }, + { + "name": "accept-api-version", + "value": "resource=1.1" + }, + { + "name": "accept-encoding", + "value": "gzip, compress, deflate, br" + }, + { + "name": "host", + "value": "openam-frodo-dev.forgeblocks.com" + } + ], + "headersSize": 370, + "httpVersion": "HTTP/1.1", + "method": "GET", + "queryString": [], + "url": "https://platform.dev.trivir.com/am/json/serverinfo/*" + }, + "response": { + "bodySize": 587, + "content": { + "mimeType": "application/json;charset=UTF-8", + "size": 587, + "text": "{\"_id\":\"*\",\"_rev\":\"2075994313\",\"domains\":[],\"protectedUserAttributes\":[\"telephoneNumber\",\"mail\"],\"cookieName\":\"iPlanetDirectoryPro\",\"secureCookie\":true,\"forgotPassword\":\"false\",\"forgotUsername\":\"false\",\"kbaEnabled\":\"false\",\"selfRegistration\":\"false\",\"lang\":\"en-US\",\"successfulUserRegistrationDestination\":\"default\",\"socialImplementations\":[],\"referralsEnabled\":\"false\",\"zeroPageLogin\":{\"enabled\":false,\"refererWhitelist\":[],\"allowedWithoutReferer\":true},\"realm\":\"/\",\"xuiUserSessionValidationEnabled\":true,\"fileBasedConfiguration\":true,\"userIdAttributes\":[],\"nodeDesignerXuiEnabled\":true}" + }, + "cookies": [ + { + "httpOnly": true, + "name": "route", + "path": "/am", + "secure": true, + "value": "" + } + ], + "headers": [ + { + "name": "date", + "value": "Mon, 13 Apr 2026 22:11:13 GMT" + }, + { + "name": "content-type", + "value": "application/json;charset=UTF-8" + }, + { + "name": "content-length", + "value": "587" + }, + { + "name": "connection", + "value": "keep-alive" + }, + { + "_fromType": "array", + "name": "set-cookie", + "value": "route=; Path=/am; Secure; HttpOnly" + }, + { + "name": "x-frame-options", + "value": "SAMEORIGIN" + }, + { + "name": "x-content-type-options", + "value": "nosniff" + }, + { + "name": "cache-control", + "value": "no-store" + }, + { + "name": "content-api-version", + "value": "resource=1.1" + }, + { + "name": "content-security-policy", + "value": "default-src 'none';frame-ancestors 'none';sandbox" + }, + { + "name": "cross-origin-opener-policy", + "value": "same-origin" + }, + { + "name": "cross-origin-resource-policy", + "value": "same-origin" + }, + { + "name": "etag", + "value": "\"2075994313\"" + }, + { + "name": "expires", + "value": "0" + }, + { + "name": "pragma", + "value": "no-cache" + }, + { + "name": "strict-transport-security", + "value": "max-age=31536000; includeSubDomains" + } + ], + "headersSize": 631, + "httpVersion": "HTTP/1.1", + "redirectURL": "", + "status": 200, + "statusText": "OK" + }, + "startedDateTime": "2026-04-13T22:11:13.521Z", + "time": 12, + "timings": { + "blocked": -1, + "connect": -1, + "dns": -1, + "receive": 0, + "send": 0, + "ssl": -1, + "wait": 12 + } + }, + { + "_id": "9f5671275c36a1c0090d0df26ce0e93f", + "_order": 0, + "cache": {}, + "request": { + "bodySize": 2, + "cookies": [], + "headers": [ + { + "name": "accept", + "value": "application/json, text/plain, */*" + }, + { + "name": "content-type", + "value": "application/json" + }, + { + "name": "user-agent", + "value": "@rockcarver/frodo-lib/4.0.0-36" + }, + { + "name": "x-forgerock-transactionid", + "value": "frodo-57641519-67ef-4da6-8b71-2538f4143c60" + }, + { + "name": "accept-api-version", + "value": "resource=2.0, protocol=1.0" + }, + { + "name": "x-openam-username", + "value": "amadmin" + }, + { + "name": "x-openam-password", + "value": "41ghjnKpNFAFU/HXw82HbFbitYNOOJ0g" + }, + { + "name": "content-length", + "value": "2" + }, + { + "name": "accept-encoding", + "value": "gzip, compress, deflate, br" + }, + { + "name": "host", + "value": "openam-frodo-dev.forgeblocks.com" + } + ], + "headersSize": 497, + "httpVersion": "HTTP/1.1", + "method": "POST", + "postData": { + "mimeType": "application/json", + "params": [], + "text": "{}" + }, + "queryString": [], + "url": "https://platform.dev.trivir.com/am/json/realms/root/authenticate" + }, + "response": { + "bodySize": 167, + "content": { + "mimeType": "application/json", + "size": 167, + "text": "{\"tokenId\":\"\",\"successUrl\":\"/am/console\",\"realm\":\"/\"}" + }, + "cookies": [ + { + "httpOnly": true, + "name": "route", + "path": "/am", + "secure": true, + "value": "" + }, + { + "httpOnly": true, + "name": "iPlanetDirectoryPro", + "path": "/", + "sameSite": "none", + "secure": true, + "value": "" + }, + { + "httpOnly": true, + "name": "amlbcookie", + "path": "/", + "sameSite": "none", + "secure": true, + "value": "" + } + ], + "headers": [ + { + "name": "date", + "value": "Mon, 13 Apr 2026 22:11:13 GMT" + }, + { + "name": "content-type", + "value": "application/json" + }, + { + "name": "content-length", + "value": "167" + }, + { + "name": "connection", + "value": "keep-alive" + }, + { + "_fromType": "array", + "name": "set-cookie", + "value": "route=; Path=/am; Secure; HttpOnly" + }, + { + "_fromType": "array", + "name": "set-cookie", + "value": "iPlanetDirectoryPro=; Path=/; Secure; HttpOnly; SameSite=none" + }, + { + "_fromType": "array", + "name": "set-cookie", + "value": "amlbcookie=; Path=/; Secure; HttpOnly; SameSite=none" + }, + { + "name": "x-frame-options", + "value": "SAMEORIGIN" + }, + { + "name": "x-content-type-options", + "value": "nosniff" + }, + { + "name": "cache-control", + "value": "private" + }, + { + "name": "content-api-version", + "value": "resource=2.1" + }, + { + "name": "expires", + "value": "0" + }, + { + "name": "pragma", + "value": "no-cache" + }, + { + "name": "strict-transport-security", + "value": "max-age=31536000; includeSubDomains" + } + ], + "headersSize": 693, + "httpVersion": "HTTP/1.1", + "redirectURL": "", + "status": 200, + "statusText": "OK" + }, + "startedDateTime": "2026-04-13T22:11:13.539Z", + "time": 24, + "timings": { + "blocked": -1, + "connect": -1, + "dns": -1, + "receive": 0, + "send": 0, + "ssl": -1, + "wait": 24 + } + }, + { + "_id": "6a3744385d3fd7416ea7089e610fa7e7", + "_order": 0, + "cache": {}, + "request": { + "bodySize": 128, + "cookies": [], + "headers": [ + { + "name": "accept", + "value": "application/json, text/plain, */*" + }, + { + "name": "content-type", + "value": "application/json" + }, + { + "name": "user-agent", + "value": "@rockcarver/frodo-lib/4.0.0-36" + }, + { + "name": "x-forgerock-transactionid", + "value": "frodo-57641519-67ef-4da6-8b71-2538f4143c60" + }, + { + "name": "accept-api-version", + "value": "resource=4.0" + }, + { + "name": "content-length", + "value": "128" + }, + { + "name": "accept-encoding", + "value": "gzip, compress, deflate, br" + }, + { + "name": "host", + "value": "openam-frodo-dev.forgeblocks.com" + } + ], + "headersSize": 424, + "httpVersion": "HTTP/1.1", + "method": "POST", + "postData": { + "mimeType": "application/json", + "params": [], + "text": "{\"tokenId\":\"\"}" + }, + "queryString": [ + { + "name": "_action", + "value": "getSessionInfo" + } + ], + "url": "https://platform.dev.trivir.com/am/json/realms/root/sessions/?_action=getSessionInfo" + }, + "response": { + "bodySize": 291, + "content": { + "mimeType": "application/json;charset=UTF-8", + "size": 291, + "text": "{\"username\":\"amadmin\",\"universalId\":\"id=amadmin,ou=user,ou=am-config\",\"realm\":\"/\",\"latestAccessTime\":\"2026-04-13T22:11:13Z\",\"maxIdleExpirationTime\":\"2026-04-13T22:41:13Z\",\"maxSessionExpirationTime\":\"2026-04-14T00:11:12Z\",\"properties\":{\"AMCtxId\":\"d65b280f-e163-4042-871b-1d0ffe1512eb-12065\"}}" + }, + "cookies": [ + { + "httpOnly": true, + "name": "route", + "path": "/am", + "secure": true, + "value": "" + } + ], + "headers": [ + { + "name": "date", + "value": "Mon, 13 Apr 2026 22:11:13 GMT" + }, + { + "name": "content-type", + "value": "application/json;charset=UTF-8" + }, + { + "name": "content-length", + "value": "291" + }, + { + "name": "connection", + "value": "keep-alive" + }, + { + "_fromType": "array", + "name": "set-cookie", + "value": "route=; Path=/am; Secure; HttpOnly" + }, + { + "name": "x-frame-options", + "value": "SAMEORIGIN" + }, + { + "name": "x-content-type-options", + "value": "nosniff" + }, + { + "name": "cache-control", + "value": "private" + }, + { + "name": "content-api-version", + "value": "resource=4.0" + }, + { + "name": "content-security-policy", + "value": "default-src 'none';frame-ancestors 'none';sandbox" + }, + { + "name": "cross-origin-opener-policy", + "value": "same-origin" + }, + { + "name": "cross-origin-resource-policy", + "value": "same-origin" + }, + { + "name": "expires", + "value": "0" + }, + { + "name": "pragma", + "value": "no-cache" + }, + { + "name": "strict-transport-security", + "value": "max-age=31536000; includeSubDomains" + } + ], + "headersSize": 610, + "httpVersion": "HTTP/1.1", + "redirectURL": "", + "status": 200, + "statusText": "OK" + }, + "startedDateTime": "2026-04-13T22:11:13.570Z", + "time": 8, + "timings": { + "blocked": -1, + "connect": -1, + "dns": -1, + "receive": 0, + "send": 0, + "ssl": -1, + "wait": 8 + } + }, + { + "_id": "6125d0328ad0dcaee55f73fd8b22ca14", + "_order": 0, + "cache": {}, + "request": { + "bodySize": 0, + "cookies": [], + "headers": [ + { + "name": "accept", + "value": "application/json, text/plain, */*" + }, + { + "name": "content-type", + "value": "application/json" + }, + { + "name": "user-agent", + "value": "@rockcarver/frodo-lib/4.0.0-36" + }, + { + "name": "x-forgerock-transactionid", + "value": "frodo-57641519-67ef-4da6-8b71-2538f4143c60" + }, + { + "name": "accept-api-version", + "value": "resource=1.0" + }, + { + "name": "cookie", + "value": "iPlanetDirectoryPro=" + }, + { + "name": "accept-encoding", + "value": "gzip, compress, deflate, br" + }, + { + "name": "host", + "value": "openam-frodo-dev.forgeblocks.com" + } + ], + "headersSize": 520, + "httpVersion": "HTTP/1.1", + "method": "GET", + "queryString": [], + "url": "https://platform.dev.trivir.com/am/json/serverinfo/version" + }, + "response": { + "bodySize": 257, + "content": { + "mimeType": "application/json;charset=UTF-8", + "size": 257, + "text": "{\"_id\":\"version\",\"_rev\":\"-466575464\",\"version\":\"8.0.1\",\"fullVersion\":\"ForgeRock Access Management 8.0.1 Build b59bc0908346197b0c33afcb9e733d0400feeea1 (2025-April-15 11:37)\",\"revision\":\"b59bc0908346197b0c33afcb9e733d0400feeea1\",\"date\":\"2025-April-15 11:37\"}" + }, + "cookies": [ + { + "httpOnly": true, + "name": "route", + "path": "/am", + "secure": true, + "value": "" + } + ], + "headers": [ + { + "name": "date", + "value": "Mon, 13 Apr 2026 22:11:13 GMT" + }, + { + "name": "content-type", + "value": "application/json;charset=UTF-8" + }, + { + "name": "content-length", + "value": "257" + }, + { + "name": "connection", + "value": "keep-alive" + }, + { + "_fromType": "array", + "name": "set-cookie", + "value": "route=; Path=/am; Secure; HttpOnly" + }, + { + "name": "x-frame-options", + "value": "SAMEORIGIN" + }, + { + "name": "x-content-type-options", + "value": "nosniff" + }, + { + "name": "cache-control", + "value": "no-store" + }, + { + "name": "content-api-version", + "value": "resource=1.0" + }, + { + "name": "content-security-policy", + "value": "default-src 'none';frame-ancestors 'none';sandbox" + }, + { + "name": "cross-origin-opener-policy", + "value": "same-origin" + }, + { + "name": "cross-origin-resource-policy", + "value": "same-origin" + }, + { + "name": "etag", + "value": "\"-466575464\"" + }, + { + "name": "expires", + "value": "0" + }, + { + "name": "pragma", + "value": "no-cache" + }, + { + "name": "strict-transport-security", + "value": "max-age=31536000; includeSubDomains" + } + ], + "headersSize": 631, + "httpVersion": "HTTP/1.1", + "redirectURL": "", + "status": 200, + "statusText": "OK" + }, + "startedDateTime": "2026-04-13T22:11:13.583Z", + "time": 6, + "timings": { + "blocked": -1, + "connect": -1, + "dns": -1, + "receive": 0, + "send": 0, + "ssl": -1, + "wait": 6 + } + }, + { + "_id": "e6efe3392d787815b92258f4573fd0b4", + "_order": 0, + "cache": {}, + "request": { + "bodySize": 0, + "cookies": [], + "headers": [ + { + "name": "accept", + "value": "application/json, text/plain, */*" + }, + { + "name": "content-type", + "value": "application/json" + }, + { + "name": "user-agent", + "value": "@rockcarver/frodo-lib/4.0.0-36" + }, + { + "name": "x-forgerock-transactionid", + "value": "frodo-57641519-67ef-4da6-8b71-2538f4143c60" + }, + { + "name": "accept-api-version", + "value": "protocol=2.1,resource=1.0" + }, + { + "name": "cookie", + "value": "iPlanetDirectoryPro=" + }, + { + "name": "accept-encoding", + "value": "gzip, compress, deflate, br" + }, + { + "name": "host", + "value": "openam-frodo-dev.forgeblocks.com" + } + ], + "headersSize": 556, + "httpVersion": "HTTP/1.1", + "method": "GET", + "queryString": [ + { + "name": "_queryFilter", + "value": "true" + } + ], + "url": "https://platform.dev.trivir.com/am/json/node-designer/node-type?_queryFilter=true" + }, + "response": { + "bodySize": 33591, + "content": { + "mimeType": "application/json;charset=UTF-8", + "size": 33591, + "text": "{\"result\":[{\"_id\":\"c6063fb2f5dc42dd9772bedc93898bd8-1\",\"_rev\":\"1733504144\",\"serviceName\":\"c6063fb2f5dc42dd9772bedc93898bd8\",\"displayName\":\"ALU\",\"description\":\"Simple ALU that performs basic binary math operations. Expects an \\\"x\\\" and \\\"y\\\" value on the shared state, and will produce a new \\\"z\\\" value on the shared state as output.\",\"outcomes\":[\"Success\"],\"outputs\":[\"z\"],\"inputs\":[\"x\",\"y\"],\"script\":\"var SCRIPT_OUTCOMES = {\\n SUCCESS: 'Success'\\n};\\n\\nvar OPERATORS = {\\n ADD: \\\"ADD\\\",\\n SUBTRACT: \\\"SUBTRACT\\\",\\n MULTIPLY: \\\"MULTIPLY\\\",\\n DIVIDE: \\\"DIVIDE\\\"\\n}\\n\\nfunction main() {\\n var a = Number(properties.a);\\n var b = Number(properties.b);\\n switch (properties.operator) {\\n case OPERATORS.ADD:\\n nodeState.putShared(\\\"z\\\", a + b);\\n break;\\n case OPERATORS.SUBTRACT:\\n nodeState.putShared(\\\"z\\\", a - b);\\n break;\\n case OPERATORS.MULTIPLY:\\n nodeState.putShared(\\\"z\\\", a * b);\\n break;\\n case OPERATORS.DIVIDE:\\n if (b == 0) throw new Error(\\\"Cannot divide by 0\\\");\\n nodeState.putShared(\\\"z\\\", a / b);\\n break;\\n default: throw new Error(\\\"Unknown operator.\\\");\\n }\\n action.goTo(SCRIPT_OUTCOMES.SUCCESS);\\n}\\n\\nmain();\\n\",\"errorOutcome\":true,\"tags\":[\"math\",\"utilities\"],\"properties\":{\"operator\":{\"title\":\"Operator\",\"description\":\"The operation to perform.\",\"type\":\"STRING\",\"required\":true,\"defaultValue\":\"ADD\",\"options\":{\"ADD\":\"+\",\"MULTIPLY\":\"*\",\"SUBTRACT\":\"-\",\"DIVIDE\":\"/\"},\"multivalued\":false}}},{\"_id\":\"8ab9f1aad4b4460a9c45d15fb148e221-1\",\"_rev\":\"1713151721\",\"serviceName\":\"8ab9f1aad4b4460a9c45d15fb148e221\",\"displayName\":\"Display State\",\"description\":\"Debug node that displays the shared and transient state of the journey for debugging purposes.\",\"outcomes\":[\"outcome\"],\"outputs\":[],\"inputs\":[],\"script\":\"var SCRIPT_OUTCOMES = {\\n OUTCOME: \\\"outcome\\\"\\n};\\n\\nfunction main() {\\n if (!callbacks.isEmpty()) {\\n action.goTo(SCRIPT_OUTCOMES.OUTCOME);\\n return;\\n }\\n var keySet = nodeState.keys(); // Java Set\\n var keys = Array.from(keySet); // Make it into JavaScript array\\n debugState = {};\\n for (var i in keys) {\\n var k = new String(keys[i]);\\n var item = nodeState.get(k);\\n if (typeof item === \\\"object\\\") {\\n debugState[k] = nodeState.getObject(k);\\n } else {\\n debugState[k] = nodeState.get(k);\\n }\\n }\\n if (properties.displayFormat === \\\"JSON\\\") {\\n callbacksBuilder.textOutputCallback(0, `
${JSON.stringify(debugState, null, 2)}
`);\\n return;\\n }\\n callbacksBuilder.textOutputCallback(0, `${Array.from(Object.keys(debugState).map(k => ``))}
KeyValue
${k}
${debugState[k]}
`);\\n}\\n\\nmain();\\n\",\"errorOutcome\":false,\"tags\":[\"debug\",\"testing\"],\"properties\":{\"displayFormat\":{\"title\":\"Display Format\",\"description\":\"The format in which to display the states.\",\"type\":\"STRING\",\"required\":true,\"defaultValue\":\"TABLE\",\"options\":{\"TABLE\":\"HTML Table\",\"JSON\":\"Raw JSON\"},\"multivalued\":false}}},{\"_id\":\"c605506774a848f7877b4d17a453bd39-1\",\"_rev\":\"1583432423\",\"serviceName\":\"c605506774a848f7877b4d17a453bd39\",\"displayName\":\"Has Session\",\"description\":\"Checks if the user has a current session.\",\"outcomes\":[\"True\",\"False\"],\"outputs\":[],\"inputs\":[],\"script\":\"var SCRIPT_OUTCOMES = {\\n TRUE: 'True',\\n FALSE: 'False'\\n}\\n\\nfunction main() {\\n action.goTo(typeof existingSession === \\\"undefined\\\" ? SCRIPT_OUTCOMES.FALSE : SCRIPT_OUTCOMES.TRUE);\\n}\\n\\nmain();\\n\",\"errorOutcome\":false,\"tags\":[\"utilities\"],\"properties\":{}},{\"_id\":\"session-1\",\"_rev\":\"1248028795\",\"serviceName\":\"session\",\"displayName\":\"Has Session AM\",\"description\":\"Checks if the user has a current session.\",\"outcomes\":[\"True\",\"False\"],\"outputs\":[],\"inputs\":[],\"script\":\"var SCRIPT_OUTCOMES = {\\n TRUE: 'True',\\n FALSE: 'False'\\n}\\n\\nfunction main() {\\n action.goTo(typeof existingSession === \\\"undefined\\\" ? SCRIPT_OUTCOMES.FALSE : SCRIPT_OUTCOMES.TRUE);\\n}\\n\\nmain();\\n\",\"errorOutcome\":false,\"tags\":[\"utilities\"],\"properties\":{}},{\"_id\":\"c15e2efb3deb4d4ea338c74a6440b69f-1\",\"_rev\":\"-2034215288\",\"serviceName\":\"c15e2efb3deb4d4ea338c74a6440b69f\",\"displayName\":\"Vector ALU\",\"description\":\"Simple ALU that performs basic binary vector math operations. Outputs the result onto the shared state with key \\\"c\\\".\",\"outcomes\":[\"Success\"],\"outputs\":[\"c\"],\"inputs\":[],\"script\":\"var SCRIPT_OUTCOMES = {\\n SUCCESS: 'Success'\\n};\\n\\nvar OPERATORS = {\\n ADD: \\\"ADD\\\",\\n SUBTRACT: \\\"SUBTRACT\\\",\\n DOT: \\\"DOT\\\",\\n CROSS: \\\"CROSS\\\"\\n}\\n\\nfunction add(a, b) {\\n return a.map((v, i) => v + b[i]);\\n}\\n\\nfunction subtract(a, b) {\\n return a.map((v, i) => v - b[i]);\\n}\\n\\nfunction dot(a, b) {\\n return a.reduce((sum, v, i) => sum + v * b[i], 0);\\n}\\n\\nfunction cross(a, b) {\\n return [\\n a[1] * b[2] - a[2] * b[1],\\n a[2] * b[0] - a[0] * b[2],\\n a[0] * b[1] - a[1] * b[0]\\n ];\\n}\\n\\nfunction main() {\\n if (properties.a.length !== properties.b.length) throw new Error(\\\"Vectors not the same dimension.\\\");\\n switch (properties.operator) {\\n case OPERATORS.ADD:\\n nodeState.putShared(\\\"c\\\", add(properties.a, properties.b));\\n break;\\n case OPERATORS.SUBTRACT:\\n nodeState.putShared(\\\"c\\\", subtract(properties.a, properties.b));\\n break;\\n case OPERATORS.DOT:\\n nodeState.putShared(\\\"c\\\", dot(properties.a, properties.b));\\n break;\\n case OPERATORS.CROSS:\\n if (properties.a.length !== 3) throw new Error(\\\"Vectors not dimension 3 for cross product\\\");\\n nodeState.putShared(\\\"c\\\", cross(properties.a, properties.b));\\n break;\\n default: throw new Error(\\\"Unknown operator.\\\");\\n }\\n action.goTo(SCRIPT_OUTCOMES.SUCCESS);\\n}\\n\\nmain();\\n\",\"errorOutcome\":true,\"tags\":[\"math\",\"vector\",\"utilities\"],\"properties\":{\"a\":{\"title\":\"A\",\"description\":\"Left vector operand\",\"type\":\"NUMBER\",\"required\":true,\"defaultValue\":[1,2,3],\"multivalued\":true},\"b\":{\"title\":\"B\",\"description\":\"Right vector operand\",\"type\":\"NUMBER\",\"required\":true,\"defaultValue\":[4,5,6],\"multivalued\":true},\"operator\":{\"title\":\"Operator\",\"description\":\"The binary operation to perform on the vectors.\",\"type\":\"STRING\",\"required\":true,\"defaultValue\":\"DOT\",\"options\":{\"ADD\":\"+\",\"CROSS\":\"X\",\"DOT\":\".\",\"SUBTRACT\":\"-\"},\"multivalued\":false}}},{\"_id\":\"e5ad0110c8ee4dafaae983003cd05d4a-1\",\"_rev\":\"573016413\",\"serviceName\":\"e5ad0110c8ee4dafaae983003cd05d4a\",\"displayName\":\"Generate JWT\",\"description\":\"Generate a signed JWT using the HMAC SHA-256 algorithm.\",\"outcomes\":[\"True\",\"False\"],\"outputs\":[],\"inputs\":[],\"script\":\"var aud = properties.audience;\\nvar iss = properties.issuer;\\nvar validity = properties.validity;\\nvar esv = properties.signingkey;\\n\\nvar signingkey = systemEnv.getProperty(esv);\\n\\nvar username = nodeState.get(\\\"username\\\");\\n\\nvar data = {\\n jwtType:\\\"SIGNED\\\",\\n jwsAlgorithm: \\\"HS256\\\",\\n issuer: iss,\\n subject: username,\\n audience: aud,\\n type: \\\"JWT\\\",\\n validityMinutes: validity,\\n signingKey: signingkey\\n};\\n\\nvar jwt = jwtAssertion.generateJwt(data);\\n\\nif (jwt !== null && jwt.length > 0) {\\n nodeState.putShared(\\\"assertionJwt\\\" , jwt);\\n action.goTo(\\\"True\\\");\\n} else {\\n action.goTo(\\\"False\\\");\\n}\\n\",\"errorOutcome\":true,\"tags\":[\"Utilities\",\"utilities\"],\"properties\":{\"audience\":{\"title\":\"Audience\",\"description\":\"The audience (aud) claim\",\"type\":\"STRING\",\"required\":true,\"multivalued\":false},\"issuer\":{\"title\":\"Issuer\",\"description\":\"The issuer (iss) claim\",\"type\":\"STRING\",\"required\":true,\"multivalued\":false},\"signingkey\":{\"title\":\"HMAC Signing Key\",\"description\":\"The secret label for the HMAC signing key\",\"type\":\"STRING\",\"required\":true,\"defaultValue\":\"esv.signing.key\",\"multivalued\":false},\"validity\":{\"title\":\"Validity (minutes)\",\"description\":\"\",\"type\":\"NUMBER\",\"required\":true,\"defaultValue\":5,\"multivalued\":false}}},{\"_id\":\"ef81b1a52c914710b3388caebfe7233a-1\",\"_rev\":\"1723458869\",\"serviceName\":\"ef81b1a52c914710b3388caebfe7233a\",\"displayName\":\"Display Callback\",\"description\":\"Displays custom callback to the page\",\"outcomes\":[\"outcome\"],\"outputs\":[],\"inputs\":[],\"script\":\"var SCRIPT_OUTCOMES = {\\n OUTCOME: 'outcome'\\n};\\n\\nvar CALLBACKS = {\\n\\tBOOLEAN_ATTRIBUTE_INPUT_CALLBACK: \\\"BOOLEAN_ATTRIBUTE_INPUT_CALLBACK\\\",\\n\\tCHOICE_CALLBACK: \\\"CHOICE_CALLBACK\\\",\\n\\tCONFIRMATION_CALLBACK: \\\"CONFIRMATION_CALLBACK\\\",\\n\\tCONSENT_MAPPING_CALLBACK: \\\"CONSENT_MAPPING_CALLBACK\\\",\\n\\tDEVICE_PROFILE_CALLBACK: \\\"DEVICE_PROFILE_CALLBACK\\\",\\n\\tHIDDEN_VALUE_CALLBACK: \\\"HIDDEN_VALUE_CALLBACK\\\",\\n\\tHTTP_CALLBACK: \\\"HTTP_CALLBACK\\\",\\n\\tIDP_CALLBACK: \\\"IDP_CALLBACK\\\",\\n\\tKBA_CREATE_CALLBACK: \\\"KBA_CREATE_CALLBACK\\\",\\n\\tLANGUAGE_CALLBACK: \\\"LANGUAGE_CALLBACK\\\",\\n\\tMETADATA_CALLBACK: \\\"METADATA_CALLBACK\\\",\\n\\tNAME_CALLBACK: \\\"NAME_CALLBACK\\\",\\n\\tNUMBER_ATTRIBUTE_INPUT_CALLBACK: \\\"NUMBER_ATTRIBUTE_INPUT_CALLBACK\\\",\\n\\tPASSWORD_CALLBACK: \\\"PASSWORD_CALLBACK\\\",\\n\\tPOLLING_WAIT_CALLBACK: \\\"POLLING_WAIT_CALLBACK\\\",\\n REDIRECT_CALLBACK: \\\"REDIRECT_CALLBACK\\\",\\n\\tSCRIPT_TEXT_OUTPUT_CALLBACK: \\\"SCRIPT_TEXT_OUTPUT_CALLBACK\\\",\\n\\tSELECT_IDP_CALLBACK: \\\"SELECT_IDP_CALLBACK\\\",\\n\\tSTRING_ATTRIBUTE_INPUT_CALLBACK: \\\"STRING_ATTRIBUTE_INPUT_CALLBACK\\\",\\n\\tSUSPENDED_TEXT_OUTPUT_CALLBACK: \\\"SUSPENDED_TEXT_OUTPUT_CALLBACK\\\",\\n\\tTERMS_AND_CONDITIONS_CALLBACK: \\\"TERMS_AND_CONDITIONS_CALLBACK\\\",\\n\\tTEXT_INPUT_CALLBACK: \\\"TEXT_INPUT_CALLBACK\\\",\\n\\tTEXT_OUTPUT_CALLBACK: \\\"TEXT_OUTPUT_CALLBACK\\\",\\n\\tVALIDATED_PASSWORD_CALLBACK: \\\"VALIDATED_PASSWORD_CALLBACK\\\",\\n\\tVALIDATED_USERNAME_CALLBACK: \\\"VALIDATED_USERNAME_CALLBACK\\\",\\n\\tX509_CERTIFICATE_CALLBACK: \\\"X509_CERTIFICATE_CALLBACK\\\"\\n}\\n\\nfunction isStringPresent(value) {\\n return value;\\n}\\n\\nfunction getString(value) {\\n return value || '';\\n}\\n\\nfunction isArrayPresent(value) {\\n return value;\\n}\\n\\nfunction getArray(value) {\\n return value ? JSON.parse(value) : [];\\n}\\n\\nfunction isObjectPresent(value) {\\n return value;\\n}\\n\\nfunction getObject(value) {\\n return value ? JSON.parse(value) : {};\\n}\\n\\nfunction isIntPresent(value) {\\n return value;\\n}\\n\\nfunction getInt(value) {\\n return value ? parseInt(value) : 0;\\n}\\n\\nfunction isDoublePresent(value) {\\n return value;\\n}\\n\\nfunction getDouble(value) {\\n return value ? parseFloat(value) : 0.0;\\n}\\n\\nfunction isBooleanPresent(value) {\\n return value;\\n}\\n\\nfunction getBoolean(value) {\\n return value ? value.toLowerCase() === 'true' : false;\\n}\\n\\nfunction setProperty(value) {\\n if (properties.sharedProperty) nodeState.putShared(properties.sharedProperty, value);\\n if (properties.transientProperty) nodeState.putTransient(properties.transientProperty, value);\\n if (properties.objectSharedProperty) {\\n var attributes = {};\\n attributes[properties.objectSharedProperty] = value;\\n nodeState.mergeShared({\\n objectAttributes: attributes\\n });\\n }\\n if (properties.objectTransientProperty) {\\n var attributes = {};\\n attributes[properties.objectTransientProperty] = value;\\n nodeState.mergeTransient({\\n objectAttributes: attributes\\n });\\n }\\n}\\n\\nfunction booleanAttributeInputCallback() {\\n var name = getString(properties.options.name);\\n var prompt = getString(properties.options.prompt);\\n var value = getBoolean(properties.options.value);\\n var required = getBoolean(properties.options.required);\\n var policies = getObject(properties.options.policies);\\n var validateOnly = getBoolean(properties.options.validateOnly);\\n var failedPolicies = getArray(properties.options.failedPolicies);\\n if (isBooleanPresent(properties.options.validateOnly) || isObjectPresent(properties.options.policies)) {\\n if (isArrayPresent(failedPolicies)) {\\n callbacksBuilder.booleanAttributeInputCallback(name, prompt, value, required, policies, validateOnly, failedPolicies);\\n } else {\\n callbacksBuilder.booleanAttributeInputCallback(name, prompt, value, required, policies, validateOnly);\\n }\\n } else if (isArrayPresent(failedPolicies)) {\\n callbacksBuilder.booleanAttributeInputCallback(name, prompt, value, required, failedPolicies);\\n } else {\\n callbacksBuilder.booleanAttributeInputCallback(name, prompt, value, required);\\n }\\n}\\n\\nfunction choiceCallback() {\\n var prompt = getString(properties.options.prompt);\\n var choices = getArray(properties.options.choices);\\n var defaultChoice = getInt(properties.options.defaultChoice);\\n var multipleSelectionsAllowed = getBoolean(properties.options.multipleSelectionsAllowed);\\n callbacksBuilder.choiceCallback(prompt, choices, defaultChoice, multipleSelectionsAllowed);\\n}\\n\\nfunction confirmationCallback() {\\n var prompt = getString(properties.options.prompt);\\n var messageType = getInt(properties.options.messageType);\\n var options = getArray(properties.options.options);\\n var optionType = getInt(properties.options.optionType);\\n var defaultOption = getInt(properties.options.defaultOption);\\n if (isStringPresent(properties.options.prompt)) {\\n if (isIntPresent(properties.options.optionType)) {\\n callbacksBuilder.confirmationCallback(prompt, messageType, optionType, defaultOption);\\n } else {\\n callbacksBuilder.confirmationCallback(prompt, messageType, options, defaultOption);\\n }\\n } else {\\n if (isIntPresent(properties.options.optionType)) {\\n callbacksBuilder.confirmationCallback(messageType, optionType, defaultOption);\\n } else {\\n callbacksBuilder.confirmationCallback(messageType, options, defaultOption);\\n }\\n }\\n}\\n\\nfunction consentMappingCallback() {\\n var config = getObject(properties.options.config);\\n var message = getString(properties.options.message);\\n var isRequired = getBoolean(properties.options.isRequired);\\n var name = getString(properties.options.name);\\n var displayName = getString(properties.options.displayName);\\n var icon = getString(properties.options.icon);\\n var accessLevel = getString(properties.options.accessLevel);\\n var titles = getArray(properties.options.titles);\\n if (isObjectPresent(properties.options.prompt)) {\\n callbacksBuilder.consentMappingCallback(config, message, isRequired);\\n } else {\\n callbacksBuilder.consentMappingCallback(name, displayName, icon, accessLevel, titles, message, isRequired);\\n }\\n}\\n\\nfunction deviceProfileCallback() {\\n var metadata = getBoolean(properties.options.metadata);\\n var location = getBoolean(properties.options.location);\\n var message = getString(properties.options.message);\\n callbacksBuilder.deviceProfileCallback(metadata, location, message);\\n}\\n\\nfunction hiddenValueCallback() {\\n var id = getString(properties.options.id);\\n var value = getString(properties.options.value);\\n callbacksBuilder.hiddenValueCallback(id, value);\\n}\\n\\nfunction httpCallback() {\\n var authorizationHeader = getString(properties.options.authorizationHeader);\\n var negotiationHeader = getString(properties.options.negotiationHeader);\\n var authRHeader = getString(properties.options.authRHeader);\\n var negoName = getString(properties.options.negoName);\\n var negoValue = getString(properties.options.negoValue);\\n if (isStringPresent(properties.options.authorizationHeader) || isStringPresent(properties.options.negotiationHeader)) {\\n var errorCode = getString(properties.options.errorCode);\\n callbacksBuilder.httpCallback(authorizationHeader, negotiationHeader, errorCode);\\n } else {\\n var errorCode = getInt(properties.options.errorCode);\\n callbacksBuilder.httpCallback(authRHeader, negoName, negoValue, errorCode);\\n }\\n}\\n\\nfunction idPCallback() {\\n var provider = getString(properties.options.provider);\\n var clientId = getString(properties.options.clientId);\\n var redirectUri = getString(properties.options.redirectUri);\\n var scope = getArray(properties.options.scope);\\n var nonce = getString(properties.options.nonce);\\n var request = getString(properties.options.request);\\n var requestUri = getString(properties.options.requestUri);\\n var acrValues = getArray(properties.options.acrValues);\\n var requestNativeAppForUserInfo = getBoolean(properties.options.requestNativeAppForUserInfo);\\n var token = getString(properties.options.token);\\n var tokenType = getString(properties.options.tokenType);\\n if (isStringPresent(properties.options.token) || isStringPresent(properties.options.tokenType)) {\\n callbacksBuilder.idPCallback(provider, clientId, redirectUri, scope, nonce, request, requestUri, acrValues, requestNativeAppForUserInfo, token, tokenType);\\n } else {\\n callbacksBuilder.idPCallback(provider, clientId, redirectUri, scope, nonce, request, requestUri, acrValues, requestNativeAppForUserInfo);\\n }\\n}\\n\\nfunction kbaCreateCallback() {\\n var prompt = getString(properties.options.prompt);\\n var predefinedQuestions = getArray(properties.options.predefinedQuestions);\\n var allowUserDefinedQuestions = getBoolean(properties.options.allowUserDefinedQuestions);\\n callbacksBuilder.kbaCreateCallback(prompt, predefinedQuestions, allowUserDefinedQuestions);\\n}\\n\\nfunction languageCallback() {\\n var language = getString(properties.options.language);\\n var country = getString(properties.options.country);\\n callbacksBuilder.languageCallback(language, country);\\n}\\n\\nfunction metadataCallback() {\\n var outputValue = getObject(properties.options.outputValue);\\n callbacksBuilder.metadataCallback(outputValue);\\n}\\n\\nfunction nameCallback() {\\n var prompt = getString(properties.options.prompt);\\n var defaultName = getString(properties.options.defaultName);\\n if (isStringPresent(properties.options.defaultName)) {\\n callbacksBuilder.nameCallback(prompt, defaultName);\\n } else {\\n callbacksBuilder.nameCallback(prompt);\\n }\\n}\\n\\nfunction numberAttributeInputCallback() {\\n var name = getString(properties.options.name);\\n var prompt = getString(properties.options.prompt);\\n var value = getDouble(properties.options.value);\\n var required = getBoolean(properties.options.required);\\n var policies = getObject(properties.options.policies);\\n var validateOnly = getBoolean(properties.options.validateOnly);\\n var failedPolicies = getArray(properties.options.failedPolicies);\\n if (isBooleanPresent(properties.options.validateOnly) || isObjectPresent(properties.options.policies)) {\\n if (isArrayPresent(failedPolicies)) {\\n callbacksBuilder.numberAttributeInputCallback(name, prompt, value, required, policies, validateOnly, failedPolicies);\\n } else {\\n callbacksBuilder.numberAttributeInputCallback(name, prompt, value, required, policies, validateOnly);\\n }\\n } else if (isArrayPresent(failedPolicies)) {\\n callbacksBuilder.numberAttributeInputCallback(name, prompt, value, required, failedPolicies);\\n } else {\\n callbacksBuilder.numberAttributeInputCallback(name, prompt, value, required);\\n }\\n}\\n\\nfunction passwordCallback() {\\n var prompt = getString(properties.options.prompt);\\n var echoOn = getBoolean(properties.options.echoOn);\\n callbacksBuilder.passwordCallback(prompt, echoOn);\\n}\\n\\nfunction pollingWaitCallback() {\\n var waitTime = getString(properties.options.waitTime);\\n var message = getString(properties.options.message);\\n callbacksBuilder.pollingWaitCallback(waitTime, message);\\n}\\n\\nfunction redirectCallback() {\\n throw new Error('Not Implemented');\\n}\\n\\nfunction scriptTextOutputCallback() {\\n var message = getString(properties.options.message);\\n callbacksBuilder.scriptTextOutputCallback(message);\\n}\\n\\nfunction selectIdPCallback() {\\n var providers = getObject(properties.options.providers);\\n callbacksBuilder.selectIdPCallback(providers);\\n}\\n\\nfunction stringAttributeInputCallback() {\\n var name = getString(properties.options.name);\\n var prompt = getString(properties.options.prompt);\\n var value = getString(properties.options.value);\\n var required = getBoolean(properties.options.required);\\n var policies = getObject(properties.options.policies);\\n var validateOnly = getBoolean(properties.options.validateOnly);\\n var failedPolicies = getArray(properties.options.failedPolicies);\\n if (isBooleanPresent(properties.options.validateOnly) || isObjectPresent(properties.options.policies)) {\\n if (isArrayPresent(failedPolicies)) {\\n callbacksBuilder.stringAttributeInputCallback(name, prompt, value, required, policies, validateOnly, failedPolicies);\\n } else {\\n callbacksBuilder.stringAttributeInputCallback(name, prompt, value, required, policies, validateOnly);\\n }\\n } else if (isArrayPresent(failedPolicies)) {\\n callbacksBuilder.stringAttributeInputCallback(name, prompt, value, required, failedPolicies);\\n } else {\\n callbacksBuilder.stringAttributeInputCallback(name, prompt, value, required);\\n }\\n}\\n\\nfunction suspendedTextOutputCallback() {\\n var messageType = getInt(properties.options.messageType);\\n var message = getString(properties.options.message);\\n callbacksBuilder.suspendedTextOutputCallback(messageType, message);\\n}\\n\\nfunction termsAndConditionsCallback() {\\n var version = getString(properties.options.version);\\n var terms = getString(properties.options.terms);\\n var createDate = getString(properties.options.createDate);\\n callbacksBuilder.termsAndConditionsCallback(version, terms, createDate);\\n}\\n\\nfunction textInputCallback() {\\n var prompt = getString(properties.options.prompt);\\n var defaultText = getString(properties.options.defaultText);\\n if (isStringPresent(properties.options.defaultText)) {\\n callbacksBuilder.textInputCallback(prompt, defaultText);\\n } else {\\n callbacksBuilder.textInputCallback(prompt);\\n }\\n}\\n\\nfunction textOutputCallback() {\\n var messageType = getString(properties.options.messageType);\\n var message = getString(properties.options.message);\\n callbacksBuilder.textOutputCallback(messageType, message);\\n}\\n\\nfunction validatedPasswordCallback() {\\n var prompt = getString(properties.options.prompt);\\n var echoOn = getBoolean(properties.options.echoOn);\\n var policies = getObject(properties.options.policies);\\n var validateOnly = getBoolean(properties.options.validateOnly);\\n var failedPolicies = getArray(properties.options.failedPolicies);\\n if (isArrayPresent(properties.options.failedPolicies)) {\\n callbacksBuilder.validatedPasswordCallback(prompt, echoOn, policies, validateOnly, failedPolicies);\\n } else {\\n callbacksBuilder.validatedPasswordCallback(prompt, echoOn, policies, validateOnly);\\n }\\n}\\n\\nfunction validatedUsernameCallback() {\\n var prompt = getString(properties.options.prompt);\\n var policies = getObject(properties.options.policies);\\n var validateOnly = getBoolean(properties.options.validateOnly);\\n var failedPolicies = getArray(properties.options.failedPolicies);\\n if (isArrayPresent(properties.options.failedPolicies)) {\\n callbacksBuilder.validatedUsernameCallback(prompt, policies, validateOnly, failedPolicies);\\n } else {\\n callbacksBuilder.validatedUsernameCallback(prompt, policies, validateOnly);\\n }\\n}\\n\\nfunction x509CertificateCallback() {\\n throw new Error('Not Implemented');\\n}\\n\\nfunction getBooleanAttributeInputCallback() {\\n setProperty(callbacks.getBooleanAttributeInputCallbacks().get(0));\\n}\\n\\nfunction getChoiceCallback() {\\n var multipleSelectionsAllowed = getBoolean(properties.options.multipleSelectionsAllowed);\\n var selections = callbacks.getChoiceCallbacks().get(0);\\n setProperty(multipleSelectionsAllowed ? selections : selections[0]);\\n}\\n\\nfunction getConfirmationCallback() {\\n setProperty(callbacks.getConfirmationCallbacks().get(0));\\n}\\n\\nfunction getConsentMappingCallback() {\\n setProperty(callbacks.getConsentMappingCallbacks().get(0));\\n}\\n\\nfunction getDeviceProfileCallback() {\\n setProperty(callbacks.getDeviceProfileCallbacks().get(0));\\n}\\n\\nfunction getHiddenValueCallback() {\\n var id = getString(properties.options.id);\\n setProperty(callbacks.getHiddenValueCallbacks().get(id));\\n}\\n\\nfunction getHttpCallback() {\\n setProperty(callbacks.getHttpCallbacks().get(0));\\n}\\n\\nfunction getIdPCallback() {\\n setProperty(callbacks.getIdpCallbacks().get(0));\\n}\\n\\nfunction getKbaCreateCallback() {\\n setProperty(callbacks.getKbaCreateCallbacks().get(0));\\n}\\n\\nfunction getLanguageCallback() {\\n setProperty(callbacks.getLanguageCallbacks().get(0));\\n}\\n\\nfunction getNameCallback() {\\n setProperty(callbacks.getNameCallbacks().get(0));\\n}\\n\\nfunction getNumberAttributeInputCallback() {\\n setProperty(callbacks.getNumberAttributeInputCallbacks().get(0));\\n}\\n\\nfunction getPasswordCallback() {\\n setProperty(callbacks.getPasswordCallbacks().get(0));\\n}\\n\\nfunction getSelectIdPCallback() {\\n setProperty(callbacks.getSelectIdPCallbacks().get(0));\\n}\\n\\nfunction getStringAttributeInputCallback() {\\n setProperty(callbacks.getStringAttributeInputCallbacks().get(0));\\n}\\n\\nfunction getTermsAndConditionsCallback() {\\n setProperty(callbacks.getTermsAndConditionsCallbacks().get(0));\\n}\\n\\nfunction getTextInputCallback() {\\n setProperty(callbacks.getTextInputCallbacks().get(0));\\n}\\n\\nfunction getValidatedPasswordCallback() {\\n setProperty(callbacks.getValidatedPasswordCallbacks().get(0));\\n}\\n\\nfunction getValidatedUsernameCallback() {\\n setProperty(callbacks.getValidatedUsernameCallbacks().get(0));\\n}\\n\\nfunction getX509CertificateCallback() {\\n setProperty(callbacks.getX509CertificateCallbacks().get(0));\\n}\\n\\nfunction main() {\\n if (!callbacks.isEmpty()) {\\n switch (properties.callback) {\\n case CALLBACKS.BOOLEAN_ATTRIBUTE_INPUT_CALLBACK: getBooleanAttributeInputCallback(); break;\\n case CALLBACKS.CHOICE_CALLBACK: getChoiceCallback(); break;\\n case CALLBACKS.CONFIRMATION_CALLBACK: getConfirmationCallback(); break;\\n case CALLBACKS.CONSENT_MAPPING_CALLBACK: getConsentMappingCallback(); break;\\n case CALLBACKS.DEVICE_PROFILE_CALLBACK: getDeviceProfileCallback(); break;\\n case CALLBACKS.HIDDEN_VALUE_CALLBACK: getHiddenValueCallback(); break;\\n case CALLBACKS.HTTP_CALLBACK: getHttpCallback(); break;\\n case CALLBACKS.IDP_CALLBACK: getIdPCallback(); break;\\n case CALLBACKS.KBA_CREATE_CALLBACK: getKbaCreateCallback(); break;\\n case CALLBACKS.LANGUAGE_CALLBACK: getLanguageCallback(); break;\\n case CALLBACKS.NAME_CALLBACK: getNameCallback(); break;\\n case CALLBACKS.NUMBER_ATTRIBUTE_INPUT_CALLBACK: getNumberAttributeInputCallback(); break;\\n case CALLBACKS.PASSWORD_CALLBACK: getPasswordCallback(); break;\\n case CALLBACKS.SELECT_IDP_CALLBACK: getSelectIdPCallback(); break;\\n case CALLBACKS.STRING_ATTRIBUTE_INPUT_CALLBACK: getStringAttributeInputCallback(); break;\\n case CALLBACKS.TERMS_AND_CONDITIONS_CALLBACK: getTermsAndConditionsCallback(); break;\\n case CALLBACKS.TEXT_INPUT_CALLBACK: getTextInputCallback(); break;\\n case CALLBACKS.VALIDATED_PASSWORD_CALLBACK: getValidatedPasswordCallback(); break;\\n case CALLBACKS.VALIDATED_USERNAME_CALLBACK: getValidatedUsernameCallback(); break;\\n case CALLBACKS.X509_CERTIFICATE_CALLBACK: getX509CertificateCallback(); break;\\n default: break;\\n }\\n action.goTo(SCRIPT_OUTCOMES.OUTCOME);\\n return;\\n }\\n\\n switch (properties.callback) {\\n case CALLBACKS.BOOLEAN_ATTRIBUTE_INPUT_CALLBACK: booleanAttributeInputCallback(); break;\\n case CALLBACKS.CHOICE_CALLBACK: choiceCallback(); break;\\n case CALLBACKS.CONFIRMATION_CALLBACK: confirmationCallback(); break;\\n case CALLBACKS.CONSENT_MAPPING_CALLBACK: consentMappingCallback(); break;\\n case CALLBACKS.DEVICE_PROFILE_CALLBACK: deviceProfileCallback(); break;\\n case CALLBACKS.HIDDEN_VALUE_CALLBACK: hiddenValueCallback(); break;\\n case CALLBACKS.HTTP_CALLBACK: httpCallback(); break;\\n case CALLBACKS.IDP_CALLBACK: idPCallback(); break;\\n case CALLBACKS.KBA_CREATE_CALLBACK: kbaCreateCallback(); break;\\n case CALLBACKS.LANGUAGE_CALLBACK: languageCallback(); break;\\n case CALLBACKS.METADATA_CALLBACK: metadataCallback(); break;\\n case CALLBACKS.NAME_CALLBACK: nameCallback(); break;\\n case CALLBACKS.NUMBER_ATTRIBUTE_INPUT_CALLBACK: numberAttributeInputCallback(); break;\\n case CALLBACKS.PASSWORD_CALLBACK: passwordCallback(); break;\\n case CALLBACKS.POLLING_WAIT_CALLBACK: pollingWaitCallback(); break;\\n case CALLBACKS.REDIRECT_CALLBACK: redirectCallback(); break;\\n case CALLBACKS.SCRIPT_TEXT_OUTPUT_CALLBACK: scriptTextOutputCallback(); break;\\n case CALLBACKS.SELECT_IDP_CALLBACK: selectIdPCallback(); break;\\n case CALLBACKS.STRING_ATTRIBUTE_INPUT_CALLBACK: stringAttributeInputCallback(); break;\\n case CALLBACKS.SUSPENDED_TEXT_OUTPUT_CALLBACK: suspendedTextOutputCallback(); break;\\n case CALLBACKS.TERMS_AND_CONDITIONS_CALLBACK: termsAndConditionsCallback(); break;\\n case CALLBACKS.TEXT_INPUT_CALLBACK: textInputCallback(); break;\\n case CALLBACKS.TEXT_OUTPUT_CALLBACK: textOutputCallback(); break;\\n case CALLBACKS.VALIDATED_PASSWORD_CALLBACK: validatedPasswordCallback(); break;\\n case CALLBACKS.VALIDATED_USERNAME_CALLBACK: validatedUsernameCallback(); break;\\n case CALLBACKS.X509_CERTIFICATE_CALLBACK: x509CertificateCallback(); break;\\n default: throw new Error('Unknown Callback'); // Should never reach this case\\n }\\n}\\n\\nmain();\\n\",\"errorOutcome\":false,\"tags\":[\"callback\",\"utilities\"],\"properties\":{\"callback\":{\"title\":\"Callback\",\"description\":\"The callback to display\",\"type\":\"STRING\",\"required\":true,\"options\":{\"METADATA_CALLBACK\":\"metadataCallback\",\"TERMS_AND_CONDITIONS_CALLBACK\":\"termsAndConditionsCallback\",\"NUMBER_ATTRIBUTE_INPUT_CALLBACK\":\"numberAttributeInputCallback\",\"TEXT_OUTPUT_CALLBACK\":\"textOutputCallback\",\"SCRIPT_TEXT_OUTPUT_CALLBACK\":\"scriptTextOutputCallback\",\"CONSENT_MAPPING_CALLBACK\":\"consentMappingCallback\",\"STRING_ATTRIBUTE_INPUT_CALLBACK\":\"stringAttributeInputCallback\",\"IDP_CALLBACK\":\"idPCallback\",\"VALIDATED_PASSWORD_CALLBACK\":\"validatedPasswordCallback\",\"SELECT_IDP_CALLBACK\":\"selectIdPCallback\",\"POLLING_WAIT_CALLBACK\":\"pollingWaitCallback\",\"NAME_CALLBACK\":\"nameCallback\",\"SUSPENDED_TEXT_OUTPUT_CALLBACK\":\"suspendedTextOutputCallback\",\"REDIRECT_CALLBACK\":\"redirectCallback\",\"X509_CERTIFICATE_CALLBACK\":\"x509CertificateCallback\",\"PASSWORD_CALLBACK\":\"passwordCallback\",\"TEXT_INPUT_CALLBACK\":\"textInputCallback\",\"BOOLEAN_ATTRIBUTE_INPUT_CALLBACK\":\"booleanAttributeInputCallback\",\"CONFIRMATION_CALLBACK\":\"confirmationCallback\",\"CHOICE_CALLBACK\":\"choiceCallback\",\"DEVICE_PROFILE_CALLBACK\":\"deviceProfileCallback\",\"HIDDEN_VALUE_CALLBACK\":\"hiddenValueCallback\",\"HTTP_CALLBACK\":\"httpCallback\",\"VALIDATED_USERNAME_CALLBACK\":\"validatedUsernameCallback\",\"KBA_CREATE_CALLBACK\":\"kbaCreateCallback\",\"LANGUAGE_CALLBACK\":\"languageCallback\"},\"multivalued\":false},\"objectSharedProperty\":{\"title\":\"Object Attributes Shared Property\",\"description\":\"The objectAttributes property on the shared state to put the callback input into (if applicable)\",\"type\":\"STRING\",\"required\":false,\"multivalued\":false},\"objectTransientProperty\":{\"title\":\"Object Attributes Transient Property\",\"description\":\"The objectAttributes property on the transient state to put the callback input into (if applicable)\",\"type\":\"STRING\",\"required\":false,\"multivalued\":false},\"options\":{\"title\":\"Options\",\"description\":\"The options containing the parameters for the callback (see documentation for possible parameters: https://docs.pingidentity.com/pingoneaic/latest/am-scripting/scripting-api-node.html#scripting-api-node-callbacks). \\n\\nFor example, for textOutputCallback, the options could be: { messageType: 0, message: \\\"Hello World!\\\" }. \\n\\nNote that for required parameters that are not specified in the options will use default values based on the type of the parameter (\\\"\\\" for Strings, [] for Arrays, {} for Objects, 0 for Ints, 0.0 for Doubles, and false for Booleans).\",\"type\":\"OBJECT\",\"required\":true,\"multivalued\":false},\"sharedProperty\":{\"title\":\"Shared State Property\",\"description\":\"The shared state property to put the callback input into (if applicable)\",\"type\":\"STRING\",\"required\":false,\"multivalued\":false},\"transientProperty\":{\"title\":\"Transient State Property\",\"description\":\"The transient state property to put the callback input into (if applicable)\",\"type\":\"STRING\",\"required\":false,\"multivalued\":false}}}],\"resultCount\":7,\"pagedResultsCookie\":null,\"totalPagedResultsPolicy\":\"EXACT\",\"totalPagedResults\":7,\"remainingPagedResults\":-1}" + }, + "cookies": [ + { + "httpOnly": true, + "name": "route", + "path": "/am", + "secure": true, + "value": "" + } + ], + "headers": [ + { + "name": "date", + "value": "Mon, 13 Apr 2026 22:11:13 GMT" + }, + { + "name": "content-type", + "value": "application/json;charset=UTF-8" + }, + { + "name": "transfer-encoding", + "value": "chunked" + }, + { + "name": "connection", + "value": "keep-alive" + }, + { + "_fromType": "array", + "name": "set-cookie", + "value": "route=; Path=/am; Secure; HttpOnly" + }, + { + "name": "x-frame-options", + "value": "SAMEORIGIN" + }, + { + "name": "x-content-type-options", + "value": "nosniff" + }, + { + "name": "cache-control", + "value": "private" + }, + { + "name": "content-api-version", + "value": "protocol=2.1,resource=1.0, resource=1.0" + }, + { + "name": "content-security-policy", + "value": "default-src 'none';frame-ancestors 'none';sandbox" + }, + { + "name": "cross-origin-opener-policy", + "value": "same-origin" + }, + { + "name": "cross-origin-resource-policy", + "value": "same-origin" + }, + { + "name": "expires", + "value": "0" + }, + { + "name": "pragma", + "value": "no-cache" + }, + { + "name": "strict-transport-security", + "value": "max-age=31536000; includeSubDomains" + } + ], + "headersSize": 644, + "httpVersion": "HTTP/1.1", + "redirectURL": "", + "status": 200, + "statusText": "OK" + }, + "startedDateTime": "2026-04-13T22:11:13.677Z", + "time": 9, + "timings": { + "blocked": -1, + "connect": -1, + "dns": -1, + "receive": 0, + "send": 0, + "ssl": -1, + "wait": 9 + } + } + ], + "pages": [], + "version": "1.2" + } +} diff --git a/test/e2e/mocks/config-manager_4167095917/pull_2167214206/custom-nodes_3091214966/0_D_m_314327836/oauth2_393036114/recording.har b/test/e2e/mocks/config-manager_4167095917/pull_2167214206/custom-nodes_3091214966/0_D_m_314327836/oauth2_393036114/recording.har new file mode 100644 index 000000000..b34b30eda --- /dev/null +++ b/test/e2e/mocks/config-manager_4167095917/pull_2167214206/custom-nodes_3091214966/0_D_m_314327836/oauth2_393036114/recording.har @@ -0,0 +1,289 @@ +{ + "log": { + "_recordingName": "config-manager/pull/custom-nodes/0_D_m/oauth2", + "creator": { + "comment": "persister:fs", + "name": "Polly.JS", + "version": "6.0.6" + }, + "entries": [ + { + "_id": "a684e2f67fd67a4263878c3124af167a", + "_order": 0, + "cache": {}, + "request": { + "bodySize": 365, + "cookies": [], + "headers": [ + { + "name": "accept", + "value": "application/json, text/plain, */*" + }, + { + "name": "content-type", + "value": "application/x-www-form-urlencoded" + }, + { + "name": "user-agent", + "value": "@rockcarver/frodo-lib/4.0.0-36" + }, + { + "name": "x-forgerock-transactionid", + "value": "frodo-57641519-67ef-4da6-8b71-2538f4143c60" + }, + { + "name": "accept-api-version", + "value": "protocol=2.1,resource=1.0" + }, + { + "name": "cookie", + "value": "iPlanetDirectoryPro=" + }, + { + "name": "content-length", + "value": "365" + }, + { + "name": "accept-encoding", + "value": "gzip, compress, deflate, br" + }, + { + "name": "host", + "value": "openam-frodo-dev.forgeblocks.com" + } + ], + "headersSize": 565, + "httpVersion": "HTTP/1.1", + "method": "POST", + "postData": { + "mimeType": "application/x-www-form-urlencoded", + "params": [], + "text": "redirect_uri=https://platform.dev.trivir.com/platform/appAuthHelperRedirect.html&scope=fr:idm:* openid&response_type=code&client_id=idm-admin-ui&csrf=TZTPpCLGkex90Xi3gF9X9bnWlPQ.*AAJTSQACMDIAAlNLABw2VnJPSmdBcXdZNWNacXhtM0ZOOGdqNC9oNVU9AAR0eXBlAANDVFMAAlMxAAIwMQ..*&decision=allow&code_challenge=ZByMVKUzuPfJ54tcv4ytC8jLxg8Vp2InlKA_Xoe_RGo&code_challenge_method=S256" + }, + "queryString": [], + "url": "https://platform.dev.trivir.com/am/oauth2/authorize" + }, + "response": { + "bodySize": 0, + "content": { + "mimeType": "text/plain", + "size": 0 + }, + "cookies": [ + { + "httpOnly": true, + "name": "route", + "path": "/am", + "secure": true, + "value": "" + }, + { + "expires": "1970-01-01T00:00:00.000Z", + "httpOnly": true, + "name": "OAUTH_REQUEST_ATTRIBUTES", + "path": "/", + "sameSite": "none", + "secure": true, + "value": "" + } + ], + "headers": [ + { + "name": "date", + "value": "Mon, 13 Apr 2026 22:11:13 GMT" + }, + { + "name": "content-length", + "value": "0" + }, + { + "name": "connection", + "value": "keep-alive" + }, + { + "_fromType": "array", + "name": "set-cookie", + "value": "route=; Path=/am; Secure; HttpOnly" + }, + { + "_fromType": "array", + "name": "set-cookie", + "value": "OAUTH_REQUEST_ATTRIBUTES=; Expires=Thu, 01 Jan 1970 00:00:00 GMT; Path=/; Secure; HttpOnly; SameSite=none" + }, + { + "name": "x-frame-options", + "value": "SAMEORIGIN" + }, + { + "name": "x-content-type-options", + "value": "nosniff" + }, + { + "name": "cache-control", + "value": "no-store" + }, + { + "name": "location", + "value": "https://platform.dev.trivir.com/platform/appAuthHelperRedirect.html?code=yidr7CqLl83wCrLAUtbTVLECXxo&iss=https%3A%2F%2Fplatform.dev.trivir.com%2Fam%2Foauth2&client_id=idm-admin-ui" + }, + { + "name": "pragma", + "value": "no-cache" + }, + { + "name": "strict-transport-security", + "value": "max-age=31536000; includeSubDomains" + } + ], + "headersSize": 673, + "httpVersion": "HTTP/1.1", + "redirectURL": "https://platform.dev.trivir.com/platform/appAuthHelperRedirect.html?code=yidr7CqLl83wCrLAUtbTVLECXxo&iss=https%3A%2F%2Fplatform.dev.trivir.com%2Fam%2Foauth2&client_id=idm-admin-ui", + "status": 302, + "statusText": "Found" + }, + "startedDateTime": "2026-04-13T22:11:13.596Z", + "time": 19, + "timings": { + "blocked": -1, + "connect": -1, + "dns": -1, + "receive": 0, + "send": 0, + "ssl": -1, + "wait": 19 + } + }, + { + "_id": "ff75519a93ccab829f8ee8cf5e92b49f", + "_order": 0, + "cache": {}, + "request": { + "bodySize": 224, + "cookies": [], + "headers": [ + { + "name": "accept", + "value": "application/json, text/plain, */*" + }, + { + "name": "content-type", + "value": "application/x-www-form-urlencoded" + }, + { + "name": "user-agent", + "value": "@rockcarver/frodo-lib/4.0.0-36" + }, + { + "name": "x-forgerock-transactionid", + "value": "frodo-57641519-67ef-4da6-8b71-2538f4143c60" + }, + { + "name": "accept-api-version", + "value": "protocol=2.1,resource=1.0" + }, + { + "name": "content-length", + "value": "224" + }, + { + "name": "accept-encoding", + "value": "gzip, compress, deflate, br" + }, + { + "name": "host", + "value": "openam-frodo-dev.forgeblocks.com" + } + ], + "headersSize": 424, + "httpVersion": "HTTP/1.1", + "method": "POST", + "postData": { + "mimeType": "application/x-www-form-urlencoded", + "params": [], + "text": "client_id=idm-admin-ui&redirect_uri=https://platform.dev.trivir.com/platform/appAuthHelperRedirect.html&grant_type=authorization_code&code=yidr7CqLl83wCrLAUtbTVLECXxo&code_verifier=MMypQYIABQU7mcr6pH2fb5qrX9BJKGHvI8tJ_1jL7V0" + }, + "queryString": [], + "url": "https://platform.dev.trivir.com/am/oauth2/access_token" + }, + "response": { + "bodySize": 1249, + "content": { + "mimeType": "application/json;charset=UTF-8", + "size": 1249, + "text": "{\"access_token\":\"\",\"scope\":\"openid fr:idm:*\",\"id_token\":\"\",\"token_type\":\"Bearer\",\"expires_in\":239}" + }, + "cookies": [ + { + "httpOnly": true, + "name": "route", + "path": "/am", + "secure": true, + "value": "" + } + ], + "headers": [ + { + "name": "date", + "value": "Mon, 13 Apr 2026 22:11:13 GMT" + }, + { + "name": "content-type", + "value": "application/json;charset=UTF-8" + }, + { + "name": "content-length", + "value": "1249" + }, + { + "name": "connection", + "value": "keep-alive" + }, + { + "_fromType": "array", + "name": "set-cookie", + "value": "route=; Path=/am; Secure; HttpOnly" + }, + { + "name": "x-frame-options", + "value": "SAMEORIGIN" + }, + { + "name": "x-content-type-options", + "value": "nosniff" + }, + { + "name": "cache-control", + "value": "no-store" + }, + { + "name": "pragma", + "value": "no-cache" + }, + { + "name": "strict-transport-security", + "value": "max-age=31536000; includeSubDomains" + } + ], + "headersSize": 404, + "httpVersion": "HTTP/1.1", + "redirectURL": "", + "status": 200, + "statusText": "OK" + }, + "startedDateTime": "2026-04-13T22:11:13.622Z", + "time": 46, + "timings": { + "blocked": -1, + "connect": -1, + "dns": -1, + "receive": 0, + "send": 0, + "ssl": -1, + "wait": 46 + } + } + ], + "pages": [], + "version": "1.2" + } +} diff --git a/test/e2e/mocks/config-manager_4167095917/pull_2167214206/custom-nodes_3091214966/0_D_n_m_3294969001/am_1076162899/recording.har b/test/e2e/mocks/config-manager_4167095917/pull_2167214206/custom-nodes_3091214966/0_D_n_m_3294969001/am_1076162899/recording.har new file mode 100644 index 000000000..94f535f1b --- /dev/null +++ b/test/e2e/mocks/config-manager_4167095917/pull_2167214206/custom-nodes_3091214966/0_D_n_m_3294969001/am_1076162899/recording.har @@ -0,0 +1,780 @@ +{ + "log": { + "_recordingName": "config-manager/pull/custom-nodes/0_D_n_m/am", + "creator": { + "comment": "persister:fs", + "name": "Polly.JS", + "version": "6.0.6" + }, + "entries": [ + { + "_id": "ccd7a5defd0fdeaa986a2b54642d911a", + "_order": 0, + "cache": {}, + "request": { + "bodySize": 0, + "cookies": [], + "headers": [ + { + "name": "accept", + "value": "application/json, text/plain, */*" + }, + { + "name": "content-type", + "value": "application/json" + }, + { + "name": "user-agent", + "value": "@rockcarver/frodo-lib/4.0.0-36" + }, + { + "name": "x-forgerock-transactionid", + "value": "frodo-2bbd1177-cbbd-4974-972a-04dbc344d69a" + }, + { + "name": "accept-api-version", + "value": "resource=1.1" + }, + { + "name": "accept-encoding", + "value": "gzip, compress, deflate, br" + }, + { + "name": "host", + "value": "openam-frodo-dev.forgeblocks.com" + } + ], + "headersSize": 370, + "httpVersion": "HTTP/1.1", + "method": "GET", + "queryString": [], + "url": "https://platform.dev.trivir.com/am/json/serverinfo/*" + }, + "response": { + "bodySize": 587, + "content": { + "mimeType": "application/json;charset=UTF-8", + "size": 587, + "text": "{\"_id\":\"*\",\"_rev\":\"2075994313\",\"domains\":[],\"protectedUserAttributes\":[\"telephoneNumber\",\"mail\"],\"cookieName\":\"iPlanetDirectoryPro\",\"secureCookie\":true,\"forgotPassword\":\"false\",\"forgotUsername\":\"false\",\"kbaEnabled\":\"false\",\"selfRegistration\":\"false\",\"lang\":\"en-US\",\"successfulUserRegistrationDestination\":\"default\",\"socialImplementations\":[],\"referralsEnabled\":\"false\",\"zeroPageLogin\":{\"enabled\":false,\"refererWhitelist\":[],\"allowedWithoutReferer\":true},\"realm\":\"/\",\"xuiUserSessionValidationEnabled\":true,\"fileBasedConfiguration\":true,\"userIdAttributes\":[],\"nodeDesignerXuiEnabled\":true}" + }, + "cookies": [ + { + "httpOnly": true, + "name": "route", + "path": "/am", + "secure": true, + "value": "" + } + ], + "headers": [ + { + "name": "date", + "value": "Mon, 13 Apr 2026 22:11:37 GMT" + }, + { + "name": "content-type", + "value": "application/json;charset=UTF-8" + }, + { + "name": "content-length", + "value": "587" + }, + { + "name": "connection", + "value": "keep-alive" + }, + { + "_fromType": "array", + "name": "set-cookie", + "value": "route=; Path=/am; Secure; HttpOnly" + }, + { + "name": "x-frame-options", + "value": "SAMEORIGIN" + }, + { + "name": "x-content-type-options", + "value": "nosniff" + }, + { + "name": "cache-control", + "value": "no-store" + }, + { + "name": "content-api-version", + "value": "resource=1.1" + }, + { + "name": "content-security-policy", + "value": "default-src 'none';frame-ancestors 'none';sandbox" + }, + { + "name": "cross-origin-opener-policy", + "value": "same-origin" + }, + { + "name": "cross-origin-resource-policy", + "value": "same-origin" + }, + { + "name": "etag", + "value": "\"2075994313\"" + }, + { + "name": "expires", + "value": "0" + }, + { + "name": "pragma", + "value": "no-cache" + }, + { + "name": "strict-transport-security", + "value": "max-age=31536000; includeSubDomains" + } + ], + "headersSize": 631, + "httpVersion": "HTTP/1.1", + "redirectURL": "", + "status": 200, + "statusText": "OK" + }, + "startedDateTime": "2026-04-13T22:11:37.978Z", + "time": 14, + "timings": { + "blocked": -1, + "connect": -1, + "dns": -1, + "receive": 0, + "send": 0, + "ssl": -1, + "wait": 14 + } + }, + { + "_id": "9f5671275c36a1c0090d0df26ce0e93f", + "_order": 0, + "cache": {}, + "request": { + "bodySize": 2, + "cookies": [], + "headers": [ + { + "name": "accept", + "value": "application/json, text/plain, */*" + }, + { + "name": "content-type", + "value": "application/json" + }, + { + "name": "user-agent", + "value": "@rockcarver/frodo-lib/4.0.0-36" + }, + { + "name": "x-forgerock-transactionid", + "value": "frodo-2bbd1177-cbbd-4974-972a-04dbc344d69a" + }, + { + "name": "accept-api-version", + "value": "resource=2.0, protocol=1.0" + }, + { + "name": "x-openam-username", + "value": "amadmin" + }, + { + "name": "x-openam-password", + "value": "41ghjnKpNFAFU/HXw82HbFbitYNOOJ0g" + }, + { + "name": "content-length", + "value": "2" + }, + { + "name": "accept-encoding", + "value": "gzip, compress, deflate, br" + }, + { + "name": "host", + "value": "openam-frodo-dev.forgeblocks.com" + } + ], + "headersSize": 497, + "httpVersion": "HTTP/1.1", + "method": "POST", + "postData": { + "mimeType": "application/json", + "params": [], + "text": "{}" + }, + "queryString": [], + "url": "https://platform.dev.trivir.com/am/json/realms/root/authenticate" + }, + "response": { + "bodySize": 167, + "content": { + "mimeType": "application/json", + "size": 167, + "text": "{\"tokenId\":\"\",\"successUrl\":\"/am/console\",\"realm\":\"/\"}" + }, + "cookies": [ + { + "httpOnly": true, + "name": "route", + "path": "/am", + "secure": true, + "value": "" + }, + { + "httpOnly": true, + "name": "iPlanetDirectoryPro", + "path": "/", + "sameSite": "none", + "secure": true, + "value": "" + }, + { + "httpOnly": true, + "name": "amlbcookie", + "path": "/", + "sameSite": "none", + "secure": true, + "value": "" + } + ], + "headers": [ + { + "name": "date", + "value": "Mon, 13 Apr 2026 22:11:37 GMT" + }, + { + "name": "content-type", + "value": "application/json" + }, + { + "name": "content-length", + "value": "167" + }, + { + "name": "connection", + "value": "keep-alive" + }, + { + "_fromType": "array", + "name": "set-cookie", + "value": "route=; Path=/am; Secure; HttpOnly" + }, + { + "_fromType": "array", + "name": "set-cookie", + "value": "iPlanetDirectoryPro=; Path=/; Secure; HttpOnly; SameSite=none" + }, + { + "_fromType": "array", + "name": "set-cookie", + "value": "amlbcookie=; Path=/; Secure; HttpOnly; SameSite=none" + }, + { + "name": "x-frame-options", + "value": "SAMEORIGIN" + }, + { + "name": "x-content-type-options", + "value": "nosniff" + }, + { + "name": "cache-control", + "value": "private" + }, + { + "name": "content-api-version", + "value": "resource=2.1" + }, + { + "name": "expires", + "value": "0" + }, + { + "name": "pragma", + "value": "no-cache" + }, + { + "name": "strict-transport-security", + "value": "max-age=31536000; includeSubDomains" + } + ], + "headersSize": 693, + "httpVersion": "HTTP/1.1", + "redirectURL": "", + "status": 200, + "statusText": "OK" + }, + "startedDateTime": "2026-04-13T22:11:37.997Z", + "time": 18, + "timings": { + "blocked": -1, + "connect": -1, + "dns": -1, + "receive": 0, + "send": 0, + "ssl": -1, + "wait": 18 + } + }, + { + "_id": "6a3744385d3fd7416ea7089e610fa7e7", + "_order": 0, + "cache": {}, + "request": { + "bodySize": 128, + "cookies": [], + "headers": [ + { + "name": "accept", + "value": "application/json, text/plain, */*" + }, + { + "name": "content-type", + "value": "application/json" + }, + { + "name": "user-agent", + "value": "@rockcarver/frodo-lib/4.0.0-36" + }, + { + "name": "x-forgerock-transactionid", + "value": "frodo-2bbd1177-cbbd-4974-972a-04dbc344d69a" + }, + { + "name": "accept-api-version", + "value": "resource=4.0" + }, + { + "name": "content-length", + "value": "128" + }, + { + "name": "accept-encoding", + "value": "gzip, compress, deflate, br" + }, + { + "name": "host", + "value": "openam-frodo-dev.forgeblocks.com" + } + ], + "headersSize": 424, + "httpVersion": "HTTP/1.1", + "method": "POST", + "postData": { + "mimeType": "application/json", + "params": [], + "text": "{\"tokenId\":\"\"}" + }, + "queryString": [ + { + "name": "_action", + "value": "getSessionInfo" + } + ], + "url": "https://platform.dev.trivir.com/am/json/realms/root/sessions/?_action=getSessionInfo" + }, + "response": { + "bodySize": 291, + "content": { + "mimeType": "application/json;charset=UTF-8", + "size": 291, + "text": "{\"username\":\"amadmin\",\"universalId\":\"id=amadmin,ou=user,ou=am-config\",\"realm\":\"/\",\"latestAccessTime\":\"2026-04-13T22:11:37Z\",\"maxIdleExpirationTime\":\"2026-04-13T22:41:37Z\",\"maxSessionExpirationTime\":\"2026-04-14T00:11:36Z\",\"properties\":{\"AMCtxId\":\"d65b280f-e163-4042-871b-1d0ffe1512eb-12127\"}}" + }, + "cookies": [ + { + "httpOnly": true, + "name": "route", + "path": "/am", + "secure": true, + "value": "" + } + ], + "headers": [ + { + "name": "date", + "value": "Mon, 13 Apr 2026 22:11:37 GMT" + }, + { + "name": "content-type", + "value": "application/json;charset=UTF-8" + }, + { + "name": "content-length", + "value": "291" + }, + { + "name": "connection", + "value": "keep-alive" + }, + { + "_fromType": "array", + "name": "set-cookie", + "value": "route=; Path=/am; Secure; HttpOnly" + }, + { + "name": "x-frame-options", + "value": "SAMEORIGIN" + }, + { + "name": "x-content-type-options", + "value": "nosniff" + }, + { + "name": "cache-control", + "value": "private" + }, + { + "name": "content-api-version", + "value": "resource=4.0" + }, + { + "name": "content-security-policy", + "value": "default-src 'none';frame-ancestors 'none';sandbox" + }, + { + "name": "cross-origin-opener-policy", + "value": "same-origin" + }, + { + "name": "cross-origin-resource-policy", + "value": "same-origin" + }, + { + "name": "expires", + "value": "0" + }, + { + "name": "pragma", + "value": "no-cache" + }, + { + "name": "strict-transport-security", + "value": "max-age=31536000; includeSubDomains" + } + ], + "headersSize": 609, + "httpVersion": "HTTP/1.1", + "redirectURL": "", + "status": 200, + "statusText": "OK" + }, + "startedDateTime": "2026-04-13T22:11:38.021Z", + "time": 8, + "timings": { + "blocked": -1, + "connect": -1, + "dns": -1, + "receive": 0, + "send": 0, + "ssl": -1, + "wait": 8 + } + }, + { + "_id": "6125d0328ad0dcaee55f73fd8b22ca14", + "_order": 0, + "cache": {}, + "request": { + "bodySize": 0, + "cookies": [], + "headers": [ + { + "name": "accept", + "value": "application/json, text/plain, */*" + }, + { + "name": "content-type", + "value": "application/json" + }, + { + "name": "user-agent", + "value": "@rockcarver/frodo-lib/4.0.0-36" + }, + { + "name": "x-forgerock-transactionid", + "value": "frodo-2bbd1177-cbbd-4974-972a-04dbc344d69a" + }, + { + "name": "accept-api-version", + "value": "resource=1.0" + }, + { + "name": "cookie", + "value": "iPlanetDirectoryPro=" + }, + { + "name": "accept-encoding", + "value": "gzip, compress, deflate, br" + }, + { + "name": "host", + "value": "openam-frodo-dev.forgeblocks.com" + } + ], + "headersSize": 520, + "httpVersion": "HTTP/1.1", + "method": "GET", + "queryString": [], + "url": "https://platform.dev.trivir.com/am/json/serverinfo/version" + }, + "response": { + "bodySize": 257, + "content": { + "mimeType": "application/json;charset=UTF-8", + "size": 257, + "text": "{\"_id\":\"version\",\"_rev\":\"-466575464\",\"version\":\"8.0.1\",\"fullVersion\":\"ForgeRock Access Management 8.0.1 Build b59bc0908346197b0c33afcb9e733d0400feeea1 (2025-April-15 11:37)\",\"revision\":\"b59bc0908346197b0c33afcb9e733d0400feeea1\",\"date\":\"2025-April-15 11:37\"}" + }, + "cookies": [ + { + "httpOnly": true, + "name": "route", + "path": "/am", + "secure": true, + "value": "" + } + ], + "headers": [ + { + "name": "date", + "value": "Mon, 13 Apr 2026 22:11:37 GMT" + }, + { + "name": "content-type", + "value": "application/json;charset=UTF-8" + }, + { + "name": "content-length", + "value": "257" + }, + { + "name": "connection", + "value": "keep-alive" + }, + { + "_fromType": "array", + "name": "set-cookie", + "value": "route=; Path=/am; Secure; HttpOnly" + }, + { + "name": "x-frame-options", + "value": "SAMEORIGIN" + }, + { + "name": "x-content-type-options", + "value": "nosniff" + }, + { + "name": "cache-control", + "value": "no-store" + }, + { + "name": "content-api-version", + "value": "resource=1.0" + }, + { + "name": "content-security-policy", + "value": "default-src 'none';frame-ancestors 'none';sandbox" + }, + { + "name": "cross-origin-opener-policy", + "value": "same-origin" + }, + { + "name": "cross-origin-resource-policy", + "value": "same-origin" + }, + { + "name": "etag", + "value": "\"-466575464\"" + }, + { + "name": "expires", + "value": "0" + }, + { + "name": "pragma", + "value": "no-cache" + }, + { + "name": "strict-transport-security", + "value": "max-age=31536000; includeSubDomains" + } + ], + "headersSize": 631, + "httpVersion": "HTTP/1.1", + "redirectURL": "", + "status": 200, + "statusText": "OK" + }, + "startedDateTime": "2026-04-13T22:11:38.036Z", + "time": 6, + "timings": { + "blocked": -1, + "connect": -1, + "dns": -1, + "receive": 0, + "send": 0, + "ssl": -1, + "wait": 6 + } + }, + { + "_id": "e6efe3392d787815b92258f4573fd0b4", + "_order": 0, + "cache": {}, + "request": { + "bodySize": 0, + "cookies": [], + "headers": [ + { + "name": "accept", + "value": "application/json, text/plain, */*" + }, + { + "name": "content-type", + "value": "application/json" + }, + { + "name": "user-agent", + "value": "@rockcarver/frodo-lib/4.0.0-36" + }, + { + "name": "x-forgerock-transactionid", + "value": "frodo-2bbd1177-cbbd-4974-972a-04dbc344d69a" + }, + { + "name": "accept-api-version", + "value": "protocol=2.1,resource=1.0" + }, + { + "name": "cookie", + "value": "iPlanetDirectoryPro=" + }, + { + "name": "accept-encoding", + "value": "gzip, compress, deflate, br" + }, + { + "name": "host", + "value": "openam-frodo-dev.forgeblocks.com" + } + ], + "headersSize": 556, + "httpVersion": "HTTP/1.1", + "method": "GET", + "queryString": [ + { + "name": "_queryFilter", + "value": "true" + } + ], + "url": "https://platform.dev.trivir.com/am/json/node-designer/node-type?_queryFilter=true" + }, + "response": { + "bodySize": 33591, + "content": { + "mimeType": "application/json;charset=UTF-8", + "size": 33591, + "text": "{\"result\":[{\"_id\":\"c6063fb2f5dc42dd9772bedc93898bd8-1\",\"_rev\":\"1733504144\",\"serviceName\":\"c6063fb2f5dc42dd9772bedc93898bd8\",\"displayName\":\"ALU\",\"description\":\"Simple ALU that performs basic binary math operations. Expects an \\\"x\\\" and \\\"y\\\" value on the shared state, and will produce a new \\\"z\\\" value on the shared state as output.\",\"outcomes\":[\"Success\"],\"outputs\":[\"z\"],\"inputs\":[\"x\",\"y\"],\"script\":\"var SCRIPT_OUTCOMES = {\\n SUCCESS: 'Success'\\n};\\n\\nvar OPERATORS = {\\n ADD: \\\"ADD\\\",\\n SUBTRACT: \\\"SUBTRACT\\\",\\n MULTIPLY: \\\"MULTIPLY\\\",\\n DIVIDE: \\\"DIVIDE\\\"\\n}\\n\\nfunction main() {\\n var a = Number(properties.a);\\n var b = Number(properties.b);\\n switch (properties.operator) {\\n case OPERATORS.ADD:\\n nodeState.putShared(\\\"z\\\", a + b);\\n break;\\n case OPERATORS.SUBTRACT:\\n nodeState.putShared(\\\"z\\\", a - b);\\n break;\\n case OPERATORS.MULTIPLY:\\n nodeState.putShared(\\\"z\\\", a * b);\\n break;\\n case OPERATORS.DIVIDE:\\n if (b == 0) throw new Error(\\\"Cannot divide by 0\\\");\\n nodeState.putShared(\\\"z\\\", a / b);\\n break;\\n default: throw new Error(\\\"Unknown operator.\\\");\\n }\\n action.goTo(SCRIPT_OUTCOMES.SUCCESS);\\n}\\n\\nmain();\\n\",\"errorOutcome\":true,\"tags\":[\"math\",\"utilities\"],\"properties\":{\"operator\":{\"title\":\"Operator\",\"description\":\"The operation to perform.\",\"type\":\"STRING\",\"required\":true,\"defaultValue\":\"ADD\",\"options\":{\"ADD\":\"+\",\"MULTIPLY\":\"*\",\"SUBTRACT\":\"-\",\"DIVIDE\":\"/\"},\"multivalued\":false}}},{\"_id\":\"8ab9f1aad4b4460a9c45d15fb148e221-1\",\"_rev\":\"1713151721\",\"serviceName\":\"8ab9f1aad4b4460a9c45d15fb148e221\",\"displayName\":\"Display State\",\"description\":\"Debug node that displays the shared and transient state of the journey for debugging purposes.\",\"outcomes\":[\"outcome\"],\"outputs\":[],\"inputs\":[],\"script\":\"var SCRIPT_OUTCOMES = {\\n OUTCOME: \\\"outcome\\\"\\n};\\n\\nfunction main() {\\n if (!callbacks.isEmpty()) {\\n action.goTo(SCRIPT_OUTCOMES.OUTCOME);\\n return;\\n }\\n var keySet = nodeState.keys(); // Java Set\\n var keys = Array.from(keySet); // Make it into JavaScript array\\n debugState = {};\\n for (var i in keys) {\\n var k = new String(keys[i]);\\n var item = nodeState.get(k);\\n if (typeof item === \\\"object\\\") {\\n debugState[k] = nodeState.getObject(k);\\n } else {\\n debugState[k] = nodeState.get(k);\\n }\\n }\\n if (properties.displayFormat === \\\"JSON\\\") {\\n callbacksBuilder.textOutputCallback(0, `
${JSON.stringify(debugState, null, 2)}
`);\\n return;\\n }\\n callbacksBuilder.textOutputCallback(0, `${Array.from(Object.keys(debugState).map(k => ``))}
KeyValue
${k}
${debugState[k]}
`);\\n}\\n\\nmain();\\n\",\"errorOutcome\":false,\"tags\":[\"debug\",\"testing\"],\"properties\":{\"displayFormat\":{\"title\":\"Display Format\",\"description\":\"The format in which to display the states.\",\"type\":\"STRING\",\"required\":true,\"defaultValue\":\"TABLE\",\"options\":{\"TABLE\":\"HTML Table\",\"JSON\":\"Raw JSON\"},\"multivalued\":false}}},{\"_id\":\"c605506774a848f7877b4d17a453bd39-1\",\"_rev\":\"1583432423\",\"serviceName\":\"c605506774a848f7877b4d17a453bd39\",\"displayName\":\"Has Session\",\"description\":\"Checks if the user has a current session.\",\"outcomes\":[\"True\",\"False\"],\"outputs\":[],\"inputs\":[],\"script\":\"var SCRIPT_OUTCOMES = {\\n TRUE: 'True',\\n FALSE: 'False'\\n}\\n\\nfunction main() {\\n action.goTo(typeof existingSession === \\\"undefined\\\" ? SCRIPT_OUTCOMES.FALSE : SCRIPT_OUTCOMES.TRUE);\\n}\\n\\nmain();\\n\",\"errorOutcome\":false,\"tags\":[\"utilities\"],\"properties\":{}},{\"_id\":\"session-1\",\"_rev\":\"1248028795\",\"serviceName\":\"session\",\"displayName\":\"Has Session AM\",\"description\":\"Checks if the user has a current session.\",\"outcomes\":[\"True\",\"False\"],\"outputs\":[],\"inputs\":[],\"script\":\"var SCRIPT_OUTCOMES = {\\n TRUE: 'True',\\n FALSE: 'False'\\n}\\n\\nfunction main() {\\n action.goTo(typeof existingSession === \\\"undefined\\\" ? SCRIPT_OUTCOMES.FALSE : SCRIPT_OUTCOMES.TRUE);\\n}\\n\\nmain();\\n\",\"errorOutcome\":false,\"tags\":[\"utilities\"],\"properties\":{}},{\"_id\":\"c15e2efb3deb4d4ea338c74a6440b69f-1\",\"_rev\":\"-2034215288\",\"serviceName\":\"c15e2efb3deb4d4ea338c74a6440b69f\",\"displayName\":\"Vector ALU\",\"description\":\"Simple ALU that performs basic binary vector math operations. Outputs the result onto the shared state with key \\\"c\\\".\",\"outcomes\":[\"Success\"],\"outputs\":[\"c\"],\"inputs\":[],\"script\":\"var SCRIPT_OUTCOMES = {\\n SUCCESS: 'Success'\\n};\\n\\nvar OPERATORS = {\\n ADD: \\\"ADD\\\",\\n SUBTRACT: \\\"SUBTRACT\\\",\\n DOT: \\\"DOT\\\",\\n CROSS: \\\"CROSS\\\"\\n}\\n\\nfunction add(a, b) {\\n return a.map((v, i) => v + b[i]);\\n}\\n\\nfunction subtract(a, b) {\\n return a.map((v, i) => v - b[i]);\\n}\\n\\nfunction dot(a, b) {\\n return a.reduce((sum, v, i) => sum + v * b[i], 0);\\n}\\n\\nfunction cross(a, b) {\\n return [\\n a[1] * b[2] - a[2] * b[1],\\n a[2] * b[0] - a[0] * b[2],\\n a[0] * b[1] - a[1] * b[0]\\n ];\\n}\\n\\nfunction main() {\\n if (properties.a.length !== properties.b.length) throw new Error(\\\"Vectors not the same dimension.\\\");\\n switch (properties.operator) {\\n case OPERATORS.ADD:\\n nodeState.putShared(\\\"c\\\", add(properties.a, properties.b));\\n break;\\n case OPERATORS.SUBTRACT:\\n nodeState.putShared(\\\"c\\\", subtract(properties.a, properties.b));\\n break;\\n case OPERATORS.DOT:\\n nodeState.putShared(\\\"c\\\", dot(properties.a, properties.b));\\n break;\\n case OPERATORS.CROSS:\\n if (properties.a.length !== 3) throw new Error(\\\"Vectors not dimension 3 for cross product\\\");\\n nodeState.putShared(\\\"c\\\", cross(properties.a, properties.b));\\n break;\\n default: throw new Error(\\\"Unknown operator.\\\");\\n }\\n action.goTo(SCRIPT_OUTCOMES.SUCCESS);\\n}\\n\\nmain();\\n\",\"errorOutcome\":true,\"tags\":[\"math\",\"vector\",\"utilities\"],\"properties\":{\"a\":{\"title\":\"A\",\"description\":\"Left vector operand\",\"type\":\"NUMBER\",\"required\":true,\"defaultValue\":[1,2,3],\"multivalued\":true},\"b\":{\"title\":\"B\",\"description\":\"Right vector operand\",\"type\":\"NUMBER\",\"required\":true,\"defaultValue\":[4,5,6],\"multivalued\":true},\"operator\":{\"title\":\"Operator\",\"description\":\"The binary operation to perform on the vectors.\",\"type\":\"STRING\",\"required\":true,\"defaultValue\":\"DOT\",\"options\":{\"ADD\":\"+\",\"CROSS\":\"X\",\"DOT\":\".\",\"SUBTRACT\":\"-\"},\"multivalued\":false}}},{\"_id\":\"e5ad0110c8ee4dafaae983003cd05d4a-1\",\"_rev\":\"573016413\",\"serviceName\":\"e5ad0110c8ee4dafaae983003cd05d4a\",\"displayName\":\"Generate JWT\",\"description\":\"Generate a signed JWT using the HMAC SHA-256 algorithm.\",\"outcomes\":[\"True\",\"False\"],\"outputs\":[],\"inputs\":[],\"script\":\"var aud = properties.audience;\\nvar iss = properties.issuer;\\nvar validity = properties.validity;\\nvar esv = properties.signingkey;\\n\\nvar signingkey = systemEnv.getProperty(esv);\\n\\nvar username = nodeState.get(\\\"username\\\");\\n\\nvar data = {\\n jwtType:\\\"SIGNED\\\",\\n jwsAlgorithm: \\\"HS256\\\",\\n issuer: iss,\\n subject: username,\\n audience: aud,\\n type: \\\"JWT\\\",\\n validityMinutes: validity,\\n signingKey: signingkey\\n};\\n\\nvar jwt = jwtAssertion.generateJwt(data);\\n\\nif (jwt !== null && jwt.length > 0) {\\n nodeState.putShared(\\\"assertionJwt\\\" , jwt);\\n action.goTo(\\\"True\\\");\\n} else {\\n action.goTo(\\\"False\\\");\\n}\\n\",\"errorOutcome\":true,\"tags\":[\"Utilities\",\"utilities\"],\"properties\":{\"audience\":{\"title\":\"Audience\",\"description\":\"The audience (aud) claim\",\"type\":\"STRING\",\"required\":true,\"multivalued\":false},\"issuer\":{\"title\":\"Issuer\",\"description\":\"The issuer (iss) claim\",\"type\":\"STRING\",\"required\":true,\"multivalued\":false},\"signingkey\":{\"title\":\"HMAC Signing Key\",\"description\":\"The secret label for the HMAC signing key\",\"type\":\"STRING\",\"required\":true,\"defaultValue\":\"esv.signing.key\",\"multivalued\":false},\"validity\":{\"title\":\"Validity (minutes)\",\"description\":\"\",\"type\":\"NUMBER\",\"required\":true,\"defaultValue\":5,\"multivalued\":false}}},{\"_id\":\"ef81b1a52c914710b3388caebfe7233a-1\",\"_rev\":\"1723458869\",\"serviceName\":\"ef81b1a52c914710b3388caebfe7233a\",\"displayName\":\"Display Callback\",\"description\":\"Displays custom callback to the page\",\"outcomes\":[\"outcome\"],\"outputs\":[],\"inputs\":[],\"script\":\"var SCRIPT_OUTCOMES = {\\n OUTCOME: 'outcome'\\n};\\n\\nvar CALLBACKS = {\\n\\tBOOLEAN_ATTRIBUTE_INPUT_CALLBACK: \\\"BOOLEAN_ATTRIBUTE_INPUT_CALLBACK\\\",\\n\\tCHOICE_CALLBACK: \\\"CHOICE_CALLBACK\\\",\\n\\tCONFIRMATION_CALLBACK: \\\"CONFIRMATION_CALLBACK\\\",\\n\\tCONSENT_MAPPING_CALLBACK: \\\"CONSENT_MAPPING_CALLBACK\\\",\\n\\tDEVICE_PROFILE_CALLBACK: \\\"DEVICE_PROFILE_CALLBACK\\\",\\n\\tHIDDEN_VALUE_CALLBACK: \\\"HIDDEN_VALUE_CALLBACK\\\",\\n\\tHTTP_CALLBACK: \\\"HTTP_CALLBACK\\\",\\n\\tIDP_CALLBACK: \\\"IDP_CALLBACK\\\",\\n\\tKBA_CREATE_CALLBACK: \\\"KBA_CREATE_CALLBACK\\\",\\n\\tLANGUAGE_CALLBACK: \\\"LANGUAGE_CALLBACK\\\",\\n\\tMETADATA_CALLBACK: \\\"METADATA_CALLBACK\\\",\\n\\tNAME_CALLBACK: \\\"NAME_CALLBACK\\\",\\n\\tNUMBER_ATTRIBUTE_INPUT_CALLBACK: \\\"NUMBER_ATTRIBUTE_INPUT_CALLBACK\\\",\\n\\tPASSWORD_CALLBACK: \\\"PASSWORD_CALLBACK\\\",\\n\\tPOLLING_WAIT_CALLBACK: \\\"POLLING_WAIT_CALLBACK\\\",\\n REDIRECT_CALLBACK: \\\"REDIRECT_CALLBACK\\\",\\n\\tSCRIPT_TEXT_OUTPUT_CALLBACK: \\\"SCRIPT_TEXT_OUTPUT_CALLBACK\\\",\\n\\tSELECT_IDP_CALLBACK: \\\"SELECT_IDP_CALLBACK\\\",\\n\\tSTRING_ATTRIBUTE_INPUT_CALLBACK: \\\"STRING_ATTRIBUTE_INPUT_CALLBACK\\\",\\n\\tSUSPENDED_TEXT_OUTPUT_CALLBACK: \\\"SUSPENDED_TEXT_OUTPUT_CALLBACK\\\",\\n\\tTERMS_AND_CONDITIONS_CALLBACK: \\\"TERMS_AND_CONDITIONS_CALLBACK\\\",\\n\\tTEXT_INPUT_CALLBACK: \\\"TEXT_INPUT_CALLBACK\\\",\\n\\tTEXT_OUTPUT_CALLBACK: \\\"TEXT_OUTPUT_CALLBACK\\\",\\n\\tVALIDATED_PASSWORD_CALLBACK: \\\"VALIDATED_PASSWORD_CALLBACK\\\",\\n\\tVALIDATED_USERNAME_CALLBACK: \\\"VALIDATED_USERNAME_CALLBACK\\\",\\n\\tX509_CERTIFICATE_CALLBACK: \\\"X509_CERTIFICATE_CALLBACK\\\"\\n}\\n\\nfunction isStringPresent(value) {\\n return value;\\n}\\n\\nfunction getString(value) {\\n return value || '';\\n}\\n\\nfunction isArrayPresent(value) {\\n return value;\\n}\\n\\nfunction getArray(value) {\\n return value ? JSON.parse(value) : [];\\n}\\n\\nfunction isObjectPresent(value) {\\n return value;\\n}\\n\\nfunction getObject(value) {\\n return value ? JSON.parse(value) : {};\\n}\\n\\nfunction isIntPresent(value) {\\n return value;\\n}\\n\\nfunction getInt(value) {\\n return value ? parseInt(value) : 0;\\n}\\n\\nfunction isDoublePresent(value) {\\n return value;\\n}\\n\\nfunction getDouble(value) {\\n return value ? parseFloat(value) : 0.0;\\n}\\n\\nfunction isBooleanPresent(value) {\\n return value;\\n}\\n\\nfunction getBoolean(value) {\\n return value ? value.toLowerCase() === 'true' : false;\\n}\\n\\nfunction setProperty(value) {\\n if (properties.sharedProperty) nodeState.putShared(properties.sharedProperty, value);\\n if (properties.transientProperty) nodeState.putTransient(properties.transientProperty, value);\\n if (properties.objectSharedProperty) {\\n var attributes = {};\\n attributes[properties.objectSharedProperty] = value;\\n nodeState.mergeShared({\\n objectAttributes: attributes\\n });\\n }\\n if (properties.objectTransientProperty) {\\n var attributes = {};\\n attributes[properties.objectTransientProperty] = value;\\n nodeState.mergeTransient({\\n objectAttributes: attributes\\n });\\n }\\n}\\n\\nfunction booleanAttributeInputCallback() {\\n var name = getString(properties.options.name);\\n var prompt = getString(properties.options.prompt);\\n var value = getBoolean(properties.options.value);\\n var required = getBoolean(properties.options.required);\\n var policies = getObject(properties.options.policies);\\n var validateOnly = getBoolean(properties.options.validateOnly);\\n var failedPolicies = getArray(properties.options.failedPolicies);\\n if (isBooleanPresent(properties.options.validateOnly) || isObjectPresent(properties.options.policies)) {\\n if (isArrayPresent(failedPolicies)) {\\n callbacksBuilder.booleanAttributeInputCallback(name, prompt, value, required, policies, validateOnly, failedPolicies);\\n } else {\\n callbacksBuilder.booleanAttributeInputCallback(name, prompt, value, required, policies, validateOnly);\\n }\\n } else if (isArrayPresent(failedPolicies)) {\\n callbacksBuilder.booleanAttributeInputCallback(name, prompt, value, required, failedPolicies);\\n } else {\\n callbacksBuilder.booleanAttributeInputCallback(name, prompt, value, required);\\n }\\n}\\n\\nfunction choiceCallback() {\\n var prompt = getString(properties.options.prompt);\\n var choices = getArray(properties.options.choices);\\n var defaultChoice = getInt(properties.options.defaultChoice);\\n var multipleSelectionsAllowed = getBoolean(properties.options.multipleSelectionsAllowed);\\n callbacksBuilder.choiceCallback(prompt, choices, defaultChoice, multipleSelectionsAllowed);\\n}\\n\\nfunction confirmationCallback() {\\n var prompt = getString(properties.options.prompt);\\n var messageType = getInt(properties.options.messageType);\\n var options = getArray(properties.options.options);\\n var optionType = getInt(properties.options.optionType);\\n var defaultOption = getInt(properties.options.defaultOption);\\n if (isStringPresent(properties.options.prompt)) {\\n if (isIntPresent(properties.options.optionType)) {\\n callbacksBuilder.confirmationCallback(prompt, messageType, optionType, defaultOption);\\n } else {\\n callbacksBuilder.confirmationCallback(prompt, messageType, options, defaultOption);\\n }\\n } else {\\n if (isIntPresent(properties.options.optionType)) {\\n callbacksBuilder.confirmationCallback(messageType, optionType, defaultOption);\\n } else {\\n callbacksBuilder.confirmationCallback(messageType, options, defaultOption);\\n }\\n }\\n}\\n\\nfunction consentMappingCallback() {\\n var config = getObject(properties.options.config);\\n var message = getString(properties.options.message);\\n var isRequired = getBoolean(properties.options.isRequired);\\n var name = getString(properties.options.name);\\n var displayName = getString(properties.options.displayName);\\n var icon = getString(properties.options.icon);\\n var accessLevel = getString(properties.options.accessLevel);\\n var titles = getArray(properties.options.titles);\\n if (isObjectPresent(properties.options.prompt)) {\\n callbacksBuilder.consentMappingCallback(config, message, isRequired);\\n } else {\\n callbacksBuilder.consentMappingCallback(name, displayName, icon, accessLevel, titles, message, isRequired);\\n }\\n}\\n\\nfunction deviceProfileCallback() {\\n var metadata = getBoolean(properties.options.metadata);\\n var location = getBoolean(properties.options.location);\\n var message = getString(properties.options.message);\\n callbacksBuilder.deviceProfileCallback(metadata, location, message);\\n}\\n\\nfunction hiddenValueCallback() {\\n var id = getString(properties.options.id);\\n var value = getString(properties.options.value);\\n callbacksBuilder.hiddenValueCallback(id, value);\\n}\\n\\nfunction httpCallback() {\\n var authorizationHeader = getString(properties.options.authorizationHeader);\\n var negotiationHeader = getString(properties.options.negotiationHeader);\\n var authRHeader = getString(properties.options.authRHeader);\\n var negoName = getString(properties.options.negoName);\\n var negoValue = getString(properties.options.negoValue);\\n if (isStringPresent(properties.options.authorizationHeader) || isStringPresent(properties.options.negotiationHeader)) {\\n var errorCode = getString(properties.options.errorCode);\\n callbacksBuilder.httpCallback(authorizationHeader, negotiationHeader, errorCode);\\n } else {\\n var errorCode = getInt(properties.options.errorCode);\\n callbacksBuilder.httpCallback(authRHeader, negoName, negoValue, errorCode);\\n }\\n}\\n\\nfunction idPCallback() {\\n var provider = getString(properties.options.provider);\\n var clientId = getString(properties.options.clientId);\\n var redirectUri = getString(properties.options.redirectUri);\\n var scope = getArray(properties.options.scope);\\n var nonce = getString(properties.options.nonce);\\n var request = getString(properties.options.request);\\n var requestUri = getString(properties.options.requestUri);\\n var acrValues = getArray(properties.options.acrValues);\\n var requestNativeAppForUserInfo = getBoolean(properties.options.requestNativeAppForUserInfo);\\n var token = getString(properties.options.token);\\n var tokenType = getString(properties.options.tokenType);\\n if (isStringPresent(properties.options.token) || isStringPresent(properties.options.tokenType)) {\\n callbacksBuilder.idPCallback(provider, clientId, redirectUri, scope, nonce, request, requestUri, acrValues, requestNativeAppForUserInfo, token, tokenType);\\n } else {\\n callbacksBuilder.idPCallback(provider, clientId, redirectUri, scope, nonce, request, requestUri, acrValues, requestNativeAppForUserInfo);\\n }\\n}\\n\\nfunction kbaCreateCallback() {\\n var prompt = getString(properties.options.prompt);\\n var predefinedQuestions = getArray(properties.options.predefinedQuestions);\\n var allowUserDefinedQuestions = getBoolean(properties.options.allowUserDefinedQuestions);\\n callbacksBuilder.kbaCreateCallback(prompt, predefinedQuestions, allowUserDefinedQuestions);\\n}\\n\\nfunction languageCallback() {\\n var language = getString(properties.options.language);\\n var country = getString(properties.options.country);\\n callbacksBuilder.languageCallback(language, country);\\n}\\n\\nfunction metadataCallback() {\\n var outputValue = getObject(properties.options.outputValue);\\n callbacksBuilder.metadataCallback(outputValue);\\n}\\n\\nfunction nameCallback() {\\n var prompt = getString(properties.options.prompt);\\n var defaultName = getString(properties.options.defaultName);\\n if (isStringPresent(properties.options.defaultName)) {\\n callbacksBuilder.nameCallback(prompt, defaultName);\\n } else {\\n callbacksBuilder.nameCallback(prompt);\\n }\\n}\\n\\nfunction numberAttributeInputCallback() {\\n var name = getString(properties.options.name);\\n var prompt = getString(properties.options.prompt);\\n var value = getDouble(properties.options.value);\\n var required = getBoolean(properties.options.required);\\n var policies = getObject(properties.options.policies);\\n var validateOnly = getBoolean(properties.options.validateOnly);\\n var failedPolicies = getArray(properties.options.failedPolicies);\\n if (isBooleanPresent(properties.options.validateOnly) || isObjectPresent(properties.options.policies)) {\\n if (isArrayPresent(failedPolicies)) {\\n callbacksBuilder.numberAttributeInputCallback(name, prompt, value, required, policies, validateOnly, failedPolicies);\\n } else {\\n callbacksBuilder.numberAttributeInputCallback(name, prompt, value, required, policies, validateOnly);\\n }\\n } else if (isArrayPresent(failedPolicies)) {\\n callbacksBuilder.numberAttributeInputCallback(name, prompt, value, required, failedPolicies);\\n } else {\\n callbacksBuilder.numberAttributeInputCallback(name, prompt, value, required);\\n }\\n}\\n\\nfunction passwordCallback() {\\n var prompt = getString(properties.options.prompt);\\n var echoOn = getBoolean(properties.options.echoOn);\\n callbacksBuilder.passwordCallback(prompt, echoOn);\\n}\\n\\nfunction pollingWaitCallback() {\\n var waitTime = getString(properties.options.waitTime);\\n var message = getString(properties.options.message);\\n callbacksBuilder.pollingWaitCallback(waitTime, message);\\n}\\n\\nfunction redirectCallback() {\\n throw new Error('Not Implemented');\\n}\\n\\nfunction scriptTextOutputCallback() {\\n var message = getString(properties.options.message);\\n callbacksBuilder.scriptTextOutputCallback(message);\\n}\\n\\nfunction selectIdPCallback() {\\n var providers = getObject(properties.options.providers);\\n callbacksBuilder.selectIdPCallback(providers);\\n}\\n\\nfunction stringAttributeInputCallback() {\\n var name = getString(properties.options.name);\\n var prompt = getString(properties.options.prompt);\\n var value = getString(properties.options.value);\\n var required = getBoolean(properties.options.required);\\n var policies = getObject(properties.options.policies);\\n var validateOnly = getBoolean(properties.options.validateOnly);\\n var failedPolicies = getArray(properties.options.failedPolicies);\\n if (isBooleanPresent(properties.options.validateOnly) || isObjectPresent(properties.options.policies)) {\\n if (isArrayPresent(failedPolicies)) {\\n callbacksBuilder.stringAttributeInputCallback(name, prompt, value, required, policies, validateOnly, failedPolicies);\\n } else {\\n callbacksBuilder.stringAttributeInputCallback(name, prompt, value, required, policies, validateOnly);\\n }\\n } else if (isArrayPresent(failedPolicies)) {\\n callbacksBuilder.stringAttributeInputCallback(name, prompt, value, required, failedPolicies);\\n } else {\\n callbacksBuilder.stringAttributeInputCallback(name, prompt, value, required);\\n }\\n}\\n\\nfunction suspendedTextOutputCallback() {\\n var messageType = getInt(properties.options.messageType);\\n var message = getString(properties.options.message);\\n callbacksBuilder.suspendedTextOutputCallback(messageType, message);\\n}\\n\\nfunction termsAndConditionsCallback() {\\n var version = getString(properties.options.version);\\n var terms = getString(properties.options.terms);\\n var createDate = getString(properties.options.createDate);\\n callbacksBuilder.termsAndConditionsCallback(version, terms, createDate);\\n}\\n\\nfunction textInputCallback() {\\n var prompt = getString(properties.options.prompt);\\n var defaultText = getString(properties.options.defaultText);\\n if (isStringPresent(properties.options.defaultText)) {\\n callbacksBuilder.textInputCallback(prompt, defaultText);\\n } else {\\n callbacksBuilder.textInputCallback(prompt);\\n }\\n}\\n\\nfunction textOutputCallback() {\\n var messageType = getString(properties.options.messageType);\\n var message = getString(properties.options.message);\\n callbacksBuilder.textOutputCallback(messageType, message);\\n}\\n\\nfunction validatedPasswordCallback() {\\n var prompt = getString(properties.options.prompt);\\n var echoOn = getBoolean(properties.options.echoOn);\\n var policies = getObject(properties.options.policies);\\n var validateOnly = getBoolean(properties.options.validateOnly);\\n var failedPolicies = getArray(properties.options.failedPolicies);\\n if (isArrayPresent(properties.options.failedPolicies)) {\\n callbacksBuilder.validatedPasswordCallback(prompt, echoOn, policies, validateOnly, failedPolicies);\\n } else {\\n callbacksBuilder.validatedPasswordCallback(prompt, echoOn, policies, validateOnly);\\n }\\n}\\n\\nfunction validatedUsernameCallback() {\\n var prompt = getString(properties.options.prompt);\\n var policies = getObject(properties.options.policies);\\n var validateOnly = getBoolean(properties.options.validateOnly);\\n var failedPolicies = getArray(properties.options.failedPolicies);\\n if (isArrayPresent(properties.options.failedPolicies)) {\\n callbacksBuilder.validatedUsernameCallback(prompt, policies, validateOnly, failedPolicies);\\n } else {\\n callbacksBuilder.validatedUsernameCallback(prompt, policies, validateOnly);\\n }\\n}\\n\\nfunction x509CertificateCallback() {\\n throw new Error('Not Implemented');\\n}\\n\\nfunction getBooleanAttributeInputCallback() {\\n setProperty(callbacks.getBooleanAttributeInputCallbacks().get(0));\\n}\\n\\nfunction getChoiceCallback() {\\n var multipleSelectionsAllowed = getBoolean(properties.options.multipleSelectionsAllowed);\\n var selections = callbacks.getChoiceCallbacks().get(0);\\n setProperty(multipleSelectionsAllowed ? selections : selections[0]);\\n}\\n\\nfunction getConfirmationCallback() {\\n setProperty(callbacks.getConfirmationCallbacks().get(0));\\n}\\n\\nfunction getConsentMappingCallback() {\\n setProperty(callbacks.getConsentMappingCallbacks().get(0));\\n}\\n\\nfunction getDeviceProfileCallback() {\\n setProperty(callbacks.getDeviceProfileCallbacks().get(0));\\n}\\n\\nfunction getHiddenValueCallback() {\\n var id = getString(properties.options.id);\\n setProperty(callbacks.getHiddenValueCallbacks().get(id));\\n}\\n\\nfunction getHttpCallback() {\\n setProperty(callbacks.getHttpCallbacks().get(0));\\n}\\n\\nfunction getIdPCallback() {\\n setProperty(callbacks.getIdpCallbacks().get(0));\\n}\\n\\nfunction getKbaCreateCallback() {\\n setProperty(callbacks.getKbaCreateCallbacks().get(0));\\n}\\n\\nfunction getLanguageCallback() {\\n setProperty(callbacks.getLanguageCallbacks().get(0));\\n}\\n\\nfunction getNameCallback() {\\n setProperty(callbacks.getNameCallbacks().get(0));\\n}\\n\\nfunction getNumberAttributeInputCallback() {\\n setProperty(callbacks.getNumberAttributeInputCallbacks().get(0));\\n}\\n\\nfunction getPasswordCallback() {\\n setProperty(callbacks.getPasswordCallbacks().get(0));\\n}\\n\\nfunction getSelectIdPCallback() {\\n setProperty(callbacks.getSelectIdPCallbacks().get(0));\\n}\\n\\nfunction getStringAttributeInputCallback() {\\n setProperty(callbacks.getStringAttributeInputCallbacks().get(0));\\n}\\n\\nfunction getTermsAndConditionsCallback() {\\n setProperty(callbacks.getTermsAndConditionsCallbacks().get(0));\\n}\\n\\nfunction getTextInputCallback() {\\n setProperty(callbacks.getTextInputCallbacks().get(0));\\n}\\n\\nfunction getValidatedPasswordCallback() {\\n setProperty(callbacks.getValidatedPasswordCallbacks().get(0));\\n}\\n\\nfunction getValidatedUsernameCallback() {\\n setProperty(callbacks.getValidatedUsernameCallbacks().get(0));\\n}\\n\\nfunction getX509CertificateCallback() {\\n setProperty(callbacks.getX509CertificateCallbacks().get(0));\\n}\\n\\nfunction main() {\\n if (!callbacks.isEmpty()) {\\n switch (properties.callback) {\\n case CALLBACKS.BOOLEAN_ATTRIBUTE_INPUT_CALLBACK: getBooleanAttributeInputCallback(); break;\\n case CALLBACKS.CHOICE_CALLBACK: getChoiceCallback(); break;\\n case CALLBACKS.CONFIRMATION_CALLBACK: getConfirmationCallback(); break;\\n case CALLBACKS.CONSENT_MAPPING_CALLBACK: getConsentMappingCallback(); break;\\n case CALLBACKS.DEVICE_PROFILE_CALLBACK: getDeviceProfileCallback(); break;\\n case CALLBACKS.HIDDEN_VALUE_CALLBACK: getHiddenValueCallback(); break;\\n case CALLBACKS.HTTP_CALLBACK: getHttpCallback(); break;\\n case CALLBACKS.IDP_CALLBACK: getIdPCallback(); break;\\n case CALLBACKS.KBA_CREATE_CALLBACK: getKbaCreateCallback(); break;\\n case CALLBACKS.LANGUAGE_CALLBACK: getLanguageCallback(); break;\\n case CALLBACKS.NAME_CALLBACK: getNameCallback(); break;\\n case CALLBACKS.NUMBER_ATTRIBUTE_INPUT_CALLBACK: getNumberAttributeInputCallback(); break;\\n case CALLBACKS.PASSWORD_CALLBACK: getPasswordCallback(); break;\\n case CALLBACKS.SELECT_IDP_CALLBACK: getSelectIdPCallback(); break;\\n case CALLBACKS.STRING_ATTRIBUTE_INPUT_CALLBACK: getStringAttributeInputCallback(); break;\\n case CALLBACKS.TERMS_AND_CONDITIONS_CALLBACK: getTermsAndConditionsCallback(); break;\\n case CALLBACKS.TEXT_INPUT_CALLBACK: getTextInputCallback(); break;\\n case CALLBACKS.VALIDATED_PASSWORD_CALLBACK: getValidatedPasswordCallback(); break;\\n case CALLBACKS.VALIDATED_USERNAME_CALLBACK: getValidatedUsernameCallback(); break;\\n case CALLBACKS.X509_CERTIFICATE_CALLBACK: getX509CertificateCallback(); break;\\n default: break;\\n }\\n action.goTo(SCRIPT_OUTCOMES.OUTCOME);\\n return;\\n }\\n\\n switch (properties.callback) {\\n case CALLBACKS.BOOLEAN_ATTRIBUTE_INPUT_CALLBACK: booleanAttributeInputCallback(); break;\\n case CALLBACKS.CHOICE_CALLBACK: choiceCallback(); break;\\n case CALLBACKS.CONFIRMATION_CALLBACK: confirmationCallback(); break;\\n case CALLBACKS.CONSENT_MAPPING_CALLBACK: consentMappingCallback(); break;\\n case CALLBACKS.DEVICE_PROFILE_CALLBACK: deviceProfileCallback(); break;\\n case CALLBACKS.HIDDEN_VALUE_CALLBACK: hiddenValueCallback(); break;\\n case CALLBACKS.HTTP_CALLBACK: httpCallback(); break;\\n case CALLBACKS.IDP_CALLBACK: idPCallback(); break;\\n case CALLBACKS.KBA_CREATE_CALLBACK: kbaCreateCallback(); break;\\n case CALLBACKS.LANGUAGE_CALLBACK: languageCallback(); break;\\n case CALLBACKS.METADATA_CALLBACK: metadataCallback(); break;\\n case CALLBACKS.NAME_CALLBACK: nameCallback(); break;\\n case CALLBACKS.NUMBER_ATTRIBUTE_INPUT_CALLBACK: numberAttributeInputCallback(); break;\\n case CALLBACKS.PASSWORD_CALLBACK: passwordCallback(); break;\\n case CALLBACKS.POLLING_WAIT_CALLBACK: pollingWaitCallback(); break;\\n case CALLBACKS.REDIRECT_CALLBACK: redirectCallback(); break;\\n case CALLBACKS.SCRIPT_TEXT_OUTPUT_CALLBACK: scriptTextOutputCallback(); break;\\n case CALLBACKS.SELECT_IDP_CALLBACK: selectIdPCallback(); break;\\n case CALLBACKS.STRING_ATTRIBUTE_INPUT_CALLBACK: stringAttributeInputCallback(); break;\\n case CALLBACKS.SUSPENDED_TEXT_OUTPUT_CALLBACK: suspendedTextOutputCallback(); break;\\n case CALLBACKS.TERMS_AND_CONDITIONS_CALLBACK: termsAndConditionsCallback(); break;\\n case CALLBACKS.TEXT_INPUT_CALLBACK: textInputCallback(); break;\\n case CALLBACKS.TEXT_OUTPUT_CALLBACK: textOutputCallback(); break;\\n case CALLBACKS.VALIDATED_PASSWORD_CALLBACK: validatedPasswordCallback(); break;\\n case CALLBACKS.VALIDATED_USERNAME_CALLBACK: validatedUsernameCallback(); break;\\n case CALLBACKS.X509_CERTIFICATE_CALLBACK: x509CertificateCallback(); break;\\n default: throw new Error('Unknown Callback'); // Should never reach this case\\n }\\n}\\n\\nmain();\\n\",\"errorOutcome\":false,\"tags\":[\"callback\",\"utilities\"],\"properties\":{\"callback\":{\"title\":\"Callback\",\"description\":\"The callback to display\",\"type\":\"STRING\",\"required\":true,\"options\":{\"METADATA_CALLBACK\":\"metadataCallback\",\"TERMS_AND_CONDITIONS_CALLBACK\":\"termsAndConditionsCallback\",\"NUMBER_ATTRIBUTE_INPUT_CALLBACK\":\"numberAttributeInputCallback\",\"TEXT_OUTPUT_CALLBACK\":\"textOutputCallback\",\"SCRIPT_TEXT_OUTPUT_CALLBACK\":\"scriptTextOutputCallback\",\"CONSENT_MAPPING_CALLBACK\":\"consentMappingCallback\",\"STRING_ATTRIBUTE_INPUT_CALLBACK\":\"stringAttributeInputCallback\",\"IDP_CALLBACK\":\"idPCallback\",\"VALIDATED_PASSWORD_CALLBACK\":\"validatedPasswordCallback\",\"SELECT_IDP_CALLBACK\":\"selectIdPCallback\",\"POLLING_WAIT_CALLBACK\":\"pollingWaitCallback\",\"NAME_CALLBACK\":\"nameCallback\",\"SUSPENDED_TEXT_OUTPUT_CALLBACK\":\"suspendedTextOutputCallback\",\"REDIRECT_CALLBACK\":\"redirectCallback\",\"X509_CERTIFICATE_CALLBACK\":\"x509CertificateCallback\",\"PASSWORD_CALLBACK\":\"passwordCallback\",\"TEXT_INPUT_CALLBACK\":\"textInputCallback\",\"BOOLEAN_ATTRIBUTE_INPUT_CALLBACK\":\"booleanAttributeInputCallback\",\"CONFIRMATION_CALLBACK\":\"confirmationCallback\",\"CHOICE_CALLBACK\":\"choiceCallback\",\"DEVICE_PROFILE_CALLBACK\":\"deviceProfileCallback\",\"HIDDEN_VALUE_CALLBACK\":\"hiddenValueCallback\",\"HTTP_CALLBACK\":\"httpCallback\",\"VALIDATED_USERNAME_CALLBACK\":\"validatedUsernameCallback\",\"KBA_CREATE_CALLBACK\":\"kbaCreateCallback\",\"LANGUAGE_CALLBACK\":\"languageCallback\"},\"multivalued\":false},\"objectSharedProperty\":{\"title\":\"Object Attributes Shared Property\",\"description\":\"The objectAttributes property on the shared state to put the callback input into (if applicable)\",\"type\":\"STRING\",\"required\":false,\"multivalued\":false},\"objectTransientProperty\":{\"title\":\"Object Attributes Transient Property\",\"description\":\"The objectAttributes property on the transient state to put the callback input into (if applicable)\",\"type\":\"STRING\",\"required\":false,\"multivalued\":false},\"options\":{\"title\":\"Options\",\"description\":\"The options containing the parameters for the callback (see documentation for possible parameters: https://docs.pingidentity.com/pingoneaic/latest/am-scripting/scripting-api-node.html#scripting-api-node-callbacks). \\n\\nFor example, for textOutputCallback, the options could be: { messageType: 0, message: \\\"Hello World!\\\" }. \\n\\nNote that for required parameters that are not specified in the options will use default values based on the type of the parameter (\\\"\\\" for Strings, [] for Arrays, {} for Objects, 0 for Ints, 0.0 for Doubles, and false for Booleans).\",\"type\":\"OBJECT\",\"required\":true,\"multivalued\":false},\"sharedProperty\":{\"title\":\"Shared State Property\",\"description\":\"The shared state property to put the callback input into (if applicable)\",\"type\":\"STRING\",\"required\":false,\"multivalued\":false},\"transientProperty\":{\"title\":\"Transient State Property\",\"description\":\"The transient state property to put the callback input into (if applicable)\",\"type\":\"STRING\",\"required\":false,\"multivalued\":false}}}],\"resultCount\":7,\"pagedResultsCookie\":null,\"totalPagedResultsPolicy\":\"EXACT\",\"totalPagedResults\":7,\"remainingPagedResults\":-1}" + }, + "cookies": [ + { + "httpOnly": true, + "name": "route", + "path": "/am", + "secure": true, + "value": "" + } + ], + "headers": [ + { + "name": "date", + "value": "Mon, 13 Apr 2026 22:11:38 GMT" + }, + { + "name": "content-type", + "value": "application/json;charset=UTF-8" + }, + { + "name": "transfer-encoding", + "value": "chunked" + }, + { + "name": "connection", + "value": "keep-alive" + }, + { + "_fromType": "array", + "name": "set-cookie", + "value": "route=; Path=/am; Secure; HttpOnly" + }, + { + "name": "x-frame-options", + "value": "SAMEORIGIN" + }, + { + "name": "x-content-type-options", + "value": "nosniff" + }, + { + "name": "cache-control", + "value": "private" + }, + { + "name": "content-api-version", + "value": "protocol=2.1,resource=1.0, resource=1.0" + }, + { + "name": "content-security-policy", + "value": "default-src 'none';frame-ancestors 'none';sandbox" + }, + { + "name": "cross-origin-opener-policy", + "value": "same-origin" + }, + { + "name": "cross-origin-resource-policy", + "value": "same-origin" + }, + { + "name": "expires", + "value": "0" + }, + { + "name": "pragma", + "value": "no-cache" + }, + { + "name": "strict-transport-security", + "value": "max-age=31536000; includeSubDomains" + } + ], + "headersSize": 643, + "httpVersion": "HTTP/1.1", + "redirectURL": "", + "status": 200, + "statusText": "OK" + }, + "startedDateTime": "2026-04-13T22:11:38.121Z", + "time": 8, + "timings": { + "blocked": -1, + "connect": -1, + "dns": -1, + "receive": 0, + "send": 0, + "ssl": -1, + "wait": 8 + } + } + ], + "pages": [], + "version": "1.2" + } +} diff --git a/test/e2e/mocks/config-manager_4167095917/pull_2167214206/custom-nodes_3091214966/0_D_n_m_3294969001/oauth2_393036114/recording.har b/test/e2e/mocks/config-manager_4167095917/pull_2167214206/custom-nodes_3091214966/0_D_n_m_3294969001/oauth2_393036114/recording.har new file mode 100644 index 000000000..06d46a68f --- /dev/null +++ b/test/e2e/mocks/config-manager_4167095917/pull_2167214206/custom-nodes_3091214966/0_D_n_m_3294969001/oauth2_393036114/recording.har @@ -0,0 +1,289 @@ +{ + "log": { + "_recordingName": "config-manager/pull/custom-nodes/0_D_n_m/oauth2", + "creator": { + "comment": "persister:fs", + "name": "Polly.JS", + "version": "6.0.6" + }, + "entries": [ + { + "_id": "a684e2f67fd67a4263878c3124af167a", + "_order": 0, + "cache": {}, + "request": { + "bodySize": 365, + "cookies": [], + "headers": [ + { + "name": "accept", + "value": "application/json, text/plain, */*" + }, + { + "name": "content-type", + "value": "application/x-www-form-urlencoded" + }, + { + "name": "user-agent", + "value": "@rockcarver/frodo-lib/4.0.0-36" + }, + { + "name": "x-forgerock-transactionid", + "value": "frodo-2bbd1177-cbbd-4974-972a-04dbc344d69a" + }, + { + "name": "accept-api-version", + "value": "protocol=2.1,resource=1.0" + }, + { + "name": "cookie", + "value": "iPlanetDirectoryPro=" + }, + { + "name": "content-length", + "value": "365" + }, + { + "name": "accept-encoding", + "value": "gzip, compress, deflate, br" + }, + { + "name": "host", + "value": "openam-frodo-dev.forgeblocks.com" + } + ], + "headersSize": 565, + "httpVersion": "HTTP/1.1", + "method": "POST", + "postData": { + "mimeType": "application/x-www-form-urlencoded", + "params": [], + "text": "redirect_uri=https://platform.dev.trivir.com/platform/appAuthHelperRedirect.html&scope=fr:idm:* openid&response_type=code&client_id=idm-admin-ui&csrf=nqXBJnakFDlQfqJ63GeMDj28iqs.*AAJTSQACMDIAAlNLABw2QTg5aTl6bGlqNzhqamdMLzZZVU5wZDY5T3M9AAR0eXBlAANDVFMAAlMxAAIwMQ..*&decision=allow&code_challenge=MDXqt6c4KfHPoXHhjueJybxpVLf0f-IsIfeeHEqEnTo&code_challenge_method=S256" + }, + "queryString": [], + "url": "https://platform.dev.trivir.com/am/oauth2/authorize" + }, + "response": { + "bodySize": 0, + "content": { + "mimeType": "text/plain", + "size": 0 + }, + "cookies": [ + { + "httpOnly": true, + "name": "route", + "path": "/am", + "secure": true, + "value": "" + }, + { + "expires": "1970-01-01T00:00:00.000Z", + "httpOnly": true, + "name": "OAUTH_REQUEST_ATTRIBUTES", + "path": "/", + "sameSite": "none", + "secure": true, + "value": "" + } + ], + "headers": [ + { + "name": "date", + "value": "Mon, 13 Apr 2026 22:11:38 GMT" + }, + { + "name": "content-length", + "value": "0" + }, + { + "name": "connection", + "value": "keep-alive" + }, + { + "_fromType": "array", + "name": "set-cookie", + "value": "route=; Path=/am; Secure; HttpOnly" + }, + { + "_fromType": "array", + "name": "set-cookie", + "value": "OAUTH_REQUEST_ATTRIBUTES=; Expires=Thu, 01 Jan 1970 00:00:00 GMT; Path=/; Secure; HttpOnly; SameSite=none" + }, + { + "name": "x-frame-options", + "value": "SAMEORIGIN" + }, + { + "name": "x-content-type-options", + "value": "nosniff" + }, + { + "name": "cache-control", + "value": "no-store" + }, + { + "name": "location", + "value": "https://platform.dev.trivir.com/platform/appAuthHelperRedirect.html?code=2EfmesXRo_rOB64xgZGI_Rpt7sk&iss=https%3A%2F%2Fplatform.dev.trivir.com%2Fam%2Foauth2&client_id=idm-admin-ui" + }, + { + "name": "pragma", + "value": "no-cache" + }, + { + "name": "strict-transport-security", + "value": "max-age=31536000; includeSubDomains" + } + ], + "headersSize": 673, + "httpVersion": "HTTP/1.1", + "redirectURL": "https://platform.dev.trivir.com/platform/appAuthHelperRedirect.html?code=2EfmesXRo_rOB64xgZGI_Rpt7sk&iss=https%3A%2F%2Fplatform.dev.trivir.com%2Fam%2Foauth2&client_id=idm-admin-ui", + "status": 302, + "statusText": "Found" + }, + "startedDateTime": "2026-04-13T22:11:38.048Z", + "time": 20, + "timings": { + "blocked": -1, + "connect": -1, + "dns": -1, + "receive": 0, + "send": 0, + "ssl": -1, + "wait": 20 + } + }, + { + "_id": "ff75519a93ccab829f8ee8cf5e92b49f", + "_order": 0, + "cache": {}, + "request": { + "bodySize": 224, + "cookies": [], + "headers": [ + { + "name": "accept", + "value": "application/json, text/plain, */*" + }, + { + "name": "content-type", + "value": "application/x-www-form-urlencoded" + }, + { + "name": "user-agent", + "value": "@rockcarver/frodo-lib/4.0.0-36" + }, + { + "name": "x-forgerock-transactionid", + "value": "frodo-2bbd1177-cbbd-4974-972a-04dbc344d69a" + }, + { + "name": "accept-api-version", + "value": "protocol=2.1,resource=1.0" + }, + { + "name": "content-length", + "value": "224" + }, + { + "name": "accept-encoding", + "value": "gzip, compress, deflate, br" + }, + { + "name": "host", + "value": "openam-frodo-dev.forgeblocks.com" + } + ], + "headersSize": 424, + "httpVersion": "HTTP/1.1", + "method": "POST", + "postData": { + "mimeType": "application/x-www-form-urlencoded", + "params": [], + "text": "client_id=idm-admin-ui&redirect_uri=https://platform.dev.trivir.com/platform/appAuthHelperRedirect.html&grant_type=authorization_code&code=2EfmesXRo_rOB64xgZGI_Rpt7sk&code_verifier=MCcQh-8Acvr7RnDUugNPSwsUPGwsjtKnrNXGI5Y1EDA" + }, + "queryString": [], + "url": "https://platform.dev.trivir.com/am/oauth2/access_token" + }, + "response": { + "bodySize": 1249, + "content": { + "mimeType": "application/json;charset=UTF-8", + "size": 1249, + "text": "{\"access_token\":\"\",\"scope\":\"openid fr:idm:*\",\"id_token\":\"\",\"token_type\":\"Bearer\",\"expires_in\":239}" + }, + "cookies": [ + { + "httpOnly": true, + "name": "route", + "path": "/am", + "secure": true, + "value": "" + } + ], + "headers": [ + { + "name": "date", + "value": "Mon, 13 Apr 2026 22:11:38 GMT" + }, + { + "name": "content-type", + "value": "application/json;charset=UTF-8" + }, + { + "name": "content-length", + "value": "1249" + }, + { + "name": "connection", + "value": "keep-alive" + }, + { + "_fromType": "array", + "name": "set-cookie", + "value": "route=; Path=/am; Secure; HttpOnly" + }, + { + "name": "x-frame-options", + "value": "SAMEORIGIN" + }, + { + "name": "x-content-type-options", + "value": "nosniff" + }, + { + "name": "cache-control", + "value": "no-store" + }, + { + "name": "pragma", + "value": "no-cache" + }, + { + "name": "strict-transport-security", + "value": "max-age=31536000; includeSubDomains" + } + ], + "headersSize": 405, + "httpVersion": "HTTP/1.1", + "redirectURL": "", + "status": 200, + "statusText": "OK" + }, + "startedDateTime": "2026-04-13T22:11:38.076Z", + "time": 35, + "timings": { + "blocked": -1, + "connect": -1, + "dns": -1, + "receive": 0, + "send": 0, + "ssl": -1, + "wait": 35 + } + } + ], + "pages": [], + "version": "1.2" + } +}