aboutsummaryrefslogtreecommitdiff
path: root/node_modules/selenium-webdriver/firefox/extension.js
diff options
context:
space:
mode:
authorFlorian Dold <florian.dold@gmail.com>2016-11-03 01:33:53 +0100
committerFlorian Dold <florian.dold@gmail.com>2016-11-03 01:33:53 +0100
commitd1291f67551c58168af43698a359cb5ddfd266b0 (patch)
tree55a13ed29fe1915e3f42f1b1b7038dafa2e975a7 /node_modules/selenium-webdriver/firefox/extension.js
parentd0a0695fb5d34996850723f7d4b1b59c3df909c2 (diff)
node_modules
Diffstat (limited to 'node_modules/selenium-webdriver/firefox/extension.js')
-rw-r--r--node_modules/selenium-webdriver/firefox/extension.js187
1 files changed, 187 insertions, 0 deletions
diff --git a/node_modules/selenium-webdriver/firefox/extension.js b/node_modules/selenium-webdriver/firefox/extension.js
new file mode 100644
index 000000000..60abb06b8
--- /dev/null
+++ b/node_modules/selenium-webdriver/firefox/extension.js
@@ -0,0 +1,187 @@
+// Licensed to the Software Freedom Conservancy (SFC) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The SFC licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+/** @fileoverview Utilities for working with Firefox extensions. */
+
+'use strict';
+
+const AdmZip = require('adm-zip'),
+ fs = require('fs'),
+ path = require('path'),
+ xml = require('xml2js');
+
+const io = require('../io');
+
+
+/**
+ * Thrown when there an add-on is malformed.
+ */
+class AddonFormatError extends Error {
+ /** @param {string} msg The error message. */
+ constructor(msg) {
+ super(msg);
+ /** @override */
+ this.name = this.constructor.name;
+ }
+}
+
+
+
+/**
+ * Installs an extension to the given directory.
+ * @param {string} extension Path to the extension to install, as either a xpi
+ * file or a directory.
+ * @param {string} dir Path to the directory to install the extension in.
+ * @return {!Promise<string>} A promise for the add-on ID once
+ * installed.
+ */
+function install(extension, dir) {
+ return getDetails(extension).then(function(details) {
+ var dst = path.join(dir, details.id);
+ if (extension.slice(-4) === '.xpi') {
+ if (!details.unpack) {
+ return io.copy(extension, dst + '.xpi').then(() => details.id);
+ } else {
+ return Promise.resolve().then(function() {
+ // TODO: find an async library for inflating a zip archive.
+ new AdmZip(extension).extractAllTo(dst, true);
+ return details.id;
+ });
+ }
+ } else {
+ return io.copyDir(extension, dst).then(() => details.id);
+ }
+ });
+}
+
+
+/**
+ * Describes a Firefox add-on.
+ * @typedef {{id: string, name: string, version: string, unpack: boolean}}
+ */
+var AddonDetails;
+
+/** @typedef {{$: !Object<string, string>}} */
+var RdfRoot;
+
+
+
+/**
+ * Extracts the details needed to install an add-on.
+ * @param {string} addonPath Path to the extension directory.
+ * @return {!Promise<!AddonDetails>} A promise for the add-on details.
+ */
+function getDetails(addonPath) {
+ return readManifest(addonPath).then(function(doc) {
+ var em = getNamespaceId(doc, 'http://www.mozilla.org/2004/em-rdf#');
+ var rdf = getNamespaceId(
+ doc, 'http://www.w3.org/1999/02/22-rdf-syntax-ns#');
+
+ var description = doc[rdf + 'RDF'][rdf + 'Description'][0];
+ var details = {
+ id: getNodeText(description, em + 'id'),
+ name: getNodeText(description, em + 'name'),
+ version: getNodeText(description, em + 'version'),
+ unpack: getNodeText(description, em + 'unpack') || false
+ };
+
+ if (typeof details.unpack === 'string') {
+ details.unpack = details.unpack.toLowerCase() === 'true';
+ }
+
+ if (!details.id) {
+ throw new AddonFormatError('Could not find add-on ID for ' + addonPath);
+ }
+
+ return details;
+ });
+
+ function getNodeText(node, name) {
+ return node[name] && node[name][0] || '';
+ }
+
+ function getNamespaceId(doc, url) {
+ var keys = Object.keys(doc);
+ if (keys.length !== 1) {
+ throw new AddonFormatError('Malformed manifest for add-on ' + addonPath);
+ }
+
+ var namespaces = /** @type {!RdfRoot} */(doc[keys[0]]).$;
+ var id = '';
+ Object.keys(namespaces).some(function(ns) {
+ if (namespaces[ns] !== url) {
+ return false;
+ }
+
+ if (ns.indexOf(':') != -1) {
+ id = ns.split(':')[1] + ':';
+ }
+ return true;
+ });
+ return id;
+ }
+}
+
+
+/**
+ * Reads the manifest for a Firefox add-on.
+ * @param {string} addonPath Path to a Firefox add-on as a xpi or an extension.
+ * @return {!Promise<!Object>} A promise for the parsed manifest.
+ */
+function readManifest(addonPath) {
+ var manifest;
+
+ if (addonPath.slice(-4) === '.xpi') {
+ manifest = new Promise((resolve, reject) => {
+ let zip = new AdmZip(addonPath);
+
+ if (!zip.getEntry('install.rdf')) {
+ reject(new AddonFormatError(
+ 'Could not find install.rdf in ' + addonPath));
+ return;
+ }
+
+ zip.readAsTextAsync('install.rdf', resolve);
+ });
+ } else {
+ manifest = io.stat(addonPath).then(function(stats) {
+ if (!stats.isDirectory()) {
+ throw Error(
+ 'Add-on path is niether a xpi nor a directory: ' + addonPath);
+ }
+ return io.read(path.join(addonPath, 'install.rdf'));
+ });
+ }
+
+ return manifest.then(function(content) {
+ return new Promise((resolve, reject) => {
+ xml.parseString(content, (err, data) => {
+ if (err) {
+ reject(err);
+ } else {
+ resolve(data);
+ }
+ });
+ });
+ });
+}
+
+
+// PUBLIC API
+
+
+exports.install = install;