Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  NormandyApi.sys.mjs   Sprache: unbekannt

 
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

const lazy = {};

ChromeUtils.defineESModuleGetters(lazy, {
  CanonicalJSON: "resource://gre/modules/CanonicalJSON.sys.mjs",
});

const prefs = Services.prefs.getBranch("app.normandy.");

let indexPromise = null;

function getChainRootIdentifier() {
  const normandy_url = Services.prefs.getCharPref("app.normandy.api_url");
  if (normandy_url == "https://normandy.cdn.mozilla.net/api/v1") {
    return Ci.nsIContentSignatureVerifier.ContentSignatureProdRoot;
  }
  if (normandy_url.includes("stage.")) {
    return Ci.nsIContentSignatureVerifier.ContentSignatureStageRoot;
  }
  if (normandy_url.includes("dev.")) {
    return Ci.nsIContentSignatureVerifier.ContentSignatureDevRoot;
  }
  if (Services.env.exists("XPCSHELL_TEST_PROFILE_DIR")) {
    return Ci.nsIX509CertDB.AppXPCShellRoot;
  }
  return Ci.nsIContentSignatureVerifier.ContentSignatureLocalRoot;
}

export var NormandyApi = {
  InvalidSignatureError: class InvalidSignatureError extends Error {},

  clearIndexCache() {
    indexPromise = null;
  },

  get(endpoint, data) {
    const url = new URL(endpoint);
    if (data) {
      for (const key of Object.keys(data)) {
        url.searchParams.set(key, data[key]);
      }
    }
    return fetch(url.href, {
      method: "get",
      headers: { Accept: "application/json" },
      credentials: "omit",
    });
  },

  absolutify(url) {
    if (url.startsWith("http")) {
      return url;
    }
    const apiBase = prefs.getCharPref("api_url");
    const server = new URL(apiBase).origin;
    if (url.startsWith("/")) {
      return server + url;
    }
    throw new Error("Can't use relative urls");
  },

  async getApiUrl(name) {
    if (!indexPromise) {
      const apiBase = new URL(prefs.getCharPref("api_url"));
      if (!apiBase.pathname.endsWith("/")) {
        apiBase.pathname += "/";
      }
      indexPromise = this.get(apiBase.toString()).then(res => res.json());
    }
    const index = await indexPromise;
    if (!(name in index)) {
      throw new Error(`API endpoint with name "${name}" not found.`);
    }
    const url = index[name];
    return this.absolutify(url);
  },

  /**
   * Verify content signature, by serializing the specified `object` as
   * canonical JSON, and using the Normandy signer verifier to check that
   * it matches the signature specified in `signaturePayload`.
   *
   * If the the signature is not valid, an error is thrown. Otherwise this
   * function returns undefined.
   *
   * @param {object|String} data The object (or string) to be checked
   * @param {object} signaturePayload The signature information
   * @param {String} signaturePayload.x5u The certificate chain URL
   * @param {String} signaturePayload.signature base64 signature bytes
   * @param {String} type The object type (eg. `"recipe"`, `"action"`)
   * @returns {Promise<undefined>} If the signature is valid, this function returns without error
   * @throws {NormandyApi.InvalidSignatureError} if signature is invalid.
   */
  async verifyObjectSignature(data, signaturePayload, type) {
    const { signature, x5u } = signaturePayload;
    const certChainResponse = await this.get(this.absolutify(x5u));
    const certChain = await certChainResponse.text();
    const builtSignature = `p384ecdsa=${signature}`;

    const serialized =
      typeof data == "string" ? data : lazy.CanonicalJSON.stringify(data);

    const verifier = Cc[
      "@mozilla.org/security/contentsignatureverifier;1"
    ].createInstance(Ci.nsIContentSignatureVerifier);

    let valid;
    try {
      valid = await verifier.asyncVerifyContentSignature(
        serialized,
        builtSignature,
        certChain,
        "normandy.content-signature.mozilla.org",
        getChainRootIdentifier()
      );
    } catch (err) {
      throw new NormandyApi.InvalidSignatureError(
        `${type} signature validation failed: ${err}`
      );
    }

    if (!valid) {
      throw new NormandyApi.InvalidSignatureError(
        `${type} signature is not valid`
      );
    }
  },

  /**
   * Fetch metadata about this client determined by the server.
   * @return {object} Metadata specified by the server
   */
  async classifyClient() {
    const classifyClientUrl = await this.getApiUrl("classify-client");
    const response = await this.get(classifyClientUrl);
    const clientData = await response.json();
    clientData.request_time = new Date(clientData.request_time);
    return clientData;
  },

  /**
   * Fetch details for an extension from the server.
   * @param extensionId {integer} The ID of the extension to look up
   * @resolves {Object}
   */
  async fetchExtensionDetails(extensionId) {
    const baseUrl = await this.getApiUrl("extension-list");
    const extensionDetailsUrl = `${baseUrl}${extensionId}/`;
    const response = await this.get(extensionDetailsUrl);
    return response.json();
  },
};

[ Dauer der Verarbeitung: 0.27 Sekunden  (vorverarbeitet)  ]

                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge