All files / src/context/directory index.ts

94.54% Statements 52/55
90.9% Branches 30/33
100% Functions 10/10
94.54% Lines 52/55

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 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 1361x 1x 1x   1x 1x 1x 1x   1x 1x       1x                   111x 111x 111x 111x 111x     111x   111x                     11x 11x 11x   3x   11x             67x 67x   65x   65x   1885x 1885x       1597x 1584x 1584x     52x   2x       1x 1x 1x       1x   1x 1x 1x   1x   1x                     1x         1x     1x 1x     1x     29x 29x     1x 1x 1x                  
import * as path from 'path';
import { loadFileAndReplaceKeywords, Auth0 } from '../../tools';
import pagedClient from '../../tools/auth0/client';
 
import cleanAssets from '../../readonly';
import log from '../../logger';
import handlers, { DirectoryHandler } from './handlers';
import { isDirectory, isFile, stripIdentifiers, toConfigFn } from '../../utils';
import { Assets, Auth0APIClient, Config, AssetTypes } from '../../types';
import { filterOnlyIncludedResourceTypes } from '..';
import { preserveKeywords } from '../../keywordPreservation';
 
type KeywordMappings = { [key: string]: (string | number)[] | string | number };
 
export default class DirectoryContext {
  basePath: string;
  filePath: string;
  config: Config;
  mappings: KeywordMappings;
  mgmtClient: Auth0APIClient;
  assets: Assets;
  disableKeywordReplacement: boolean;
 
  constructor(config: Config, mgmtClient: Auth0APIClient) {
    this.filePath = config.AUTH0_INPUT_FILE;
    this.config = config;
    this.mappings = config.AUTH0_KEYWORD_REPLACE_MAPPINGS || {};
    this.mgmtClient = pagedClient(mgmtClient);
    this.disableKeywordReplacement = false;
 
    //@ts-ignore for now
    this.assets = {};
    // Get excluded rules
    this.assets.exclude = {
      rules: config.AUTH0_EXCLUDED_RULES || [],
      clients: config.AUTH0_EXCLUDED_CLIENTS || [],
      databases: config.AUTH0_EXCLUDED_DATABASES || [],
      connections: config.AUTH0_EXCLUDED_CONNECTIONS || [],
      resourceServers: config.AUTH0_EXCLUDED_RESOURCE_SERVERS || [],
      defaults: config.AUTH0_EXCLUDED_DEFAULTS || [],
    };
  }
 
  loadFile(f: string, folder: string) {
    const basePath = path.join(this.filePath, folder);
    let toLoad = path.join(basePath, f);
    if (!isFile(toLoad)) {
      // try load not relative to yaml file
      toLoad = f;
    }
    return loadFileAndReplaceKeywords(toLoad, {
      mappings: this.mappings,
      disableKeywordReplacement: this.disableKeywordReplacement,
    });
  }
 
  async loadAssetsFromLocal(opts = { disableKeywordReplacement: false }): Promise<void> {
    this.disableKeywordReplacement = opts.disableKeywordReplacement;
    if (isDirectory(this.filePath)) {
      /* If this is a directory, look for each file in the directory */
      log.info(`Processing directory ${this.filePath}`);
 
      Object.entries(handlers)
        .filter(([handlerName]: [AssetTypes, DirectoryHandler<any>]) => {
          const excludedAssetTypes = this.config.AUTH0_EXCLUDED || [];
          return !excludedAssetTypes.includes(handlerName);
        })
        .filter(filterOnlyIncludedResourceTypes(this.config.AUTH0_INCLUDED_ONLY))
        .forEach(([_name, handler]) => {
          const parsed = handler.parse(this);
          Object.entries(parsed).forEach(([k, v]) => {
            this.assets[k] = v;
          });
        });
      return;
    }
    throw new Error(`Not sure what to do with, ${this.filePath} as it is not a directory...`);
  }
 
  async dump(): Promise<void> {
    const auth0 = new Auth0(this.mgmtClient, this.assets, toConfigFn(this.config));
    log.info('Loading Auth0 Tenant Data');
    await auth0.loadAssetsFromAuth0();
 
    const shouldPreserveKeywords =
      //@ts-ignore because the string=>boolean conversion may not have happened if passed-in as env var
      this.config.AUTH0_PRESERVE_KEYWORDS === 'true' ||
      this.config.AUTH0_PRESERVE_KEYWORDS === true;
    Eif (shouldPreserveKeywords) {
      await this.loadAssetsFromLocal({ disableKeywordReplacement: true }); //Need to disable keyword replacement to retrieve the raw keyword markers (ex: ##KEYWORD##)
      const localAssets = { ...this.assets };
      //@ts-ignore
      delete this['assets'];
 
      this.assets = preserveKeywords({
        localAssets,
        remoteAssets: auth0.assets,
        keywordMappings: this.config.AUTH0_KEYWORD_REPLACE_MAPPINGS || {},
        auth0Handlers: auth0.handlers,
      });
    } else {
      this.assets = auth0.assets;
    }
 
    // Clean known read only fields
    this.assets = cleanAssets(this.assets, this.config);
 
    // Copy clients to be used by handlers which require converting client_id to the name
    // Must copy as the client_id will be stripped if AUTH0_EXPORT_IDENTIFIERS is false
    //@ts-ignore because assets haven't been typed yet TODO: type assets
    this.assets.clientsOrig = [...(this.assets.clients || [])];
 
    // Optionally Strip identifiers
    Eif (!this.config.AUTH0_EXPORT_IDENTIFIERS) {
      this.assets = stripIdentifiers(auth0, this.assets);
    }
 
    await Promise.all(
      Object.entries(handlers)
        .filter(([handlerName]: [AssetTypes, DirectoryHandler<any>]) => {
          const excludedAssetTypes = this.config.AUTH0_EXCLUDED || [];
          return !excludedAssetTypes.includes(handlerName);
        })
        .filter(filterOnlyIncludedResourceTypes(this.config.AUTH0_INCLUDED_ONLY))
        .map(async ([name, handler]) => {
          try {
            await handler.dump(this);
          } catch (err) {
            log.debug(err.stack);
            throw new Error(`Problem exporting ${name}`);
          }
        })
    );
  }
}