1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 |
|
17 |
|
18 |
|
19 |
|
20 | 'use strict';
|
21 |
|
22 | const AdmZip = require('adm-zip'),
|
23 | fs = require('fs'),
|
24 | path = require('path'),
|
25 | xml = require('xml2js');
|
26 |
|
27 | const io = require('../io');
|
28 |
|
29 |
|
30 |
|
31 |
|
32 |
|
33 | class AddonFormatError extends Error {
|
34 |
|
35 | constructor(msg) {
|
36 | super(msg);
|
37 |
|
38 | this.name = this.constructor.name;
|
39 | }
|
40 | }
|
41 |
|
42 |
|
43 |
|
44 |
|
45 |
|
46 |
|
47 |
|
48 |
|
49 |
|
50 |
|
51 |
|
52 | function install(extension, dir) {
|
53 | return getDetails(extension).then(function(details) {
|
54 | var dst = path.join(dir, details.id);
|
55 | if (extension.slice(-4) === '.xpi') {
|
56 | if (!details.unpack) {
|
57 | return io.copy(extension, dst + '.xpi').then(() => details.id);
|
58 | } else {
|
59 | return Promise.resolve().then(function() {
|
60 |
|
61 | new AdmZip(extension).extractAllTo(dst, true);
|
62 | return details.id;
|
63 | });
|
64 | }
|
65 | } else {
|
66 | return io.copyDir(extension, dst).then(() => details.id);
|
67 | }
|
68 | });
|
69 | }
|
70 |
|
71 |
|
72 |
|
73 |
|
74 |
|
75 |
|
76 | var AddonDetails;
|
77 |
|
78 |
|
79 | var RdfRoot;
|
80 |
|
81 |
|
82 |
|
83 |
|
84 |
|
85 |
|
86 |
|
87 |
|
88 | function getDetails(addonPath) {
|
89 | return readManifest(addonPath).then(function(doc) {
|
90 | var em = getNamespaceId(doc, 'http://www.mozilla.org/2004/em-rdf#');
|
91 | var rdf = getNamespaceId(
|
92 | doc, 'http://www.w3.org/1999/02/22-rdf-syntax-ns#');
|
93 |
|
94 | var description = doc[rdf + 'RDF'][rdf + 'Description'][0];
|
95 | var details = {
|
96 | id: getNodeText(description, em + 'id'),
|
97 | name: getNodeText(description, em + 'name'),
|
98 | version: getNodeText(description, em + 'version'),
|
99 | unpack: getNodeText(description, em + 'unpack') || false
|
100 | };
|
101 |
|
102 | if (typeof details.unpack === 'string') {
|
103 | details.unpack = details.unpack.toLowerCase() === 'true';
|
104 | }
|
105 |
|
106 | if (!details.id) {
|
107 | throw new AddonFormatError('Could not find add-on ID for ' + addonPath);
|
108 | }
|
109 |
|
110 | return details;
|
111 | });
|
112 |
|
113 | function getNodeText(node, name) {
|
114 | return node[name] && node[name][0] || '';
|
115 | }
|
116 |
|
117 | function getNamespaceId(doc, url) {
|
118 | var keys = Object.keys(doc);
|
119 | if (keys.length !== 1) {
|
120 | throw new AddonFormatError('Malformed manifest for add-on ' + addonPath);
|
121 | }
|
122 |
|
123 | var namespaces = (doc[keys[0]]).$;
|
124 | var id = '';
|
125 | Object.keys(namespaces).some(function(ns) {
|
126 | if (namespaces[ns] !== url) {
|
127 | return false;
|
128 | }
|
129 |
|
130 | if (ns.indexOf(':') != -1) {
|
131 | id = ns.split(':')[1] + ':';
|
132 | }
|
133 | return true;
|
134 | });
|
135 | return id;
|
136 | }
|
137 | }
|
138 |
|
139 |
|
140 |
|
141 |
|
142 |
|
143 |
|
144 |
|
145 | function readManifest(addonPath) {
|
146 | var manifest;
|
147 |
|
148 | if (addonPath.slice(-4) === '.xpi') {
|
149 | manifest = new Promise((resolve, reject) => {
|
150 | let zip = new AdmZip(addonPath);
|
151 |
|
152 | if (!zip.getEntry('install.rdf')) {
|
153 | reject(new AddonFormatError(
|
154 | 'Could not find install.rdf in ' + addonPath));
|
155 | return;
|
156 | }
|
157 |
|
158 | zip.readAsTextAsync('install.rdf', resolve);
|
159 | });
|
160 | } else {
|
161 | manifest = io.stat(addonPath).then(function(stats) {
|
162 | if (!stats.isDirectory()) {
|
163 | throw Error(
|
164 | 'Add-on path is niether a xpi nor a directory: ' + addonPath);
|
165 | }
|
166 | return io.read(path.join(addonPath, 'install.rdf'));
|
167 | });
|
168 | }
|
169 |
|
170 | return manifest.then(function(content) {
|
171 | return new Promise((resolve, reject) => {
|
172 | xml.parseString(content, (err, data) => {
|
173 | if (err) {
|
174 | reject(err);
|
175 | } else {
|
176 | resolve(data);
|
177 | }
|
178 | });
|
179 | });
|
180 | });
|
181 | }
|
182 |
|
183 |
|
184 |
|
185 |
|
186 |
|
187 | exports.install = install;
|