11cb0ef41Sopenharmony_ci'use strict';
21cb0ef41Sopenharmony_ci
31cb0ef41Sopenharmony_ci// #region imports
41cb0ef41Sopenharmony_ciconst {
51cb0ef41Sopenharmony_ci  ArrayIsArray,
61cb0ef41Sopenharmony_ci  ArrayPrototypeSort,
71cb0ef41Sopenharmony_ci  ObjectCreate,
81cb0ef41Sopenharmony_ci  ObjectEntries,
91cb0ef41Sopenharmony_ci  ObjectFreeze,
101cb0ef41Sopenharmony_ci  ObjectKeys,
111cb0ef41Sopenharmony_ci  ObjectSetPrototypeOf,
121cb0ef41Sopenharmony_ci  RegExpPrototypeExec,
131cb0ef41Sopenharmony_ci  SafeMap,
141cb0ef41Sopenharmony_ci  SafeSet,
151cb0ef41Sopenharmony_ci  RegExpPrototypeSymbolReplace,
161cb0ef41Sopenharmony_ci  StringPrototypeEndsWith,
171cb0ef41Sopenharmony_ci  StringPrototypeStartsWith,
181cb0ef41Sopenharmony_ci  Symbol,
191cb0ef41Sopenharmony_ci} = primordials;
201cb0ef41Sopenharmony_ciconst {
211cb0ef41Sopenharmony_ci  ERR_MANIFEST_ASSERT_INTEGRITY,
221cb0ef41Sopenharmony_ci  ERR_MANIFEST_INVALID_RESOURCE_FIELD,
231cb0ef41Sopenharmony_ci  ERR_MANIFEST_INVALID_SPECIFIER,
241cb0ef41Sopenharmony_ci  ERR_MANIFEST_UNKNOWN_ONERROR,
251cb0ef41Sopenharmony_ci} = require('internal/errors').codes;
261cb0ef41Sopenharmony_cilet debug = require('internal/util/debuglog').debuglog('policy', (fn) => {
271cb0ef41Sopenharmony_ci  debug = fn;
281cb0ef41Sopenharmony_ci});
291cb0ef41Sopenharmony_ciconst SRI = require('internal/policy/sri');
301cb0ef41Sopenharmony_ciconst { URL } = require('internal/url');
311cb0ef41Sopenharmony_ciconst { internalVerifyIntegrity } = internalBinding('crypto');
321cb0ef41Sopenharmony_ciconst kRelativeURLStringPattern = /^\.{0,2}\//;
331cb0ef41Sopenharmony_ciconst { getOptionValue } = require('internal/options');
341cb0ef41Sopenharmony_ciconst shouldAbortOnUncaughtException = getOptionValue(
351cb0ef41Sopenharmony_ci  '--abort-on-uncaught-exception',
361cb0ef41Sopenharmony_ci);
371cb0ef41Sopenharmony_ciconst { abort, exit, _rawDebug } = process;
381cb0ef41Sopenharmony_ci// #endregion
391cb0ef41Sopenharmony_ci
401cb0ef41Sopenharmony_ci// #region constants
411cb0ef41Sopenharmony_ci// From https://url.spec.whatwg.org/#special-scheme
421cb0ef41Sopenharmony_ciconst kSpecialSchemes = new SafeSet([
431cb0ef41Sopenharmony_ci  'file:',
441cb0ef41Sopenharmony_ci  'ftp:',
451cb0ef41Sopenharmony_ci  'http:',
461cb0ef41Sopenharmony_ci  'https:',
471cb0ef41Sopenharmony_ci  'ws:',
481cb0ef41Sopenharmony_ci  'wss:',
491cb0ef41Sopenharmony_ci]);
501cb0ef41Sopenharmony_ci
511cb0ef41Sopenharmony_ci/**
521cb0ef41Sopenharmony_ci * @type {symbol}
531cb0ef41Sopenharmony_ci */
541cb0ef41Sopenharmony_ciconst kCascade = Symbol('cascade');
551cb0ef41Sopenharmony_ci/**
561cb0ef41Sopenharmony_ci * @type {symbol}
571cb0ef41Sopenharmony_ci */
581cb0ef41Sopenharmony_ciconst kFallThrough = Symbol('fall through');
591cb0ef41Sopenharmony_ci
601cb0ef41Sopenharmony_cifunction REACTION_THROW(error) {
611cb0ef41Sopenharmony_ci  throw error;
621cb0ef41Sopenharmony_ci}
631cb0ef41Sopenharmony_ci
641cb0ef41Sopenharmony_cifunction REACTION_EXIT(error) {
651cb0ef41Sopenharmony_ci  REACTION_LOG(error);
661cb0ef41Sopenharmony_ci  if (shouldAbortOnUncaughtException) {
671cb0ef41Sopenharmony_ci    abort();
681cb0ef41Sopenharmony_ci  }
691cb0ef41Sopenharmony_ci  exit(1);
701cb0ef41Sopenharmony_ci}
711cb0ef41Sopenharmony_ci
721cb0ef41Sopenharmony_cifunction REACTION_LOG(error) {
731cb0ef41Sopenharmony_ci  _rawDebug(error.stack);
741cb0ef41Sopenharmony_ci}
751cb0ef41Sopenharmony_ci
761cb0ef41Sopenharmony_ci// #endregion
771cb0ef41Sopenharmony_ci
781cb0ef41Sopenharmony_ci// #region DependencyMapperInstance
791cb0ef41Sopenharmony_ciclass DependencyMapperInstance {
801cb0ef41Sopenharmony_ci  /**
811cb0ef41Sopenharmony_ci   * @type {string}
821cb0ef41Sopenharmony_ci   */
831cb0ef41Sopenharmony_ci  href;
841cb0ef41Sopenharmony_ci  /**
851cb0ef41Sopenharmony_ci   * @type {DependencyMap | undefined}
861cb0ef41Sopenharmony_ci   */
871cb0ef41Sopenharmony_ci  #dependencies;
881cb0ef41Sopenharmony_ci  /**
891cb0ef41Sopenharmony_ci   * @type {PatternDependencyMap | undefined}
901cb0ef41Sopenharmony_ci   */
911cb0ef41Sopenharmony_ci  #patternDependencies;
921cb0ef41Sopenharmony_ci  /**
931cb0ef41Sopenharmony_ci   * @type {DependencyMapperInstance | null | undefined}
941cb0ef41Sopenharmony_ci   */
951cb0ef41Sopenharmony_ci  #parentDependencyMapper;
961cb0ef41Sopenharmony_ci  /**
971cb0ef41Sopenharmony_ci   * @type {boolean}
981cb0ef41Sopenharmony_ci   */
991cb0ef41Sopenharmony_ci  #normalized = false;
1001cb0ef41Sopenharmony_ci  /**
1011cb0ef41Sopenharmony_ci   * @type {boolean}
1021cb0ef41Sopenharmony_ci   */
1031cb0ef41Sopenharmony_ci  cascade;
1041cb0ef41Sopenharmony_ci  /**
1051cb0ef41Sopenharmony_ci   * @type {boolean}
1061cb0ef41Sopenharmony_ci   */
1071cb0ef41Sopenharmony_ci  allowSameHREFScope;
1081cb0ef41Sopenharmony_ci  /**
1091cb0ef41Sopenharmony_ci   * @param {string} parentHREF
1101cb0ef41Sopenharmony_ci   * @param {DependencyMap | undefined} dependencies
1111cb0ef41Sopenharmony_ci   * @param {boolean} cascade
1121cb0ef41Sopenharmony_ci   * @param {boolean} allowSameHREFScope
1131cb0ef41Sopenharmony_ci   */
1141cb0ef41Sopenharmony_ci  constructor(
1151cb0ef41Sopenharmony_ci    parentHREF,
1161cb0ef41Sopenharmony_ci    dependencies,
1171cb0ef41Sopenharmony_ci    cascade = false,
1181cb0ef41Sopenharmony_ci    allowSameHREFScope = false) {
1191cb0ef41Sopenharmony_ci    this.href = parentHREF;
1201cb0ef41Sopenharmony_ci    if (dependencies === kFallThrough ||
1211cb0ef41Sopenharmony_ci        dependencies === undefined ||
1221cb0ef41Sopenharmony_ci        dependencies === null) {
1231cb0ef41Sopenharmony_ci      this.#dependencies = dependencies;
1241cb0ef41Sopenharmony_ci      this.#patternDependencies = undefined;
1251cb0ef41Sopenharmony_ci    } else {
1261cb0ef41Sopenharmony_ci      const patterns = [];
1271cb0ef41Sopenharmony_ci      const keys = ObjectKeys(dependencies);
1281cb0ef41Sopenharmony_ci      for (let i = 0; i < keys.length; i++) {
1291cb0ef41Sopenharmony_ci        const key = keys[i];
1301cb0ef41Sopenharmony_ci        if (StringPrototypeEndsWith(key, '*')) {
1311cb0ef41Sopenharmony_ci          const target = RegExpPrototypeExec(/^([^*]*)\*([^*]*)$/);
1321cb0ef41Sopenharmony_ci          if (!target) {
1331cb0ef41Sopenharmony_ci            throw new ERR_MANIFEST_INVALID_SPECIFIER(
1341cb0ef41Sopenharmony_ci              this.href,
1351cb0ef41Sopenharmony_ci              `${target}, pattern needs to have a single trailing "*" in target`,
1361cb0ef41Sopenharmony_ci            );
1371cb0ef41Sopenharmony_ci          }
1381cb0ef41Sopenharmony_ci          const prefix = target[1];
1391cb0ef41Sopenharmony_ci          const suffix = target[2];
1401cb0ef41Sopenharmony_ci          patterns.push([
1411cb0ef41Sopenharmony_ci            target.slice(0, -1),
1421cb0ef41Sopenharmony_ci            [prefix, suffix],
1431cb0ef41Sopenharmony_ci          ]);
1441cb0ef41Sopenharmony_ci        }
1451cb0ef41Sopenharmony_ci      }
1461cb0ef41Sopenharmony_ci      ArrayPrototypeSort(patterns, (a, b) => {
1471cb0ef41Sopenharmony_ci        return a[0] < b[0] ? -1 : 1;
1481cb0ef41Sopenharmony_ci      });
1491cb0ef41Sopenharmony_ci      this.#dependencies = dependencies;
1501cb0ef41Sopenharmony_ci      this.#patternDependencies = patterns;
1511cb0ef41Sopenharmony_ci    }
1521cb0ef41Sopenharmony_ci    this.cascade = cascade;
1531cb0ef41Sopenharmony_ci    this.allowSameHREFScope = allowSameHREFScope;
1541cb0ef41Sopenharmony_ci    ObjectFreeze(this);
1551cb0ef41Sopenharmony_ci  }
1561cb0ef41Sopenharmony_ci  /**
1571cb0ef41Sopenharmony_ci   *
1581cb0ef41Sopenharmony_ci   * @param {string} normalizedSpecifier
1591cb0ef41Sopenharmony_ci   * @param {Set<string>} conditions
1601cb0ef41Sopenharmony_ci   * @param {Manifest} manifest
1611cb0ef41Sopenharmony_ci   * @returns {URL | typeof kFallThrough | null}
1621cb0ef41Sopenharmony_ci   */
1631cb0ef41Sopenharmony_ci  _resolveAlreadyNormalized(normalizedSpecifier, conditions, manifest) {
1641cb0ef41Sopenharmony_ci    let dependencies = this.#dependencies;
1651cb0ef41Sopenharmony_ci    debug(this.href, 'resolving', normalizedSpecifier);
1661cb0ef41Sopenharmony_ci    if (dependencies === kFallThrough) return true;
1671cb0ef41Sopenharmony_ci    if (dependencies !== undefined && typeof dependencies === 'object') {
1681cb0ef41Sopenharmony_ci      const normalized = this.#normalized;
1691cb0ef41Sopenharmony_ci      if (normalized !== true) {
1701cb0ef41Sopenharmony_ci        /**
1711cb0ef41Sopenharmony_ci         * @type {Record<string, string>}
1721cb0ef41Sopenharmony_ci         */
1731cb0ef41Sopenharmony_ci        const normalizedDependencyMap = ObjectCreate(null);
1741cb0ef41Sopenharmony_ci        for (let specifier in dependencies) {
1751cb0ef41Sopenharmony_ci          const target = dependencies[specifier];
1761cb0ef41Sopenharmony_ci          specifier = canonicalizeSpecifier(specifier, manifest.href);
1771cb0ef41Sopenharmony_ci          normalizedDependencyMap[specifier] = target;
1781cb0ef41Sopenharmony_ci        }
1791cb0ef41Sopenharmony_ci        ObjectFreeze(normalizedDependencyMap);
1801cb0ef41Sopenharmony_ci        dependencies = normalizedDependencyMap;
1811cb0ef41Sopenharmony_ci        this.#dependencies = normalizedDependencyMap;
1821cb0ef41Sopenharmony_ci        this.#normalized = true;
1831cb0ef41Sopenharmony_ci      }
1841cb0ef41Sopenharmony_ci      debug(dependencies);
1851cb0ef41Sopenharmony_ci      if (normalizedSpecifier in dependencies === true) {
1861cb0ef41Sopenharmony_ci        const to = searchDependencies(
1871cb0ef41Sopenharmony_ci          this.href,
1881cb0ef41Sopenharmony_ci          dependencies[normalizedSpecifier],
1891cb0ef41Sopenharmony_ci          conditions,
1901cb0ef41Sopenharmony_ci        );
1911cb0ef41Sopenharmony_ci        debug({ to });
1921cb0ef41Sopenharmony_ci        if (to === true) {
1931cb0ef41Sopenharmony_ci          return true;
1941cb0ef41Sopenharmony_ci        }
1951cb0ef41Sopenharmony_ci        let ret;
1961cb0ef41Sopenharmony_ci        if (parsedURLs && parsedURLs.has(to)) {
1971cb0ef41Sopenharmony_ci          ret = parsedURLs.get(to);
1981cb0ef41Sopenharmony_ci        } else if (RegExpPrototypeExec(kRelativeURLStringPattern, to) !== null) {
1991cb0ef41Sopenharmony_ci          ret = resolve(to, manifest.href);
2001cb0ef41Sopenharmony_ci        } else {
2011cb0ef41Sopenharmony_ci          ret = resolve(to);
2021cb0ef41Sopenharmony_ci        }
2031cb0ef41Sopenharmony_ci        return ret;
2041cb0ef41Sopenharmony_ci      }
2051cb0ef41Sopenharmony_ci    }
2061cb0ef41Sopenharmony_ci    const { cascade } = this;
2071cb0ef41Sopenharmony_ci    if (cascade !== true) {
2081cb0ef41Sopenharmony_ci      return null;
2091cb0ef41Sopenharmony_ci    }
2101cb0ef41Sopenharmony_ci    let parentDependencyMapper = this.#parentDependencyMapper;
2111cb0ef41Sopenharmony_ci    if (parentDependencyMapper === undefined) {
2121cb0ef41Sopenharmony_ci      parentDependencyMapper = manifest.getScopeDependencyMapper(
2131cb0ef41Sopenharmony_ci        this.href,
2141cb0ef41Sopenharmony_ci        this.allowSameHREFScope,
2151cb0ef41Sopenharmony_ci      );
2161cb0ef41Sopenharmony_ci      this.#parentDependencyMapper = parentDependencyMapper;
2171cb0ef41Sopenharmony_ci    }
2181cb0ef41Sopenharmony_ci    if (parentDependencyMapper === null) {
2191cb0ef41Sopenharmony_ci      return null;
2201cb0ef41Sopenharmony_ci    }
2211cb0ef41Sopenharmony_ci    return parentDependencyMapper._resolveAlreadyNormalized(
2221cb0ef41Sopenharmony_ci      normalizedSpecifier,
2231cb0ef41Sopenharmony_ci      conditions,
2241cb0ef41Sopenharmony_ci      manifest,
2251cb0ef41Sopenharmony_ci    );
2261cb0ef41Sopenharmony_ci  }
2271cb0ef41Sopenharmony_ci}
2281cb0ef41Sopenharmony_ci
2291cb0ef41Sopenharmony_ciconst kArbitraryDependencies = new DependencyMapperInstance(
2301cb0ef41Sopenharmony_ci  'arbitrary dependencies',
2311cb0ef41Sopenharmony_ci  kFallThrough,
2321cb0ef41Sopenharmony_ci  false,
2331cb0ef41Sopenharmony_ci  true,
2341cb0ef41Sopenharmony_ci);
2351cb0ef41Sopenharmony_ciconst kNoDependencies = new DependencyMapperInstance(
2361cb0ef41Sopenharmony_ci  'no dependencies',
2371cb0ef41Sopenharmony_ci  null,
2381cb0ef41Sopenharmony_ci  false,
2391cb0ef41Sopenharmony_ci  true,
2401cb0ef41Sopenharmony_ci);
2411cb0ef41Sopenharmony_ci/**
2421cb0ef41Sopenharmony_ci * @param {string} href
2431cb0ef41Sopenharmony_ci * @param {JSONDependencyMap} dependencies
2441cb0ef41Sopenharmony_ci * @param {boolean} cascade
2451cb0ef41Sopenharmony_ci * @param {boolean} allowSameHREFScope
2461cb0ef41Sopenharmony_ci * @param {Map<string | null | undefined, DependencyMapperInstance>} store
2471cb0ef41Sopenharmony_ci */
2481cb0ef41Sopenharmony_ciconst insertDependencyMap = (
2491cb0ef41Sopenharmony_ci  href,
2501cb0ef41Sopenharmony_ci  dependencies,
2511cb0ef41Sopenharmony_ci  cascade,
2521cb0ef41Sopenharmony_ci  allowSameHREFScope,
2531cb0ef41Sopenharmony_ci  store,
2541cb0ef41Sopenharmony_ci) => {
2551cb0ef41Sopenharmony_ci  if (cascade !== undefined && typeof cascade !== 'boolean') {
2561cb0ef41Sopenharmony_ci    throw new ERR_MANIFEST_INVALID_RESOURCE_FIELD(href, 'cascade');
2571cb0ef41Sopenharmony_ci  }
2581cb0ef41Sopenharmony_ci  if (dependencies === true) {
2591cb0ef41Sopenharmony_ci    store.set(href, kArbitraryDependencies);
2601cb0ef41Sopenharmony_ci    return;
2611cb0ef41Sopenharmony_ci  }
2621cb0ef41Sopenharmony_ci  if (dependencies === null || dependencies === undefined) {
2631cb0ef41Sopenharmony_ci    store.set(
2641cb0ef41Sopenharmony_ci      href,
2651cb0ef41Sopenharmony_ci      cascade ?
2661cb0ef41Sopenharmony_ci        new DependencyMapperInstance(href, null, true, allowSameHREFScope) :
2671cb0ef41Sopenharmony_ci        kNoDependencies,
2681cb0ef41Sopenharmony_ci    );
2691cb0ef41Sopenharmony_ci    return;
2701cb0ef41Sopenharmony_ci  }
2711cb0ef41Sopenharmony_ci  if (objectButNotArray(dependencies)) {
2721cb0ef41Sopenharmony_ci    store.set(
2731cb0ef41Sopenharmony_ci      href,
2741cb0ef41Sopenharmony_ci      new DependencyMapperInstance(
2751cb0ef41Sopenharmony_ci        href,
2761cb0ef41Sopenharmony_ci        dependencies,
2771cb0ef41Sopenharmony_ci        cascade,
2781cb0ef41Sopenharmony_ci        allowSameHREFScope,
2791cb0ef41Sopenharmony_ci      ),
2801cb0ef41Sopenharmony_ci    );
2811cb0ef41Sopenharmony_ci    return;
2821cb0ef41Sopenharmony_ci  }
2831cb0ef41Sopenharmony_ci  throw new ERR_MANIFEST_INVALID_RESOURCE_FIELD(href, 'dependencies');
2841cb0ef41Sopenharmony_ci};
2851cb0ef41Sopenharmony_ci/**
2861cb0ef41Sopenharmony_ci * Finds the longest key within `this.#scopeDependencies` that covers a
2871cb0ef41Sopenharmony_ci * specific HREF
2881cb0ef41Sopenharmony_ci * @param {string} href
2891cb0ef41Sopenharmony_ci * @param {ScopeStore} scopeStore
2901cb0ef41Sopenharmony_ci * @returns {null | string}
2911cb0ef41Sopenharmony_ci */
2921cb0ef41Sopenharmony_cifunction findScopeHREF(href, scopeStore, allowSame) {
2931cb0ef41Sopenharmony_ci  let protocol;
2941cb0ef41Sopenharmony_ci  if (href !== '') {
2951cb0ef41Sopenharmony_ci    // default URL parser does some stuff to special urls... skip if this is
2961cb0ef41Sopenharmony_ci    // just the protocol
2971cb0ef41Sopenharmony_ci    if (RegExpPrototypeExec(/^[^:]*[:]$/, href) !== null) {
2981cb0ef41Sopenharmony_ci      protocol = href;
2991cb0ef41Sopenharmony_ci    } else {
3001cb0ef41Sopenharmony_ci      let currentURL = new URL(href);
3011cb0ef41Sopenharmony_ci      const normalizedHREF = currentURL.href;
3021cb0ef41Sopenharmony_ci      protocol = currentURL.protocol;
3031cb0ef41Sopenharmony_ci      // Non-opaque blobs adopt origins
3041cb0ef41Sopenharmony_ci      if (protocol === 'blob:' && currentURL.origin !== 'null') {
3051cb0ef41Sopenharmony_ci        currentURL = new URL(currentURL.origin);
3061cb0ef41Sopenharmony_ci        protocol = currentURL.protocol;
3071cb0ef41Sopenharmony_ci      }
3081cb0ef41Sopenharmony_ci      // Only a few schemes are hierarchical
3091cb0ef41Sopenharmony_ci      if (kSpecialSchemes.has(currentURL.protocol)) {
3101cb0ef41Sopenharmony_ci        // Make first '..' act like '.'
3111cb0ef41Sopenharmony_ci        if (!StringPrototypeEndsWith(currentURL.pathname, '/')) {
3121cb0ef41Sopenharmony_ci          currentURL.pathname += '/';
3131cb0ef41Sopenharmony_ci        }
3141cb0ef41Sopenharmony_ci        let lastHREF;
3151cb0ef41Sopenharmony_ci        let currentHREF = currentURL.href;
3161cb0ef41Sopenharmony_ci        do {
3171cb0ef41Sopenharmony_ci          if (scopeStore.has(currentHREF)) {
3181cb0ef41Sopenharmony_ci            if (allowSame || currentHREF !== normalizedHREF) {
3191cb0ef41Sopenharmony_ci              return currentHREF;
3201cb0ef41Sopenharmony_ci            }
3211cb0ef41Sopenharmony_ci          }
3221cb0ef41Sopenharmony_ci          lastHREF = currentHREF;
3231cb0ef41Sopenharmony_ci          currentURL = new URL('..', currentURL);
3241cb0ef41Sopenharmony_ci          currentHREF = currentURL.href;
3251cb0ef41Sopenharmony_ci        } while (lastHREF !== currentHREF);
3261cb0ef41Sopenharmony_ci      }
3271cb0ef41Sopenharmony_ci    }
3281cb0ef41Sopenharmony_ci  }
3291cb0ef41Sopenharmony_ci  if (scopeStore.has(protocol)) {
3301cb0ef41Sopenharmony_ci    if (allowSame || protocol !== href) return protocol;
3311cb0ef41Sopenharmony_ci  }
3321cb0ef41Sopenharmony_ci  if (scopeStore.has('')) {
3331cb0ef41Sopenharmony_ci    if (allowSame || '' !== href) return '';
3341cb0ef41Sopenharmony_ci  }
3351cb0ef41Sopenharmony_ci  return null;
3361cb0ef41Sopenharmony_ci}
3371cb0ef41Sopenharmony_ci// #endregion
3381cb0ef41Sopenharmony_ci
3391cb0ef41Sopenharmony_ci/**
3401cb0ef41Sopenharmony_ci * @typedef {Record<string, string> | typeof kFallThrough} DependencyMap
3411cb0ef41Sopenharmony_ci * @typedef {Array<[string, [string, string]]>} PatternDependencyMap
3421cb0ef41Sopenharmony_ci * @typedef {Record<string, string> | null | true} JSONDependencyMap
3431cb0ef41Sopenharmony_ci */
3441cb0ef41Sopenharmony_ci/**
3451cb0ef41Sopenharmony_ci * @typedef {Map<string, any>} ScopeStore
3461cb0ef41Sopenharmony_ci * @typedef {(specifier: string) => true | URL} DependencyMapper
3471cb0ef41Sopenharmony_ci * @typedef {boolean | string | SRI[] | typeof kCascade} Integrity
3481cb0ef41Sopenharmony_ci */
3491cb0ef41Sopenharmony_ci
3501cb0ef41Sopenharmony_ciclass Manifest {
3511cb0ef41Sopenharmony_ci  #defaultDependencies;
3521cb0ef41Sopenharmony_ci  /**
3531cb0ef41Sopenharmony_ci   * @type {string}
3541cb0ef41Sopenharmony_ci   */
3551cb0ef41Sopenharmony_ci  href;
3561cb0ef41Sopenharmony_ci  /**
3571cb0ef41Sopenharmony_ci   * @type {(err: Error) => void}
3581cb0ef41Sopenharmony_ci   *
3591cb0ef41Sopenharmony_ci   * Performs default action for what happens when a manifest encounters
3601cb0ef41Sopenharmony_ci   * a violation such as abort()ing or exiting the process, throwing the error,
3611cb0ef41Sopenharmony_ci   * or logging the error.
3621cb0ef41Sopenharmony_ci   */
3631cb0ef41Sopenharmony_ci  #reaction;
3641cb0ef41Sopenharmony_ci  /**
3651cb0ef41Sopenharmony_ci   * @type {Map<string, DependencyMapperInstance>}
3661cb0ef41Sopenharmony_ci   *
3671cb0ef41Sopenharmony_ci   * Used to find where a dependency is located.
3681cb0ef41Sopenharmony_ci   *
3691cb0ef41Sopenharmony_ci   * This stores functions to lazily calculate locations as needed.
3701cb0ef41Sopenharmony_ci   * `true` is used to signify that the location is not specified
3711cb0ef41Sopenharmony_ci   * by the manifest and default resolution should be allowed.
3721cb0ef41Sopenharmony_ci   *
3731cb0ef41Sopenharmony_ci   * The functions return `null` to signify that a dependency is
3741cb0ef41Sopenharmony_ci   * not found
3751cb0ef41Sopenharmony_ci   */
3761cb0ef41Sopenharmony_ci  #resourceDependencies = new SafeMap();
3771cb0ef41Sopenharmony_ci  /**
3781cb0ef41Sopenharmony_ci   * @type {Map<string, Integrity>}
3791cb0ef41Sopenharmony_ci   *
3801cb0ef41Sopenharmony_ci   * Used to compare a resource to the content body at the resource.
3811cb0ef41Sopenharmony_ci   * `true` is used to signify that all integrities are allowed, otherwise,
3821cb0ef41Sopenharmony_ci   * SRI strings are parsed to compare with the body.
3831cb0ef41Sopenharmony_ci   *
3841cb0ef41Sopenharmony_ci   * This stores strings instead of eagerly parsing SRI strings
3851cb0ef41Sopenharmony_ci   * and only converts them to SRI data structures when needed.
3861cb0ef41Sopenharmony_ci   * This avoids needing to parse all SRI strings at startup even
3871cb0ef41Sopenharmony_ci   * if some never end up being used.
3881cb0ef41Sopenharmony_ci   */
3891cb0ef41Sopenharmony_ci  #resourceIntegrities = new SafeMap();
3901cb0ef41Sopenharmony_ci  /**
3911cb0ef41Sopenharmony_ci   * @type {ScopeStore}
3921cb0ef41Sopenharmony_ci   *
3931cb0ef41Sopenharmony_ci   * Used to compare a resource to the content body at the resource.
3941cb0ef41Sopenharmony_ci   * `true` is used to signify that all integrities are allowed, otherwise,
3951cb0ef41Sopenharmony_ci   * SRI strings are parsed to compare with the body.
3961cb0ef41Sopenharmony_ci   *
3971cb0ef41Sopenharmony_ci   * Separate from #resourceDependencies due to conflicts with things like
3981cb0ef41Sopenharmony_ci   * `blob:` being both a scope and a resource potentially as well as
3991cb0ef41Sopenharmony_ci   * `file:` being parsed to `file:///` instead of remaining host neutral.
4001cb0ef41Sopenharmony_ci   */
4011cb0ef41Sopenharmony_ci  #scopeDependencies = new SafeMap();
4021cb0ef41Sopenharmony_ci  /**
4031cb0ef41Sopenharmony_ci   * @type {Map<string, boolean | null | typeof kCascade>}
4041cb0ef41Sopenharmony_ci   *
4051cb0ef41Sopenharmony_ci   * Used to allow arbitrary loading within a scope
4061cb0ef41Sopenharmony_ci   */
4071cb0ef41Sopenharmony_ci  #scopeIntegrities = new SafeMap();
4081cb0ef41Sopenharmony_ci  /**
4091cb0ef41Sopenharmony_ci   * `obj` should match the policy file format described in the docs
4101cb0ef41Sopenharmony_ci   * it is expected to not have prototype pollution issues either by reassigning
4111cb0ef41Sopenharmony_ci   * the prototype to `null` for values or by running prior to any user code.
4121cb0ef41Sopenharmony_ci   *
4131cb0ef41Sopenharmony_ci   * `manifestURL` is a URL to resolve relative locations against.
4141cb0ef41Sopenharmony_ci   * @param {object} obj
4151cb0ef41Sopenharmony_ci   * @param {string} manifestHREF
4161cb0ef41Sopenharmony_ci   */
4171cb0ef41Sopenharmony_ci  constructor(obj, manifestHREF) {
4181cb0ef41Sopenharmony_ci    this.href = manifestHREF;
4191cb0ef41Sopenharmony_ci    const scopes = this.#scopeDependencies;
4201cb0ef41Sopenharmony_ci    const integrities = this.#resourceIntegrities;
4211cb0ef41Sopenharmony_ci    const resourceDependencies = this.#resourceDependencies;
4221cb0ef41Sopenharmony_ci    let reaction = REACTION_THROW;
4231cb0ef41Sopenharmony_ci
4241cb0ef41Sopenharmony_ci    if (objectButNotArray(obj) && 'onerror' in obj) {
4251cb0ef41Sopenharmony_ci      const behavior = obj.onerror;
4261cb0ef41Sopenharmony_ci      if (behavior === 'exit') {
4271cb0ef41Sopenharmony_ci        reaction = REACTION_EXIT;
4281cb0ef41Sopenharmony_ci      } else if (behavior === 'log') {
4291cb0ef41Sopenharmony_ci        reaction = REACTION_LOG;
4301cb0ef41Sopenharmony_ci      } else if (behavior !== 'throw') {
4311cb0ef41Sopenharmony_ci        throw new ERR_MANIFEST_UNKNOWN_ONERROR(behavior);
4321cb0ef41Sopenharmony_ci      }
4331cb0ef41Sopenharmony_ci    }
4341cb0ef41Sopenharmony_ci
4351cb0ef41Sopenharmony_ci    this.#reaction = reaction;
4361cb0ef41Sopenharmony_ci    const jsonResourcesEntries = ObjectEntries(
4371cb0ef41Sopenharmony_ci      obj.resources ?? ObjectCreate(null),
4381cb0ef41Sopenharmony_ci    );
4391cb0ef41Sopenharmony_ci    const jsonScopesEntries = ObjectEntries(obj.scopes ?? ObjectCreate(null));
4401cb0ef41Sopenharmony_ci    const defaultDependencies = obj.dependencies ?? ObjectCreate(null);
4411cb0ef41Sopenharmony_ci
4421cb0ef41Sopenharmony_ci    this.#defaultDependencies = new DependencyMapperInstance(
4431cb0ef41Sopenharmony_ci      'default',
4441cb0ef41Sopenharmony_ci      defaultDependencies === true ? kFallThrough : defaultDependencies,
4451cb0ef41Sopenharmony_ci      false,
4461cb0ef41Sopenharmony_ci    );
4471cb0ef41Sopenharmony_ci
4481cb0ef41Sopenharmony_ci    for (let i = 0; i < jsonResourcesEntries.length; i++) {
4491cb0ef41Sopenharmony_ci      const { 0: originalHREF, 1: descriptor } = jsonResourcesEntries[i];
4501cb0ef41Sopenharmony_ci      const { cascade, dependencies, integrity } = descriptor;
4511cb0ef41Sopenharmony_ci      const href = resolve(originalHREF, manifestHREF).href;
4521cb0ef41Sopenharmony_ci
4531cb0ef41Sopenharmony_ci      if (typeof integrity !== 'undefined') {
4541cb0ef41Sopenharmony_ci        debug('Manifest contains integrity for resource %s', originalHREF);
4551cb0ef41Sopenharmony_ci        if (typeof integrity === 'string') {
4561cb0ef41Sopenharmony_ci          integrities.set(href, integrity);
4571cb0ef41Sopenharmony_ci        } else if (integrity === true) {
4581cb0ef41Sopenharmony_ci          integrities.set(href, true);
4591cb0ef41Sopenharmony_ci        } else {
4601cb0ef41Sopenharmony_ci          throw new ERR_MANIFEST_INVALID_RESOURCE_FIELD(href, 'integrity');
4611cb0ef41Sopenharmony_ci        }
4621cb0ef41Sopenharmony_ci      } else {
4631cb0ef41Sopenharmony_ci        integrities.set(href, cascade === true ? kCascade : false);
4641cb0ef41Sopenharmony_ci      }
4651cb0ef41Sopenharmony_ci      insertDependencyMap(
4661cb0ef41Sopenharmony_ci        href,
4671cb0ef41Sopenharmony_ci        dependencies,
4681cb0ef41Sopenharmony_ci        cascade,
4691cb0ef41Sopenharmony_ci        true,
4701cb0ef41Sopenharmony_ci        resourceDependencies,
4711cb0ef41Sopenharmony_ci      );
4721cb0ef41Sopenharmony_ci    }
4731cb0ef41Sopenharmony_ci
4741cb0ef41Sopenharmony_ci    const scopeIntegrities = this.#scopeIntegrities;
4751cb0ef41Sopenharmony_ci    for (let i = 0; i < jsonScopesEntries.length; i++) {
4761cb0ef41Sopenharmony_ci      const { 0: originalHREF, 1: descriptor } = jsonScopesEntries[i];
4771cb0ef41Sopenharmony_ci      const { cascade, dependencies, integrity } = descriptor;
4781cb0ef41Sopenharmony_ci      const href = emptyOrProtocolOrResolve(originalHREF, manifestHREF);
4791cb0ef41Sopenharmony_ci      if (typeof integrity !== 'undefined') {
4801cb0ef41Sopenharmony_ci        debug('Manifest contains integrity for scope %s', originalHREF);
4811cb0ef41Sopenharmony_ci        if (integrity === true) {
4821cb0ef41Sopenharmony_ci          scopeIntegrities.set(href, true);
4831cb0ef41Sopenharmony_ci        } else {
4841cb0ef41Sopenharmony_ci          throw new ERR_MANIFEST_INVALID_RESOURCE_FIELD(href, 'integrity');
4851cb0ef41Sopenharmony_ci        }
4861cb0ef41Sopenharmony_ci      } else {
4871cb0ef41Sopenharmony_ci        scopeIntegrities.set(href, cascade === true ? kCascade : false);
4881cb0ef41Sopenharmony_ci      }
4891cb0ef41Sopenharmony_ci      insertDependencyMap(href, dependencies, cascade, false, scopes);
4901cb0ef41Sopenharmony_ci    }
4911cb0ef41Sopenharmony_ci
4921cb0ef41Sopenharmony_ci    ObjectFreeze(this);
4931cb0ef41Sopenharmony_ci  }
4941cb0ef41Sopenharmony_ci
4951cb0ef41Sopenharmony_ci  /**
4961cb0ef41Sopenharmony_ci   * @param {string} requester
4971cb0ef41Sopenharmony_ci   * @returns {{resolve: any, reaction: (err: any) => void}}
4981cb0ef41Sopenharmony_ci   */
4991cb0ef41Sopenharmony_ci  getDependencyMapper(requester) {
5001cb0ef41Sopenharmony_ci    const requesterHREF = `${requester}`;
5011cb0ef41Sopenharmony_ci    const dependencies = this.#resourceDependencies;
5021cb0ef41Sopenharmony_ci    /**
5031cb0ef41Sopenharmony_ci     * @type {DependencyMapperInstance}
5041cb0ef41Sopenharmony_ci     */
5051cb0ef41Sopenharmony_ci    const instance = (
5061cb0ef41Sopenharmony_ci      dependencies.has(requesterHREF) ?
5071cb0ef41Sopenharmony_ci        dependencies.get(requesterHREF) ?? null :
5081cb0ef41Sopenharmony_ci        this.getScopeDependencyMapper(requesterHREF, true)
5091cb0ef41Sopenharmony_ci    ) ?? this.#defaultDependencies;
5101cb0ef41Sopenharmony_ci    return {
5111cb0ef41Sopenharmony_ci      resolve: (specifier, conditions) => {
5121cb0ef41Sopenharmony_ci        const normalizedSpecifier = canonicalizeSpecifier(
5131cb0ef41Sopenharmony_ci          specifier,
5141cb0ef41Sopenharmony_ci          requesterHREF,
5151cb0ef41Sopenharmony_ci        );
5161cb0ef41Sopenharmony_ci        const result = instance._resolveAlreadyNormalized(
5171cb0ef41Sopenharmony_ci          normalizedSpecifier,
5181cb0ef41Sopenharmony_ci          conditions,
5191cb0ef41Sopenharmony_ci          this,
5201cb0ef41Sopenharmony_ci        );
5211cb0ef41Sopenharmony_ci        if (result === kFallThrough) return true;
5221cb0ef41Sopenharmony_ci        return result;
5231cb0ef41Sopenharmony_ci      },
5241cb0ef41Sopenharmony_ci      reaction: this.#reaction,
5251cb0ef41Sopenharmony_ci    };
5261cb0ef41Sopenharmony_ci  }
5271cb0ef41Sopenharmony_ci
5281cb0ef41Sopenharmony_ci  mightAllow(url, onreact) {
5291cb0ef41Sopenharmony_ci    const href = `${url}`;
5301cb0ef41Sopenharmony_ci    debug('Checking for entry of %s', href);
5311cb0ef41Sopenharmony_ci    if (StringPrototypeStartsWith(href, 'node:')) {
5321cb0ef41Sopenharmony_ci      return true;
5331cb0ef41Sopenharmony_ci    }
5341cb0ef41Sopenharmony_ci    if (this.#resourceIntegrities.has(href)) {
5351cb0ef41Sopenharmony_ci      return true;
5361cb0ef41Sopenharmony_ci    }
5371cb0ef41Sopenharmony_ci    let scope = findScopeHREF(href, this.#scopeIntegrities, true);
5381cb0ef41Sopenharmony_ci    while (scope !== null) {
5391cb0ef41Sopenharmony_ci      if (this.#scopeIntegrities.has(scope)) {
5401cb0ef41Sopenharmony_ci        const entry = this.#scopeIntegrities.get(scope);
5411cb0ef41Sopenharmony_ci        if (entry === true) {
5421cb0ef41Sopenharmony_ci          return true;
5431cb0ef41Sopenharmony_ci        } else if (entry !== kCascade) {
5441cb0ef41Sopenharmony_ci          break;
5451cb0ef41Sopenharmony_ci        }
5461cb0ef41Sopenharmony_ci      }
5471cb0ef41Sopenharmony_ci      const nextScope = findScopeHREF(
5481cb0ef41Sopenharmony_ci        new URL('..', scope),
5491cb0ef41Sopenharmony_ci        this.#scopeIntegrities,
5501cb0ef41Sopenharmony_ci        false,
5511cb0ef41Sopenharmony_ci      );
5521cb0ef41Sopenharmony_ci      if (!nextScope || nextScope === scope) {
5531cb0ef41Sopenharmony_ci        break;
5541cb0ef41Sopenharmony_ci      }
5551cb0ef41Sopenharmony_ci      scope = nextScope;
5561cb0ef41Sopenharmony_ci    }
5571cb0ef41Sopenharmony_ci    if (onreact) {
5581cb0ef41Sopenharmony_ci      this.#reaction(onreact());
5591cb0ef41Sopenharmony_ci    }
5601cb0ef41Sopenharmony_ci    return false;
5611cb0ef41Sopenharmony_ci  }
5621cb0ef41Sopenharmony_ci
5631cb0ef41Sopenharmony_ci  assertIntegrity(url, content) {
5641cb0ef41Sopenharmony_ci    const href = `${url}`;
5651cb0ef41Sopenharmony_ci    debug('Checking integrity of %s', href);
5661cb0ef41Sopenharmony_ci    const realIntegrities = new SafeMap();
5671cb0ef41Sopenharmony_ci    const integrities = this.#resourceIntegrities;
5681cb0ef41Sopenharmony_ci    function processEntry(href) {
5691cb0ef41Sopenharmony_ci      let integrityEntries = integrities.get(href);
5701cb0ef41Sopenharmony_ci      if (integrityEntries === true) return true;
5711cb0ef41Sopenharmony_ci      if (typeof integrityEntries === 'string') {
5721cb0ef41Sopenharmony_ci        const sri = ObjectFreeze(SRI.parse(integrityEntries));
5731cb0ef41Sopenharmony_ci        integrities.set(href, sri);
5741cb0ef41Sopenharmony_ci        integrityEntries = sri;
5751cb0ef41Sopenharmony_ci      }
5761cb0ef41Sopenharmony_ci      return integrityEntries;
5771cb0ef41Sopenharmony_ci    }
5781cb0ef41Sopenharmony_ci    if (integrities.has(href)) {
5791cb0ef41Sopenharmony_ci      const integrityEntries = processEntry(href);
5801cb0ef41Sopenharmony_ci      if (integrityEntries === true) return true;
5811cb0ef41Sopenharmony_ci      if (ArrayIsArray(integrityEntries)) {
5821cb0ef41Sopenharmony_ci        // Avoid clobbered Symbol.iterator
5831cb0ef41Sopenharmony_ci        for (let i = 0; i < integrityEntries.length; i++) {
5841cb0ef41Sopenharmony_ci          const { algorithm, value: expected } = integrityEntries[i];
5851cb0ef41Sopenharmony_ci          // TODO(tniessen): the content should not be passed as a string in the
5861cb0ef41Sopenharmony_ci          // first place, see https://github.com/nodejs/node/issues/39707
5871cb0ef41Sopenharmony_ci          const mismatchedIntegrity = internalVerifyIntegrity(algorithm, content, expected);
5881cb0ef41Sopenharmony_ci          if (mismatchedIntegrity === undefined) {
5891cb0ef41Sopenharmony_ci            return true;
5901cb0ef41Sopenharmony_ci          }
5911cb0ef41Sopenharmony_ci          realIntegrities.set(algorithm, mismatchedIntegrity);
5921cb0ef41Sopenharmony_ci        }
5931cb0ef41Sopenharmony_ci      }
5941cb0ef41Sopenharmony_ci
5951cb0ef41Sopenharmony_ci      if (integrityEntries !== kCascade) {
5961cb0ef41Sopenharmony_ci        const error = new ERR_MANIFEST_ASSERT_INTEGRITY(url, realIntegrities);
5971cb0ef41Sopenharmony_ci        this.#reaction(error);
5981cb0ef41Sopenharmony_ci      }
5991cb0ef41Sopenharmony_ci    }
6001cb0ef41Sopenharmony_ci    let scope = findScopeHREF(href, this.#scopeIntegrities, true);
6011cb0ef41Sopenharmony_ci    while (scope !== null) {
6021cb0ef41Sopenharmony_ci      if (this.#scopeIntegrities.has(scope)) {
6031cb0ef41Sopenharmony_ci        const entry = this.#scopeIntegrities.get(scope);
6041cb0ef41Sopenharmony_ci        if (entry === true) {
6051cb0ef41Sopenharmony_ci          return true;
6061cb0ef41Sopenharmony_ci        } else if (entry !== kCascade) {
6071cb0ef41Sopenharmony_ci          break;
6081cb0ef41Sopenharmony_ci        }
6091cb0ef41Sopenharmony_ci      }
6101cb0ef41Sopenharmony_ci      const nextScope = findScopeHREF(scope, this.#scopeDependencies, false);
6111cb0ef41Sopenharmony_ci      if (!nextScope) {
6121cb0ef41Sopenharmony_ci        break;
6131cb0ef41Sopenharmony_ci      }
6141cb0ef41Sopenharmony_ci      scope = nextScope;
6151cb0ef41Sopenharmony_ci    }
6161cb0ef41Sopenharmony_ci    const error = new ERR_MANIFEST_ASSERT_INTEGRITY(url, realIntegrities);
6171cb0ef41Sopenharmony_ci    this.#reaction(error);
6181cb0ef41Sopenharmony_ci  }
6191cb0ef41Sopenharmony_ci  /**
6201cb0ef41Sopenharmony_ci   * @param {string} href
6211cb0ef41Sopenharmony_ci   * @param {boolean} allowSameHREFScope
6221cb0ef41Sopenharmony_ci   * @returns {DependencyMapperInstance | null}
6231cb0ef41Sopenharmony_ci   */
6241cb0ef41Sopenharmony_ci  getScopeDependencyMapper(href, allowSameHREFScope) {
6251cb0ef41Sopenharmony_ci    if (href === null) {
6261cb0ef41Sopenharmony_ci      return this.#defaultDependencies;
6271cb0ef41Sopenharmony_ci    }
6281cb0ef41Sopenharmony_ci    /** @type {string | null} */
6291cb0ef41Sopenharmony_ci    const scopeHREF = findScopeHREF(
6301cb0ef41Sopenharmony_ci      href,
6311cb0ef41Sopenharmony_ci      this.#scopeDependencies,
6321cb0ef41Sopenharmony_ci      allowSameHREFScope,
6331cb0ef41Sopenharmony_ci    );
6341cb0ef41Sopenharmony_ci    if (scopeHREF === null) return this.#defaultDependencies;
6351cb0ef41Sopenharmony_ci    return this.#scopeDependencies.get(scopeHREF);
6361cb0ef41Sopenharmony_ci  }
6371cb0ef41Sopenharmony_ci}
6381cb0ef41Sopenharmony_ci
6391cb0ef41Sopenharmony_ci// Lock everything down to avoid problems even if reference is leaked somehow
6401cb0ef41Sopenharmony_ciObjectSetPrototypeOf(Manifest, null);
6411cb0ef41Sopenharmony_ciObjectSetPrototypeOf(Manifest.prototype, null);
6421cb0ef41Sopenharmony_ciObjectFreeze(Manifest);
6431cb0ef41Sopenharmony_ciObjectFreeze(Manifest.prototype);
6441cb0ef41Sopenharmony_cimodule.exports = ObjectFreeze({ Manifest });
6451cb0ef41Sopenharmony_ci
6461cb0ef41Sopenharmony_ci// #region URL utils
6471cb0ef41Sopenharmony_ci
6481cb0ef41Sopenharmony_ci/**
6491cb0ef41Sopenharmony_ci * Attempts to canonicalize relative URL strings against a base URL string
6501cb0ef41Sopenharmony_ci * Does not perform I/O
6511cb0ef41Sopenharmony_ci * If not able to canonicalize, returns the original specifier
6521cb0ef41Sopenharmony_ci *
6531cb0ef41Sopenharmony_ci * This effectively removes the possibility of the return value being a relative
6541cb0ef41Sopenharmony_ci * URL string
6551cb0ef41Sopenharmony_ci * @param {string} specifier
6561cb0ef41Sopenharmony_ci * @param {string} base
6571cb0ef41Sopenharmony_ci * @returns {string}
6581cb0ef41Sopenharmony_ci */
6591cb0ef41Sopenharmony_cifunction canonicalizeSpecifier(specifier, base) {
6601cb0ef41Sopenharmony_ci  try {
6611cb0ef41Sopenharmony_ci    if (RegExpPrototypeExec(kRelativeURLStringPattern, specifier) !== null) {
6621cb0ef41Sopenharmony_ci      return resolve(specifier, base).href;
6631cb0ef41Sopenharmony_ci    }
6641cb0ef41Sopenharmony_ci    return resolve(specifier).href;
6651cb0ef41Sopenharmony_ci  } catch {
6661cb0ef41Sopenharmony_ci    // Continue regardless of error.
6671cb0ef41Sopenharmony_ci  }
6681cb0ef41Sopenharmony_ci  return specifier;
6691cb0ef41Sopenharmony_ci}
6701cb0ef41Sopenharmony_ci
6711cb0ef41Sopenharmony_ci/**
6721cb0ef41Sopenharmony_ci * Does a special allowance for scopes to be non-valid URLs
6731cb0ef41Sopenharmony_ci * that are only protocol strings or the empty string
6741cb0ef41Sopenharmony_ci * @param {string} resourceHREF
6751cb0ef41Sopenharmony_ci * @param {string} [base]
6761cb0ef41Sopenharmony_ci * @returns {string}
6771cb0ef41Sopenharmony_ci */
6781cb0ef41Sopenharmony_ciconst emptyOrProtocolOrResolve = (resourceHREF, base) => {
6791cb0ef41Sopenharmony_ci  if (resourceHREF === '') return '';
6801cb0ef41Sopenharmony_ci  if (StringPrototypeEndsWith(resourceHREF, ':')) {
6811cb0ef41Sopenharmony_ci    // URL parse will trim these anyway, save the compute
6821cb0ef41Sopenharmony_ci    resourceHREF = RegExpPrototypeSymbolReplace(
6831cb0ef41Sopenharmony_ci      // eslint-disable-next-line
6841cb0ef41Sopenharmony_ci      /^[\x00-\x1F\x20]|\x09\x0A\x0D|[\x00-\x1F\x20]$/g,
6851cb0ef41Sopenharmony_ci      resourceHREF,
6861cb0ef41Sopenharmony_ci      '',
6871cb0ef41Sopenharmony_ci    );
6881cb0ef41Sopenharmony_ci    if (RegExpPrototypeExec(/^[a-zA-Z][a-zA-Z+\-.]*:$/, resourceHREF) !== null) {
6891cb0ef41Sopenharmony_ci      return resourceHREF;
6901cb0ef41Sopenharmony_ci    }
6911cb0ef41Sopenharmony_ci  }
6921cb0ef41Sopenharmony_ci  return resolve(resourceHREF, base).href;
6931cb0ef41Sopenharmony_ci};
6941cb0ef41Sopenharmony_ci
6951cb0ef41Sopenharmony_ci/**
6961cb0ef41Sopenharmony_ci * @type {Map<string, URL>}
6971cb0ef41Sopenharmony_ci */
6981cb0ef41Sopenharmony_cilet parsedURLs;
6991cb0ef41Sopenharmony_ci/**
7001cb0ef41Sopenharmony_ci * Resolves a valid url string and uses the parsed cache to avoid double parsing
7011cb0ef41Sopenharmony_ci * costs.
7021cb0ef41Sopenharmony_ci * @param {string} originalHREF
7031cb0ef41Sopenharmony_ci * @param {string} [base]
7041cb0ef41Sopenharmony_ci * @returns {Readonly<URL>}
7051cb0ef41Sopenharmony_ci */
7061cb0ef41Sopenharmony_ciconst resolve = (originalHREF, base) => {
7071cb0ef41Sopenharmony_ci  parsedURLs = parsedURLs ?? new SafeMap();
7081cb0ef41Sopenharmony_ci  if (parsedURLs.has(originalHREF)) {
7091cb0ef41Sopenharmony_ci    return parsedURLs.get(originalHREF);
7101cb0ef41Sopenharmony_ci  } else if (RegExpPrototypeExec(kRelativeURLStringPattern, originalHREF) !== null) {
7111cb0ef41Sopenharmony_ci    const resourceURL = new URL(originalHREF, base);
7121cb0ef41Sopenharmony_ci    parsedURLs.set(resourceURL.href, resourceURL);
7131cb0ef41Sopenharmony_ci    return resourceURL;
7141cb0ef41Sopenharmony_ci  }
7151cb0ef41Sopenharmony_ci  const resourceURL = new URL(originalHREF);
7161cb0ef41Sopenharmony_ci  parsedURLs.set(originalHREF, resourceURL);
7171cb0ef41Sopenharmony_ci  return resourceURL;
7181cb0ef41Sopenharmony_ci};
7191cb0ef41Sopenharmony_ci
7201cb0ef41Sopenharmony_ci// #endregion
7211cb0ef41Sopenharmony_ci
7221cb0ef41Sopenharmony_ci/**
7231cb0ef41Sopenharmony_ci * @param {any} o
7241cb0ef41Sopenharmony_ci * @returns {o is object}
7251cb0ef41Sopenharmony_ci */
7261cb0ef41Sopenharmony_cifunction objectButNotArray(o) {
7271cb0ef41Sopenharmony_ci  return o && typeof o === 'object' && !ArrayIsArray(o);
7281cb0ef41Sopenharmony_ci}
7291cb0ef41Sopenharmony_ci
7301cb0ef41Sopenharmony_cifunction searchDependencies(href, target, conditions) {
7311cb0ef41Sopenharmony_ci  if (objectButNotArray(target)) {
7321cb0ef41Sopenharmony_ci    const keys = ObjectKeys(target);
7331cb0ef41Sopenharmony_ci    for (let i = 0; i < keys.length; i++) {
7341cb0ef41Sopenharmony_ci      const key = keys[i];
7351cb0ef41Sopenharmony_ci      if (conditions.has(key)) {
7361cb0ef41Sopenharmony_ci        const ret = searchDependencies(href, target[key], conditions);
7371cb0ef41Sopenharmony_ci        if (ret != null) {
7381cb0ef41Sopenharmony_ci          return ret;
7391cb0ef41Sopenharmony_ci        }
7401cb0ef41Sopenharmony_ci      }
7411cb0ef41Sopenharmony_ci    }
7421cb0ef41Sopenharmony_ci  } else if (typeof target === 'string') {
7431cb0ef41Sopenharmony_ci    return target;
7441cb0ef41Sopenharmony_ci  } else if (target === true) {
7451cb0ef41Sopenharmony_ci    return target;
7461cb0ef41Sopenharmony_ci  } else {
7471cb0ef41Sopenharmony_ci    throw new ERR_MANIFEST_INVALID_RESOURCE_FIELD(href, 'dependencies');
7481cb0ef41Sopenharmony_ci  }
7491cb0ef41Sopenharmony_ci  return null;
7501cb0ef41Sopenharmony_ci}
751