diff --git a/index.js b/index.js index a6d8f50..0b7ad39 100644 --- a/index.js +++ b/index.js @@ -1,73 +1,148 @@ -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; +const languageRedirect = true; //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(`/order/${orderIdUP}`); + } else { + next(); } }; // General handler for the rest of the URLs -var generalHandler = (req, res) => { +const generalHandler = (req, res) => { + 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"]; + const testPaymentMethods = [ + { code: "ADVC", name: "ADVCASH" }, + { code: "PR", name: "PAYEER" }, + { code: "SEPA", name: "SEPA" }, + ]; + let testPaymentMethod = undefined; let redirectRequired = false; - let params = {}; - if (req.query.cur_from && req.query.cur_to) { + + // 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]; + res.cookie("resetToken", token); + + urlPath = urlPath.replace(`\/${token}`, ""); + redirectRequired = true; + } + + // Dont add language path in url if set to false + if (!languageRedirect) lang = ""; + + if (validLanguages.includes(langInPath)) { + res.cookie("i18next", lang); + + urlPath = urlPath.substr(lang.length + 1); + + // 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) { + const paymentMethod = fromCurr.substr(0, fromCurr.length - 3); + + // 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; + } + } + + 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); + // 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( + `${testUrl}/en/orders/buy-${toCurr.toLowerCase()}-with-${getCur( + fromCurr + ).toLowerCase()}/${getCur(toCurr).toUpperCase()}${getCur( + fromCurr + ).toUpperCase()}/?payment_method=${testPaymentMethod.name.toLowerCase()}` + ); + return; + } + + const redirectUrl = url.format({ + pathname: urlPath === "/" ? `/${lang}` : `/${lang}${urlPath}`, + query: req.query, + }); + + 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!") +); 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..7cef04f --- /dev/null +++ b/test.js @@ -0,0 +1,69 @@ +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); + }); + }); +}); + +describe("partner card redirect", () => { + 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 + ); + }); + }); + + 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 + ); + }); + }); +});