From e0eb853ce0ef1cab65434e38134082b93ba0b741 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Th=C3=A9riault?= Date: Sat, 20 Apr 2019 13:23:45 -0400 Subject: [PATCH 01/22] Added PGP signing of uploads --- .gitignore | 3 +- package.json | 4 +- src/server/v1/modules/ModService.ts | 35 +++++++++++++++ src/utils/pgpKeygen.js | 70 +++++++++++++++++++++++++++++ 4 files changed, 110 insertions(+), 2 deletions(-) create mode 100644 src/utils/pgpKeygen.js diff --git a/.gitignore b/.gitignore index 6de704e..aca2d31 100755 --- a/.gitignore +++ b/.gitignore @@ -26,4 +26,5 @@ yarn.lock tunnel.sh uploads/* -images/* \ No newline at end of file +images/* +keys/* diff --git a/package.json b/package.json index c2c87d1..99f9fb7 100755 --- a/package.json +++ b/package.json @@ -15,7 +15,8 @@ "debug": "babel-node src/app.ts --extensions \".ts\" --inspect-brk=9889", "build:dev": "babel-node src/app.ts --extensions \".ts\"", "build:prod": "cross-env NODE_ENV=production babel src -d dist/ --extensions \".ts\" && webpack --env.production --config ./webpack.config", - "ts-check": "tsc" + "ts-check": "tsc", + "keygen": "node src/utils/pgpKeygen.js" }, "lint-staged": { "src/**/**.{ts,tsx}": [ @@ -75,6 +76,7 @@ "node-sass": "^4.7.2", "node-stream-zip": "^1.8.0", "nodemon": "^1.17.2", + "openpgp": "^4.4.10", "postcss-flexbugs-fixes": "3.2.0", "postcss-loader": "^2.1.3", "prettier": "^1.16.4", diff --git a/src/server/v1/modules/ModService.ts b/src/server/v1/modules/ModService.ts index b3ffbde..7452ade 100644 --- a/src/server/v1/modules/ModService.ts +++ b/src/server/v1/modules/ModService.ts @@ -8,6 +8,8 @@ import path from "path"; const StreamZip = require("node-stream-zip"); import AuditLogService from "./AuditLogService"; import DiscordManager from "../../modules/DiscordManager"; +const openpgp = require("openpgp"); +let privkey; export default class ModService { constructor(protected ctx: IContext) { this.dao = new ModDAO(this.ctx.db); @@ -181,6 +183,22 @@ export default class ModService { }; const { _id } = (await this.insert(mod)) as IDbMod & { _id: Id }; mod._id = toId(_id); + try { + privkey = await new Promise((res, rej) => { + fs.readFile(path.join(process.cwd(), "/keys/privkey.asc"), "utf-8", (err, data) => { + if (err) { + rej(err); + } + openpgp.key.readArmored(data).then(output => { + res(output.keys[0]); + }); + }); + }); + await privkey.decrypt(process.env.PASSPHRASE); + } catch (err) { + console.error("ModService.create", "KEY Read", err); + throw new ServerError("mod.upload.key.read"); + } let index = 0; for (const file of files) { const type = files.length === 1 ? "universal" : index === 0 ? "steam" : "oculus"; @@ -188,6 +206,7 @@ export default class ModService { const fileName = `${name}-${version}.zip`; const fullPath = path.join(process.cwd(), filePath); const fullFile = path.join(fullPath, fileName); + const fullSigFile = `${fullFile}.sig`; try { await new Promise((res, rej) => { const mkdir = (dirPath: string, root = "") => { @@ -245,6 +264,22 @@ export default class ModService { console.error("ModService.create zip.read", error); throw new ServerError("mod.upload.zip.corrupt"); } + try { + await new Promise((res, rej) => { + const signOptions = { + message: openpgp.message.fromBinary(fs.createReadStream(fullFile)), + privateKeys: [privkey], + streaming: "node" + }; + openpgp.sign(signOptions).then(signed => { + signed.data.pipe(fs.createWriteStream(fullSigFile)); + res(); + }); + }); + } catch (err) { + console.error("ModService.create", "SIG Create", err); + throw new ServerError("mod.upload.sig.create"); + } index++; } if (mod.downloads && !mod.downloads.length) { diff --git a/src/utils/pgpKeygen.js b/src/utils/pgpKeygen.js new file mode 100644 index 0000000..fd3c411 --- /dev/null +++ b/src/utils/pgpKeygen.js @@ -0,0 +1,70 @@ +const fs = require("fs"); +const path = require("path"); +const openpgp = require("openpgp"); +const rl = require("readline").createInterface({ + input: process.stdin, + output: process.stdout +}); +let userId = {}; +let numBits; +let passphrase; +let dir; +let key; + +function ask (question) { + return new Promise((res, rej) => { + rl.question(question, answer => { + res(answer); + }); + }); +} + +function writeKey (filePath, fileKey, type) { + return new Promise((res, rej) => { + fs.writeFile(filePath, fileKey, err => { + if (err) { + rej(err); + } + console.log(` Done writing ${type} to ${filePath}`); + res(); + }); + }); +} + +console.log("======== PGP Key Pair Generator ========"); +console.log("- Awaiting info..."); +ask(" Name [Beat Saber Modding Group] : ").then(answer => { + userId.name = answer || "Beat Saber Modding Group"; + return ask(" Email [bsmg@beatmods.com] : "); +}).then(answer => { + userId.email = answer || "bsmg@beatmods.com"; + return ask(" Passphrase [q1w2e3r4t5y6] : "); +}).then(answer => { + passphrase = answer || "q1w2e3r4t5y6"; + return ask(" 4096 bits ? (More secure, slower) [yes] : "); +}).then(answer => { + numBits = (answer.toLowerCase() === "n" || answer.toLowerCase() === "no") ? 2048 : 4096; + return ask(" Output directory [./keys] : "); +}).then(answer => { + dir = answer || path.join(__dirname, 'keys'); + rl.close(); + const genOptions = { + userIds: [userId], + numBits: numBits, + passphrase: passphrase + }; + console.log(`- Generating ${numBits} bits key pair with user ID ${userId.name} <${userId.email}>...`); + return openpgp.generateKey(genOptions); +}).then(generated => { + key = generated; + console.log("- Writing keys..."); + return writeKey(path.join(dir, "privkey.asc"), key.privateKeyArmored, "private key"); +}).then(() => { + return writeKey(path.join(dir, "pubkey.asc"), key.publicKeyArmored, "public key"); +}).then(() => { + return writeKey(path.join(dir, "revcert.asc"), key.revocationCertificate, "revocation certificate"); +}).then(() => { + console.log("========================================"); +}).catch(err => { + console.error(err); +}); From f99345fdd98b414f4373511cd87febab6927dbab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Th=C3=A9riault?= Date: Sat, 20 Apr 2019 13:32:08 -0400 Subject: [PATCH 02/22] Fixed spacing in new footer --- src/client/app/layouts/default/footer.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/client/app/layouts/default/footer.tsx b/src/client/app/layouts/default/footer.tsx index 40f59af..31e08b1 100644 --- a/src/client/app/layouts/default/footer.tsx +++ b/src/client/app/layouts/default/footer.tsx @@ -7,7 +7,7 @@ export default class DefaultFooter extends React.Component<{}, {}> {
vanZeben and - contributors + contributors © 2019
From 668da58c8c4f76b5ba0ee8322451e9976b677a34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Th=C3=A9riault?= Date: Sat, 20 Apr 2019 13:23:45 -0400 Subject: [PATCH 03/22] Added PGP signing of uploads --- .gitignore | 3 +- package.json | 4 +- src/server/v1/modules/ModService.ts | 35 +++++++++++++++ src/utils/pgpKeygen.js | 70 +++++++++++++++++++++++++++++ 4 files changed, 110 insertions(+), 2 deletions(-) create mode 100644 src/utils/pgpKeygen.js diff --git a/.gitignore b/.gitignore index 6de704e..aca2d31 100755 --- a/.gitignore +++ b/.gitignore @@ -26,4 +26,5 @@ yarn.lock tunnel.sh uploads/* -images/* \ No newline at end of file +images/* +keys/* diff --git a/package.json b/package.json index c2c87d1..99f9fb7 100755 --- a/package.json +++ b/package.json @@ -15,7 +15,8 @@ "debug": "babel-node src/app.ts --extensions \".ts\" --inspect-brk=9889", "build:dev": "babel-node src/app.ts --extensions \".ts\"", "build:prod": "cross-env NODE_ENV=production babel src -d dist/ --extensions \".ts\" && webpack --env.production --config ./webpack.config", - "ts-check": "tsc" + "ts-check": "tsc", + "keygen": "node src/utils/pgpKeygen.js" }, "lint-staged": { "src/**/**.{ts,tsx}": [ @@ -75,6 +76,7 @@ "node-sass": "^4.7.2", "node-stream-zip": "^1.8.0", "nodemon": "^1.17.2", + "openpgp": "^4.4.10", "postcss-flexbugs-fixes": "3.2.0", "postcss-loader": "^2.1.3", "prettier": "^1.16.4", diff --git a/src/server/v1/modules/ModService.ts b/src/server/v1/modules/ModService.ts index 181c6ad..722a8df 100644 --- a/src/server/v1/modules/ModService.ts +++ b/src/server/v1/modules/ModService.ts @@ -8,6 +8,8 @@ import path from "path"; const StreamZip = require("node-stream-zip"); import AuditLogService from "./AuditLogService"; import DiscordManager from "../../modules/DiscordManager"; +const openpgp = require("openpgp"); +let privkey; export default class ModService { constructor(protected ctx: IContext) { this.dao = new ModDAO(this.ctx.db); @@ -181,6 +183,22 @@ export default class ModService { }; const { _id } = (await this.insert(mod)) as IDbMod & { _id: Id }; mod._id = toId(_id); + try { + privkey = await new Promise((res, rej) => { + fs.readFile(path.join(process.cwd(), "/keys/privkey.asc"), "utf-8", (err, data) => { + if (err) { + rej(err); + } + openpgp.key.readArmored(data).then(output => { + res(output.keys[0]); + }); + }); + }); + await privkey.decrypt(process.env.PASSPHRASE); + } catch (err) { + console.error("ModService.create", "KEY Read", err); + throw new ServerError("mod.upload.key.read"); + } let index = 0; for (const file of files) { const type = files.length === 1 ? "universal" : index === 0 ? "steam" : "oculus"; @@ -188,6 +206,7 @@ export default class ModService { const fileName = `${name}-${version}.zip`; const fullPath = path.join(process.cwd(), filePath); const fullFile = path.join(fullPath, fileName); + const fullSigFile = `${fullFile}.sig`; try { await new Promise((res, rej) => { const mkdir = (dirPath: string, root = "") => { @@ -245,6 +264,22 @@ export default class ModService { console.error("ModService.create zip.read", error); throw new ServerError("mod.upload.zip.corrupt"); } + try { + await new Promise((res, rej) => { + const signOptions = { + message: openpgp.message.fromBinary(fs.createReadStream(fullFile)), + privateKeys: [privkey], + streaming: "node" + }; + openpgp.sign(signOptions).then(signed => { + signed.data.pipe(fs.createWriteStream(fullSigFile)); + res(); + }); + }); + } catch (err) { + console.error("ModService.create", "SIG Create", err); + throw new ServerError("mod.upload.sig.create"); + } index++; } if (mod.downloads && !mod.downloads.length) { diff --git a/src/utils/pgpKeygen.js b/src/utils/pgpKeygen.js new file mode 100644 index 0000000..fd3c411 --- /dev/null +++ b/src/utils/pgpKeygen.js @@ -0,0 +1,70 @@ +const fs = require("fs"); +const path = require("path"); +const openpgp = require("openpgp"); +const rl = require("readline").createInterface({ + input: process.stdin, + output: process.stdout +}); +let userId = {}; +let numBits; +let passphrase; +let dir; +let key; + +function ask (question) { + return new Promise((res, rej) => { + rl.question(question, answer => { + res(answer); + }); + }); +} + +function writeKey (filePath, fileKey, type) { + return new Promise((res, rej) => { + fs.writeFile(filePath, fileKey, err => { + if (err) { + rej(err); + } + console.log(` Done writing ${type} to ${filePath}`); + res(); + }); + }); +} + +console.log("======== PGP Key Pair Generator ========"); +console.log("- Awaiting info..."); +ask(" Name [Beat Saber Modding Group] : ").then(answer => { + userId.name = answer || "Beat Saber Modding Group"; + return ask(" Email [bsmg@beatmods.com] : "); +}).then(answer => { + userId.email = answer || "bsmg@beatmods.com"; + return ask(" Passphrase [q1w2e3r4t5y6] : "); +}).then(answer => { + passphrase = answer || "q1w2e3r4t5y6"; + return ask(" 4096 bits ? (More secure, slower) [yes] : "); +}).then(answer => { + numBits = (answer.toLowerCase() === "n" || answer.toLowerCase() === "no") ? 2048 : 4096; + return ask(" Output directory [./keys] : "); +}).then(answer => { + dir = answer || path.join(__dirname, 'keys'); + rl.close(); + const genOptions = { + userIds: [userId], + numBits: numBits, + passphrase: passphrase + }; + console.log(`- Generating ${numBits} bits key pair with user ID ${userId.name} <${userId.email}>...`); + return openpgp.generateKey(genOptions); +}).then(generated => { + key = generated; + console.log("- Writing keys..."); + return writeKey(path.join(dir, "privkey.asc"), key.privateKeyArmored, "private key"); +}).then(() => { + return writeKey(path.join(dir, "pubkey.asc"), key.publicKeyArmored, "public key"); +}).then(() => { + return writeKey(path.join(dir, "revcert.asc"), key.revocationCertificate, "revocation certificate"); +}).then(() => { + console.log("========================================"); +}).catch(err => { + console.error(err); +}); From 62d651578c2002bd301406b264ebbd1044e699e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Th=C3=A9riault?= Date: Sat, 20 Apr 2019 13:32:08 -0400 Subject: [PATCH 04/22] Fixed spacing in new footer --- src/client/app/layouts/default/footer.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/client/app/layouts/default/footer.tsx b/src/client/app/layouts/default/footer.tsx index 40f59af..31e08b1 100644 --- a/src/client/app/layouts/default/footer.tsx +++ b/src/client/app/layouts/default/footer.tsx @@ -7,7 +7,7 @@ export default class DefaultFooter extends React.Component<{}, {}> {
vanZeben and - contributors + contributors © 2019
From 198c36e937f3a0ae38034bcecda038b5ba3128d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Th=C3=A9riault?= Date: Fri, 26 Apr 2019 20:08:27 -0400 Subject: [PATCH 05/22] Switched to detached signatures --- src/server/v1/modules/ModService.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/server/v1/modules/ModService.ts b/src/server/v1/modules/ModService.ts index 722a8df..d376d93 100644 --- a/src/server/v1/modules/ModService.ts +++ b/src/server/v1/modules/ModService.ts @@ -269,10 +269,12 @@ export default class ModService { const signOptions = { message: openpgp.message.fromBinary(fs.createReadStream(fullFile)), privateKeys: [privkey], + detached: true, streaming: "node" }; openpgp.sign(signOptions).then(signed => { - signed.data.pipe(fs.createWriteStream(fullSigFile)); + signed.signature.pipe(fs.createWriteStream(fullSigFile)); + openpgp.stream.readToEnd(signOptions.message.armor()).catch(err => rej(err)); res(); }); }); From 5df5ff087aa6677c41e80cadeaedbe5887c202a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Th=C3=A9riault?= Date: Fri, 26 Apr 2019 22:14:46 -0400 Subject: [PATCH 06/22] Sign API responses --- src/server/v1/index.ts | 10 ++++- src/server/v1/modules/ModService.ts | 61 +++++++++++++++++++++-------- src/server/v1/pgpMod.ts | 16 ++++++++ 3 files changed, 69 insertions(+), 18 deletions(-) create mode 100644 src/server/v1/pgpMod.ts diff --git a/src/server/v1/index.ts b/src/server/v1/index.ts index 15cdf7a..6c22f07 100644 --- a/src/server/v1/index.ts +++ b/src/server/v1/index.ts @@ -6,6 +6,7 @@ import { checkAuthorization } from "../modules/AuthManager"; import config from "../config"; import userRouter from "./user"; import modRouter from "./mod"; +import pgpModRouter from "./pgpMod"; import { catchErrors } from "../modules/Utils"; const authTokenService = new AuthTokenService({ @@ -24,10 +25,17 @@ router.post("/signOut", catchErrors(authSessionManager.signOff())); router.post("/register", catchErrors(authSessionManager.register())); router.use( checkAuthorization().unless({ - path: [{ url: "/api/v1/mod", methods: ["GET"] }, { url: "/api/v1/user", methods: ["GET"] }, "/api/v1/user/current", "/api/v1/user/create"] + path: [ + { url: "/api/v1/mod", methods: ["GET"] }, + { url: "/api/v1/pgpmod", methods: ["GET"] }, + { url: "/api/v1/user", methods: ["GET"] }, + "/api/v1/user/current", + "/api/v1/user/create" + ] }) ); router.use("/mod", modRouter); +router.use("/pgpmod", pgpModRouter); router.use("/user", userRouter); export default router; diff --git a/src/server/v1/modules/ModService.ts b/src/server/v1/modules/ModService.ts index d376d93..b206248 100644 --- a/src/server/v1/modules/ModService.ts +++ b/src/server/v1/modules/ModService.ts @@ -50,7 +50,7 @@ export default class ModService { $options: "i" }; } - public async list(params?: any) { + public async list(params?: any, pgp: boolean = false) { const query: dynamic = {}; let sort: dynamic | undefined; if (params && Object.keys(params).length) { @@ -89,7 +89,27 @@ export default class ModService { } } } - return mods.map(mod => mod as IDbMod); + + const modMap = mods.map(mod => mod as IDbMod); + if (!pgp) { + return modMap; + } else { + if (privkey === undefined) { + privkey = await readPrivkey(); + } + return await new Promise((res, rej) => { + const signOptions = { + message: openpgp.cleartext.fromText(JSON.stringify(modMap)), + privateKeys: [privkey] + }; + openpgp + .sign(signOptions) + .then(signed => { + res(signed.data); + }) + .catch(err => rej(err)); + }); + } } public async update(mod: IDbMod, isInsert = false) { @@ -183,21 +203,13 @@ export default class ModService { }; const { _id } = (await this.insert(mod)) as IDbMod & { _id: Id }; mod._id = toId(_id); - try { - privkey = await new Promise((res, rej) => { - fs.readFile(path.join(process.cwd(), "/keys/privkey.asc"), "utf-8", (err, data) => { - if (err) { - rej(err); - } - openpgp.key.readArmored(data).then(output => { - res(output.keys[0]); - }); - }); - }); - await privkey.decrypt(process.env.PASSPHRASE); - } catch (err) { - console.error("ModService.create", "KEY Read", err); - throw new ServerError("mod.upload.key.read"); + if (privkey === undefined) { + try { + privkey = await readPrivkey(); + } catch (err) { + console.error("ModService.create", "KEY Read", err); + throw new ServerError("mod.upload.key.read"); + } } let index = 0; for (const file of files) { @@ -294,3 +306,18 @@ export default class ModService { return true; } } + +async function readPrivkey() { + const pk: any = await new Promise((res, rej) => { + fs.readFile(path.join(process.cwd(), "/keys/privkey.asc"), "utf-8", (err, data) => { + if (err) { + rej(err); + } + openpgp.key.readArmored(data).then(output => { + res(output.keys[0]); + }); + }); + }); + await pk.decrypt(process.env.PASSPHRASE); + return pk; +} diff --git a/src/server/v1/pgpMod.ts b/src/server/v1/pgpMod.ts new file mode 100644 index 0000000..4f40123 --- /dev/null +++ b/src/server/v1/pgpMod.ts @@ -0,0 +1,16 @@ +import * as express from "express"; + +import { catchErrors } from "../modules/Utils"; +import ModService from "./modules/ModService"; + +const router = express.Router(); + +router.get( + "/", + catchErrors(async (req, res, next) => { + const modService = new ModService(req.ctx); + return res.send(await modService.list(req.query, true)); + }) +); + +export default router; From 78f9388b2dc038d536ee2a3597ca6a32f155facc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Th=C3=A9riault?= Date: Fri, 26 Apr 2019 23:04:13 -0400 Subject: [PATCH 07/22] Keygen script improvements --- src/utils/pgpKeygen.js | 56 +++++++++++++++++------------------------- 1 file changed, 22 insertions(+), 34 deletions(-) diff --git a/src/utils/pgpKeygen.js b/src/utils/pgpKeygen.js index fd3c411..67886ea 100644 --- a/src/utils/pgpKeygen.js +++ b/src/utils/pgpKeygen.js @@ -5,14 +5,11 @@ const rl = require("readline").createInterface({ input: process.stdin, output: process.stdout }); -let userId = {}; -let numBits; -let passphrase; -let dir; -let key; + +gen().catch(err => {throw err;}); function ask (question) { - return new Promise((res, rej) => { + return new Promise(res => { rl.question(question, answer => { res(answer); }); @@ -31,40 +28,31 @@ function writeKey (filePath, fileKey, type) { }); } -console.log("======== PGP Key Pair Generator ========"); -console.log("- Awaiting info..."); -ask(" Name [Beat Saber Modding Group] : ").then(answer => { - userId.name = answer || "Beat Saber Modding Group"; - return ask(" Email [bsmg@beatmods.com] : "); -}).then(answer => { - userId.email = answer || "bsmg@beatmods.com"; - return ask(" Passphrase [q1w2e3r4t5y6] : "); -}).then(answer => { - passphrase = answer || "q1w2e3r4t5y6"; - return ask(" 4096 bits ? (More secure, slower) [yes] : "); -}).then(answer => { - numBits = (answer.toLowerCase() === "n" || answer.toLowerCase() === "no") ? 2048 : 4096; - return ask(" Output directory [./keys] : "); -}).then(answer => { - dir = answer || path.join(__dirname, 'keys'); +async function gen () { + console.log("======== PGP Key Pair Generator ========"); + + console.log("- Awaiting info..."); + let userId = {}; + userId.name = await ask(" Name [Beat Saber Modding Group] : ") || "Beat Saber Modding Group"; + userId.email = await ask(" Email [bsmg@beatmods.com] : ") || "bsmg@beatmods.com"; + const passphrase = await ask(" Passphrase [q1w2e3r4t5y6] : ") || "q1w2e3r4t5y6"; + let numBits = await ask(" 4096 bits ? (More secure, slower) [yes] : "); + numBits = numBits && (numBits.toLowerCase() === "n" || numBits.toLowerCase() === "no") ? 2048 : 4096; + const dir = await ask(" Output directory [./keys] : ") || path.join(process.cwd(), "keys"); rl.close(); + const genOptions = { userIds: [userId], numBits: numBits, passphrase: passphrase }; console.log(`- Generating ${numBits} bits key pair with user ID ${userId.name} <${userId.email}>...`); - return openpgp.generateKey(genOptions); -}).then(generated => { - key = generated; + const key = await openpgp.generateKey(genOptions); + console.log("- Writing keys..."); - return writeKey(path.join(dir, "privkey.asc"), key.privateKeyArmored, "private key"); -}).then(() => { - return writeKey(path.join(dir, "pubkey.asc"), key.publicKeyArmored, "public key"); -}).then(() => { - return writeKey(path.join(dir, "revcert.asc"), key.revocationCertificate, "revocation certificate"); -}).then(() => { + await writeKey(path.join(dir, "privkey.asc"), key.privateKeyArmored, "private key"); + await writeKey(path.join(dir, "pubkey.asc"), key.publicKeyArmored, "public key"); + await writeKey(path.join(dir, "revcert.asc"), key.revocationCertificate, "revocation certificate"); + console.log("========================================"); -}).catch(err => { - console.error(err); -}); +} From 91821044aa68ff06f7214d03307de6620221d8ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Th=C3=A9riault?= Date: Fri, 26 Apr 2019 23:23:20 -0400 Subject: [PATCH 08/22] Fixed response not being sent as plain text --- src/server/v1/pgpMod.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/server/v1/pgpMod.ts b/src/server/v1/pgpMod.ts index 4f40123..f82b3b8 100644 --- a/src/server/v1/pgpMod.ts +++ b/src/server/v1/pgpMod.ts @@ -9,6 +9,7 @@ router.get( "/", catchErrors(async (req, res, next) => { const modService = new ModService(req.ctx); + res.set("Content-Type", "text/plain"); return res.send(await modService.list(req.query, true)); }) ); From 2a22b1d0762e5a11a167d946e81253b36530b406 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Th=C3=A9riault?= Date: Fri, 26 Apr 2019 23:44:03 -0400 Subject: [PATCH 09/22] Break lines in JSON cleartext Some PGP clients can't treat lines longer than 20000 characters --- src/server/v1/modules/ModService.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/server/v1/modules/ModService.ts b/src/server/v1/modules/ModService.ts index b206248..fae0bdd 100644 --- a/src/server/v1/modules/ModService.ts +++ b/src/server/v1/modules/ModService.ts @@ -99,7 +99,7 @@ export default class ModService { } return await new Promise((res, rej) => { const signOptions = { - message: openpgp.cleartext.fromText(JSON.stringify(modMap)), + message: openpgp.cleartext.fromText(JSON.stringify(modMap, null, 2)), privateKeys: [privkey] }; openpgp From 1a8d164babd521fdeb985fc03f73a56710140a4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Th=C3=A9riault?= Date: Sat, 27 Apr 2019 12:20:22 -0400 Subject: [PATCH 10/22] Replaced pgpmod router with query parameter --- src/server/v1/index.ts | 2 -- src/server/v1/mod.ts | 8 +++++++- src/server/v1/pgpMod.ts | 17 ----------------- 3 files changed, 7 insertions(+), 20 deletions(-) delete mode 100644 src/server/v1/pgpMod.ts diff --git a/src/server/v1/index.ts b/src/server/v1/index.ts index 6c22f07..02dc9d6 100644 --- a/src/server/v1/index.ts +++ b/src/server/v1/index.ts @@ -6,7 +6,6 @@ import { checkAuthorization } from "../modules/AuthManager"; import config from "../config"; import userRouter from "./user"; import modRouter from "./mod"; -import pgpModRouter from "./pgpMod"; import { catchErrors } from "../modules/Utils"; const authTokenService = new AuthTokenService({ @@ -35,7 +34,6 @@ router.use( }) ); router.use("/mod", modRouter); -router.use("/pgpmod", pgpModRouter); router.use("/user", userRouter); export default router; diff --git a/src/server/v1/mod.ts b/src/server/v1/mod.ts index 615f0af..f3f14d0 100644 --- a/src/server/v1/mod.ts +++ b/src/server/v1/mod.ts @@ -4,6 +4,7 @@ import { catchErrors } from "../modules/Utils"; import ModService from "./modules/ModService"; import multer from "multer"; + const storage = multer.memoryStorage(); const upload = multer({ limits: { fileSize: 25 * 1024 * 1024 }, storage }); @@ -13,7 +14,12 @@ router.get( "/", catchErrors(async (req, res, next) => { const modService = new ModService(req.ctx); - return res.send(await modService.list(req.query)); + let pgp = false; + if (req.query && req.query.hasOwnProperty("pgp")) { + res.set("Content-Type", "text/plain"); + pgp = true; + } + return res.send(await modService.list(req.query, pgp)); }) ); diff --git a/src/server/v1/pgpMod.ts b/src/server/v1/pgpMod.ts deleted file mode 100644 index f82b3b8..0000000 --- a/src/server/v1/pgpMod.ts +++ /dev/null @@ -1,17 +0,0 @@ -import * as express from "express"; - -import { catchErrors } from "../modules/Utils"; -import ModService from "./modules/ModService"; - -const router = express.Router(); - -router.get( - "/", - catchErrors(async (req, res, next) => { - const modService = new ModService(req.ctx); - res.set("Content-Type", "text/plain"); - return res.send(await modService.list(req.query, true)); - }) -); - -export default router; From 73072d02c17d86ff0027955b9860d7a52ea91d08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Th=C3=A9riault?= Date: Sat, 27 Apr 2019 12:27:37 -0400 Subject: [PATCH 11/22] Removed unnecessary verification --- src/server/v1/mod.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/server/v1/mod.ts b/src/server/v1/mod.ts index f3f14d0..9a713dd 100644 --- a/src/server/v1/mod.ts +++ b/src/server/v1/mod.ts @@ -15,7 +15,7 @@ router.get( catchErrors(async (req, res, next) => { const modService = new ModService(req.ctx); let pgp = false; - if (req.query && req.query.hasOwnProperty("pgp")) { + if (req.query.hasOwnProperty("pgp")) { res.set("Content-Type", "text/plain"); pgp = true; } From e2cd86c348c4b04371765c0a823dc3db4c3ae218 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Th=C3=A9riault?= Date: Sat, 20 Apr 2019 13:23:45 -0400 Subject: [PATCH 12/22] Added PGP signing of uploads --- .gitignore | 3 +- package.json | 6 ++- src/server/v1/modules/ModService.ts | 35 +++++++++++++++ src/utils/pgpKeygen.js | 70 +++++++++++++++++++++++++++++ 4 files changed, 111 insertions(+), 3 deletions(-) create mode 100644 src/utils/pgpKeygen.js diff --git a/.gitignore b/.gitignore index 6de704e..aca2d31 100755 --- a/.gitignore +++ b/.gitignore @@ -26,4 +26,5 @@ yarn.lock tunnel.sh uploads/* -images/* \ No newline at end of file +images/* +keys/* diff --git a/package.json b/package.json index bc89637..fd6fa47 100755 --- a/package.json +++ b/package.json @@ -15,7 +15,8 @@ "debug": "babel-node src/app.ts --extensions \".ts\" --inspect-brk=9889", "build:dev": "babel-node src/app.ts --extensions \".ts\"", "build:prod": "cross-env NODE_ENV=production babel src -d dist/ --extensions \".ts\" && webpack --env.production --config ./src/config/webpack.prod", - "ts-check": "tsc" + "ts-check": "tsc", + "keygen": "node src/utils/pgpKeygen.js" }, "lint-staged": { "src/**/**.{ts,tsx}": [ @@ -75,6 +76,7 @@ "node-sass": "^4.7.2", "node-stream-zip": "^1.8.0", "nodemon": "^1.17.2", + "openpgp": "^4.4.10", "postcss-flexbugs-fixes": "3.2.0", "postcss-loader": "^2.1.3", "prettier": "^1.16.4", @@ -140,4 +142,4 @@ "pre-commit": "npm run ts-check && lint-staged" } } -} \ No newline at end of file +} diff --git a/src/server/v1/modules/ModService.ts b/src/server/v1/modules/ModService.ts index 181c6ad..722a8df 100644 --- a/src/server/v1/modules/ModService.ts +++ b/src/server/v1/modules/ModService.ts @@ -8,6 +8,8 @@ import path from "path"; const StreamZip = require("node-stream-zip"); import AuditLogService from "./AuditLogService"; import DiscordManager from "../../modules/DiscordManager"; +const openpgp = require("openpgp"); +let privkey; export default class ModService { constructor(protected ctx: IContext) { this.dao = new ModDAO(this.ctx.db); @@ -181,6 +183,22 @@ export default class ModService { }; const { _id } = (await this.insert(mod)) as IDbMod & { _id: Id }; mod._id = toId(_id); + try { + privkey = await new Promise((res, rej) => { + fs.readFile(path.join(process.cwd(), "/keys/privkey.asc"), "utf-8", (err, data) => { + if (err) { + rej(err); + } + openpgp.key.readArmored(data).then(output => { + res(output.keys[0]); + }); + }); + }); + await privkey.decrypt(process.env.PASSPHRASE); + } catch (err) { + console.error("ModService.create", "KEY Read", err); + throw new ServerError("mod.upload.key.read"); + } let index = 0; for (const file of files) { const type = files.length === 1 ? "universal" : index === 0 ? "steam" : "oculus"; @@ -188,6 +206,7 @@ export default class ModService { const fileName = `${name}-${version}.zip`; const fullPath = path.join(process.cwd(), filePath); const fullFile = path.join(fullPath, fileName); + const fullSigFile = `${fullFile}.sig`; try { await new Promise((res, rej) => { const mkdir = (dirPath: string, root = "") => { @@ -245,6 +264,22 @@ export default class ModService { console.error("ModService.create zip.read", error); throw new ServerError("mod.upload.zip.corrupt"); } + try { + await new Promise((res, rej) => { + const signOptions = { + message: openpgp.message.fromBinary(fs.createReadStream(fullFile)), + privateKeys: [privkey], + streaming: "node" + }; + openpgp.sign(signOptions).then(signed => { + signed.data.pipe(fs.createWriteStream(fullSigFile)); + res(); + }); + }); + } catch (err) { + console.error("ModService.create", "SIG Create", err); + throw new ServerError("mod.upload.sig.create"); + } index++; } if (mod.downloads && !mod.downloads.length) { diff --git a/src/utils/pgpKeygen.js b/src/utils/pgpKeygen.js new file mode 100644 index 0000000..fd3c411 --- /dev/null +++ b/src/utils/pgpKeygen.js @@ -0,0 +1,70 @@ +const fs = require("fs"); +const path = require("path"); +const openpgp = require("openpgp"); +const rl = require("readline").createInterface({ + input: process.stdin, + output: process.stdout +}); +let userId = {}; +let numBits; +let passphrase; +let dir; +let key; + +function ask (question) { + return new Promise((res, rej) => { + rl.question(question, answer => { + res(answer); + }); + }); +} + +function writeKey (filePath, fileKey, type) { + return new Promise((res, rej) => { + fs.writeFile(filePath, fileKey, err => { + if (err) { + rej(err); + } + console.log(` Done writing ${type} to ${filePath}`); + res(); + }); + }); +} + +console.log("======== PGP Key Pair Generator ========"); +console.log("- Awaiting info..."); +ask(" Name [Beat Saber Modding Group] : ").then(answer => { + userId.name = answer || "Beat Saber Modding Group"; + return ask(" Email [bsmg@beatmods.com] : "); +}).then(answer => { + userId.email = answer || "bsmg@beatmods.com"; + return ask(" Passphrase [q1w2e3r4t5y6] : "); +}).then(answer => { + passphrase = answer || "q1w2e3r4t5y6"; + return ask(" 4096 bits ? (More secure, slower) [yes] : "); +}).then(answer => { + numBits = (answer.toLowerCase() === "n" || answer.toLowerCase() === "no") ? 2048 : 4096; + return ask(" Output directory [./keys] : "); +}).then(answer => { + dir = answer || path.join(__dirname, 'keys'); + rl.close(); + const genOptions = { + userIds: [userId], + numBits: numBits, + passphrase: passphrase + }; + console.log(`- Generating ${numBits} bits key pair with user ID ${userId.name} <${userId.email}>...`); + return openpgp.generateKey(genOptions); +}).then(generated => { + key = generated; + console.log("- Writing keys..."); + return writeKey(path.join(dir, "privkey.asc"), key.privateKeyArmored, "private key"); +}).then(() => { + return writeKey(path.join(dir, "pubkey.asc"), key.publicKeyArmored, "public key"); +}).then(() => { + return writeKey(path.join(dir, "revcert.asc"), key.revocationCertificate, "revocation certificate"); +}).then(() => { + console.log("========================================"); +}).catch(err => { + console.error(err); +}); From 4c633a75e95e0383731fe8e74fccea5abdd80e9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Th=C3=A9riault?= Date: Sat, 20 Apr 2019 13:32:08 -0400 Subject: [PATCH 13/22] Fixed spacing in new footer --- src/client/app/layouts/default/footer.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/client/app/layouts/default/footer.tsx b/src/client/app/layouts/default/footer.tsx index 40f59af..31e08b1 100644 --- a/src/client/app/layouts/default/footer.tsx +++ b/src/client/app/layouts/default/footer.tsx @@ -7,7 +7,7 @@ export default class DefaultFooter extends React.Component<{}, {}> {
vanZeben and - contributors + contributors © 2019
From 29620783ffb24e916d99876dc1c58653f708130c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Th=C3=A9riault?= Date: Fri, 26 Apr 2019 20:08:27 -0400 Subject: [PATCH 14/22] Switched to detached signatures --- src/server/v1/modules/ModService.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/server/v1/modules/ModService.ts b/src/server/v1/modules/ModService.ts index 722a8df..d376d93 100644 --- a/src/server/v1/modules/ModService.ts +++ b/src/server/v1/modules/ModService.ts @@ -269,10 +269,12 @@ export default class ModService { const signOptions = { message: openpgp.message.fromBinary(fs.createReadStream(fullFile)), privateKeys: [privkey], + detached: true, streaming: "node" }; openpgp.sign(signOptions).then(signed => { - signed.data.pipe(fs.createWriteStream(fullSigFile)); + signed.signature.pipe(fs.createWriteStream(fullSigFile)); + openpgp.stream.readToEnd(signOptions.message.armor()).catch(err => rej(err)); res(); }); }); From 440337908894e0705142e816b7d727cec4c2a342 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Th=C3=A9riault?= Date: Fri, 26 Apr 2019 22:14:46 -0400 Subject: [PATCH 15/22] Sign API responses --- src/server/v1/index.ts | 10 ++++- src/server/v1/modules/ModService.ts | 61 +++++++++++++++++++++-------- src/server/v1/pgpMod.ts | 16 ++++++++ 3 files changed, 69 insertions(+), 18 deletions(-) create mode 100644 src/server/v1/pgpMod.ts diff --git a/src/server/v1/index.ts b/src/server/v1/index.ts index 15cdf7a..6c22f07 100644 --- a/src/server/v1/index.ts +++ b/src/server/v1/index.ts @@ -6,6 +6,7 @@ import { checkAuthorization } from "../modules/AuthManager"; import config from "../config"; import userRouter from "./user"; import modRouter from "./mod"; +import pgpModRouter from "./pgpMod"; import { catchErrors } from "../modules/Utils"; const authTokenService = new AuthTokenService({ @@ -24,10 +25,17 @@ router.post("/signOut", catchErrors(authSessionManager.signOff())); router.post("/register", catchErrors(authSessionManager.register())); router.use( checkAuthorization().unless({ - path: [{ url: "/api/v1/mod", methods: ["GET"] }, { url: "/api/v1/user", methods: ["GET"] }, "/api/v1/user/current", "/api/v1/user/create"] + path: [ + { url: "/api/v1/mod", methods: ["GET"] }, + { url: "/api/v1/pgpmod", methods: ["GET"] }, + { url: "/api/v1/user", methods: ["GET"] }, + "/api/v1/user/current", + "/api/v1/user/create" + ] }) ); router.use("/mod", modRouter); +router.use("/pgpmod", pgpModRouter); router.use("/user", userRouter); export default router; diff --git a/src/server/v1/modules/ModService.ts b/src/server/v1/modules/ModService.ts index d376d93..b206248 100644 --- a/src/server/v1/modules/ModService.ts +++ b/src/server/v1/modules/ModService.ts @@ -50,7 +50,7 @@ export default class ModService { $options: "i" }; } - public async list(params?: any) { + public async list(params?: any, pgp: boolean = false) { const query: dynamic = {}; let sort: dynamic | undefined; if (params && Object.keys(params).length) { @@ -89,7 +89,27 @@ export default class ModService { } } } - return mods.map(mod => mod as IDbMod); + + const modMap = mods.map(mod => mod as IDbMod); + if (!pgp) { + return modMap; + } else { + if (privkey === undefined) { + privkey = await readPrivkey(); + } + return await new Promise((res, rej) => { + const signOptions = { + message: openpgp.cleartext.fromText(JSON.stringify(modMap)), + privateKeys: [privkey] + }; + openpgp + .sign(signOptions) + .then(signed => { + res(signed.data); + }) + .catch(err => rej(err)); + }); + } } public async update(mod: IDbMod, isInsert = false) { @@ -183,21 +203,13 @@ export default class ModService { }; const { _id } = (await this.insert(mod)) as IDbMod & { _id: Id }; mod._id = toId(_id); - try { - privkey = await new Promise((res, rej) => { - fs.readFile(path.join(process.cwd(), "/keys/privkey.asc"), "utf-8", (err, data) => { - if (err) { - rej(err); - } - openpgp.key.readArmored(data).then(output => { - res(output.keys[0]); - }); - }); - }); - await privkey.decrypt(process.env.PASSPHRASE); - } catch (err) { - console.error("ModService.create", "KEY Read", err); - throw new ServerError("mod.upload.key.read"); + if (privkey === undefined) { + try { + privkey = await readPrivkey(); + } catch (err) { + console.error("ModService.create", "KEY Read", err); + throw new ServerError("mod.upload.key.read"); + } } let index = 0; for (const file of files) { @@ -294,3 +306,18 @@ export default class ModService { return true; } } + +async function readPrivkey() { + const pk: any = await new Promise((res, rej) => { + fs.readFile(path.join(process.cwd(), "/keys/privkey.asc"), "utf-8", (err, data) => { + if (err) { + rej(err); + } + openpgp.key.readArmored(data).then(output => { + res(output.keys[0]); + }); + }); + }); + await pk.decrypt(process.env.PASSPHRASE); + return pk; +} diff --git a/src/server/v1/pgpMod.ts b/src/server/v1/pgpMod.ts new file mode 100644 index 0000000..4f40123 --- /dev/null +++ b/src/server/v1/pgpMod.ts @@ -0,0 +1,16 @@ +import * as express from "express"; + +import { catchErrors } from "../modules/Utils"; +import ModService from "./modules/ModService"; + +const router = express.Router(); + +router.get( + "/", + catchErrors(async (req, res, next) => { + const modService = new ModService(req.ctx); + return res.send(await modService.list(req.query, true)); + }) +); + +export default router; From 9bb658c525030119550ae7f8ceead5dabe78ea07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Th=C3=A9riault?= Date: Fri, 26 Apr 2019 23:04:13 -0400 Subject: [PATCH 16/22] Keygen script improvements --- src/utils/pgpKeygen.js | 56 +++++++++++++++++------------------------- 1 file changed, 22 insertions(+), 34 deletions(-) diff --git a/src/utils/pgpKeygen.js b/src/utils/pgpKeygen.js index fd3c411..67886ea 100644 --- a/src/utils/pgpKeygen.js +++ b/src/utils/pgpKeygen.js @@ -5,14 +5,11 @@ const rl = require("readline").createInterface({ input: process.stdin, output: process.stdout }); -let userId = {}; -let numBits; -let passphrase; -let dir; -let key; + +gen().catch(err => {throw err;}); function ask (question) { - return new Promise((res, rej) => { + return new Promise(res => { rl.question(question, answer => { res(answer); }); @@ -31,40 +28,31 @@ function writeKey (filePath, fileKey, type) { }); } -console.log("======== PGP Key Pair Generator ========"); -console.log("- Awaiting info..."); -ask(" Name [Beat Saber Modding Group] : ").then(answer => { - userId.name = answer || "Beat Saber Modding Group"; - return ask(" Email [bsmg@beatmods.com] : "); -}).then(answer => { - userId.email = answer || "bsmg@beatmods.com"; - return ask(" Passphrase [q1w2e3r4t5y6] : "); -}).then(answer => { - passphrase = answer || "q1w2e3r4t5y6"; - return ask(" 4096 bits ? (More secure, slower) [yes] : "); -}).then(answer => { - numBits = (answer.toLowerCase() === "n" || answer.toLowerCase() === "no") ? 2048 : 4096; - return ask(" Output directory [./keys] : "); -}).then(answer => { - dir = answer || path.join(__dirname, 'keys'); +async function gen () { + console.log("======== PGP Key Pair Generator ========"); + + console.log("- Awaiting info..."); + let userId = {}; + userId.name = await ask(" Name [Beat Saber Modding Group] : ") || "Beat Saber Modding Group"; + userId.email = await ask(" Email [bsmg@beatmods.com] : ") || "bsmg@beatmods.com"; + const passphrase = await ask(" Passphrase [q1w2e3r4t5y6] : ") || "q1w2e3r4t5y6"; + let numBits = await ask(" 4096 bits ? (More secure, slower) [yes] : "); + numBits = numBits && (numBits.toLowerCase() === "n" || numBits.toLowerCase() === "no") ? 2048 : 4096; + const dir = await ask(" Output directory [./keys] : ") || path.join(process.cwd(), "keys"); rl.close(); + const genOptions = { userIds: [userId], numBits: numBits, passphrase: passphrase }; console.log(`- Generating ${numBits} bits key pair with user ID ${userId.name} <${userId.email}>...`); - return openpgp.generateKey(genOptions); -}).then(generated => { - key = generated; + const key = await openpgp.generateKey(genOptions); + console.log("- Writing keys..."); - return writeKey(path.join(dir, "privkey.asc"), key.privateKeyArmored, "private key"); -}).then(() => { - return writeKey(path.join(dir, "pubkey.asc"), key.publicKeyArmored, "public key"); -}).then(() => { - return writeKey(path.join(dir, "revcert.asc"), key.revocationCertificate, "revocation certificate"); -}).then(() => { + await writeKey(path.join(dir, "privkey.asc"), key.privateKeyArmored, "private key"); + await writeKey(path.join(dir, "pubkey.asc"), key.publicKeyArmored, "public key"); + await writeKey(path.join(dir, "revcert.asc"), key.revocationCertificate, "revocation certificate"); + console.log("========================================"); -}).catch(err => { - console.error(err); -}); +} From 67299646b398aa802afbfe8f9226693a2c67aa53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Th=C3=A9riault?= Date: Fri, 26 Apr 2019 23:23:20 -0400 Subject: [PATCH 17/22] Fixed response not being sent as plain text --- src/server/v1/pgpMod.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/server/v1/pgpMod.ts b/src/server/v1/pgpMod.ts index 4f40123..f82b3b8 100644 --- a/src/server/v1/pgpMod.ts +++ b/src/server/v1/pgpMod.ts @@ -9,6 +9,7 @@ router.get( "/", catchErrors(async (req, res, next) => { const modService = new ModService(req.ctx); + res.set("Content-Type", "text/plain"); return res.send(await modService.list(req.query, true)); }) ); From 5cb483299539f520cd1521e9811cc94682faad76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Th=C3=A9riault?= Date: Fri, 26 Apr 2019 23:44:03 -0400 Subject: [PATCH 18/22] Break lines in JSON cleartext Some PGP clients can't treat lines longer than 20000 characters --- src/server/v1/modules/ModService.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/server/v1/modules/ModService.ts b/src/server/v1/modules/ModService.ts index b206248..fae0bdd 100644 --- a/src/server/v1/modules/ModService.ts +++ b/src/server/v1/modules/ModService.ts @@ -99,7 +99,7 @@ export default class ModService { } return await new Promise((res, rej) => { const signOptions = { - message: openpgp.cleartext.fromText(JSON.stringify(modMap)), + message: openpgp.cleartext.fromText(JSON.stringify(modMap, null, 2)), privateKeys: [privkey] }; openpgp From 46ff98dc841d3fdb439510d0e0738211e24c5594 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Th=C3=A9riault?= Date: Sat, 27 Apr 2019 12:20:22 -0400 Subject: [PATCH 19/22] Replaced pgpmod router with query parameter --- src/server/v1/index.ts | 2 -- src/server/v1/mod.ts | 8 +++++++- src/server/v1/pgpMod.ts | 17 ----------------- 3 files changed, 7 insertions(+), 20 deletions(-) delete mode 100644 src/server/v1/pgpMod.ts diff --git a/src/server/v1/index.ts b/src/server/v1/index.ts index 6c22f07..02dc9d6 100644 --- a/src/server/v1/index.ts +++ b/src/server/v1/index.ts @@ -6,7 +6,6 @@ import { checkAuthorization } from "../modules/AuthManager"; import config from "../config"; import userRouter from "./user"; import modRouter from "./mod"; -import pgpModRouter from "./pgpMod"; import { catchErrors } from "../modules/Utils"; const authTokenService = new AuthTokenService({ @@ -35,7 +34,6 @@ router.use( }) ); router.use("/mod", modRouter); -router.use("/pgpmod", pgpModRouter); router.use("/user", userRouter); export default router; diff --git a/src/server/v1/mod.ts b/src/server/v1/mod.ts index 615f0af..f3f14d0 100644 --- a/src/server/v1/mod.ts +++ b/src/server/v1/mod.ts @@ -4,6 +4,7 @@ import { catchErrors } from "../modules/Utils"; import ModService from "./modules/ModService"; import multer from "multer"; + const storage = multer.memoryStorage(); const upload = multer({ limits: { fileSize: 25 * 1024 * 1024 }, storage }); @@ -13,7 +14,12 @@ router.get( "/", catchErrors(async (req, res, next) => { const modService = new ModService(req.ctx); - return res.send(await modService.list(req.query)); + let pgp = false; + if (req.query && req.query.hasOwnProperty("pgp")) { + res.set("Content-Type", "text/plain"); + pgp = true; + } + return res.send(await modService.list(req.query, pgp)); }) ); diff --git a/src/server/v1/pgpMod.ts b/src/server/v1/pgpMod.ts deleted file mode 100644 index f82b3b8..0000000 --- a/src/server/v1/pgpMod.ts +++ /dev/null @@ -1,17 +0,0 @@ -import * as express from "express"; - -import { catchErrors } from "../modules/Utils"; -import ModService from "./modules/ModService"; - -const router = express.Router(); - -router.get( - "/", - catchErrors(async (req, res, next) => { - const modService = new ModService(req.ctx); - res.set("Content-Type", "text/plain"); - return res.send(await modService.list(req.query, true)); - }) -); - -export default router; From 7f0c430e2ff062517ec70152f9393452d5af9644 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Th=C3=A9riault?= Date: Sat, 27 Apr 2019 12:27:37 -0400 Subject: [PATCH 20/22] Removed unnecessary verification --- src/server/v1/mod.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/server/v1/mod.ts b/src/server/v1/mod.ts index f3f14d0..9a713dd 100644 --- a/src/server/v1/mod.ts +++ b/src/server/v1/mod.ts @@ -15,7 +15,7 @@ router.get( catchErrors(async (req, res, next) => { const modService = new ModService(req.ctx); let pgp = false; - if (req.query && req.query.hasOwnProperty("pgp")) { + if (req.query.hasOwnProperty("pgp")) { res.set("Content-Type", "text/plain"); pgp = true; } From 06054e1ef390d6b452bf8c17858177d335963db0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Th=C3=A9riault?= Date: Tue, 30 Apr 2019 11:14:13 -0400 Subject: [PATCH 21/22] Fixed rebase f*ck up --- src/config/webpack.common.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/config/webpack.common.js b/src/config/webpack.common.js index c68802a..318d3ce 100755 --- a/src/config/webpack.common.js +++ b/src/config/webpack.common.js @@ -69,7 +69,9 @@ module.exports = { }, plugins: [ new webpack.DefinePlugin({ - 'process.envNODE_ENV': JSON.stringify(NODE_ENV) + 'process.env': { + NODE_ENV: JSON.stringify(NODE_ENV) + } }), new HtmlWebpackPlugin({ template: helpers.root('src/client/public/index.html'), @@ -83,4 +85,4 @@ module.exports = { from: helpers.root('src/client/public') }]) ] -}; \ No newline at end of file +}; From 15b1e370291713ceb131ab391c0b2939daa19d60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Th=C3=A9riault?= Date: Tue, 30 Apr 2019 16:41:44 -0400 Subject: [PATCH 22/22] Typo --- src/config/webpack.common.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/config/webpack.common.js b/src/config/webpack.common.js index 318d3ce..b4fd9e9 100755 --- a/src/config/webpack.common.js +++ b/src/config/webpack.common.js @@ -69,9 +69,7 @@ module.exports = { }, plugins: [ new webpack.DefinePlugin({ - 'process.env': { - NODE_ENV: JSON.stringify(NODE_ENV) - } + 'process.env.NODE_ENV': JSON.stringify(NODE_ENV) }), new HtmlWebpackPlugin({ template: helpers.root('src/client/public/index.html'),