From 3283ab0cd37846e7fee6b50cdf075468dacac6e7 Mon Sep 17 00:00:00 2001 From: punit2502 Date: Sat, 16 May 2020 16:56:38 +0530 Subject: [PATCH 1/8] Feat: - Adds language path in url (only if its n.exchange) - Redirect to staging if payment method is advcash or payeer --- index.js | 112 +++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 72 insertions(+), 40 deletions(-) diff --git a/index.js b/index.js index a6d8f50..4463e59 100644 --- a/index.js +++ b/index.js @@ -1,73 +1,105 @@ -const express = require('express'); -const path = require('path'); -const helmet = require('helmet') +const express = require("express"); +const path = require("path"); +const helmet = require("helmet"); +const url = require("url"); const app = express(); -const NEXCHANGE_ROOT = process.env.NEXCHANGE_ROOT -const ICO_ROOT = process.env.ICO_ROOT +const NEXCHANGE_ROOT = process.env.NEXCHANGE_ROOT; +const ICO_ROOT = process.env.ICO_ROOT; //Helmet helps you secure your Express apps by setting various HTTP headers. -app.use(helmet()) -app.use('/ico', express.static(path.resolve(ICO_ROOT))); -app.use(express.static(path.resolve(NEXCHANGE_ROOT), {index: false})); +app.use(helmet()); +app.use("/ico", express.static(path.resolve(ICO_ROOT))); +app.use(express.static(path.resolve(NEXCHANGE_ROOT), { index: false })); function getCur(qParam) { - return qParam.toUpperCase().substr(-3); + return qParam.toUpperCase().substr(-3); } -app.get('/ico', (req, res) => { - res.sendFile(path.resolve(ICO_ROOT, 'index.html')); +app.get("/ico", (req, res) => { + res.sendFile(path.resolve(ICO_ROOT, "index.html")); }); // Handling lowercase order Ids -var orderUppercase = (req, res, next) => { - - if (req.params.orderId) { - const orderIdUP = req.params.orderId.toUpperCase() - if (req.params.orderId != orderIdUP) { - res.redirect('/order/' + orderIdUP) - } - else { - next() - } +const orderUppercase = (req, res, next) => { + const orderIdUP = req.params.orderId.toUpperCase(); + if (req.params.orderId !== orderIdUP) { + res.redirect(`/${lang}/order/${orderIdUP}`); + } else { + next(); } }; // General handler for the rest of the URLs -var generalHandler = (req, res) => { +const generalHandler = (req, res) => { + let host = undefined; + let urlPath = req.path; + const langInPath = urlPath.split("/")[1]; + const langInParam = req.query.lang ? req.query.lang.toLowerCase() : undefined; + let lang = langInPath || langInParam || "en"; + const fromCurr = req.query.cur_from; + const toCurr = req.query.cur_to; + const validLanguages = ["en", "de", "ru"]; let redirectRequired = false; - let params = {}; - if (req.query.cur_from && req.query.cur_to) { + + // Dont add language path in url, if its not n.exchange + if ( + !req.headers.host.includes("n.exchange") && + !req.headers.host.includes("localhost") + ) + lang = ""; + + if (validLanguages.includes(langInPath)) { + res.header("Set-Cookie", `i18next=${lang}`); + + urlPath = urlPath.substr(lang.length + 1); + + // If lang is in path then ignore lang in param + delete req.query["lang"]; + } + + if (fromCurr && toCurr) { + const fromCurrType = fromCurr.substr(0, fromCurr.length - 3); + + if (["ADVC", "PR"].includes(fromCurrType)) host = "s.api.n.exchange"; + + console.log(fromCurrType); + req.query.pair = getCur(toCurr) + getCur(fromCurr); + delete req.query.cur_from; + delete req.query.cur_to; redirectRequired = true; - req.query.pair = getCur(req.query.cur_to) + getCur(req.query.cur_from); - delete req.query['cur_to']; - delete req.query['cur_from']; } - if (req.query.lang && req.query.lang !== req.query.lang.toLowerCase()) { + if (req.query.lang && validLanguages.includes(langInParam)) { + delete req.query["lang"]; redirectRequired = true; - req.query.lang = req.query.lang.toLowerCase() } if (redirectRequired) { - params = req.query; - params = Object.keys(params).map(key => key + '=' + params[key]).join('&'); - res.redirect(req.path + '?' + params); + const redirectUrl = url.format({ + pathname: urlPath === "/" ? `/${lang}` : `/${lang}${urlPath}`, + query: req.query, + }); + + if (host) { + res.redirect(`https://${host}${redirectUrl}`); + return; + } + + res.redirect(redirectUrl); return; } - res.sendFile(path.resolve(process.env.NEXCHANGE_ROOT, 'index.html')); + res.sendFile(path.resolve(process.env.NEXCHANGE_ROOT, "index.html")); }; // Convert order ids to uppercase -app.get('/order/:orderId', [orderUppercase, generalHandler] -); +app.get("/order/:orderId", [orderUppercase, generalHandler]); // For all other cases -app.get('*', generalHandler); - - -app.listen(3000, () => console.log('Nexchange Frontend Proxy is listening on port 3000!')); - +app.get("*", generalHandler); +app.listen(3000, () => + console.log("Nexchange Frontend Proxy is listening on port 3000!") +); From 752ea3c962d3164c71cfb52b364c32e47eecb319 Mon Sep 17 00:00:00 2001 From: punit2502 Date: Wed, 20 May 2020 15:47:25 +0530 Subject: [PATCH 2/8] redirect to sapi if payment method is adv or pr --- index.js | 48 +++++++++++++++++++++++++++++++----------------- 1 file changed, 31 insertions(+), 17 deletions(-) diff --git a/index.js b/index.js index 4463e59..be84731 100644 --- a/index.js +++ b/index.js @@ -6,6 +6,7 @@ const url = require("url"); const app = express(); const NEXCHANGE_ROOT = process.env.NEXCHANGE_ROOT; const ICO_ROOT = process.env.ICO_ROOT; +const languageRedirect = true; //Helmet helps you secure your Express apps by setting various HTTP headers. app.use(helmet()); @@ -24,7 +25,7 @@ app.get("/ico", (req, res) => { const orderUppercase = (req, res, next) => { const orderIdUP = req.params.orderId.toUpperCase(); if (req.params.orderId !== orderIdUP) { - res.redirect(`/${lang}/order/${orderIdUP}`); + res.redirect(`/order/${orderIdUP}`); } else { next(); } @@ -32,7 +33,6 @@ const orderUppercase = (req, res, next) => { // General handler for the rest of the URLs const generalHandler = (req, res) => { - let host = undefined; let urlPath = req.path; const langInPath = urlPath.split("/")[1]; const langInParam = req.query.lang ? req.query.lang.toLowerCase() : undefined; @@ -40,15 +40,16 @@ const generalHandler = (req, res) => { const fromCurr = req.query.cur_from; const toCurr = req.query.cur_to; const validLanguages = ["en", "de", "ru"]; + const stagingPaymentMethods = [ + { code: "ADVC", name: "ADVCASH" }, + { code: "PR", name: "PAYEER" }, + ]; + let stagingPaymentMethod = undefined; let redirectRequired = false; - // Dont add language path in url, if its not n.exchange - if ( - !req.headers.host.includes("n.exchange") && - !req.headers.host.includes("localhost") - ) - lang = ""; + // Dont add language path in url if set to false + if (!languageRedirect) lang = ""; if (validLanguages.includes(langInPath)) { res.header("Set-Cookie", `i18next=${lang}`); @@ -60,11 +61,19 @@ const generalHandler = (req, res) => { } if (fromCurr && toCurr) { - const fromCurrType = fromCurr.substr(0, fromCurr.length - 3); - - if (["ADVC", "PR"].includes(fromCurrType)) host = "s.api.n.exchange"; + const paymentMethod = fromCurr.substr(0, fromCurr.length - 3); + + // Loops in staging payment methods array + for (const elem in stagingPaymentMethods) { + if (stagingPaymentMethods[elem].code === paymentMethod) { + stagingPaymentMethod = { + code: stagingPaymentMethods[elem].code, + name: stagingPaymentMethods[elem].name, + }; + break; + } + } - console.log(fromCurrType); req.query.pair = getCur(toCurr) + getCur(fromCurr); delete req.query.cur_from; delete req.query.cur_to; @@ -77,16 +86,21 @@ const generalHandler = (req, res) => { } if (redirectRequired) { + // Redirect to staging url if staging payment method is not undefined + if (stagingPaymentMethod) { + res.redirect( + `https://api.n.exchange/en/orders/buy-${toCurr.toLowerCase()}-with-${getCur( + fromCurr + ).toLowerCase()}?payment_method=${stagingPaymentMethod.name.toLowerCase()}` + ); + return; + } + const redirectUrl = url.format({ pathname: urlPath === "/" ? `/${lang}` : `/${lang}${urlPath}`, query: req.query, }); - if (host) { - res.redirect(`https://${host}${redirectUrl}`); - return; - } - res.redirect(redirectUrl); return; } From 8a9a297c0c99d51757f97e7d77d53b22cf9961cb Mon Sep 17 00:00:00 2001 From: punit2502 Date: Wed, 20 May 2020 16:51:38 +0530 Subject: [PATCH 3/8] redirect to sapi or api based on node env --- index.js | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/index.js b/index.js index be84731..8e43066 100644 --- a/index.js +++ b/index.js @@ -40,11 +40,11 @@ const generalHandler = (req, res) => { const fromCurr = req.query.cur_from; const toCurr = req.query.cur_to; const validLanguages = ["en", "de", "ru"]; - const stagingPaymentMethods = [ + const testPaymentMethods = [ { code: "ADVC", name: "ADVCASH" }, { code: "PR", name: "PAYEER" }, ]; - let stagingPaymentMethod = undefined; + let testPaymentMethod = undefined; let redirectRequired = false; @@ -63,12 +63,12 @@ const generalHandler = (req, res) => { if (fromCurr && toCurr) { const paymentMethod = fromCurr.substr(0, fromCurr.length - 3); - // Loops in staging payment methods array - for (const elem in stagingPaymentMethods) { - if (stagingPaymentMethods[elem].code === paymentMethod) { - stagingPaymentMethod = { - code: stagingPaymentMethods[elem].code, - name: stagingPaymentMethods[elem].name, + // Loops in test payment methods array + for (const elem in testPaymentMethods) { + if (testPaymentMethods[elem].code === paymentMethod) { + testPaymentMethod = { + code: testPaymentMethods[elem].code, + name: testPaymentMethods[elem].name, }; break; } @@ -86,12 +86,17 @@ const generalHandler = (req, res) => { } if (redirectRequired) { - // Redirect to staging url if staging payment method is not undefined - if (stagingPaymentMethod) { + // Redirect to testing url if testPaymentMethod is not undefined + if (testPaymentMethod) { + const testUrl = + process.env.NODE_ENV !== "production" + ? "https://sapi.n.exchange" + : "https://api.n.exchange"; + res.redirect( - `https://api.n.exchange/en/orders/buy-${toCurr.toLowerCase()}-with-${getCur( + `${testUrl}/en/orders/buy-${toCurr.toLowerCase()}-with-${getCur( fromCurr - ).toLowerCase()}?payment_method=${stagingPaymentMethod.name.toLowerCase()}` + ).toLowerCase()}?payment_method=${testPaymentMethod.name.toLowerCase()}` ); return; } From d52e7767c496e50206ac7d4e2ed8a7a5d3680579 Mon Sep 17 00:00:00 2001 From: punit2502 Date: Thu, 21 May 2020 21:06:43 +0530 Subject: [PATCH 4/8] add tests --- index.js | 5 +++++ package.json | 10 +++++++++- test.js | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 65 insertions(+), 1 deletion(-) create mode 100644 test.js diff --git a/index.js b/index.js index 8e43066..d4e8226 100644 --- a/index.js +++ b/index.js @@ -58,6 +58,11 @@ const generalHandler = (req, res) => { // If lang is in path then ignore lang in param delete req.query["lang"]; + } else { + if (languageRedirect) { + lang = langInParam || "en"; + redirectRequired = true; + } } if (fromCurr && toCurr) { diff --git a/package.json b/package.json index 80efebd..b7ebfed 100644 --- a/package.json +++ b/package.json @@ -4,12 +4,20 @@ "description": "", "main": "index.js", "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" + "start": "node index.js", + "dev": "nodemon index.js", + "test": "mocha test.js" }, "author": "", "license": "ISC", "dependencies": { "express": "^4.16.3", "helmet": "^3.21.2" + }, + "devDependencies": { + "chai": "^4.2.0", + "chai-http": "^4.3.0", + "mocha": "^7.1.2", + "nodemon": "^2.0.4" } } diff --git a/test.js b/test.js new file mode 100644 index 0000000..4501071 --- /dev/null +++ b/test.js @@ -0,0 +1,51 @@ +const chai = require("chai"), + chaiHttp = require("chai-http"); + +chai.use(chaiHttp); + +const expect = chai.expect; +const requestUrl = "http://localhost:3000"; +const request = chai.request(requestUrl); + +describe("internal redirects", () => { + it("redirect with lang", () => { + request.get("/").end((err, res) => { + expect(res).to.redirectTo(`${requestUrl}/en`, 200); + }); + }); + + it("redirect when lang in url param", () => { + request.get("/?lang=ru").end((err, res) => { + expect(res).to.have.header("Set-Cookie", "i18next=ru"); + expect(res).to.redirectTo(`${requestUrl}/ru`, 200); + }); + }); + + it("order page uppercase redirect", () => { + request.get("/order/oqmhdw").end((err, res) => { + expect(res).to.redirectTo(`${requestUrl}/en/order/OQMHDW`, 200); + }); + }); + + // it("advcash redirect", () => { + // request.get("/?cur_from=ADVCUSD&cur_to=BTC").end((err, res) => { + // expect(res).to.redirectTo( + // "https://sapi.n.exchange/en/orders/buy-btc-with-usd/?payment_method=advcash", + // 200 + // ); + // }); + // }); +}); + +describe("partner redirects", () => { + it("bestchange card usd to btc", () => { + request + .get("/?ref=RBWW77UMGTU&lang=RU&cur_from=CARDUSD&cur_to=BTC") + .end((err, res) => { + expect(res).to.redirectTo( + `${requestUrl}/ru?ref=RBWW77UMGTU&pair=BTCUSD`, + 200 + ); + }); + }); +}); From a8f1ffc4d8ed6c6ab8e944f0316b4438cf73417c Mon Sep 17 00:00:00 2001 From: punit2502 Date: Thu, 28 May 2020 20:24:50 +0530 Subject: [PATCH 5/8] add sepa payment method and update tests --- index.js | 1 + test.js | 38 ++++++++++++++++++++++++++++---------- 2 files changed, 29 insertions(+), 10 deletions(-) diff --git a/index.js b/index.js index d4e8226..dd56100 100644 --- a/index.js +++ b/index.js @@ -43,6 +43,7 @@ const generalHandler = (req, res) => { const testPaymentMethods = [ { code: "ADVC", name: "ADVCASH" }, { code: "PR", name: "PAYEER" }, + { code: "SEPA", name: "SEPA" }, ]; let testPaymentMethod = undefined; diff --git a/test.js b/test.js index 4501071..7cef04f 100644 --- a/test.js +++ b/test.js @@ -26,18 +26,9 @@ describe("internal redirects", () => { expect(res).to.redirectTo(`${requestUrl}/en/order/OQMHDW`, 200); }); }); - - // it("advcash redirect", () => { - // request.get("/?cur_from=ADVCUSD&cur_to=BTC").end((err, res) => { - // expect(res).to.redirectTo( - // "https://sapi.n.exchange/en/orders/buy-btc-with-usd/?payment_method=advcash", - // 200 - // ); - // }); - // }); }); -describe("partner redirects", () => { +describe("partner card redirect", () => { it("bestchange card usd to btc", () => { request .get("/?ref=RBWW77UMGTU&lang=RU&cur_from=CARDUSD&cur_to=BTC") @@ -48,4 +39,31 @@ describe("partner redirects", () => { ); }); }); + + it("bestchange advcash redirect", () => { + request.get("/?cur_from=ADVCUSD&cur_to=BTC").end((err, res) => { + expect(res).to.redirectTo( + "https://sapi.n.exchange/en/orders/buy-btc-with-usd/?payment_method=advcash", + 200 + ); + }); + }); + + it("bestchange payeer redirect", () => { + request.get("/?cur_from=PRUSD&cur_to=BTC").end((err, res) => { + expect(res).to.redirectTo( + "https://sapi.n.exchange/en/orders/buy-btc-with-usd/?payment_method=payeer", + 200 + ); + }); + }); + + it("bestchange sepa redirect", () => { + request.get("/?cur_from=SEPAUSD&cur_to=BTC").end((err, res) => { + expect(res).to.redirectTo( + "https://sapi.n.exchange/en/orders/buy-btc-with-usd/?payment_method=sepa", + 200 + ); + }); + }); }); From 724617522ecf96fc1a1edca95166634f67963855 Mon Sep 17 00:00:00 2001 From: punit2502 Date: Wed, 8 Jul 2020 18:10:38 +0530 Subject: [PATCH 6/8] password token in header --- index.js | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/index.js b/index.js index dd56100..7b3e51a 100644 --- a/index.js +++ b/index.js @@ -49,6 +49,21 @@ const generalHandler = (req, res) => { let redirectRequired = false; + // remove extra / from url + if (urlPath.charAt(urlPath.length - 1) === "/") { + urlPath = urlPath.substring(0, urlPath.length - 1); + redirectRequired = true; + } + + const isForgotPasswordUrl = /\/forgot-password\/\w+(\/)?$/.test(urlPath); + + if (isForgotPasswordUrl) { + const token = urlPath.split("/")[urlPath.split("/").length - 1]; + urlPath = urlPath.replace(`\/${token}`, ""); + res.header("Set-Cookie", `resetToken=${lang}`); + redirectRequired = true; + } + // Dont add language path in url if set to false if (!languageRedirect) lang = ""; From be192454f12c54f5abbd33a9cf505edb10c5b081 Mon Sep 17 00:00:00 2001 From: punit2502 Date: Wed, 8 Jul 2020 20:54:25 +0530 Subject: [PATCH 7/8] fix url --- index.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/index.js b/index.js index 7b3e51a..03c9361 100644 --- a/index.js +++ b/index.js @@ -117,7 +117,9 @@ const generalHandler = (req, res) => { res.redirect( `${testUrl}/en/orders/buy-${toCurr.toLowerCase()}-with-${getCur( fromCurr - ).toLowerCase()}?payment_method=${testPaymentMethod.name.toLowerCase()}` + ).toLowerCase()}/${getCur(toCurr).toUpperCase()}${getCur( + fromCurr + ).toUpperCase()}/?payment_method=${testPaymentMethod.name.toLowerCase()}` ); return; } From cb0b1f210c37bdc28ef9fba19f581d315cfcbc57 Mon Sep 17 00:00:00 2001 From: punit2502 Date: Wed, 8 Jul 2020 21:19:33 +0530 Subject: [PATCH 8/8] fix cookie --- index.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/index.js b/index.js index 03c9361..0b7ad39 100644 --- a/index.js +++ b/index.js @@ -59,8 +59,9 @@ const generalHandler = (req, res) => { if (isForgotPasswordUrl) { const token = urlPath.split("/")[urlPath.split("/").length - 1]; + res.cookie("resetToken", token); + urlPath = urlPath.replace(`\/${token}`, ""); - res.header("Set-Cookie", `resetToken=${lang}`); redirectRequired = true; } @@ -68,7 +69,7 @@ const generalHandler = (req, res) => { if (!languageRedirect) lang = ""; if (validLanguages.includes(langInPath)) { - res.header("Set-Cookie", `i18next=${lang}`); + res.cookie("i18next", lang); urlPath = urlPath.substr(lang.length + 1);