@okta-dfuhriman/okta-auth-js
Version:
The Okta Auth SDK
129 lines (110 loc) • 4.68 kB
text/typescript
/*!
* Copyright (c) 2021-Present, Okta, Inc. and/or its affiliates. All rights reserved.
* The Okta software accompanied by this notice is provided pursuant to the Apache License, Version 2.0 (the "License.")
*
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
* See the License for the specific language governing permissions and limitations under the License.
*/
/* eslint-disable max-len */
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-nocheck
import { OktaAuthIdxInterface } from '../../types'; // auth-js/types
import { generateRemediationFunctions } from './remediationParser';
import generateIdxAction from './generateIdxAction';
import { jsonpath } from '../../../util/jsonpath';
import { AuthSdkError } from '../../../errors';
const SKIP_FIELDS = Object.fromEntries([
'remediation', // remediations are put into proceed/neededToProceed
'context', // the API response of 'context' isn't externally useful. We ignore it and put all non-action (contextual) info into idxState.context
].map( (field) => [ field, !!'skip this field' ] ));
export const parseNonRemediations = function parseNonRemediations( authClient: OktaAuthIdxInterface, idxResponse, toPersist = {} ) {
const actions = {};
const context = {};
Object.keys(idxResponse)
.filter( field => !SKIP_FIELDS[field])
.forEach( field => {
const fieldIsObject = typeof idxResponse[field] === 'object' && !!idxResponse[field];
if ( !fieldIsObject ) {
// simple fields are contextual info
context[field] = idxResponse[field];
return;
}
if ( idxResponse[field].rel ) {
// top level actions
actions[idxResponse[field].name] = generateIdxAction(authClient, idxResponse[field], toPersist);
return;
}
const { value: fieldValue, type, ...info} = idxResponse[field];
context[field] = { type, ...info}; // add the non-action parts as context
if ( type !== 'object' ) {
// only object values hold actions
context[field].value = fieldValue;
return;
}
// We are an object field containing an object value
context[field].value = {};
Object.entries(fieldValue)
.forEach( ([subField, value]) => {
if (value.rel) { // is [field].value[subField] an action?
// add any "action" value subfields to actions
actions[`${field}-${subField.name || subField}`] = generateIdxAction(authClient, value, toPersist);
} else {
// add non-action value subfields to context
context[field].value[subField] = value;
}
});
});
return { context, actions };
};
const expandRelatesTo = (idxResponse, value) => {
Object.keys(value).forEach(k => {
if (k === 'relatesTo') {
const query = Array.isArray(value[k]) ? value[k][0] : value[k];
if (typeof query === 'string') {
const result = jsonpath({ path: query, json: idxResponse })[0];
if (result) {
value[k] = result;
return;
} else {
throw new AuthSdkError(`Cannot resolve relatesTo: ${query}`);
}
}
}
if (Array.isArray(value[k])) {
value[k].forEach(innerValue => expandRelatesTo(idxResponse, innerValue));
}
});
};
const convertRemediationAction = (authClient: OktaAuthIdxInterface, remediation, toPersist) => {
// Only remediation that has `rel` field (indicator for form submission) can have http action
if (remediation.rel) {
const remediationActions = generateRemediationFunctions( authClient, [remediation], toPersist );
const actionFn = remediationActions[remediation.name];
return {
...remediation,
action: actionFn,
};
}
return remediation;
};
export const parseIdxResponse = function parseIdxResponse( authClient: OktaAuthIdxInterface, idxResponse, toPersist = {} ): {
remediations: IdxRemediation[];
context: IdxContext;
actions: IdxActions;
} {
const remediationData = idxResponse.remediation?.value || [];
remediationData.forEach(
remediation => expandRelatesTo(idxResponse, remediation)
);
const remediations = remediationData.map(remediation => convertRemediationAction( authClient, remediation, toPersist ));
const { context, actions } = parseNonRemediations( authClient, idxResponse, toPersist );
return {
remediations,
context,
actions,
};
};