zotero-plugin 5.0.39 → 6.0.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.
@@ -0,0 +1,35 @@
1
+ #!/usr/bin/env node
2
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
3
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
4
+ }) : x)(function(x) {
5
+ if (typeof require !== "undefined") return require.apply(this, arguments);
6
+ throw Error('Dynamic require of "' + x + '" is not supported');
7
+ });
8
+
9
+ // bin/branches.ts
10
+ import "dotenv/config";
11
+ import * as path from "path";
12
+ import { Octokit } from "@octokit/rest";
13
+
14
+ // root.ts
15
+ var root_default = process.cwd();
16
+
17
+ // bin/branches.ts
18
+ process.on("unhandledRejection", (up) => {
19
+ throw up;
20
+ });
21
+ var octokit = new Octokit({ auth: `token ${process.env.GITHUB_TOKEN}` });
22
+ var pkg = __require(path.join(root_default, "package.json"));
23
+ var [, owner, repo] = pkg.repository.url.match(/:\/\/github.com\/([^/]+)\/([^.]+)\.git$/);
24
+ async function main() {
25
+ const branches = await octokit.repos.listBranches({ owner, repo });
26
+ for (const branch of branches.data) {
27
+ if (/^[0-9]+$/.exec(branch.name)) {
28
+ const issue = await octokit.issues.get({ owner, repo, issue_number: parseInt(branch.name) });
29
+ if (issue.data.state !== "open") console.log(branch.name, issue.data.state);
30
+ } else if (!["master", "main", "gh-pages"].includes(branch.name)) {
31
+ console.log(branch.name);
32
+ }
33
+ }
34
+ }
35
+ main().catch((err) => console.log(err));
@@ -0,0 +1,134 @@
1
+ #!/usr/bin/env node
2
+
3
+ // bin/fetch-log.ts
4
+ import { Command } from "commander";
5
+ import crypto2 from "crypto";
6
+ import fs from "fs";
7
+ import fetch from "node-fetch";
8
+ import StreamZip from "node-stream-zip";
9
+ import path from "path";
10
+ import { Entry as KeyRingEntry } from "@napi-rs/keyring";
11
+ import prompts from "prompts";
12
+
13
+ // package.json
14
+ var version = "6.0.0";
15
+
16
+ // bin/crypto.ts
17
+ import crypto from "crypto";
18
+ function decrypt({ ciphertext, iv, tag, salt, iterations, keyLength, algorithm }, passphrase) {
19
+ const key = crypto.pbkdf2Sync(passphrase, Buffer.from(salt, "base64"), iterations, keyLength, "sha256");
20
+ const decipher = crypto.createDecipheriv(algorithm, key, Buffer.from(iv, "base64"));
21
+ decipher.setAuthTag(Buffer.from(tag, "base64"));
22
+ let decrypted = decipher.update(ciphertext, "base64", "utf8");
23
+ decrypted += decipher.final("utf8");
24
+ return decrypted;
25
+ }
26
+
27
+ // bin/fetch-log.ts
28
+ async function getPassphrase(service, account) {
29
+ const entry = new KeyRingEntry(service, account);
30
+ let passphrase = entry.getPassword();
31
+ if (!passphrase) {
32
+ const response = await prompts({
33
+ type: "password",
34
+ name: "passphrase",
35
+ message: "Enter a passphrase to decrypt your private key for ${service} ${account}:"
36
+ });
37
+ entry.setPassword(passphrase = response.passphrase);
38
+ }
39
+ return passphrase;
40
+ }
41
+ var oops = (...args2) => {
42
+ console.error(...args2);
43
+ process.exit(1);
44
+ };
45
+ var program = new Command();
46
+ program.description("A script to generate and store an RSA key pair in an encrypted file.").option("-p, --private <path>", "Path for the encrypted private key .pem.json file", "private.pem.json").argument("<debug log id>", "debug log ID to fetch").parse(process.argv);
47
+ var options = program.opts();
48
+ var args = program.args;
49
+ if (!args.length) oops("No log ID");
50
+ var m = args[0].match(/^(?<key>[a-z0-9]+)-(?<host>[^-]+)-(?<remote>[^.]+)(?<tags>.*)$/i);
51
+ if (!m) oops(args[0], "is not a valid log ID");
52
+ if (m.groups.host !== "0x0") oops("Unexpected debug log host", m.groups.host);
53
+ options.encrypted = m.groups.tags.split(".").includes("enc");
54
+ options.zip = path.join("logs", `${m.groups.key}.zip`);
55
+ options.url = `https://0x0.st/${m.groups.remote}.zip`;
56
+ if (options.encrypted) {
57
+ if (!options.private) oops("No private key provided");
58
+ if (!fs.existsSync(options.private)) oops("Private key", options.private, "does not exist");
59
+ if (!fs.existsSync("package.json")) oops("package.json does not exist in the current directory");
60
+ }
61
+ var logs = path.join("logs", m.groups.key);
62
+ console.log(options.url, "=>", logs);
63
+ if (!fs.existsSync(logs)) {
64
+ fs.mkdirSync(logs, { recursive: true });
65
+ }
66
+ async function main() {
67
+ try {
68
+ const response = await fetch(options.url, {
69
+ method: "GET",
70
+ headers: {
71
+ "User-Agent": `Zotero plugin log fetcher ${version}`,
72
+ Accept: "*/*"
73
+ }
74
+ });
75
+ if (!response.ok) oops(`Failed to download: ${response.statusText}`);
76
+ const download = fs.createWriteStream(options.zip);
77
+ response.body.pipe(download);
78
+ await new Promise((resolve, reject) => {
79
+ download.on("finish", () => resolve());
80
+ download.on("error", (err) => reject(err));
81
+ });
82
+ let privateKey;
83
+ if (options.encrypted) {
84
+ const pkg = JSON.parse(fs.readFileSync("package.json", "utf-8"));
85
+ const passphrase = await getPassphrase(`${pkg.name} Zotero plugin`, "debug-log");
86
+ privateKey = decrypt(JSON.parse(fs.readFileSync(options.private, "utf-8")), passphrase);
87
+ }
88
+ const zipfile = new StreamZip.async({ file: options.zip });
89
+ let decryptionKey;
90
+ const fileEntries = {};
91
+ for (const entry of Object.values(await zipfile.entries())) {
92
+ if (entry.isDirectory) continue;
93
+ const m2 = entry.name.match(/(?<filename>.+)\.(?<type>key|enc|iv)$/i);
94
+ let filename = m2?.groups.filename || entry.name;
95
+ const type = (m2?.groups.ext || "").toLowerCase();
96
+ if (type && !options.encrypted) oops("unexpected", type, "file in non-encrypted log");
97
+ if (type === "key") {
98
+ decryptionKey = crypto2.privateDecrypt({
99
+ key: privateKey,
100
+ padding: crypto2.constants.RSA_PKCS1_OAEP_PADDING,
101
+ oaepHash: "sha256"
102
+ }, await zipfile.entryData(entry.name));
103
+ } else {
104
+ const key = filename.toLowerCase();
105
+ const f = fileEntries[key] = fileEntries[key] || { filename };
106
+ f[type === "iv" ? "iv" : "contents"] = entry.name;
107
+ if (type) f.encrypted = true;
108
+ }
109
+ }
110
+ if (options.encrypted && !decryptionKey) oops("no key file found");
111
+ for (const entry of Object.values(fileEntries)) {
112
+ if (!entry.contents) oops("no contents for", entry.filename);
113
+ if (entry.encrypted && !entry.iv) oops("no iv for", entry.filename);
114
+ const data = await zipfile.entryData(entry.contents);
115
+ const target = path.join("logs", entry.filename);
116
+ if (entry.iv) {
117
+ const iv = await zipfile.entryData(entry.iv);
118
+ const tag = data.slice(-16);
119
+ const ciphertext = data.slice(0, -16);
120
+ const decipher = crypto2.createDecipheriv("aes-256-gcm", decryptionKey, iv);
121
+ decipher.setAuthTag(tag);
122
+ const decrypted = Buffer.concat([decipher.update(ciphertext), decipher.final()]);
123
+ fs.writeFileSync(target, decrypted);
124
+ } else {
125
+ fs.writeFileSync(target, data);
126
+ }
127
+ }
128
+ } finally {
129
+ if (fs.existsSync(options.zip)) fs.unlinkSync(options.zip);
130
+ }
131
+ }
132
+ main().catch((err) => {
133
+ oops(err.message);
134
+ });
@@ -0,0 +1,99 @@
1
+ #!/usr/bin/env node
2
+
3
+ // bin/keypair.ts
4
+ import { Command } from "commander";
5
+ import crypto2 from "crypto";
6
+ import { stat, writeFile } from "fs/promises";
7
+ import { resolve } from "path";
8
+ import prompts from "prompts";
9
+
10
+ // bin/crypto.ts
11
+ import crypto from "crypto";
12
+ function encrypt(plaintext, passphrase) {
13
+ const salt = crypto.randomBytes(16);
14
+ const iterations = 1e5;
15
+ const keyLength = 32;
16
+ const algorithm = "aes-256-gcm";
17
+ const key = crypto.pbkdf2Sync(passphrase, salt, iterations, keyLength, "sha256");
18
+ const iv = crypto.randomBytes(12);
19
+ const cipher = crypto.createCipheriv(algorithm, key, iv);
20
+ let ciphertext = cipher.update(plaintext, "utf8", "base64");
21
+ ciphertext += cipher.final("base64");
22
+ const tag = cipher.getAuthTag();
23
+ return {
24
+ ciphertext,
25
+ iv: iv.toString("base64"),
26
+ tag: tag.toString("base64"),
27
+ salt: salt.toString("base64"),
28
+ iterations,
29
+ keyLength,
30
+ algorithm
31
+ };
32
+ }
33
+
34
+ // bin/keypair.ts
35
+ import { config as dotenvConfig } from "dotenv";
36
+ dotenvConfig({ quiet: true, override: true });
37
+ var program = new Command();
38
+ program.description("A script to generate and store an RSA key pair in an encrypted file.").option("-p, --public <path>", "Path for the public key .pem file", "public.pem").option("--private <path>", "Path for the encrypted private key .pem.json file", "private.pem.json").option("-r, --replace", "Replace existing files", false).parse(process.argv);
39
+ var options = program.opts();
40
+ async function main() {
41
+ try {
42
+ const publicKeyPath = resolve(options.public);
43
+ const encryptedKeyPath = resolve(options.private);
44
+ if (!publicKeyPath.endsWith(".pem")) {
45
+ console.error("Public key file must have a .pem extension.");
46
+ process.exit(1);
47
+ }
48
+ if (!encryptedKeyPath.endsWith(".pem.json")) {
49
+ console.error("Encrypted key file must have a .pem.json extension.");
50
+ process.exit(1);
51
+ }
52
+ const fileExists = async (path) => {
53
+ try {
54
+ await stat(path);
55
+ return true;
56
+ } catch (e) {
57
+ if (e.code === "ENOENT") {
58
+ return false;
59
+ }
60
+ throw e;
61
+ }
62
+ };
63
+ if (await fileExists(publicKeyPath) && !options.replace) {
64
+ console.error(`Will not overwrite existing public key file: ${publicKeyPath}`);
65
+ process.exit(1);
66
+ }
67
+ if (await fileExists(encryptedKeyPath) && !options.replace) {
68
+ console.error(`Will not overwrite existing encrypted key file: ${encryptedKeyPath}`);
69
+ process.exit(1);
70
+ }
71
+ const { privateKey, publicKey } = crypto2.generateKeyPairSync("rsa", {
72
+ modulusLength: 2048,
73
+ publicKeyEncoding: {
74
+ type: "spki",
75
+ format: "pem"
76
+ },
77
+ privateKeyEncoding: {
78
+ type: "pkcs8",
79
+ format: "pem"
80
+ }
81
+ });
82
+ const { passphrase } = await prompts({
83
+ type: "password",
84
+ name: "passphrase",
85
+ message: "Enter a passphrase to encrypt your private key:"
86
+ });
87
+ if (!passphrase) {
88
+ console.error("Passphrase is required for encryption.");
89
+ process.exit(1);
90
+ }
91
+ await writeFile(encryptedKeyPath, JSON.stringify(encrypt(privateKey, passphrase), null, 2));
92
+ console.log(`Encrypted private key saved to: ${encryptedKeyPath}`);
93
+ await writeFile(publicKeyPath, publicKey);
94
+ console.log(`Public key saved to: ${publicKeyPath}`);
95
+ } catch (error) {
96
+ throw error;
97
+ }
98
+ }
99
+ main();
package/bin/link.mjs ADDED
@@ -0,0 +1,32 @@
1
+ #!/usr/bin/env node
2
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
3
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
4
+ }) : x)(function(x) {
5
+ if (typeof require !== "undefined") return require.apply(this, arguments);
6
+ throw Error('Dynamic require of "' + x + '" is not supported');
7
+ });
8
+
9
+ // bin/link.ts
10
+ import * as fs from "fs";
11
+ import * as path from "path";
12
+
13
+ // root.ts
14
+ var root_default = process.cwd();
15
+
16
+ // bin/link.ts
17
+ var pkg = { ...__require(path.join(root_default, "package.json")) };
18
+ if (!pkg.id) pkg.id = `${pkg.name.replace(/^zotero-/, "")}@${pkg.author.email.replace(/.*@/, "")}`.toLowerCase();
19
+ if (pkg.xpi) Object.assign(pkg, pkg.xpi);
20
+ var build = path.join(root_default, "build");
21
+ var zotero = process.argv[2];
22
+ if (!zotero) {
23
+ console.log("No directory specified");
24
+ process.exit(1);
25
+ }
26
+ var extensions = path.join(zotero, "extensions");
27
+ if (!fs.existsSync(extensions)) {
28
+ console.log(`${extensions} does not exist`);
29
+ process.exit(1);
30
+ }
31
+ var extension = path.join(extensions, pkg.id);
32
+ fs.writeFileSync(extension, build);