From 68f97d915f7aa20211d66944973d1330fcd8881a Mon Sep 17 00:00:00 2001 From: Dominik Hebeler <dominik@suma-ev.de> Date: Fri, 18 Nov 2022 16:54:42 +0100 Subject: [PATCH] added first redeem checks --- pass/app.js | 4 +-- pass/app/Crypto.js | 40 +++++++++++++++++++++++++++ pass/resources/js/checkout.js | 21 +++++++++++--- pass/routes/{capture.js => redeem.js} | 22 +++++++++++---- 4 files changed, 75 insertions(+), 12 deletions(-) rename pass/routes/{capture.js => redeem.js} (70%) diff --git a/pass/app.js b/pass/app.js index 33e7fd9..2dfc737 100644 --- a/pass/app.js +++ b/pass/app.js @@ -8,7 +8,7 @@ var logger = require("morgan"); var indexRouter = require("./routes/index"); var checkoutRouter = require("./routes/checkout/checkout"); -var captureRouter = require("./routes/capture.js"); +var redeemRouter = require("./routes/redeem.js"); var app = express(); @@ -25,7 +25,7 @@ app.use(express.static(path.join(__dirname, "public"))); app.use("/", indexRouter); app.use("/checkout", checkoutRouter); -app.use("/capture", captureRouter); +app.use("/redeem", redeemRouter); // Browserified Javascript files app.get( diff --git a/pass/app/Crypto.js b/pass/app/Crypto.js index e7b2fe7..d7bed25 100644 --- a/pass/app/Crypto.js +++ b/pass/app/Crypto.js @@ -70,6 +70,46 @@ class Crypto { return private_key; } + async validateMetaGerPassCode(expiration_month, metager_pass_codes) { + expiration_month = this.#dayjs(expiration_month); + // Check if codes are expired + if (!this.#dayjs().isBefore(expiration_month, "month")) { + return Promise.reject("Redeem Codes are expired."); + } + + let private_key = await this.#private_key_get(expiration_month); + + let uuid_regexExp = + /^[0-9a-fA-F]{8}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{12}$/gi; + for (let i = 0; i < metager_pass_codes.length; i++) { + // Check if code iss in correct format + let metager_pass_code = metager_pass_codes[i]; + if ( + !metager_pass_code.hasOwnProperty("code") || + !metager_pass_code.code.match(uuid_regexExp) + ) { + return Promise.reject(metager_pass_code.code + " is not a valid UUID"); + } + // Check if signature is in correct format + if ( + !metager_pass_code.hasOwnProperty("signature") || + !metager_pass_code.signature.match(/^\d+$/gi) + ) { + return Promise.reject(i + 1 + ". signature has not a valid format"); + } + + let verification_result = BlindSignature.verify2({ + unblinded: metager_pass_code.signature, + key: private_key, + message: metager_pass_code.code, + }); + if (!verification_result) { + console.log(i); + return Promise.reject("One or more signatures could not be verified"); + } + } + } + async sign(encrypted_sales_receipts, order_date) { let private_key = await this.#private_key_get(order_date); let signed_encrypted_sales_receipts = []; diff --git a/pass/resources/js/checkout.js b/pass/resources/js/checkout.js index 2c4c2cb..a040db1 100644 --- a/pass/resources/js/checkout.js +++ b/pass/resources/js/checkout.js @@ -138,15 +138,28 @@ function four_finish_purchase() { // Make Create Key button work let create_key_button = document.getElementById("create-key-button"); + let order_month = require("dayjs") + .unix(metager_pass_order_id.substr(0, 10)) + .format("YYYY-MM-01"); create_key_button.addEventListener("pointerdown", () => { - fetch("/capture/create", { + let redeem_data = { + expiration_month: metager_pass_expires_at, + generation_month: order_month, + metager_pass_codes: [], + }; + for (let i = 0; i < metager_pass_sales_receipts.length; i++) { + redeem_data.metager_pass_codes.push({ + code: metager_pass_sales_receipts[i], + signature: metager_pass_signatures[i], + }); + } + + fetch("/redeem/create", { method: "POST", headers: { "Content-Type": "application/json;charset=utf-8", }, - body: JSON.stringify({ - expiration_month: metager_pass_expires_at, - }), + body: JSON.stringify(redeem_data), }); }); } diff --git a/pass/routes/capture.js b/pass/routes/redeem.js similarity index 70% rename from pass/routes/capture.js rename to pass/routes/redeem.js index 0089cd5..5936b89 100644 --- a/pass/routes/capture.js +++ b/pass/routes/redeem.js @@ -3,6 +3,7 @@ var router = express.Router(); const { query, body, validationResult } = require("express-validator"); const dayjs = require("dayjs"); +const Crypto = require("../app/Crypto"); var customParseFormat = require("dayjs/plugin/customParseFormat"); dayjs.extend(customParseFormat); @@ -18,12 +19,21 @@ router.use( .isDate() .matches(/^\d{4}-\d{2}-\d{2}$/) .withMessage("Invalid Purchase Date supplied"), - body("receipts") - .custom((receipts) => { - let expiration_month = dayjs(req.body.expiration_month); - return true; - }) - .withMessage("Supplied Receipts are invalid"), + body("receipts").custom(async (receipts, { req }) => { + return new Promise((resolve, reject) => { + new Crypto() + .validateMetaGerPassCode( + req.body.expiration_month, + req.body.metager_pass_codes + ) + .then(() => { + resolve(true); + }) + .catch((reason) => { + reject(reason); + }); + }); + }), (req, res, next) => { const errors = validationResult(req); if (!errors.isEmpty()) { -- GitLab