diff options
author | Florian Dold <florian.dold@gmail.com> | 2016-11-03 01:33:53 +0100 |
---|---|---|
committer | Florian Dold <florian.dold@gmail.com> | 2016-11-03 01:33:53 +0100 |
commit | d1291f67551c58168af43698a359cb5ddfd266b0 (patch) | |
tree | 55a13ed29fe1915e3f42f1b1b7038dafa2e975a7 /node_modules/selenium-webdriver/firefox/extension.js | |
parent | d0a0695fb5d34996850723f7d4b1b59c3df909c2 (diff) |
node_modules
Diffstat (limited to 'node_modules/selenium-webdriver/firefox/extension.js')
-rw-r--r-- | node_modules/selenium-webdriver/firefox/extension.js | 187 |
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; |