diff --git a/pass/public/styles/checkout.css b/pass/public/styles/checkout.css index 86871c32d6f9fd08ca0bc5b5642c7689fb66a672..e5fa58a2a963b1b8f9b363183577938a8880ac32 100644 --- a/pass/public/styles/checkout.css +++ b/pass/public/styles/checkout.css @@ -1 +1 @@ -#payment-container{width:max-content;border:1px solid #777;border-radius:.2rem}#payment-container>#heading{border:1px solid #777;background-color:#eaeaea;padding:.5rem}#payment-container #payment-provider-container{display:flex;align-items:center}#payment-container #payment-provider-container>#payment-information{margin:0 auto}#payment-container #payment-provider-container>#payment-providers{border-right:1px solid #777;padding:.5rem}#payment-container #payment-provider-container>#payment-providers>h1{margin:0;font-size:.7rem;font-weight:normal}#payment-container #payment-provider-container>#payment-providers>ul{list-style-type:none;margin:0;padding:0}#payment-container #payment-provider-container>#payment-providers>ul>li{cursor:pointer;padding:.5rem 1rem;background-color:#f5f5f5}#payment-container #payment-provider-container>#payment-providers>ul>li[data-active="true"]{background-color:orange;color:white;font-weight:bold;-webkit-text-stroke:#777 .01rem}#payment-container #payment-provider-container>#payment-providers>ul>li:not(:last-child){border-bottom:1px dashed #777}#payment-container>.step{border:1px solid #777;padding:1rem;color:rgba(120,120,120,0.314)}#payment-container>.step>.section-heading{display:flex;gap:.5rem}#payment-container>.step>.section-heading>.status{width:1rem}#payment-container>.step>.section-heading>.status>*{display:none}#payment-container>.step>.section-heading>.content{flex-grow:1}#payment-container>.step>.section-heading>.location{text-align:right;border-left:1px solid rgba(120,120,120,0.314);padding-left:.6rem}#payment-container>.step>.section-body{display:none}#payment-container>.step.current{color:inherit}#payment-container>.step.current .loading{display:block}#payment-container>.step.current .location{color:#777;border-color:#777}#payment-container>.step.current>.section-body{display:block}#payment-container>.step.finished .finished{display:block} \ No newline at end of file +#payment-container{width:max-content;max-width:980px;border:1px solid #777;border-radius:.2rem}#payment-container>#heading{border:1px solid #777;background-color:#eaeaea;padding:.5rem}#payment-container #payment-provider-container{display:flex;align-items:center}#payment-container #payment-provider-container>#payment-information{margin:0 auto}#payment-container #payment-provider-container>#payment-providers{border-right:1px solid #777;padding:.5rem}#payment-container #payment-provider-container>#payment-providers>h1{margin:0;font-size:.7rem;font-weight:normal}#payment-container #payment-provider-container>#payment-providers>ul{list-style-type:none;margin:0;padding:0}#payment-container #payment-provider-container>#payment-providers>ul>li{cursor:pointer;padding:.5rem 1rem;background-color:#f5f5f5}#payment-container #payment-provider-container>#payment-providers>ul>li[data-active="true"]{background-color:orange;color:white;font-weight:bold;-webkit-text-stroke:#777 .01rem}#payment-container #payment-provider-container>#payment-providers>ul>li:not(:last-child){border-bottom:1px dashed #777}#payment-container>.step{border:1px solid #777;padding:1rem;color:rgba(120,120,120,0.5)}#payment-container>.step>.section-heading{display:flex;gap:.5rem}#payment-container>.step>.section-heading>.status{width:1rem}#payment-container>.step>.section-heading>.status>*{display:none}#payment-container>.step>.section-heading>.content{flex-grow:1}#payment-container>.step>.section-heading>.location{text-align:right;border-left:1px solid rgba(120,120,120,0.314);padding-left:.6rem}#payment-container>.step>.section-body{display:none}#payment-container>.step.current{color:inherit}#payment-container>.step.current .loading{display:block}#payment-container>.step.current .location{color:#777;border-color:#777}#payment-container>.step.current>.section-body{display:block}#payment-container>.step.finished{color:#40da50}#payment-container>.step.finished .finished{display:block}#finish-purchase .section-body>.options{display:flex;gap:2rem;justify-content:space-around}#finish-purchase .section-body>.options>label{display:block;cursor:pointer;padding:1rem;border:1px solid #777;border-radius:.8rem}#finish-purchase .section-body>input[type="radio"]{display:none}#finish-purchase .section-body>div.option-body{display:none}#finish-purchase .section-body .option-selected{background-color:#ff8000;color:white;-webkit-text-stroke:#777 .01rem;font-weight:bold;border-color:#fb8d21}#finish-purchase .section-body>#create-voucher-radio:checked~div#create-voucher.option-body{display:block}#finish-purchase .section-body>#create-voucher-radio:checked~.options>label[for="create-voucher-radio"]{background-color:#ff8000;color:white;-webkit-text-stroke:#777 .01rem;font-weight:bold;border-color:#fb8d21}#finish-purchase .section-body>#create-key-radio:checked~div#create-key.option-body{display:block}#finish-purchase .section-body>#create-key-radio:checked~.options>label[for="create-key-radio"]{background-color:#ff8000;color:white;-webkit-text-stroke:#777 .01rem;font-weight:bold;border-color:#fb8d21}#finish-purchase .section-body>#recharge-key-radio:checked~div#recharge-key.option-body{display:block}#finish-purchase .section-body>#recharge-key-radio:checked~.options>label[for="recharge-key-radio"]{background-color:#ff8000;color:white;-webkit-text-stroke:#777 .01rem;font-weight:bold;border-color:#fb8d21} \ No newline at end of file diff --git a/pass/public/styles/checkout.less b/pass/public/styles/checkout.less index 6afed0bdce5bf038705f7865acdf44dc6e81413e..57333ea4af5d4e783355d3ed8c8e4c785ad8234f 100644 --- a/pass/public/styles/checkout.less +++ b/pass/public/styles/checkout.less @@ -1,5 +1,6 @@ #payment-container { width: max-content; + max-width: 980px; border: 1px solid #777; border-radius: 0.2rem; @@ -49,7 +50,7 @@ > .step { border: 1px solid #777; padding: 1rem; - color: hsla(0, 0%, 47%, 0.314); + color: hsla(0, 0%, 47%, 0.5); > .section-heading { display: flex; gap: 0.5rem; @@ -84,8 +85,71 @@ display: block; } } - &.finished .finished { - display: block; + &.finished { + color: rgb(64, 218, 80); + .finished { + display: block; + } + } + } +} + +// Finish Purchase Styles +#finish-purchase { + .section-body { + > .options { + display: flex; + gap: 2rem; + justify-content: space-around; + > label { + display: block; + cursor: pointer; + padding: 1rem; + border: 1px solid #777; + border-radius: 0.8rem; + } + } + + // Styles to change content based on selected option + > input[type="radio"] { + display: none; + } + > div.option-body { + display: none; + } + + .option-selected { + background-color: rgb(255, 128, 0); + background-color: #ff8000; + color: white; + -webkit-text-stroke: #777 0.01rem; + font-weight: bold; + border-color: rgb(251, 141, 33); + } + > #create-voucher-radio:checked { + ~ div#create-voucher.option-body { + display: block; + } + ~ .options > label[for="create-voucher-radio"] { + .option-selected(); + } + } + + > #create-key-radio:checked { + ~ div#create-key.option-body { + display: block; + } + ~ .options > label[for="create-key-radio"] { + .option-selected(); + } + } + > #recharge-key-radio:checked { + ~ div#recharge-key.option-body { + display: block; + } + ~ .options > label[for="recharge-key-radio"] { + .option-selected(); + } } } } diff --git a/pass/resources/js/checkout.js b/pass/resources/js/checkout.js index bf8342b291914184322b3044fbac681d6eeb7d42..49d90d3321d57b70841ba79f4b627b92abb4d2cf 100644 --- a/pass/resources/js/checkout.js +++ b/pass/resources/js/checkout.js @@ -1,6 +1,7 @@ const uuid_generator = require("uuid"); const BlindSignature = require("blind-signatures"); +var metager_pass_order_id = null; var metager_pass_sales_receipts = []; var metager_pass_encrypted_sales_receipts = []; // Stores the encrypted sales receipts that get signed by our server after successful purchase var metager_pass_encrypted_sales_receipts_r = []; // Those are the secrets for decrypting the signed sales_receipts; Should never leave the clients computer @@ -41,8 +42,6 @@ function one_generate_encrypted_sales_receipt() { metager_pass_encrypted_sales_receipts_r.push(r.toString()); } - console.log(metager_pass_encrypted_sales_receipts); - current_step_container.classList.remove("current"); current_step_container.classList.add("finished"); next_step_container.classList.add("current"); @@ -52,7 +51,6 @@ function one_generate_encrypted_sales_receipt() { function two_execute_payment() { let current_step_container = document.getElementById("execute-payment"); - let next_step_container = document.getElementById("verify-and-decrypt"); let development_handler_button = document.getElementById( "payment_method_development" ); @@ -73,12 +71,18 @@ function two_execute_payment() { current_step_container.addEventListener("payment-complete", (e) => { current_step_container.classList.remove("current"); current_step_container.classList.add("finished"); - next_step_container.classList.add("current"); three_verify_and_decrypt(e.detail); }); } function three_verify_and_decrypt(signatures) { + let current_step_container = document.getElementById("verify-and-decrypt"); + let next_step_container = document.getElementById("finish-purchase"); + + current_step_container.classList.add("current"); + + metager_pass_order_id = signatures.order_id; + let N = document.querySelector("input[name=public_key_n]").value; let E = document.querySelector("input[name=public_key_e]").value; // Decrypting/Unblinding Signatures @@ -93,6 +97,7 @@ function three_verify_and_decrypt(signatures) { } // Verify Signatures + // ToDo do something with invalid signatures for (let i = 0; i < metager_pass_sales_receipts.length; i++) { let verification = BlindSignature.verify({ unblinded: metager_pass_signatures[i], @@ -102,4 +107,30 @@ function three_verify_and_decrypt(signatures) { }); console.log(metager_pass_sales_receipts[i] + " => " + verification); } + + current_step_container.classList.remove("current"); + current_step_container.classList.add("finished"); + four_finish_purchase(); +} + +function four_finish_purchase() { + let current_step_container = document.getElementById("finish-purchase"); + current_step_container.classList.add("current"); + + // Prepare Voucher download + let dayjs = require("dayjs"); + let order_date = dayjs.unix(metager_pass_order_id.substr(0, 10)); + let voucher_link = document.getElementById("voucher-link"); + let voucher_data = { + month: order_date.format("MM/YYYY"), + receipt: { + receipts: metager_pass_sales_receipts, + signatures: metager_pass_signatures, + }, + }; + voucher_data = + "data:application/mgpass;charset=utf-8;base64," + + btoa(JSON.stringify(voucher_data, null, 4)); + voucher_link.href = voucher_data; + voucher_link.download = "mgpass_coupon.json"; } diff --git a/pass/resources/js/checkout_development.js b/pass/resources/js/checkout_development.js index 8dac4ced22653cb677dee0b4caf487a2e1bc6c5f..f1ede9cb5012137bdfccfe2c647687408fbf3ea9 100644 --- a/pass/resources/js/checkout_development.js +++ b/pass/resources/js/checkout_development.js @@ -47,6 +47,7 @@ function execute_payment_paypal(encrypted_sales_receipts) { .then((data) => { let paymentEvent = new CustomEvent("payment-complete", { detail: { + order_id: data.order_id, signatures: data.signatures, }, bubbles: true, diff --git a/pass/resources/js/checkout_paypal.js b/pass/resources/js/checkout_paypal.js index b677204acb6ec3efa3a27265f7ecef4b47304fcb..dc6bbe3853d948a33c7e8b84e37131f49aa6b657 100644 --- a/pass/resources/js/checkout_paypal.js +++ b/pass/resources/js/checkout_paypal.js @@ -80,6 +80,7 @@ function execute_payment_paypal(encrypted_sales_receipts) { .then((orderData) => { let paymentEvent = new CustomEvent("payment-complete", { detail: { + order_id: orderData.order_id, signatures: orderData.signatures, }, bubbles: true, diff --git a/pass/routes/checkout/checkout.js b/pass/routes/checkout/checkout.js index 5562a3fc2e8a942b2b075cf4c1dde264cf3f0dd2..2e4cdced8b11f0192b9b7aff68791e290fdec2ce 100644 --- a/pass/routes/checkout/checkout.js +++ b/pass/routes/checkout/checkout.js @@ -12,7 +12,8 @@ router.get( "/", query("amount") .isInt({ min: 0, max: 12 }) - .withMessage("Amount needs to be between 0 and 4."), + .withMessage("Amount needs to be between 0 and 4.") + .toInt(), async function (req, res, next) { const errors = validationResult(req); if (!errors.isEmpty()) { diff --git a/pass/routes/checkout/development.js b/pass/routes/checkout/development.js index 65129add41c495c9d0b0460da77155b51c3195e9..a9c2dfa4c63e5eddcba60a37b28350a9d30ecaac 100644 --- a/pass/routes/checkout/development.js +++ b/pass/routes/checkout/development.js @@ -33,6 +33,7 @@ router.post( order.signOrder().then(() => { order.save().then(() => { res.json({ + order_id: req.body.order_id, signatures: order.getSignatures(), }); }); diff --git a/pass/routes/checkout/paypal.js b/pass/routes/checkout/paypal.js index e7f30cc16e94f089292d449c2612832cad1ad563..dd466f24fdeda7adc24023990d7b86f0c40c0e2a 100644 --- a/pass/routes/checkout/paypal.js +++ b/pass/routes/checkout/paypal.js @@ -51,6 +51,7 @@ router.post("/capture", async (req, res) => { .save() .then(() => { captureData.signatures = loaded_order.getSignatures(); + captureData.order_id = req.body.order_id; res.json(captureData); }) .catch((error) => { diff --git a/pass/views/checkout/checkout.ejs b/pass/views/checkout/checkout.ejs index f070d0014d312e5036b3b7ba0a17200c58b15236..0f15b66f8873533b7ec3acce6eb4c2feb82065ac 100644 --- a/pass/views/checkout/checkout.ejs +++ b/pass/views/checkout/checkout.ejs @@ -17,7 +17,7 @@ <img src="/images/loader.gif" alt="Loading" class="loading"> <div class="finished">✓</div> </div> - <div class="content">MetaGer Pass Code erstellen und verschlüsseln</div> + <div class="content">Kaufbeleg erstellen und verschlüsseln</div> <div class="location">Lokal</div> </div> <div class="section-body"> @@ -60,10 +60,51 @@ <img src="/images/loader.gif" alt="Loading" class="loading"> <div class="finished">✓</div> </div> - <div class="content">MetaGer Pass Code verifizieren und entschlüsseln</div> + <div class="content">Kaufbeleg verifizieren und entschlüsseln</div> <div class="location">Lokal</div> </div> </div> + <div id="finish-purchase" class="step"> + <div class="section-heading"> + <div class="status"> + <img src="/images/loader.gif" alt="Loading" class="loading"> + <div class="finished">✓</div> + </div> + <div class="content">MetaGer-Pass Schlüssel erstellen/aufladen</div> + <div class="location">Server</div> + </div> + <div class="section-body"> + <input type="radio" name="finish-purchase-options" value="create-voucher" id="create-voucher-radio"> + <input type="radio" name="finish-purchase-options" value="create-key" id="create-key-radio"> + <input type="radio" name="finish-purchase-options" value="recharge-key" id="recharge-key-radio"> + <div class="options"> + <label for="create-voucher-radio">Gutschein herunterladen</label> + <label for="create-key-radio">Neuen Schlüssel erstellen</label> + <label for="recharge-key-radio">Bestehenden Schlüssel aufladen</label> + </div> + <div id="create-voucher" class="option-body"> + <p> + Mit einem MetaGer-Pass Coupon können Sie Ihren Einkauf zu einem späteren Zeitpunkt einlösen. Der Vorteil wäre, dass es dadurch keinen zeitlichen Bezug zwischen Einkauf und dem verwendeten Schlüssel gibt. Außerdem können Sie den Coupon bei Bedarf auch an andere Personen zur Verwendung weiter geben. Alternativ können Sie die gekauften Suchanfragen auch sofort einlösen. + </p> + <div> + <a href="data:application/mgpass;charset=utf-8;base64,dGVzdHRlYWU=" download="voucher.mgpass" target="_blank" id="voucher-link">Gutschein herunterladen</a> + </div> + </div> + <div id="create-key" class="option-body"> + <p> + Erstellen Sie sich nachfolgend einen neuen anonymen MetaGer-Pass Schlüssel. Auf diesem werden Ihre gekauften Suchanfragen anschließend gutgeschrieben. + </p> + <div> + <form action="" method="post"></form> + </div> + </div> + <div id="recharge-key" class="option-body"> + <p> + Haben Sie bereits einen MetaGer-Pass Schlüssel und möchten diesen weiter verwenden? Geben Sie nachfolgend Ihren bekannten Schlüssel ein um die gekauften Suchanfragen darauf gutzuschreiben. + </p> + </div> + </div> + </div> </div> </main>