);

export let WebsiteFilter = {
  _observerAdded: false,

  init(blocklist, exceptionlist) {
    let blockArray = [],
      exceptionArray = [];

    for (let i = 0; i < blocklist.length && i < LIST_LENGTH_LIMIT; i++) {
      try {
        let pattern = new MatchPattern(blocklist[i].toLowerCase());
        blockArray.push(pattern);
        lazy.log.debug(
          `Pattern added to WebsiteFilter. Block: ${blocklist[i]}`
        );
      } catch (e) {
        lazy.log.error(
          `Invalid pattern on WebsiteFilter. Block: ${blocklist[i]}`
        );
      }
    }

    this._blockPatterns = new MatchPatternSet(blockArray);

    for (let i = 0; i < exceptionlist.length && i < LIST_LENGTH_LIMIT; i++) {
      try {
        let pattern = new MatchPattern(exceptionlist[i].toLowerCase());
        exceptionArray.push(pattern);
        lazy.log.debug(
          `Pattern added to WebsiteFilter. Exception: ${exceptionlist[i]}`
        );
      } catch (e) {
        lazy.log.error(
          `Invalid pattern on WebsiteFilter. Exception: ${exceptionlist[i]}`
        );
      }
    }

    if (exceptionArray.length) {
      this._exceptionsPatterns = new MatchPatternSet(exceptionArray);
    }

    let registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);

    if (!registrar.isContractIDRegistered(this.contractID)) {
      registrar.registerFactory(
        this.classID,
        this.classDescription,
        this.contractID,
        this
      );

      Services.catMan.addCategoryEntry(
        "content-policy",
        this.contractID,
        this.contractID,
        false,
        true
      );
    }
    // We have to do this to catch 30X redirects.
    // See bug 456957.
    if (!this._observerAdded) {
      this._observerAdded = true;
      // We rely on weak references, so we never remove this observer.
      Services.obs.addObserver(this, "http-on-examine-response", true);
    }
  },

  shouldLoad(contentLocation, loadInfo) {
    let contentType = loadInfo.externalContentPolicyType;
    let url = contentLocation.spec.toLowerCase();
    if (contentLocation.scheme == "view-source") {
      url = contentLocation.pathQueryRef;
    } else if (url.startsWith("about:reader?url=")) {
      url = decodeURIComponent(url.substr(17));
    }
    if (
      contentType == Ci.nsIContentPolicy.TYPE_DOCUMENT ||
      contentType == Ci.nsIContentPolicy.TYPE_SUBDOCUMENT
    ) {
      if (!this.isAllowed(url)) {
        return Ci.nsIContentPolicy.REJECT_POLICY;
      }
    }
    return Ci.nsIContentPolicy.ACCEPT;
  },
  shouldProcess() {
    return Ci.nsIContentPolicy.ACCEPT;
  },
  observe(subject) {
    try {
      let channel = subject.QueryInterface(Ci.nsIHttpChannel);
      if (
        !channel.isDocument ||
        channel.responseStatus < 300 ||
        channel.responseStatus >= 400
      ) {
        return;
      }
      let location = channel.getResponseHeader("location");
      // location might not be a fully qualified URL
      let url = URL.parse(location);
      if (!url) {
        url = URL.parse(location, channel.URI.spec);
      }
      if (url && !this.isAllowed(url.href)) {
        channel.cancel(Cr.NS_ERROR_BLOCKED_BY_POLICY);
      }
    } catch (e) {}
  },
  classDescription: "Policy Engine File Content Policy",
  contractID: "@mozilla-org/policy-engine-file-content-policy-service;1",
  classID: Components.ID("{c0bbb557-813e-4e25-809d-b46a531a258f}"),
  QueryInterface: ChromeUtils.generateQI([
    "nsIContentPolicy",
    "nsIObserver",
    "nsISupportsWeakReference",
  ]),
  createInstance(iid) {
    return this.QueryInterface(iid);
  },
  isAllowed(url) {
    if (this._blockPatterns?.matches(url.toLowerCase())) {
      if (
        !this._exceptionsPatterns ||
        !this._exceptionsPatterns.matches(url.toLowerCase())
      ) {
        return false;
      }
    }
    return true;
  },
};
PK