Skip to content

Commit

Permalink
Merge branch '6.5' into sw-backport-6.5.1
Browse files Browse the repository at this point in the history
  • Loading branch information
shuowu committed May 9, 2022
2 parents 5c6a826 + 003673d commit 5180144
Show file tree
Hide file tree
Showing 6 changed files with 584 additions and 75 deletions.
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,16 @@
# Changelog

## 6.5.1

### Fixes

- [#1200](https://github.com/okta/okta-auth-js/pull/1200) Fixes `canRemediate` logic in GenericRemediator (beta) to handle nested fields
- [1207](https://github.com/okta/okta-auth-js/pull/1207) Fixes `canRemediate` logic in GenericRemediator (beta) to handle `options` fields

### Other

- [#1200](https://github.com/okta/okta-auth-js/pull/1200) Adds missing fields to `Input` type in `idx` module

## 6.5.0

### Features
Expand Down
61 changes: 50 additions & 11 deletions lib/idx/remediators/GenericRemediator/util.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
/* eslint-disable complexity */
import { AuthSdkError } from '../../../errors';
import { Input } from '../../types';

export function unwrapFormValue(remediation): Input {
Expand Down Expand Up @@ -40,22 +41,60 @@ export function unwrapFormValue(remediation): Input {
// TODO: support SDK layer type based input validation
export function hasValidInputValue(input, values) {
const fn = (input, values, requiredTracker) => {
const { name, value, required } = input;
const isRequired = required
|| requiredTracker
// TODO: confirm with backend why `required` meta is missing for authenticator remediation
|| name === 'authenticator';
if (!isRequired) {
return true;
}
const { name, value, type, options, required } = input;
const isRequired = required || requiredTracker;

// handle nested value - all required fields should be avaiable in values
if (Array.isArray(value)) {
return value.reduce((acc, item) => {
return acc && fn(item, values[name], isRequired);
return acc && fn(item, values[name], isRequired); // recursive call
}, true);
} else {
return !!(values && values[name]);
}

// handle options field
// 1. object type options - check if each object field is required and value can be found from the selectedOption
// 2. primitive options - required field is avaiable from top level
if (options) {
// object type options
if (type === 'object') {
const selectedOption = values[name];
if (!selectedOption?.id) {
return false;
}
const optionSchema = options.find((option) => {
const idSchema = option.value.find(({ name }) => name === 'id' );
return idSchema.value === selectedOption.id;
});
if (!optionSchema) {
return false;
}
return optionSchema.value
.filter(({ required }) => !!required)
.reduce((acc, { name }) => {
return acc && !!selectedOption[name];
}, true);
}

// primitive options, not required - always valid
if (required === false) {
return true;
}

// primitive options, required - check if value is available
if (required === true) {
return !!values[name];
}

// unknown options, throw
throw new AuthSdkError(`Unknown options type, ${JSON.stringify(input)}`);
}

// base case
if (!isRequired) {
return true;
}

return !!(values && values[name]);
};

return fn(input, values, false);
Expand Down
3 changes: 3 additions & 0 deletions lib/idx/types/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ export type Input = {
secret?: boolean;
required?: boolean;
options?: IdxOption[];
relatesTo?: IdxAuthenticator;
mutable?: boolean;
visible?: boolean;
}


Expand Down
38 changes: 19 additions & 19 deletions lib/idx/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -211,27 +211,27 @@ export function getRemediator(
}

const remediatorCandidates: Remediator[] = [];
for (let remediation of idxRemediations) {
const isRemeditionInFlow = Object.keys(remediators as object).includes(remediation.name);
if (!isRemeditionInFlow) {
continue;
}
if (useGenericRemediator) {
// always pick the first remediation for when use GenericRemediator
remediatorCandidates.push(new GenericRemediator(idxRemediations[0], values, options));
} else {
for (let remediation of idxRemediations) {
const isRemeditionInFlow = Object.keys(remediators as object).includes(remediation.name);
if (!isRemeditionInFlow) {
continue;
}

// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const T = getRemediatorClass(remediation, options)!;
remediator = new T(remediation, values, options);
if (remediator.canRemediate()) {
// found the remediator
return remediator;
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const T = getRemediatorClass(remediation, options)!;
remediator = new T(remediation, values, options);
if (remediator.canRemediate()) {
// found the remediator
return remediator;
}
// remediator cannot handle the current values
// maybe return for next step
remediatorCandidates.push(remediator);
}
// remediator cannot handle the current values
// maybe return for next step
remediatorCandidates.push(remediator);
}

// If no remedition is picked, use the first one with GenericRemeditor for default flow
if (!remediatorCandidates.length && !!idxRemediations.length && useGenericRemediator) {
return new GenericRemediator(idxRemediations[0], values, options);
}

return remediatorCandidates[0];
Expand Down
Loading

0 comments on commit 5180144

Please sign in to comment.