diff --git a/pass/app/Key.js b/pass/app/Key.js index a048dbc58d2a129a650b8227c87d0f6248647311..f79e0a18bfde6df2cc18f8b50423b1ea69c97d8b 100644 --- a/pass/app/Key.js +++ b/pass/app/Key.js @@ -70,7 +70,6 @@ class Key { let dayjs = require("dayjs"); let expiration = dayjs().add(Key.EXPIRATION_AFTER_CHARGE_DAYS, "day"); redis_client.pipeline().incrby(Key.DATABASE_PREFIX + key, amount).expireat(Key.DATABASE_PREFIX + key, expiration.unix()).exec().then(result => { - console.log(result); resolve({ status: "SUCCESS", metager_pass_key: { diff --git a/pass/resources/js/checkout.js b/pass/resources/js/checkout.js index c6fc400f48a53b22561ca5583c085f1b8960adc8..888a69affe60206d496f8fb4f785edb7c09cb31b 100644 --- a/pass/resources/js/checkout.js +++ b/pass/resources/js/checkout.js @@ -176,7 +176,13 @@ function four_finish_purchase() { // Make Redeem Button Work let redeem_button = document.getElementById("recharge-key-button"); - redeem_button.addEventListener("pointerdown", () => { + redeem_button.addEventListener("pointerdown", e => { + if (e.target.disabled) { + return; + } else { + e.target.disabled = true; + document.getElementById("metager-pass-key").disabled = true; + } let post_data = { ...redeem_data }; post_data.metager_pass_key = document.getElementById("metager-pass-key").value; fetch("/redeem", { @@ -187,7 +193,12 @@ function four_finish_purchase() { body: JSON.stringify(post_data), }).then(response => response.json()) .then(response => { + console.log(response); + }).catch(reason => { + e.target.disabled = false; + document.getElementById("metager-pass-key").disabled = false; + console.error(reason); }); }); } diff --git a/pass/routes/redeem.js b/pass/routes/redeem.js index a82acb080aa8354bf0d8b0d65840871751e7eb2a..d1e247763d6ece5202358ad4cad45c77597c9ea5 100644 --- a/pass/routes/redeem.js +++ b/pass/routes/redeem.js @@ -8,6 +8,9 @@ const Crypto = require("../app/Crypto"); var customParseFormat = require("dayjs/plugin/customParseFormat"); const Key = require("../app/Key"); const Order = require("../app/Order"); +const path = require('path'); +const fs = require('fs'); +const readline = require('readline'); dayjs.extend(customParseFormat); /** @@ -47,7 +50,7 @@ router.use( ); /* Recharge a MetaGer-Pass Key */ -router.post("/", body("metager_pass_key").isWhitelisted(Key.KEY_CHARSET).isLength({ min: 6, max: 20 }), (req, res, next) => { +router.post("/", body("metager_pass_key").isWhitelisted(Key.KEY_CHARSET).isLength({ min: 6, max: 20 }), async (req, res, next) => { const errors = validationResult(req); if (!errors.isEmpty()) { return res.status(400).json({ errors: errors.array() }); @@ -74,6 +77,37 @@ router.post("/", body("metager_pass_key").isWhitelisted(Key.KEY_CHARSET).isLengt charge_amount += Order.PACKET_SIZE; } + // Check one or more of the codes was already used to redeem a MetaGer-Pass Key + let order_month = dayjs(req.body.generation_month); + let redeem_file_path = path.join( + config.get("storage.data_path"), + process.env.NODE_ENV, + order_month.format("YYYY"), + order_month.format("MM"), + "redeemed.json"); + if (!fs.existsSync(path.dirname(redeem_file_path))) { + fs.mkdirSync(path.dirname(redeem_file_path), { recursive: true }); + } + + if (fs.existsSync(redeem_file_path)) { + let rl = readline.createInterface({ + input: fs.createReadStream(redeem_file_path), + output: process.stdout, + terminal: false + }); + for await (const line of rl) { + for (let i = 0; i < req.body.metager_pass_codes.length; i++) { + if (req.body.metager_pass_codes[i].code === line.trim()) { + return res.status(400).json({ + status: "FAILED", + msg: ["One or more of the provided MetaGer-Pass Codes are already redeemed."] + }); + } + } + } + } + + let recharge_tries = 0; redis_client.mget(key_recharge_cache_keys).then(async response => { for (let i = 0; i < response.length; i++) { @@ -100,6 +134,11 @@ router.post("/", body("metager_pass_key").isWhitelisted(Key.KEY_CHARSET).isLengt await redis_pipeline.exec(); Key.CHARGE_EXISTING_KEY(req.body.metager_pass_key, charge_amount).then(result => { + // Key is charged store the redeem codes into filesystem so they can only be used once + for (let i = 0; i < req.body.metager_pass_codes.length; i++) { + fs.appendFileSync(redeem_file_path, req.body.metager_pass_codes[i].code + "\n"); + } + res.json(result); }).catch(reason => { res.status(400).json({