All files / src readonly.ts

100% Statements 36/36
94.11% Branches 16/17
100% Functions 10/10
100% Lines 31/31

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 871x 1x       1x                                               7x   7x 7x 7x   7x   3x 4x   3x 1x           2x     6x 1x 1x 9x         6x       11x 53x 11x     1x 7x 7x   6x 31x 31x   20x   14x     6x       6x    
import dotProp from 'dot-prop';
import _ from 'lodash';
import { Asset, Assets, AssetTypes, Config } from './types';
 
// Filter out known read only fields during dump
const readOnlyFields: Partial<Record<AssetTypes, string[]>> = {
  guardianFactors: ['trial_expired'],
  connections: ['provisioning_ticket_url', 'realms'],
  databases: ['options.configuration'],
  tenant: [
    'sandbox_versions_available',
    'flags.allow_changing_enable_sso',
    'flags.enable_sso',
    'flags.disable_impersonation',
    'flags.remove_stale_idp_attributes',
  ],
  clients: [
    'client_secret',
    'callback_url_template',
    'signing_keys',
    'global',
    'tenant',
    'custom_login_page_preview',
    'config_route',
    'owners',
  ],
};
 
function getExcludedFields(config: Config) {
  const strippedFields = { ...readOnlyFields };
 
  let { EXCLUDED_PROPS: excluded, INCLUDED_PROPS: included } = config;
  if (typeof excluded !== 'object') excluded = {};
  if (typeof included !== 'object') included = {};
 
  Object.entries(excluded).forEach(([name, fields]) => {
    // Do not allow same field to be included and excluded at the same time
    const intersections = fields.filter(
      (field) => included && included[name] && included[name].includes(field)
    );
    if (intersections.length > 0) {
      throw new Error(
        `EXCLUDED_PROPS should NOT have any intersections with INCLUDED_PROPS. Intersections found: ${name}: ${intersections.join(
          ', '
        )}`
      );
    }
    strippedFields[name] = (strippedFields[name] || []).concat(fields);
  });
 
  Object.entries(included).forEach(([name, fields]) => {
    Eif (strippedFields[name]) {
      strippedFields[name] = strippedFields[name].filter(
        (field: string) => !fields.includes(field)
      );
    }
  });
 
  return strippedFields;
}
 
function deleteKeys(obj: Asset, keys: string[]): { [key: string]: any } {
  const newObj = { ...obj };
  keys.forEach((k) => dotProp.delete(newObj, k));
  return newObj;
}
 
export default function cleanAssets(assets: Assets, config: Config): Assets {
  const cleaned = { ...assets };
  const excludedFields = getExcludedFields(config);
 
  Object.entries(excludedFields).forEach(([name, fields]: [AssetTypes, string[]]) => {
    const obj = cleaned[name];
    if (!obj) return;
 
    if (Array.isArray(obj)) {
      //@ts-ignore because `message_types` and `policies` on guardianPhoneFactorMessageTypes and guardianPolicies don't adhere to the expect types
      cleaned[name] = obj.map((o) => deleteKeys(o, fields));
    } else {
      //@ts-ignore because `message_types` and `policies` on guardianPhoneFactorMessageTypes and guardianPolicies don't adhere to the expect types
      cleaned[name] = deleteKeys(cleaned[name], fields);
    }
  });
 
  return _.pickBy(cleaned, _.identity) as Assets;
}