pack-crx 1.0.1 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/index.ts DELETED
@@ -1,660 +0,0 @@
1
- import { createHash } from "node:crypto";
2
- import Pbf from "pbf";
3
- import * as crx3 from "./crx3.pb";
4
- import JSZip from "jszip";
5
- import fs from "node:fs/promises";
6
- import { join, relative, resolve } from "node:path";
7
- import { Buffer } from "node:buffer";
8
- import RSA from "node-rsa";
9
-
10
- interface ChromeBaseManifest {
11
- // Required keys
12
- manifest_version: number;
13
- name: string;
14
- version: string;
15
-
16
- // Required by Chrome Web Store
17
- description?: string;
18
- icons?: {[x: `${number}`]: string};
19
-
20
- // Optional
21
- author?: string;
22
- background?: {
23
- service_worker?: string;
24
- type?: "module";
25
- };
26
- chrome_settings_overrides?: {
27
- alternate_urls?: string[];
28
- encoding?: string;
29
- favicon_url?: string;
30
- homepage?: string;
31
- image_url?: string;
32
- image_url_post_params?: string;
33
- is_default?: boolean;
34
- keyword?: string;
35
- name?: string;
36
- prepopulated_id?: number;
37
- search_provider?: object;
38
- search_url?: string;
39
- search_url_post_params?: string;
40
- startup_pages?: string[];
41
- suggest_url?: string;
42
- suggest_url_post_params?: string;
43
- };
44
- chrome_url_overrides?: {
45
- bookmarks?: string;
46
- history?: string;
47
- newtab?: string;
48
- };
49
- commands?: {
50
- [x: string]: {
51
- description: string;
52
- suggested_key?: string;
53
- }
54
- };
55
- content_scripts?: {
56
- matches: string[];
57
- css?: string[];
58
- js?: string[];
59
- run_at?: "document_start" | "document_end" | "document_idle";
60
- match_about_blank?: boolean;
61
- match_origin_as_fallback?: boolean;
62
- world?: "ISOLATED" | "MAIN";
63
- }[];
64
- content_security_policy?: {
65
- extension_pages?: string;
66
- sandbox?: string;
67
- };
68
- cross_origin_embedder_policy?: string;
69
- cross_origin_opener_policy?: string;
70
- declarative_net_request?: {
71
- rule_resources?: {
72
- id: string;
73
- enabled: boolean;
74
- path: string;
75
- }[];
76
- };
77
- default_locale?: string;
78
- devtools_page?: string;
79
- export?: {
80
- allowlist?: string[];
81
- };
82
- externally_connectable?: {
83
- ids?: string[];
84
- matches?: string[];
85
- accepts_tls_channel_id?: boolean;
86
- };
87
- homepage_url?: string;
88
- host_permissions?: string[];
89
- import?: {
90
- id: string;
91
- minimum_version?: string;
92
- }[];
93
- incognito?: "spanning" | "split" | "not_allowed";
94
- key?: string;
95
- minimum_chrome_version?: string;
96
- oauth2?: {
97
- client_id: string;
98
- scopes: string[];
99
- };
100
- omnibox?: {
101
- keyword?: string;
102
- };
103
- optional_host_permissions?: string[];
104
- optional_permissions?: string[];
105
- options_page?: string;
106
- options_ui?: {
107
- page: string;
108
- open_in_tab?: boolean;
109
- };
110
- permissions?: string[];
111
- requirements?: {
112
- [x: string]: {features: string[]};
113
- };
114
- sandbox?: {
115
- pages: string[];
116
- };
117
- short_name?: string;
118
- side_panel?: string;
119
- storage?: {
120
- managed_schema?: string;
121
- };
122
- tts_engine?: {
123
- voices?: {
124
- voice_name: string;
125
- lang?: string;
126
- event_types?: ("start" | "word" | "sentence" | "marker" | "end" | "error")[];
127
- }[];
128
- };
129
- update_url?: string;
130
- version_name?: string;
131
- web_accessible_resources?: ({
132
- resources: string[];
133
- } & ({
134
- matches: string[];
135
- } | {
136
- extension_ids: string[];
137
- }))[];
138
-
139
- // ChromeOS
140
- file_browser_handlers?: {
141
- id: string;
142
- default_title: string;
143
- file_filters: string[];
144
- }[];
145
- file_handlers?: {
146
- action: string;
147
- name: string;
148
- accept: {
149
- [x: string]: string[];
150
- };
151
- launch_type?: "single-client" | "multiple-clients";
152
- }[];
153
- file_system_provider_capabilities?: {
154
- configurable?: boolean;
155
- multiple_mounts?: boolean;
156
- watchable?: boolean;
157
- source: "file" | "device" | "network";
158
- };
159
- input_components?: {
160
- name: string;
161
- id?: string;
162
- language?: string | string[];
163
- layouts?: string | string[];
164
- input_view?: string;
165
- options_page?: string;
166
- }[];
167
- }
168
-
169
- export type ChromeMV2Manifest = ChromeBaseManifest & {
170
- manifest_version: 2;
171
- browser_action?: {
172
- default_icon?: {[x: `${number}`]: string};
173
- default_title?: string;
174
- default_popup?: string;
175
- };
176
- page_action?: {
177
- default_icon?: {[x: `${number}`]: string};
178
- default_title?: string;
179
- default_popup?: string;
180
- };
181
- };
182
-
183
- export type ChromeMV3Manifest = ChromeBaseManifest & {
184
- manifest_version: 3;
185
- action?: {
186
- default_icon?: {[x: `${number}`]: string};
187
- default_title?: string;
188
- default_popup?: string;
189
- };
190
- };
191
-
192
- export type ChromeManifest = ChromeMV2Manifest | ChromeMV3Manifest;
193
-
194
- export interface CrxFileHeader {
195
- sha256_with_rsa?: AsymmetricKeyProof[];
196
- sha256_with_ecdsa?: AsymmetricKeyProof[];
197
- signed_header_data?: Uint8Array;
198
- }
199
-
200
- export interface AsymmetricKeyProof {
201
- public_key?: Uint8Array;
202
- signature?: Uint8Array;
203
- }
204
-
205
- /**
206
- * CRX IDs are 16 bytes long
207
- * @constant
208
- */
209
- const CRX_ID_SIZE = 16;
210
-
211
- /**
212
- * CRX3 uses 32bit numbers in various places,
213
- * so let's prepare size constant for that.
214
- * @constant
215
- */
216
- const SIZE_BYTES = 4;
217
-
218
- /**
219
- * Used for file format.
220
- * @see {@link https://github.com/chromium/chromium/blob/master/components/crx_file/crx3.proto}
221
- * @constant
222
- */
223
- const kSignature = Uint8Array.from("Cr24", ch => ch.charCodeAt(0));
224
-
225
- /**
226
- * Used for file format.
227
- * @see {@link https://github.com/chromium/chromium/blob/master/components/crx_file/crx3.proto}
228
- * @constant
229
- */
230
- const kVersion = Uint8Array.from([3, 0, 0, 0]);
231
-
232
- /**
233
- * Used for generating package signatures.
234
- * @see {@link https://github.com/chromium/chromium/blob/master/components/crx_file/crx3.proto}
235
- * @constant
236
- */
237
- const kSignatureContext = Uint8Array.from("CRX3 SignedData\x00", ch => ch.charCodeAt(0));
238
-
239
- /**
240
- * Pack a CRX2 extension. Chrome stopped supporting these entirely in version 73.0.3683, which released in October of 2017.
241
- *
242
- * @param privateKey The extension's private key.
243
- * @param publicKey The extension's public key.
244
- * @param contents The zipped contents of the extension. This should contain a `manifest.json` file directly inside it, but we don't validate that in this function.
245
- *
246
- * @returns The contents of the packaged extension.
247
- *
248
- * @deprecated
249
- */
250
- export function packCrx2(privateKey: Uint8Array, publicKey: Uint8Array, contents: Uint8Array, rsa?: RSA): Uint8Array {
251
- rsa ??= new RSA(Buffer.from(privateKey), "pkcs8-private-der");
252
- rsa.setOptions({signingScheme: "pkcs1-sha1"});
253
- const signature = rsa.sign(contents);
254
- const length = 16 /* magic + version + key length + sign length */ + publicKey.length + signature.length;
255
- const result = new Uint8Array(length);
256
- result.set(kSignature, 0);
257
- const dv = new DataView(result.buffer);
258
- dv.setUint32(4, 2, true);
259
- dv.setUint32(8, publicKey.length, true);
260
- dv.setUint32(12, signature.length, true);
261
- result.set(publicKey, 16);
262
- result.set(signature, 16 + publicKey.length);
263
- result.set(contents, length);
264
- return result;
265
- }
266
-
267
- /**
268
- * Pack a CRX3 extension.
269
- *
270
- * @param privateKey The extension's private key.
271
- * @param publicKey The extension's public key.
272
- * @param contents The zipped contents of the extension. This should contain a `manifest.json` file directly inside it, but we don't validate that in this function.
273
- *
274
- * @returns The contents of the packaged extension.
275
- */
276
- export function packCrx3(privateKey: Uint8Array, publicKey: Uint8Array, contents: Uint8Array, rsa?: RSA): Uint8Array {
277
- let pb = new Pbf();
278
- crx3.SignedData.write({
279
- crx_id: generateBinaryCrxId(publicKey)
280
- }, pb);
281
- const signedHeaderData = pb.finish();
282
-
283
- const signature = generateCrx3Signature(privateKey, signedHeaderData, contents, rsa);
284
-
285
- pb = new Pbf();
286
- crx3.CrxFileHeader.write({
287
- sha256_with_rsa: [{
288
- public_key: publicKey satisfies Uint8Array,
289
- signature
290
- }],
291
- signed_header_data: signedHeaderData
292
- } as CrxFileHeader, pb);
293
- const header = pb.finish();
294
-
295
- const size =
296
- kSignature.length + // Magic constant
297
- kVersion.length + // Version number
298
- SIZE_BYTES + // Header size
299
- header.length +
300
- contents.length;
301
-
302
- const result = new Uint8Array(size);
303
-
304
- let index = 0;
305
- result.set(kSignature, index);
306
- result.set(kVersion, index += kSignature.length);
307
- new DataView(result.buffer).setUint32(index += kVersion.length, header.length, true);
308
- result.set(header, index += SIZE_BYTES);
309
- result.set(contents, index += header.length);
310
-
311
- return result;
312
- }
313
-
314
- function generateBinaryCrxId(publicKey: Uint8Array): Uint8Array {
315
- var hash = createHash("sha256");
316
- hash.update(publicKey);
317
- return Uint8Array.from(hash.digest()).slice(0, CRX_ID_SIZE);
318
- }
319
-
320
- function generateCrx3Signature(privateKey: Uint8Array, signedHeaderData: Uint8Array, contents: Uint8Array, rsa?: RSA): Uint8Array {
321
- rsa ??= new RSA(Buffer.from(privateKey), "pkcs8-private-der");
322
- rsa.setOptions({signingScheme: "pkcs1-sha256"});
323
-
324
- // Size of signed_header_data
325
- const sizeOctets = new DataView(new ArrayBuffer(SIZE_BYTES));
326
- sizeOctets.setUint32(0, signedHeaderData.length, true);
327
-
328
- const toSign = Buffer.concat([
329
- kSignatureContext,
330
- new Uint8Array(sizeOctets.buffer),
331
- signedHeaderData,
332
- contents
333
- ]);
334
-
335
- return Uint8Array.from(rsa.sign(toSign));
336
- }
337
-
338
- /**
339
- * Generate an extension's ID (32 characters, a-p) from its public key.
340
- *
341
- * @param publicKey The public key of the extension.
342
- *
343
- * @returns The generated extension ID.
344
- */
345
- export function generateCrxId(publicKey: Uint8Array): string {
346
- return createHash("sha256")
347
- .update(publicKey)
348
- .digest()
349
- .toString("hex")
350
- .split("")
351
- .map(x => (parseInt(x, 16) + 0x0a).toString(26))
352
- .join("")
353
- .slice(0, 32);
354
- }
355
-
356
- /**
357
- * Load a directory from the filesystem into a ZIP archive, using the node:fs API.
358
- *
359
- * @param where The path to the directory.
360
- */
361
- export async function packContents(where: string): Promise<{
362
- /** The ZIP-encoded data. */
363
- contents: Uint8Array,
364
- /** The manifest for the extension, parsed as JSON. */
365
- manifest: ChromeManifest
366
- }> {
367
- const zip = new JSZip();
368
- let manifest: Promise<Uint8Array> | undefined;
369
- async function f(loc: string) {
370
- for (const entry of await fs.readdir(loc, {withFileTypes: true})) {
371
- const fp = join(loc, entry.name);
372
- if (entry.isDirectory()) {
373
- await f(fp);
374
- } else {
375
- const contents = fs.readFile(fp).then(buf => Uint8Array.from(buf));
376
- const rp = relative(where, fp);
377
- if (rp == "manifest.json") manifest ??= contents;
378
- zip.file(rp, contents);
379
- }
380
- }
381
- }
382
- await f(resolve(process.cwd(), where));
383
- if (manifest == undefined) throw new Error("Manifest file not found");
384
- return {
385
- contents: await zip.generateAsync({
386
- compression: "DEFLATE",
387
- type: "uint8array"
388
- }),
389
- manifest: JSON.parse(new TextDecoder().decode(await manifest))
390
- };
391
- }
392
-
393
- /**
394
- * Generate the updates XML file for [serving an extension yourself](https://developer.chrome.com/docs/extensions/how-to/distribute/host-on-linux).
395
- *
396
- * @param crxId The extension's ID.
397
- * @param url The URL where the extension's CRX file will be hosted.
398
- * @param version The extension's version.
399
- * @param minChromeVersion The minimum Chrome version that the extension can be installed on.
400
- *
401
- * @returns The updates XML text
402
- */
403
- export function generateUpdateXML(crxId: string, url: string, version: string, minChromeVersion?: string): string {
404
- return `<?xml version='1.0' encoding='UTF-8'?>
405
- <gupdate xmlns='http://www.google.com/update2/response' protocol='2.0'>
406
- <app appid='${crxId}'>
407
- <updatecheck codebase='${url}' version='${version}'${minChromeVersion ? ` prodversionmin='${minChromeVersion}'` : ""} />
408
- </app>
409
- </gupdate>`;
410
- }
411
-
412
- export function generatePrivateKey(bits = 4096): Uint8Array {
413
- return Uint8Array.from(new RSA({b: bits}).exportKey("pkcs8-private-der"));
414
- }
415
-
416
- export function generatePublicKey(privateKey: Uint8Array): Uint8Array {
417
- return Uint8Array.from(new RSA(Buffer.from(privateKey), "pkcs8-private-der").exportKey("pkcs8-public-der"));
418
- }
419
-
420
- export function convertToPem(key: Uint8Array, type: "private" | "public"): string {
421
- return new RSA(Buffer.from(key), `pkcs8-${type}-der`).exportKey(`pkcs8-${type}-pem`);
422
- }
423
-
424
- export function convertFromPem(key: string, type: "private" | "public"): Uint8Array {
425
- return Uint8Array.from(new RSA(key, `pkcs8-${type}-pem`).exportKey(`pkcs8-${type}-der`));
426
- }
427
-
428
- /**
429
- * Unpack a CRX file and extract its contents as ZIP data.
430
- *
431
- * @param crx The CRX to be unpacked.
432
- */
433
- export function unpack(crx: Uint8Array): {
434
- /** The ZIP data. */
435
- archive: Uint8Array,
436
- /** The CRX format version. */
437
- crxVersion: 2,
438
- /** The extension's public key. */
439
- key: Uint8Array,
440
- /** The signature over the contents of the extension. */
441
- sign: Uint8Array
442
- } | {
443
- /** The ZIP data. */
444
- archive: Uint8Array,
445
- /** The CRX format version. */
446
- crxVersion: 3,
447
- /** The header for the CRX file, for signatures and things. */
448
- header: CrxFileHeader
449
- } {
450
- const abuf = crx.buffer;
451
- const dv = new DataView(abuf);
452
- if (kSignature.every((v, i) => dv.getUint8(i) == v)) {
453
- const crxVersion = dv.getUint32(4, true);
454
- if (crxVersion == 2) {
455
- const keyLength = dv.getUint32(8, true);
456
- const signLength = dv.getUint32(12, true);
457
- return {
458
- archive: crx.slice(16 + keyLength + signLength),
459
- crxVersion: 2,
460
- key: crx.slice(16, 16 + keyLength),
461
- sign: crx.slice(16 + keyLength, 16 + keyLength + signLength)
462
- };
463
- } else if (crxVersion == 3) {
464
- const headerLength = dv.getUint32(8, true);
465
- const archive = crx.slice(12 + headerLength);
466
- const header = crx.slice(12, 12 + headerLength);
467
- const pb = new Pbf(header);
468
- const decodedHeader = crx3.CrxFileHeader.read(pb);
469
- return {archive, crxVersion: 3, header: decodedHeader};
470
- }
471
- }
472
- throw new Error("The file given is not a valid CRX file");
473
- }
474
-
475
- export interface PackInput {
476
- /** The ZIP archive of the contents of the extension, or a path to the folder containing the extension. */
477
- contents?: Uint8Array | string;
478
- /** The private key for the extension, or a path to it. */
479
- privateKey?: Uint8Array | string | null;
480
- /** The size of key to generate, if needed. */
481
- keySize?: number;
482
- /** The public key for the extension, or a path to it. */
483
- publicKey?: Uint8Array | string | null;
484
- /** The instance of NodeRSA to use. */
485
- rsa?: RSA;
486
- /** The extension's ID. */
487
- id?: string | null;
488
- /** The outputted CRX file. */
489
- crx?: Uint8Array | null;
490
- /** The CRX format version to use. Defaults to 3. */
491
- crxVersion?: number;
492
- /** The URL to where the CRX file (not the updates XML) will be hosted. */
493
- crxUrl?: string;
494
- /** The [updates XML file](https://developer.chrome.com/docs/extensions/how-to/distribute/host-on-linux). */
495
- updateXML?: string | null;
496
- /** The extension's version. */
497
- extVersion?: string | null;
498
- /** The minimum Chrome version the extension requires. */
499
- minChromeVersion?: string | null;
500
- /** The extension's [manifest](https://developer.chrome.com/docs/extensions/reference/manifest). */
501
- manifest?: ChromeManifest | null;
502
- }
503
-
504
- type SetKeys<A extends object, B extends object> = {[x in keyof A | keyof B]: x extends keyof B ? unknown extends B[x] ? x extends keyof A ? A[x] : never : B[x] : x extends keyof A ? A[x] : never};
505
-
506
- export type TransformPack<I extends PackInput> =
507
- I["privateKey"] extends string ?
508
- TransformPack<SetKeys<I, {
509
- privateKey: Uint8Array | undefined;
510
- rsa: RSA;
511
- }>>
512
- : I["publicKey"] extends string ?
513
- TransformPack<SetKeys<I, {
514
- publicKey: Uint8Array | undefined;
515
- }>>
516
- : I["updateXML"] extends null ?
517
- undefined extends I["crxUrl"] ? never : TransformPack<SetKeys<I, {
518
- updateXML: string;
519
- id: undefined extends I["id"] ? null : I["id"];
520
- extVersion: undefined extends I["extVersion"] ? null : I["extVersion"];
521
- minChromeVersion: undefined extends I["minChromeVersion"] ? null : I["minChromeVersion"];
522
- }>>
523
- : I["extVersion"] extends null ?
524
- TransformPack<SetKeys<I, {
525
- extVersion: string;
526
- manifest: undefined extends I["manifest"] ? null : I["manifest"];
527
- }>>
528
- : I["minChromeVersion"] extends null ?
529
- TransformPack<SetKeys<I, {
530
- minChromeVersion: string | undefined;
531
- manifest: undefined extends I["manifest"] ? null : I["manifest"];
532
- }>>
533
- : I["manifest"] extends null ?
534
- undefined extends I["contents"] ? never
535
- : Uint8Array extends I["contents"] ? never
536
- : TransformPack<SetKeys<I, {
537
- manifest: ChromeManifest;
538
- }>>
539
- : I["crx"] extends null ?
540
- undefined extends I["contents"] ? never : TransformPack<SetKeys<I, {
541
- crx: Uint8Array;
542
- privateKey: undefined extends I["privateKey"] ? null : I["privateKey"];
543
- publicKey: undefined extends I["publicKey"] ? null : I["publicKey"];
544
- }>>
545
- : I["id"] extends null ?
546
- TransformPack<SetKeys<I, {
547
- id: string;
548
- publicKey: undefined extends I["publicKey"] ? null : I["publicKey"];
549
- }>>
550
- : I["publicKey"] extends null ?
551
- TransformPack<SetKeys<I, {
552
- publicKey: Uint8Array;
553
- privateKey: undefined extends I["privateKey"] ? null : I["privateKey"];
554
- }>>
555
- : I["privateKey"] extends null ?
556
- TransformPack<SetKeys<I, {
557
- privateKey: Uint8Array;
558
- rsa: RSA;
559
- }>>
560
- : I["contents"] extends string ?
561
- TransformPack<SetKeys<I, {
562
- contents: Uint8Array;
563
- manifest: ChromeManifest;
564
- }>>
565
- : I;
566
-
567
- /**
568
- * Use the entirety of this API in one function.
569
- *
570
- * @param options An object containing input parameters.
571
- *
572
- * If `null` is given for a property, then the function will generate a value for it based on the other properties.
573
- *
574
- * If a property requires another but that property is not requested (with `null`), then it is generated and given anyways.
575
- *
576
- * If `privateKey` or `publicKey` are strings, `pack` will load the file at each path as a key. If the extension is `.pem`, they are loaded as pkcs8-pem and converted to pkcs8-der.
577
- *
578
- * `pack` always returns a `Promise`, even if all of the operations inside are synchronous.
579
- *
580
- * However, the return result is the same object as the input - just with the properties modified - so if you *really* want synchronous operations, you can keep a reference to the input object, call the function, and access the synchronous results from that object. Just make sure you don't set `privateKey` or `manifest` to `null` or `contents` to a string, otherwise some of your values might not arrive synchronously.
581
- */
582
- export async function pack<I extends PackInput>(options: I): Promise<TransformPack<I>> {
583
- if (typeof options.privateKey == "string") {
584
- try {
585
- const isPem = options.privateKey.endsWith(".pem");
586
- const contents = await fs.readFile(options.privateKey);
587
- if (isPem) options.privateKey = Uint8Array.from((options.rsa ??= new RSA(contents, "pkcs8-private-pem")).exportKey("pkcs8-private-der"));
588
- else options.privateKey = Uint8Array.from(contents);
589
- } catch (e) {
590
- if (!`${e}`.includes("ENOENT")) throw e;
591
- options.privateKey = undefined;
592
- }
593
- }
594
- if (typeof options.publicKey == "string") {
595
- try {
596
- const isPem = options.publicKey.endsWith(".pem");
597
- const contents = await fs.readFile(options.publicKey);
598
- if (isPem) options.publicKey = Uint8Array.from(new RSA(contents, "pkcs8-public-pem").exportKey("pkcs8-public-der"));
599
- else options.publicKey = Uint8Array.from(contents);
600
- } catch (e) {
601
- if (!`${e}`.includes("ENOENT")) throw e;
602
- options.publicKey = undefined;
603
- }
604
- }
605
- if (options.updateXML === null) {
606
- if (options.crxUrl === undefined) throw new Error("crxUrl must be defined to generate updateXML");
607
- if (options.id === undefined) options.id = null;
608
- if (options.extVersion === undefined) options.extVersion = null;
609
- if (options.minChromeVersion === undefined) options.minChromeVersion = null;
610
- }
611
- if (options.extVersion === null) {
612
- if (options.manifest === undefined) options.manifest = null;
613
- }
614
- if (options.minChromeVersion === null) {
615
- if (options.manifest === undefined) options.manifest = null;
616
- }
617
- if (options.crx === null) {
618
- if (options.contents === undefined) throw new Error("contents must be defined to generate crx");
619
- if (options.privateKey === undefined) options.privateKey = null;
620
- if (options.publicKey === undefined) options.publicKey = null;
621
- }
622
- if (options.id === null) {
623
- if (options.publicKey === undefined) options.publicKey = null;
624
- }
625
- if (options.publicKey === null) {
626
- if (options.privateKey === undefined) options.privateKey = null;
627
- }
628
-
629
- if (options.privateKey === null) {
630
- options.rsa ??= new RSA({b: options.keySize || 4096});
631
- options.privateKey = Uint8Array.from(options.rsa.exportKey("pkcs8-private-der"));
632
- options.publicKey = Uint8Array.from(options.rsa.exportKey("pkcs8-public-der"));
633
- }
634
- if (options.publicKey === null) {
635
- options.publicKey = Uint8Array.from((options.rsa ??= new RSA(Buffer.from(options.privateKey!), "pkcs8-private-der")).exportKey("pkcs8-public-der"));
636
- }
637
- if (typeof options.contents == "string") {
638
- ({contents: options.contents, manifest: options.manifest} = await packContents(options.contents));
639
- }
640
- if (options.crx === null) {
641
- if (options.crxVersion == 3 || options.crxVersion == undefined) options.crx = packCrx3(options.privateKey!, options.publicKey!, options.contents!, options.rsa);
642
- else if (options.crxVersion == 2) options.crx = packCrx2(options.privateKey!, options.publicKey!, options.contents!, options.rsa);
643
- }
644
- if (options.id === null) {
645
- options.id = generateCrxId(options.publicKey!);
646
- }
647
- if (options.extVersion === null) {
648
- if (!options.manifest) throw new Error("manifest must be defined to generate extVersion");
649
- options.extVersion = options.manifest.version;
650
- }
651
- if (options.minChromeVersion === null) {
652
- options.minChromeVersion = options.manifest?.minimum_chrome_version || (options.crxVersion == 3 || options.crxVersion == undefined ? "73.0.3683" : undefined);
653
- }
654
- if (options.updateXML === null) {
655
- options.updateXML = generateUpdateXML(options.id!, options.crxUrl!, options.extVersion!, options.minChromeVersion);
656
- }
657
- return options as any;
658
- }
659
-
660
- export default pack;
package/tsconfig.json DELETED
@@ -1,27 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- // Enable latest features
4
- "lib": ["ESNext"],
5
- "target": "ESNext",
6
- "module": "ESNext",
7
- "moduleDetection": "force",
8
- "jsx": "react-jsx",
9
- "allowJs": true,
10
-
11
- // Bundler mode
12
- "moduleResolution": "bundler",
13
- "allowImportingTsExtensions": true,
14
- "verbatimModuleSyntax": true,
15
- "noEmit": true,
16
-
17
- // Best practices
18
- "strict": true,
19
- "skipLibCheck": true,
20
- "noFallthroughCasesInSwitch": true,
21
-
22
- // Some stricter flags (disabled by default)
23
- "noUnusedLocals": false,
24
- "noUnusedParameters": false,
25
- "noPropertyAccessFromIndexSignature": false
26
- }
27
- }