From 7a603b11a5a36b7e2c83e76ecd641f33b9d05242 Mon Sep 17 00:00:00 2001 From: Jeremy <23155614+jsbrn@users.noreply.github.com> Date: Fri, 24 Jan 2020 22:26:26 -0500 Subject: [PATCH 01/18] Redesign front page for v3 --- index.js | 6 +- views/assets/images/money.png | Bin 0 -> 10574 bytes views/assets/stylesheets/custom.css | 8 +++ views/home.hbs | 83 ++++++++++++++++++++-------- views/layouts/main.hbs | 7 +-- 5 files changed, 75 insertions(+), 29 deletions(-) create mode 100644 views/assets/images/money.png diff --git a/index.js b/index.js index dbb4ec1..453b92e 100644 --- a/index.js +++ b/index.js @@ -50,14 +50,14 @@ app.get('/', (request, response, next) => { var selectedCarriers = carriers.filter(c => c.id == (request.query.carrier ? request.query.carrier : "pm")); if (selectedCarriers.length == 0) { next(); return; } - database.get("codes", {carrier: selectedCarriers[0].id}, {}, -1, (codes) => { + database.get("codes", {carrier: selectedCarriers[0].id}, {lastBoost: -1}, 5, (codes) => { codes.forEach(c => c.value = c.value.substring(0, 3)); - codes.sort((a, b) => { return Math.random() > (a.priority ? 0.9 : 0.5) ? 1 : -1; }); + codes.sort((a, b) => { return Math.random() > 0.5 }); response.render("home", { layout: "main.hbs", - codes: utilities.chunkArray(codes, 3), + codes: codes, redirect: request.query.redirect, bad_code: request.query.bad_code, successful_addition: request.query.success, diff --git a/views/assets/images/money.png b/views/assets/images/money.png new file mode 100644 index 0000000000000000000000000000000000000000..c0f0445ea7b8a0e2ea819b3dc72cfbbc723771ea GIT binary patch literal 10574 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 literal 0 HcmV?d00001 diff --git a/views/assets/stylesheets/custom.css b/views/assets/stylesheets/custom.css index 0ba9e0e..7bd3559 100644 --- a/views/assets/stylesheets/custom.css +++ b/views/assets/stylesheets/custom.css @@ -1,3 +1,7 @@ +body { + font-family: 'Open Sans', sans-serif; +} + .bg-color { background: #F4E8D9; } @@ -69,6 +73,10 @@ color: #034045; } +ul { + list-style-image: url('/images/verified.png'); +} + .censored { color: #444; background: rgb(129, 116, 100); diff --git a/views/home.hbs b/views/home.hbs index ab8e1da..c8e3da7 100644 --- a/views/home.hbs +++ b/views/home.hbs @@ -14,17 +14,31 @@ {{/if}} -
- Get $10 off your first month with {{carrier.name}} -
-
- Many cellular providers offer signup rewards if you provide a code during registration. - Choose a carrier, then click the referral code you want to use. If you already have a plan and want to share your referral code, you can do that instead. +
+
+
+ Looking for a cheaper phone plan?
+ Public Mobile has what you need. +
+
+

Switch to {{carrier.name}} for $10 off your first month. It's simple:

+
    +
  1. Order a Public Mobile SIM card.
  2. +
  3. Grab a referral code by clicking one down below.
  4. +
  5. Enter the code while activating your SIM card.
  6. +
  7. Enjoy your $10 bonus and save money on a much better phone plan.
  8. +
+ Stick it to the big telecom companies and stop wasting your hard earned cash: switch to Public Mobile today! +
+
+
-
+ + +
+
+
+ Why Public Mobile? +
- {{#each row as |code|}} - - {{/each}} +
    +
  • Unlimited Canadian talk and text
  • +
  • No overage charges
  • +
  • Cheap plans
  • +
  • Lower your monthly bill by referring others
  • +
  • Keep your current number!
  • +
- {{/each}} - {{/if}} +
+
+
+ Today's Codes + +
+
+ {{#if empty}} + Looks like we're out of codes! Come back later. + {{else}} + {{#each codes as |code|}} +
+
+ + {{code.value}}### +
+
+ {{/each}} + {{/if}} +
+
+
+
{{{body}}}
- - PMReferrals.ca is a third-party tool and is not affiliated with Public Mobile. - If you have any questions or concerns, email admin@pmreferrals.ca. - + PMReferrals.ca is a third-party tool and is not affiliated with Public Mobile.
From c1469b653622b62991b68faae0ca0361e35197a4 Mon Sep 17 00:00:00 2001 From: Jeremy <23155614+jsbrn@users.noreply.github.com> Date: Sat, 25 Jan 2020 02:51:16 -0500 Subject: [PATCH 02/18] Account registration, cookies --- app/validator.js | 8 +- index.js | 186 +++++++++++++++------------- package-lock.json | 155 +++++++++++++++++++++++ package.json | 2 + views/account.hbs | 66 ++++++++++ views/assets/scripts/jquery.js | 2 + views/assets/stylesheets/custom.css | 2 +- views/home.hbs | 15 +-- views/layouts/main.hbs | 9 +- views/login.hbs | 59 +++++++++ views/register.hbs | 64 ++++++++++ views/submit.hbs | 66 ---------- 12 files changed, 465 insertions(+), 169 deletions(-) create mode 100644 views/account.hbs create mode 100644 views/assets/scripts/jquery.js create mode 100644 views/login.hbs create mode 100644 views/register.hbs delete mode 100644 views/submit.hbs diff --git a/app/validator.js b/app/validator.js index 71ac203..12fe9d0 100644 --- a/app/validator.js +++ b/app/validator.js @@ -19,17 +19,17 @@ function isValidPhone(number) { return n_patt.test(number) && number.length == 10; } -function findOnPage(needle, url, callback) { +function verifyCode(code, callback) { const agent = new https.Agent({ rejectUnauthorized: false }); - axios.get(url, { httpsAgent: agent }) + axios.get("https://activate.publicmobile.ca/?raf="+code, { httpsAgent: agent }) .then(function (axios_response) { //if it has the green checkmark it's a valid code callback({ - valid: axios_response.data.includes(needle) + valid: axios_response.data.includes("ok_16x16") }) }) .catch(function (err) { @@ -42,4 +42,4 @@ function findOnPage(needle, url, callback) { module.exports.isValidEmail = isValidEmail; module.exports.isValidPhone = isValidPhone; -module.exports.findOnPage = findOnPage; \ No newline at end of file +module.exports.verifyCode = verifyCode; \ No newline at end of file diff --git a/index.js b/index.js index 453b92e..0e83bec 100644 --- a/index.js +++ b/index.js @@ -11,6 +11,8 @@ const utilities = require('./app/utilities.js'); const mailer = require('./app/mailer.js'); const validator = require('./app/validator.js'); const moment = require('moment'); +var Cookies = require('cookies'); +const bodyParser = require('body-parser'); /*Set the Handlebars options, including the Helpers*/ app.engine('.hbs', exphbs({ @@ -28,6 +30,8 @@ app.use('/images',express.static(path.join(__dirname, 'views/assets/images'))); app.use('/css',express.static(path.join(__dirname, 'views/assets/stylesheets'))); app.use('/scripts',express.static(path.join(__dirname, 'views/assets/scripts'))); +app.use(express.json()); + /*HTTP REQUEST HANDLERS*/ //post all requests to the console or redirect if maintenance @@ -40,36 +44,45 @@ app.all("*", (request, response, next) => { submessage: process.env.SUBMESSAGE }) } else { + //fetch the sessionId cookie + var cookies = new Cookies(request, response); + var sessionId = cookies.get("userSessionId"); + request.sessionId = sessionId; next(); } }); app.get('/', (request, response, next) => { + database.get("accounts", {}, {lastBoost: -1}, 5, (accounts) => { - database.get("carriers", {}, {}, -1, (carriers) => { - var selectedCarriers = carriers.filter(c => c.id == (request.query.carrier ? request.query.carrier : "pm")); - if (selectedCarriers.length == 0) { next(); return; } - database.get("codes", {carrier: selectedCarriers[0].id}, {lastBoost: -1}, 5, (codes) => { - - codes.forEach(c => c.value = c.value.substring(0, 3)); - codes.sort((a, b) => { return Math.random() > 0.5 }); - - response.render("home", { - layout: "main.hbs", - codes: codes, - redirect: request.query.redirect, - bad_code: request.query.bad_code, - successful_addition: request.query.success, - carrier: selectedCarriers[0], - carrier_options: carriers.map((elem) => { elem.selected = elem.id == selectedCarriers[0].id; return elem; }), - empty: codes.length == 0 - }); + accounts.forEach(c => c.code = c.code.substring(0, 3)); + accounts.sort((a, b) => { return Math.random() > 0.5 }); + response.render("home", { + layout: "main.hbs", + loggedIn: request.sessionId != undefined && request.sessionId.length > 0, + accounts: accounts, + bad_code: request.query.bad_code, + successful_addition: request.query.success, + empty: accounts.length == 0 }); }); - +}); + +app.get("/account", (request, response, next) => { + database.get("accounts", {session: request.sessionId}, {}, 1, (results) => { + if (results.length == 0) { + //user not logged in + response.redirect("/login"); + } else { + response.render("account", { + layout: "main.hbs", + account: results[0] + }); + } + }, (error) => {response.send(500);}); }); app.get('/referral/:url', (request, response, next) => { @@ -77,81 +90,43 @@ app.get('/referral/:url', (request, response, next) => { database.get("codes", {url: request.params.url}, {}, 1, function (matching_codes) { if (matching_codes.length == 0) { next(); return; } //404 var code = matching_codes[0]; - database.get("carriers", {id: code.carrier}, {}, -1, (carriers) => { - if (carriers.length == 0) { next(); return; } - var selectedCarrier = carriers[0]; - validator.findOnPage(selectedCarrier.activation_needle, selectedCarrier.activation_url.replace("{{code}}", code.value), (validator_results) => { - if (validator_results.error || !validator_results.valid) { - database.remove("codes", {url: request.params.url, carrier: code.carrier}, (deleted_codes) => { - database.insert("logs", [ - {event_type: "delete", code: code.value, date: new Date()} - ], (inserted_logs) => { - response.redirect("/?carrier="+code.carrier+"&redirect=true&bad_code="+code.value); - }); - }, (err) => {}); - } else { + validator.verifyCode(code.value, (validator_results) => { + if (validator_results.error || !validator_results.valid) { + database.remove("codes", {url: request.params.url, carrier: code.carrier}, (deleted_codes) => { database.insert("logs", [ - {event_type: "view", code: code.value, date: new Date()} + {event_type: "delete", code: code.value, date: new Date()} ], (inserted_logs) => { - response.render("referral", { - layout: "main.hbs", - title: request.params.code, - url: carriers[0].activation_url.replace("{{code}}", code.value), - code: code - }); + response.redirect("/?carrier="+code.carrier+"&redirect=true&bad_code="+code.value); }); - } - }); + }, (err) => {}); + } else { + database.insert("logs", [ + {event_type: "view", code: code.value, date: new Date()} + ], (inserted_logs) => { + response.render("referral", { + layout: "main.hbs", + title: request.params.code, + url: carriers[0].activation_url.replace("{{code}}", code.value), + code: code + }); + }); + } }); }, (err) => response.send(err)); }); -app.get('/submit', (request, response, next) => { - if (request.query.code && request.query.carrier) { - database.get("carriers", {id: request.query.carrier}, {}, -1, (carriers) => { - if (carriers.length == 0) { next(); return; } - var selectedCarrier = carriers[0]; - validator.findOnPage(selectedCarrier.activation_needle, selectedCarrier.activation_url.replace("{{code}}", request.query.code), (validator_results) => { - if (validator_results.error || !validator_results.valid) { - response.redirect("/submit?invalid=true&bad_code="+request.query.code+"&carrier="+selectedCarrier.id); - return; - } - database.get("codes", {value: request.query.code, carrier: selectedCarrier.id}, {}, 1, (results) => { - if (results.length > 0) { - response.redirect("/submit?exists=true&bad_code="+request.query.code+"&carrier="+selectedCarrier.id); - } else { - database.insert("codes", [ - { - value: request.query.code, - priority: false, - url: Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15), - carrier: selectedCarrier.id - } - ], (inserted_codes) => { - database.insert("logs", [ - {event_type: "submit", code: request.query.code, date: new Date()} - ], (results) => { - response.redirect("/?success=true&carrier="+selectedCarrier.id); - }); - }, (err) => {}); - } - }, (err) => response.send(err)); - }); - }); - } else { - database.get("carriers", {}, {}, -1, (carriers) => { - response.render("submit", { - layout: "main.hbs", - title: "Submit your code", - invalid: request.query.invalid, - exists: request.query.exists, - bad_code: request.query.bad_code, - carrier_options: carriers.map((elem) => { elem.selected = elem.id == request.query.carrier; return elem; }) - }); - }); - } - +app.get("/login", (request, response) => { + response.render("login", { + layout: "main.hbs" + }); +}); + + +app.get("/register", (request, response) => { + response.render("register", { + layout: "main.hbs" + }); }); app.get('/faq', (request, response) => { @@ -229,6 +204,45 @@ app.get('/stats', (request, response) => { }); }); +app.get('/logout', (request, response) => { + var cookies = new Cookies(request, response); + cookies.set("userSessionId", ""); + response.redirect("/"); +}); + +app.post('/register', (request, response, next) => { + var cookies = new Cookies(request, response); + console.log(request.body); + database.get("accounts", {username: request.body.username, code: request.body.code}, {}, 1, (results) => { + if (results.length == 0) { + validator.verifyCode(request.body.code, (validator_results) => { + if (!validator_results.valid) { + response.json({success: false, reason: "The code "+request.body.code+" is not valid."}); + return; + } else if (validator_results.error) { + response.json({success: false, reason: "An unknown error occured."}); + } else { + var sessionId = "X"+Math.floor((Math.random() * 100000000)); + database.insert("accounts", [{ + username: request.body.username, + password: request.body.password, + code: request.body.code, + boostPoints: 0, + lastBoost: new Date(), + boostCooldown: 0, + session: sessionId + }], (results) => { + cookies.set("userSessionId", sessionId); + response.json({success: true}); + }) + } + }); + } else { + response.json({success:false, reason: "Username already exists!"}); + } + }, (err) => response.json({success:false, reason: "Database error"})); +}); + //catchall and 404 app.get('*', (request, response) => { response.render("404", { diff --git a/package-lock.json b/package-lock.json index 0f959b7..a76f709 100644 --- a/package-lock.json +++ b/package-lock.json @@ -84,6 +84,79 @@ "tweetnacl": "^0.14.3" } }, + "body-parser": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", + "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", + "requires": { + "bytes": "3.1.0", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "~1.1.2", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "on-finished": "~2.3.0", + "qs": "6.7.0", + "raw-body": "2.4.0", + "type-is": "~1.6.17" + }, + "dependencies": { + "bytes": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", + "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==" + }, + "http-errors": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", + "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.1", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.0" + } + }, + "mime-db": { + "version": "1.43.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.43.0.tgz", + "integrity": "sha512-+5dsGEEovYbT8UY9yD7eE4XTc4UwJ1jBYlgaQQF38ENsKR3wj/8q8RFZrF9WIZpB2V1ArTVFUva8sAul1NzRzQ==" + }, + "mime-types": { + "version": "2.1.26", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.26.tgz", + "integrity": "sha512-01paPWYgLrkqAyrlDorC1uDwl2p3qZT7yl806vW7DvDoxwXi46jsjFbg+WdwotBIk6/MbEhO/dh5aZ5sNj/dWQ==", + "requires": { + "mime-db": "1.43.0" + } + }, + "qs": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", + "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==" + }, + "setprototypeof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", + "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" + }, + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" + }, + "type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "requires": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + } + } + } + }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -141,6 +214,22 @@ "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" }, + "cookies": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/cookies/-/cookies-0.8.0.tgz", + "integrity": "sha512-8aPsApQfebXnuI+537McwYsDtjVxGm8gTIzQI3FDW6t5t/DAhERxtnbEPN/8RX+uZthoz4eCOgloXaE5cYyNow==", + "requires": { + "depd": "~2.0.0", + "keygrip": "~1.1.0" + }, + "dependencies": { + "depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" + } + } + }, "core-util-is": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", @@ -498,6 +587,14 @@ "resolved": "https://registry.npmjs.org/https/-/https-1.0.0.tgz", "integrity": "sha1-PDfHrhqO65ZpBKKtHpdaGUt+06Q=" }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -563,6 +660,14 @@ "verror": "1.10.0" } }, + "keygrip": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/keygrip/-/keygrip-1.1.0.tgz", + "integrity": "sha512-iYSchDJ+liQ8iwbSI2QqsQOvqv58eJCEanyJPJi+Khyu8smkcKSFUCbPwzFcL7YVtZ6eONjqRX/38caJ7QjRAQ==", + "requires": { + "tsscmp": "1.0.6" + } + }, "media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", @@ -791,6 +896,46 @@ "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=" }, + "raw-body": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", + "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", + "requires": { + "bytes": "3.1.0", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "dependencies": { + "bytes": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", + "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==" + }, + "http-errors": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", + "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.1", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.0" + } + }, + "setprototypeof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", + "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" + }, + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" + } + } + }, "request": { "version": "2.88.0", "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", @@ -961,6 +1106,11 @@ "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", "integrity": "sha1-u3PURtonlhBu/MG2AaJT1sRr0Ic=" }, + "toidentifier": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", + "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==" + }, "tough-cookie": { "version": "2.4.3", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", @@ -977,6 +1127,11 @@ } } }, + "tsscmp": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/tsscmp/-/tsscmp-1.0.6.tgz", + "integrity": "sha512-LxhtAkPDTkVCMQjt2h6eBVY28KCjikZqZfMcC15YBeNjkgUpdCfBu5HoiOTDu86v6smE8yOjyEktJ8hlbANHQA==" + }, "tunnel-agent": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", diff --git a/package.json b/package.json index 9d4cc65..b53f5ec 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,8 @@ "license": "ISC", "dependencies": { "axios": "^0.19.0", + "body-parser": "^1.19.0", + "cookies": "^0.8.0", "dotenv": "^6.1.0", "express": "^4.16.3", "express-handlebars": "^3.0.0", diff --git a/views/account.hbs b/views/account.hbs new file mode 100644 index 0000000..225818e --- /dev/null +++ b/views/account.hbs @@ -0,0 +1,66 @@ +
+
+
+ Hi, {{account.username}}! +
+
+ You can manage your account here. +
+
+ {{account.code}} +
+
+ Log out +
+
+
+
+ Boost your code +
+
+ Displays your code on the front page for a period of time. You can only + boost once every 12 hours. +
+
+ +
+
+
+ + + diff --git a/views/assets/scripts/jquery.js b/views/assets/scripts/jquery.js new file mode 100644 index 0000000..a1c07fd --- /dev/null +++ b/views/assets/scripts/jquery.js @@ -0,0 +1,2 @@ +/*! jQuery v3.4.1 | (c) JS Foundation and other contributors | jquery.org/license */ +!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(C,e){"use strict";var t=[],E=C.document,r=Object.getPrototypeOf,s=t.slice,g=t.concat,u=t.push,i=t.indexOf,n={},o=n.toString,v=n.hasOwnProperty,a=v.toString,l=a.call(Object),y={},m=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType},x=function(e){return null!=e&&e===e.window},c={type:!0,src:!0,nonce:!0,noModule:!0};function b(e,t,n){var r,i,o=(n=n||E).createElement("script");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function w(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[o.call(e)]||"object":typeof e}var f="3.4.1",k=function(e,t){return new k.fn.init(e,t)},p=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g;function d(e){var t=!!e&&"length"in e&&e.length,n=w(e);return!m(e)&&!x(e)&&("array"===n||0===t||"number"==typeof t&&0+~]|"+M+")"+M+"*"),U=new RegExp(M+"|>"),X=new RegExp($),V=new RegExp("^"+I+"$"),G={ID:new RegExp("^#("+I+")"),CLASS:new RegExp("^\\.("+I+")"),TAG:new RegExp("^("+I+"|[*])"),ATTR:new RegExp("^"+W),PSEUDO:new RegExp("^"+$),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+R+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\d$/i,K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\([\\da-f]{1,6}"+M+"?|("+M+")|.)","ig"),ne=function(e,t,n){var r="0x"+t-65536;return r!=r||n?t:r<0?String.fromCharCode(r+65536):String.fromCharCode(r>>10|55296,1023&r|56320)},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){T()},ae=be(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{H.apply(t=O.call(m.childNodes),m.childNodes),t[m.childNodes.length].nodeType}catch(e){H={apply:t.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&((e?e.ownerDocument||e:m)!==C&&T(e),e=e||C,E)){if(11!==p&&(u=Z.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!A[t+" "]&&(!v||!v.test(t))&&(1!==p||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&U.test(t)){(s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=k),o=(l=h(t)).length;while(o--)l[o]="#"+s+" "+xe(l[o]);c=l.join(","),f=ee.test(t)&&ye(e.parentNode)||e}try{return H.apply(n,f.querySelectorAll(c)),n}catch(e){A(t,!0)}finally{s===k&&e.removeAttribute("id")}}}return g(t.replace(B,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[k]=!0,e}function ce(e){var t=C.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)b.attrHandle[n[r]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e.namespaceURI,n=(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:m;return r!==C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,E=!i(C),m!==C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),d.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment("")),!e.getElementsByTagName("*").length}),d.getElementsByClassName=K.test(C.getElementsByClassName),d.getById=ce(function(e){return a.appendChild(e).id=k,!C.getElementsByName||!C.getElementsByName(k).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},b.find.CLASS=d.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){a.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll("[id~="+k+"-]").length||v.push("~="),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+k+"+*").length||v.push(".#.+[+~]")}),ce(function(e){e.innerHTML="";var t=C.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")})),(d.matchesSelector=K.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",$)}),v=v.length&&new RegExp(v.join("|")),s=s.length&&new RegExp(s.join("|")),t=K.test(a.compareDocumentPosition),y=t||K.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},D=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)===(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e===C||e.ownerDocument===m&&y(m,e)?-1:t===C||t.ownerDocument===m&&y(m,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e===C?-1:t===C?1:i?-1:o?1:u?P(u,e)-P(u,t):0;if(i===o)return pe(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?pe(a[r],s[r]):a[r]===m?-1:s[r]===m?1:0}),C},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if((e.ownerDocument||e)!==C&&T(e),d.matchesSelector&&E&&!A[t+" "]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){A(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=p[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&p(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function j(e,n,r){return m(n)?k.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?k.grep(e,function(e){return e===n!==r}):"string"!=typeof n?k.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(k.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||q,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:L.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof k?t[0]:t,k.merge(this,k.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:E,!0)),D.test(r[1])&&k.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=E.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(k):k.makeArray(e,this)}).prototype=k.fn,q=k(E);var H=/^(?:parents|prev(?:Until|All))/,O={children:!0,contents:!0,next:!0,prev:!0};function P(e,t){while((e=e[t])&&1!==e.nodeType);return e}k.fn.extend({has:function(e){var t=k(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,he=/^$|^module$|\/(?:java|ecma)script/i,ge={option:[1,""],thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};function ve(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&A(e,t)?k.merge([e],n):n}function ye(e,t){for(var n=0,r=e.length;nx",y.noCloneChecked=!!me.cloneNode(!0).lastChild.defaultValue;var Te=/^key/,Ce=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,Ee=/^([^.]*)(?:\.(.+)|)/;function ke(){return!0}function Se(){return!1}function Ne(e,t){return e===function(){try{return E.activeElement}catch(e){}}()==("focus"===t)}function Ae(e,t,n,r,i,o){var a,s;if("object"==typeof t){for(s in"string"!=typeof n&&(r=r||n,n=void 0),t)Ae(e,s,n,r,t[s],o);return e}if(null==r&&null==i?(i=n,r=n=void 0):null==i&&("string"==typeof n?(i=r,r=void 0):(i=r,r=n,n=void 0)),!1===i)i=Se;else if(!i)return e;return 1===o&&(a=i,(i=function(e){return k().off(e),a.apply(this,arguments)}).guid=a.guid||(a.guid=k.guid++)),e.each(function(){k.event.add(this,t,i,r,n)})}function De(e,i,o){o?(Q.set(e,i,!1),k.event.add(e,i,{namespace:!1,handler:function(e){var t,n,r=Q.get(this,i);if(1&e.isTrigger&&this[i]){if(r.length)(k.event.special[i]||{}).delegateType&&e.stopPropagation();else if(r=s.call(arguments),Q.set(this,i,r),t=o(this,i),this[i](),r!==(n=Q.get(this,i))||t?Q.set(this,i,!1):n={},r!==n)return e.stopImmediatePropagation(),e.preventDefault(),n.value}else r.length&&(Q.set(this,i,{value:k.event.trigger(k.extend(r[0],k.Event.prototype),r.slice(1),this)}),e.stopImmediatePropagation())}})):void 0===Q.get(e,i)&&k.event.add(e,i,ke)}k.event={global:{},add:function(t,e,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=Q.get(t);if(v){n.handler&&(n=(o=n).handler,i=o.selector),i&&k.find.matchesSelector(ie,i),n.guid||(n.guid=k.guid++),(u=v.events)||(u=v.events={}),(a=v.handle)||(a=v.handle=function(e){return"undefined"!=typeof k&&k.event.triggered!==e.type?k.event.dispatch.apply(t,arguments):void 0}),l=(e=(e||"").match(R)||[""]).length;while(l--)d=g=(s=Ee.exec(e[l])||[])[1],h=(s[2]||"").split(".").sort(),d&&(f=k.event.special[d]||{},d=(i?f.delegateType:f.bindType)||d,f=k.event.special[d]||{},c=k.extend({type:d,origType:g,data:r,handler:n,guid:n.guid,selector:i,needsContext:i&&k.expr.match.needsContext.test(i),namespace:h.join(".")},o),(p=u[d])||((p=u[d]=[]).delegateCount=0,f.setup&&!1!==f.setup.call(t,r,h,a)||t.addEventListener&&t.addEventListener(d,a)),f.add&&(f.add.call(t,c),c.handler.guid||(c.handler.guid=n.guid)),i?p.splice(p.delegateCount++,0,c):p.push(c),k.event.global[d]=!0)}},remove:function(e,t,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=Q.hasData(e)&&Q.get(e);if(v&&(u=v.events)){l=(t=(t||"").match(R)||[""]).length;while(l--)if(d=g=(s=Ee.exec(t[l])||[])[1],h=(s[2]||"").split(".").sort(),d){f=k.event.special[d]||{},p=u[d=(r?f.delegateType:f.bindType)||d]||[],s=s[2]&&new RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"),a=o=p.length;while(o--)c=p[o],!i&&g!==c.origType||n&&n.guid!==c.guid||s&&!s.test(c.namespace)||r&&r!==c.selector&&("**"!==r||!c.selector)||(p.splice(o,1),c.selector&&p.delegateCount--,f.remove&&f.remove.call(e,c));a&&!p.length&&(f.teardown&&!1!==f.teardown.call(e,h,v.handle)||k.removeEvent(e,d,v.handle),delete u[d])}else for(d in u)k.event.remove(e,d+t[l],n,r,!0);k.isEmptyObject(u)&&Q.remove(e,"handle events")}},dispatch:function(e){var t,n,r,i,o,a,s=k.event.fix(e),u=new Array(arguments.length),l=(Q.get(this,"events")||{})[s.type]||[],c=k.event.special[s.type]||{};for(u[0]=s,t=1;t\x20\t\r\n\f]*)[^>]*)\/>/gi,qe=/\s*$/g;function Oe(e,t){return A(e,"table")&&A(11!==t.nodeType?t:t.firstChild,"tr")&&k(e).children("tbody")[0]||e}function Pe(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function Re(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Me(e,t){var n,r,i,o,a,s,u,l;if(1===t.nodeType){if(Q.hasData(e)&&(o=Q.access(e),a=Q.set(t,o),l=o.events))for(i in delete a.handle,a.events={},l)for(n=0,r=l[i].length;n")},clone:function(e,t,n){var r,i,o,a,s,u,l,c=e.cloneNode(!0),f=oe(e);if(!(y.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||k.isXMLDoc(e)))for(a=ve(c),r=0,i=(o=ve(e)).length;r").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),E.head.appendChild(r[0])},abort:function(){i&&i()}}});var Vt,Gt=[],Yt=/(=)\?(?=&|$)|\?\?/;k.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Gt.pop()||k.expando+"_"+kt++;return this[e]=!0,e}}),k.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Yt.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Yt.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=m(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Yt,"$1"+r):!1!==e.jsonp&&(e.url+=(St.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||k.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=C[r],C[r]=function(){o=arguments},n.always(function(){void 0===i?k(C).removeProp(r):C[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,Gt.push(r)),o&&m(i)&&i(o[0]),o=i=void 0}),"script"}),y.createHTMLDocument=((Vt=E.implementation.createHTMLDocument("").body).innerHTML="
",2===Vt.childNodes.length),k.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(y.createHTMLDocument?((r=(t=E.implementation.createHTMLDocument("")).createElement("base")).href=E.location.href,t.head.appendChild(r)):t=E),o=!n&&[],(i=D.exec(e))?[t.createElement(i[1])]:(i=we([e],t,o),o&&o.length&&k(o).remove(),k.merge([],i.childNodes)));var r,i,o},k.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(k.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},k.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){k.fn[t]=function(e){return this.on(t,e)}}),k.expr.pseudos.animated=function(t){return k.grep(k.timers,function(e){return t===e.elem}).length},k.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=k.css(e,"position"),c=k(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=k.css(e,"top"),u=k.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),m(t)&&(t=t.call(e,n,k.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},k.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){k.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===k.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===k.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=k(e).offset()).top+=k.css(e,"borderTopWidth",!0),i.left+=k.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-k.css(r,"marginTop",!0),left:t.left-i.left-k.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===k.css(e,"position"))e=e.offsetParent;return e||ie})}}),k.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;k.fn[t]=function(e){return _(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),k.each(["top","left"],function(e,n){k.cssHooks[n]=ze(y.pixelPosition,function(e,t){if(t)return t=_e(e,n),$e.test(t)?k(e).position()[n]+"px":t})}),k.each({Height:"height",Width:"width"},function(a,s){k.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){k.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return _(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?k.css(e,t,i):k.style(e,t,n,i)},s,n?e:void 0,n)}})}),k.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){k.fn[n]=function(e,t){return 0Public Mobile has what you need.
-

Switch to {{carrier.name}} for $10 off your first month. It's simple:

+

Switch to Public Mobile for $10 off your first month. It's simple:

  1. Order a Public Mobile SIM card.
  2. Grab a referral code by clicking one down below.
  3. @@ -72,11 +72,11 @@ {{#if empty}} Looks like we're out of codes! Come back later. {{else}} - {{#each codes as |code|}} + {{#each accounts as |account|}}
    -
    - - {{code.value}}### +
    + + {{account.code}}###
    {{/each}} @@ -84,15 +84,10 @@
- @@ -20,9 +21,13 @@
- Get a referral + {{#if loggedIn}} + My Account + {{else}} + Add your code + Login + {{/if}} Statistics - FAQ
diff --git a/views/login.hbs b/views/login.hbs new file mode 100644 index 0000000..7d9c3d0 --- /dev/null +++ b/views/login.hbs @@ -0,0 +1,59 @@ +
+
+ Log in to PMReferrals.ca +
+
+
+
+ + + +
Error!!!
+
+
+
+ +
+
+
+ + + diff --git a/views/register.hbs b/views/register.hbs new file mode 100644 index 0000000..28ee243 --- /dev/null +++ b/views/register.hbs @@ -0,0 +1,64 @@ +
+
+ Sign up for PMReferrals.ca +
+
+

Add your referral code to our list and start lowering your phone bill!

+
+
+
+
+ + + + +
Error!!!
+
+
+
+ +
+
+
+ + + diff --git a/views/submit.hbs b/views/submit.hbs deleted file mode 100644 index 02eaa3b..0000000 --- a/views/submit.hbs +++ /dev/null @@ -1,66 +0,0 @@ -
- {{#if invalid}} -
-
- {{bad_code}} is not a valid referral code. Try again! -
-
- {{/if}} - {{#if exists}} -
-
- The code {{bad_code}} already exists in our database. -
-
- {{/if}} -
- Submit your Public Mobile or Koodo referral code -
-
-
-
- - -
-
-
- - Cancel -
-
-
- - - - - - From 18f01a09175e4d547e0c8baf6210871f1d89c54d Mon Sep 17 00:00:00 2001 From: Jeremy <23155614+jsbrn@users.noreply.github.com> Date: Sat, 25 Jan 2020 05:55:22 -0500 Subject: [PATCH 03/18] Finished account page, fixed logging in --- app/database.js | 4 +- index.js | 81 +++-- package-lock.json | 475 ++++++++++++++++------------ package.json | 14 +- views/account.hbs | 100 +++--- views/assets/stylesheets/custom.css | 11 + views/home.hbs | 2 +- views/layouts/main.hbs | 3 +- views/login.hbs | 8 +- views/referral.hbs | 4 +- views/register.hbs | 2 +- 11 files changed, 400 insertions(+), 304 deletions(-) diff --git a/app/database.js b/app/database.js index e7210bd..0d0ad3c 100644 --- a/app/database.js +++ b/app/database.js @@ -27,9 +27,9 @@ function disconnect() { }); } -function update(collectionName, query, new_values, onSuccess, onFailure) { +function update(collectionName, query, new_value, onSuccess, onFailure) { var collection = database.collection(collectionName); - collection.update(query, {$set: new_values}, function(err, docs) { + collection.updateMany(query, {$set: new_value}, function(err, docs) { if (err) { console.log(err.message); onFailure(); diff --git a/index.js b/index.js index 0e83bec..df0973b 100644 --- a/index.js +++ b/index.js @@ -48,20 +48,20 @@ app.all("*", (request, response, next) => { var cookies = new Cookies(request, response); var sessionId = cookies.get("userSessionId"); request.sessionId = sessionId; + request.loggedIn = request.sessionId != undefined && request.sessionId.length > 0; next(); } }); app.get('/', (request, response, next) => { - database.get("accounts", {}, {lastBoost: -1}, 5, (accounts) => { - + database.get("accounts", {}, {boostPoints: -1, lastBoost: -1}, 5, (accounts) => { accounts.forEach(c => c.code = c.code.substring(0, 3)); accounts.sort((a, b) => { return Math.random() > 0.5 }); response.render("home", { layout: "main.hbs", - loggedIn: request.sessionId != undefined && request.sessionId.length > 0, + loggedIn: request.loggedIn, accounts: accounts, bad_code: request.query.bad_code, successful_addition: request.query.success, @@ -72,48 +72,39 @@ app.get('/', (request, response, next) => { }); app.get("/account", (request, response, next) => { - database.get("accounts", {session: request.sessionId}, {}, 1, (results) => { - if (results.length == 0) { + database.get("accounts", {}, {boostPoints: -1, lastBoost: -1}, -1, (results) => { + var index = results.findIndex(account => account.session === request.sessionId); + if (index == -1) { //user not logged in response.redirect("/login"); } else { response.render("account", { layout: "main.hbs", - account: results[0] + loggedIn: request.loggedIn, + account: results[index], + rank: index + 1, + totalAccounts: results.length }); } }, (error) => {response.send(500);}); }); app.get('/referral/:url', (request, response, next) => { - - database.get("codes", {url: request.params.url}, {}, 1, function (matching_codes) { - if (matching_codes.length == 0) { next(); return; } //404 - var code = matching_codes[0]; - validator.verifyCode(code.value, (validator_results) => { - if (validator_results.error || !validator_results.valid) { - database.remove("codes", {url: request.params.url, carrier: code.carrier}, (deleted_codes) => { - database.insert("logs", [ - {event_type: "delete", code: code.value, date: new Date()} - ], (inserted_logs) => { - response.redirect("/?carrier="+code.carrier+"&redirect=true&bad_code="+code.value); - }); - }, (err) => {}); - } else { - database.insert("logs", [ - {event_type: "view", code: code.value, date: new Date()} - ], (inserted_logs) => { - response.render("referral", { - layout: "main.hbs", - title: request.params.code, - url: carriers[0].activation_url.replace("{{code}}", code.value), - code: code - }); - }); - } + database.get("accounts", {url: request.params.url}, {}, 1, function (matching_accounts) { + if (matching_accounts.length == 0) { next(); return; } //404 + var account = matching_accounts[0]; + database.insert("logs", [ + {event_type: "view", code: account.code, date: new Date()} + ], (inserted_logs) => { + response.render("referral", { + layout: "main.hbs", + loggedIn: request.loggedIn, + title: account.code, + url: "https://activate.publicmobile.ca/?raf="+account.code, + code: account.code + }); }); }, (err) => response.send(err)); - }); app.get("/login", (request, response) => { @@ -132,6 +123,7 @@ app.get("/register", (request, response) => { app.get('/faq', (request, response) => { response.render("faq", { layout: "main.hbs", + loggedIn: request.loggedIn, title: "FAQ" }); }); @@ -187,6 +179,7 @@ app.get('/stats', (request, response) => { response.render("stats", { layout: "main.hbs", + loggedIn: request.loggedIn, title: "Statistics", days: days, totalViewCount: totalViewCount, @@ -210,9 +203,27 @@ app.get('/logout', (request, response) => { response.redirect("/"); }); +app.post("/boost", (request, response) => { + +}); + +app.post('/login', (request, response, next) => { + var cookies = new Cookies(request, response); + database.get("accounts", {username: request.body.username, password: request.body.password}, {}, 1, (results) => { + if (results.length > 0) { + var sessionId = "X"+Math.floor((Math.random() * 100000000)); + database.update("accounts", {username: request.body.username}, {session: sessionId}, (results) => { + cookies.set("userSessionId", sessionId); + response.json({success: true}); + }, (error) => {response.json({success: false, reason: "Database error"})}); + } else { + response.json({success:false, reason: "Incorrect username or password!"}); + } + }, (err) => response.json({success:false, reason: "Database error"})); +}); + app.post('/register', (request, response, next) => { var cookies = new Cookies(request, response); - console.log(request.body); database.get("accounts", {username: request.body.username, code: request.body.code}, {}, 1, (results) => { if (results.length == 0) { validator.verifyCode(request.body.code, (validator_results) => { @@ -227,6 +238,9 @@ app.post('/register', (request, response, next) => { username: request.body.username, password: request.body.password, code: request.body.code, + url: [...Array(8).keys()] + .map(e => String.fromCharCode(Math.floor(Math.random() * (122-97)) + 97)) + .reduce((total, curr) => { return total+""+curr; }), boostPoints: 0, lastBoost: new Date(), boostCooldown: 0, @@ -247,6 +261,7 @@ app.post('/register', (request, response, next) => { app.get('*', (request, response) => { response.render("404", { layout: "main.hbs", + loggedIn: request.loggedIn, title: "Not found" }); }); diff --git a/package-lock.json b/package-lock.json index a76f709..0a5d538 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,12 +5,27 @@ "requires": true, "dependencies": { "accepts": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.5.tgz", - "integrity": "sha1-63d99gEXI6OxTopywIBcjoZ0a9I=", + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", + "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", "requires": { - "mime-types": "~2.1.18", - "negotiator": "0.6.1" + "mime-types": "~2.1.24", + "negotiator": "0.6.2" + }, + "dependencies": { + "mime-db": { + "version": "1.43.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.43.0.tgz", + "integrity": "sha512-+5dsGEEovYbT8UY9yD7eE4XTc4UwJ1jBYlgaQQF38ENsKR3wj/8q8RFZrF9WIZpB2V1ArTVFUva8sAul1NzRzQ==" + }, + "mime-types": { + "version": "2.1.26", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.26.tgz", + "integrity": "sha512-01paPWYgLrkqAyrlDorC1uDwl2p3qZT7yl806vW7DvDoxwXi46jsjFbg+WdwotBIk6/MbEhO/dh5aZ5sNj/dWQ==", + "requires": { + "mime-db": "1.43.0" + } + } } }, "ajv": { @@ -63,12 +78,11 @@ "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==" }, "axios": { - "version": "0.19.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.19.0.tgz", - "integrity": "sha512-1uvKqKQta3KBxIz14F2v06AEHZ/dIoeKfbTRkK1E5oqjDnuEerLmYTgJB5AiQZHJcljpg1TuRzdjDR06qNk0DQ==", + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.19.2.tgz", + "integrity": "sha512-fjgm5MvRHLhx+osE2xoekY70AhARk3a6hkN+3Io1jc00jtquGvxYlKlsFUhmUET0V5te6CcZI7lcv2Ym61mjHA==", "requires": { - "follow-redirects": "1.5.10", - "is-buffer": "^2.0.2" + "follow-redirects": "1.5.10" } }, "balanced-match": { @@ -84,6 +98,15 @@ "tweetnacl": "^0.14.3" } }, + "bl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-2.2.0.tgz", + "integrity": "sha512-wbgvOpqopSr7uq6fJrLH8EsvYMJf9gzfo2jCsL2eTy75qXPukA4pCgHamOQkZtY5vmfVtjB+P3LNlMHW5CEZXA==", + "requires": { + "readable-stream": "^2.3.5", + "safe-buffer": "^5.1.1" + } + }, "body-parser": { "version": "1.19.0", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", @@ -160,7 +183,7 @@ "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha1-PH/L9SnYcibz0vUrlm/1Jx60Qd0=", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -171,11 +194,6 @@ "resolved": "https://registry.npmjs.org/bson/-/bson-1.1.3.tgz", "integrity": "sha512-TdiJxMVnodVS7r0BdL42y/pqC9cL2iKynVwA0Ho3qbsQYr428veL3l7BQyuqiw+Q5SqqoT0m4srSY/BlZ9AxXg==" }, - "bytes": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", - "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=" - }, "caseless": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", @@ -189,15 +207,31 @@ "delayed-stream": "~1.0.0" } }, + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "optional": true + }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" }, "content-disposition": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", - "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ=" + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", + "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", + "requires": { + "safe-buffer": "5.1.2" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + } + } }, "content-type": { "version": "1.0.4", @@ -205,9 +239,9 @@ "integrity": "sha1-4TjMdeBAxyexlm/l5fjJruJW/js=" }, "cookie": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", - "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=" + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", + "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==" }, "cookie-signature": { "version": "1.0.6", @@ -252,12 +286,11 @@ } }, "define-properties": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.2.tgz", - "integrity": "sha1-g6c/L+pWmJj7c3GTyPhzyvbUXJQ=", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", "requires": { - "foreach": "^2.0.5", - "object-keys": "^1.0.8" + "object-keys": "^1.0.12" } }, "delayed-stream": { @@ -265,6 +298,11 @@ "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" }, + "denque": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/denque/-/denque-1.4.1.tgz", + "integrity": "sha512-OfzPuSZKGcgr96rf1oODnfjqBFmr1DVoc/TrItj3Ohe0Ah1C5WX5Baquw/9U9KovnQ88EqmJbD66rKYUQYN1tQ==" + }, "depd": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", @@ -276,9 +314,9 @@ "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" }, "dotenv": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-6.1.0.tgz", - "integrity": "sha512-/veDn2ztgRlB7gKmE3i9f6CmDIyXAy6d5nBq+whO9SLX+Zs1sXEgFLPi+aSuWqUuusMfbi84fT8j34fs1HaYUw==" + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-6.2.0.tgz", + "integrity": "sha512-HygQCKUBSFl8wKQZBSemMywRWcEDNidvNbjGVyZu3nbZ8qq9ubiPoGLMdRDpfSrpkkm9BXYFkpKxxFX38o/76w==" }, "ecc-jsbn": { "version": "0.1.2", @@ -310,87 +348,59 @@ "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" }, "express": { - "version": "4.16.3", - "resolved": "https://registry.npmjs.org/express/-/express-4.16.3.tgz", - "integrity": "sha1-avilAjUNsyRuzEvs9rWjTSL37VM=", + "version": "4.17.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", + "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", "requires": { - "accepts": "~1.3.5", + "accepts": "~1.3.7", "array-flatten": "1.1.1", - "body-parser": "1.18.2", - "content-disposition": "0.5.2", + "body-parser": "1.19.0", + "content-disposition": "0.5.3", "content-type": "~1.0.4", - "cookie": "0.3.1", + "cookie": "0.4.0", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "~1.1.2", "encodeurl": "~1.0.2", "escape-html": "~1.0.3", "etag": "~1.8.1", - "finalhandler": "1.1.1", + "finalhandler": "~1.1.2", "fresh": "0.5.2", "merge-descriptors": "1.0.1", "methods": "~1.1.2", "on-finished": "~2.3.0", - "parseurl": "~1.3.2", + "parseurl": "~1.3.3", "path-to-regexp": "0.1.7", - "proxy-addr": "~2.0.3", - "qs": "6.5.1", - "range-parser": "~1.2.0", - "safe-buffer": "5.1.1", - "send": "0.16.2", - "serve-static": "1.13.2", - "setprototypeof": "1.1.0", - "statuses": "~1.4.0", - "type-is": "~1.6.16", + "proxy-addr": "~2.0.5", + "qs": "6.7.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.1.2", + "send": "0.17.1", + "serve-static": "1.14.1", + "setprototypeof": "1.1.1", + "statuses": "~1.5.0", + "type-is": "~1.6.18", "utils-merge": "1.0.1", "vary": "~1.1.2" }, "dependencies": { - "body-parser": { - "version": "1.18.2", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.2.tgz", - "integrity": "sha1-h2eKGdhLR9hZuDGZvVm84iKxBFQ=", - "requires": { - "bytes": "3.0.0", - "content-type": "~1.0.4", - "debug": "2.6.9", - "depd": "~1.1.1", - "http-errors": "~1.6.2", - "iconv-lite": "0.4.19", - "on-finished": "~2.3.0", - "qs": "6.5.1", - "raw-body": "2.3.2", - "type-is": "~1.6.15" - } - }, - "iconv-lite": { - "version": "0.4.19", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz", - "integrity": "sha512-oTZqweIP51xaGPI4uPa56/Pri/480R+mo7SeU+YETByQNhDG55ycFyNLIgta9vXhILrxXDmF7ZGhqZIcuN0gJQ==" - }, - "raw-body": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.2.tgz", - "integrity": "sha1-vNYMd9Prk83gBQKVw/N5OJvIj4k=", - "requires": { - "bytes": "3.0.0", - "http-errors": "1.6.2", - "iconv-lite": "0.4.19", - "unpipe": "1.0.0" - } + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" } } }, "express-handlebars": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/express-handlebars/-/express-handlebars-3.0.0.tgz", - "integrity": "sha1-gKBwu4GbCeSvLKbQeA91zgXnXC8=", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/express-handlebars/-/express-handlebars-3.1.0.tgz", + "integrity": "sha512-7QlaXnSREMmN5P2o4gmpUZDfJlLtfBka9d6r7/ccXaU7rPp76odw9YYtwZYdIiha2JqwiaG6o2Wu6NZJQ0u7Fg==", "requires": { - "glob": "^6.0.4", + "glob": "^7.1.3", "graceful-fs": "^4.1.2", - "handlebars": "^4.0.5", - "object.assign": "^4.0.3", - "promise": "^7.0.0" + "handlebars": "^4.1.2", + "object.assign": "^4.1.0", + "promise": "^8.0.2" } }, "extend": { @@ -414,16 +424,16 @@ "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" }, "finalhandler": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz", - "integrity": "sha1-7r9O2EAHnIP0JJA4ydcDAIMBsQU=", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", "requires": { "debug": "2.6.9", "encodeurl": "~1.0.2", "escape-html": "~1.0.3", "on-finished": "~2.3.0", - "parseurl": "~1.3.2", - "statuses": "~1.4.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", "unpipe": "~1.0.0" } }, @@ -445,11 +455,6 @@ } } }, - "foreach": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz", - "integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k=" - }, "forever-agent": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", @@ -475,10 +480,15 @@ "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, "function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha1-pWiZ0+o8m6uHS7l3O3xe3pL0iV0=" + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" }, "getpass": { "version": "0.1.7", @@ -489,26 +499,27 @@ } }, "glob": { - "version": "6.0.4", - "resolved": "https://registry.npmjs.org/glob/-/glob-6.0.4.tgz", - "integrity": "sha1-DwiGD2oVUSey+t1PnOJLGqtuTSI=", + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", "requires": { + "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", - "minimatch": "2 || 3", + "minimatch": "^3.0.4", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, "graceful-fs": { - "version": "4.1.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", - "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=" + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", + "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==" }, "handlebars": { - "version": "4.5.3", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.5.3.tgz", - "integrity": "sha512-3yPecJoJHK/4c6aZhSvxOyG4vJKDshV36VHp0iVCDVh7o9w2vwi3NSnL2MMPj3YdduqaBcu7cGbggJQM0br9xA==", + "version": "4.7.2", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.2.tgz", + "integrity": "sha512-4PwqDL2laXtTWZghzzCtunQUTLbo31pcCJrd/B/9JP8XbhVzpS5ZXuKqlOzsd1rtcaLo4KqAn8nl8mkknS4MHw==", "requires": { "neo-async": "^2.6.0", "optimist": "^0.6.1", @@ -531,30 +542,26 @@ } }, "has-symbols": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz", - "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=" + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==" }, "http-errors": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.2.tgz", - "integrity": "sha1-CgAsyFcHGSp+eUbO7cERVfYOxzY=", + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.3.tgz", + "integrity": "sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw==", "requires": { - "depd": "1.1.1", - "inherits": "2.0.3", - "setprototypeof": "1.0.3", - "statuses": ">= 1.3.1 < 2" + "depd": "~1.1.2", + "inherits": "2.0.4", + "setprototypeof": "1.1.1", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.0" }, "dependencies": { - "depd": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.1.tgz", - "integrity": "sha1-V4O04cRZ8G+lyif5kfPQbnoxA1k=" - }, - "setprototypeof": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.0.3.tgz", - "integrity": "sha1-ZlZ+NwQ+608E2RvWWMDL77VbjgQ=" + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" } } }, @@ -610,20 +617,20 @@ "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" }, "ipaddr.js": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.6.0.tgz", - "integrity": "sha1-4/o1e3c9phnybpXwSdBVxyeW+Gs=" - }, - "is-buffer": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.4.tgz", - "integrity": "sha512-Kq1rokWXOPXWuaMAqZiJW4XxsmD9zGx9q4aePabbn3qCRGedtH7Cm+zV8WETitMfu1wdh+Rvd6w5egwSngUX2A==" + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.0.tgz", + "integrity": "sha512-M4Sjn6N/+O6/IXSJseKqHoFc+5FdGJ22sXqnjTpdZweHK64MzEPAyQZyEU3R/KRv2GLoa7nNtg/C2Ev6m7z+eA==" }, "is-typedarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, "isstream": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", @@ -690,9 +697,9 @@ "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" }, "mime": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", - "integrity": "sha1-Eh+evEnjdm8xGnbh+hyAA8SwOqY=" + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" }, "mime-db": { "version": "1.33.0", @@ -710,7 +717,7 @@ "minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha1-UWbihkV/AzBgZL5Ul+jbsMPTIIM=", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "requires": { "brace-expansion": "^1.1.7" } @@ -726,11 +733,13 @@ "integrity": "sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg==" }, "mongodb": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.3.4.tgz", - "integrity": "sha512-6fmHu3FJTpeZxacJcfjUGIP3BSteG0l2cxLkSrf1nnnS1OrlnVGiP9P/wAC4aB6dM6H4vQ2io8YDjkuPkje7AA==", + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.5.2.tgz", + "integrity": "sha512-Lxt4th2tK2MxmkDBR5cMik+xEnkvhwg0BC5kGcHm9RBwaNEsrIryvV5istGXOHbnif5KslMpY1FbX6YbGJ/Trg==", "requires": { + "bl": "^2.2.0", "bson": "^1.1.1", + "denque": "^1.4.1", "require_optional": "^1.0.1", "safe-buffer": "^5.1.2", "saslprep": "^1.0.0" @@ -749,19 +758,19 @@ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" }, "negotiator": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", - "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=" + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", + "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==" }, "neo-async": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.0.tgz", - "integrity": "sha512-MFh0d/Wa7vkKO3Y3LlacqAEeHK0mckVqzDieUKTT+KGxi+zIpeVsFxymkIiRpbpDziHc290Xr9A1O4Om7otoRA==" + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.1.tgz", + "integrity": "sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw==" }, "nodemailer": { - "version": "4.6.8", - "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-4.6.8.tgz", - "integrity": "sha512-A3s7EM/426OBIZbLHXq2KkgvmKbn2Xga4m4G+ZUA4IaZvG8PcZXrFh+2E4VaS2o+emhuUVRnzKN2YmpkXQ9qwA==" + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-4.7.0.tgz", + "integrity": "sha512-IludxDypFpYw4xpzKdMAozBSkzKHmNBvGanUREjJItgJ2NYcK/s8+PggVhj7c2yGFQykKsnnmv1+Aqo0ZfjHmw==" }, "nodemailer-direct-transport": { "version": "3.3.2", @@ -773,9 +782,9 @@ } }, "nodemailer-express-handlebars": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/nodemailer-express-handlebars/-/nodemailer-express-handlebars-3.0.0.tgz", - "integrity": "sha1-atkTu6dOGG0pgxzpvuMP00uPmL4=", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/nodemailer-express-handlebars/-/nodemailer-express-handlebars-3.1.0.tgz", + "integrity": "sha512-JLt+lAlo/D3TfpVnDY+imLHAAonX5L9FEHaczyiPxWCH259bsfxEjPSWl/rWgnvcoFT8uC/hwHi/I0ScFmHlIQ==", "requires": { "express-handlebars": "^3.0.0" } @@ -799,14 +808,14 @@ "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==" }, "object-keys": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.11.tgz", - "integrity": "sha1-xUYBd4rVYPEULODgG8yotW0TQm0=" + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" }, "object.assign": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", - "integrity": "sha1-lovxEA15Vrs8oIbwBvhGs7xACNo=", + "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", "requires": { "define-properties": "^1.1.2", "function-bind": "^1.1.1", @@ -840,9 +849,9 @@ } }, "parseurl": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz", - "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M=" + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" }, "path-is-absolute": { "version": "1.0.1", @@ -859,21 +868,26 @@ "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, "promise": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", - "integrity": "sha1-BktyYCsY+Q8pGSuLG8QY/9Hr078=", + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/promise/-/promise-8.0.3.tgz", + "integrity": "sha512-HeRDUL1RJiLhyA0/grn+PTShlBAcLuh/1BJGtrvjwbvRDCTLLMEz9rOGCV+R3vHY4MixIuoMEd9Yq/XvsTPcjw==", "requires": { - "asap": "~2.0.3" + "asap": "~2.0.6" } }, "proxy-addr": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.3.tgz", - "integrity": "sha512-jQTChiCJteusULxjBp8+jftSQE5Obdl3k4cnmLA6WXtK6XFuWRnvVL7aCiBqaLPM8c4ph0S4tKna8XvmIwEnXQ==", + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.5.tgz", + "integrity": "sha512-t/7RxHXPH6cJtP0pRG6smSr9QJidhB+3kXu0KgXnbGYMgzEnUxRQ4/LDdfOwZEMyIh3/xHb8PX3t+lfL9z+YVQ==", "requires": { "forwarded": "~0.1.2", - "ipaddr.js": "1.6.0" + "ipaddr.js": "1.9.0" } }, "psl": { @@ -887,14 +901,14 @@ "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" }, "qs": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz", - "integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A==" + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", + "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==" }, "range-parser": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", - "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=" + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" }, "raw-body": { "version": "2.4.0", @@ -936,6 +950,20 @@ } } }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, "request": { "version": "2.88.0", "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", @@ -1027,9 +1055,9 @@ "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" }, "send": { - "version": "0.16.2", - "resolved": "https://registry.npmjs.org/send/-/send-0.16.2.tgz", - "integrity": "sha1-bsyh4PjBVtFBWXVZhI32RzCmu8E=", + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", + "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", "requires": { "debug": "2.6.9", "depd": "~1.1.2", @@ -1038,29 +1066,36 @@ "escape-html": "~1.0.3", "etag": "~1.8.1", "fresh": "0.5.2", - "http-errors": "~1.6.2", - "mime": "1.4.1", - "ms": "2.0.0", + "http-errors": "~1.7.2", + "mime": "1.6.0", + "ms": "2.1.1", "on-finished": "~2.3.0", - "range-parser": "~1.2.0", - "statuses": "~1.4.0" + "range-parser": "~1.2.1", + "statuses": "~1.5.0" + }, + "dependencies": { + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" + } } }, "serve-static": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.2.tgz", - "integrity": "sha1-CV6Ecv1bRiN9tQzkhqQ/S4bGzsE=", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", + "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==", "requires": { "encodeurl": "~1.0.2", "escape-html": "~1.0.3", - "parseurl": "~1.3.2", - "send": "0.16.2" + "parseurl": "~1.3.3", + "send": "0.17.1" } }, "setprototypeof": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", - "integrity": "sha1-0L2FU2iHtv58DYGMuWLZ2RxU5lY=" + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", + "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" }, "smtp-connection": { "version": "2.12.0", @@ -1102,9 +1137,17 @@ } }, "statuses": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", - "integrity": "sha1-u3PURtonlhBu/MG2AaJT1sRr0Ic=" + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } }, "toidentifier": { "version": "1.0.0", @@ -1146,30 +1189,37 @@ "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" }, "type-is": { - "version": "1.6.16", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.16.tgz", - "integrity": "sha1-+JzjQVQcZysl7nrjxz3uOyvlAZQ=", + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", "requires": { "media-typer": "0.3.0", - "mime-types": "~2.1.18" + "mime-types": "~2.1.24" + }, + "dependencies": { + "mime-db": { + "version": "1.43.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.43.0.tgz", + "integrity": "sha512-+5dsGEEovYbT8UY9yD7eE4XTc4UwJ1jBYlgaQQF38ENsKR3wj/8q8RFZrF9WIZpB2V1ArTVFUva8sAul1NzRzQ==" + }, + "mime-types": { + "version": "2.1.26", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.26.tgz", + "integrity": "sha512-01paPWYgLrkqAyrlDorC1uDwl2p3qZT7yl806vW7DvDoxwXi46jsjFbg+WdwotBIk6/MbEhO/dh5aZ5sNj/dWQ==", + "requires": { + "mime-db": "1.43.0" + } + } } }, "uglify-js": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.5.1.tgz", - "integrity": "sha512-kI+3c+KphOAKIikQsZoT2oDsVYH5qvhpTtFObfMCdhPAYnjSvmW4oTWMhvDD4jtAGHJwztlBXQgozGcq3Xw9oQ==", + "version": "3.7.6", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.7.6.tgz", + "integrity": "sha512-yYqjArOYSxvqeeiYH2VGjZOqq6SVmhxzaPjJC1W2F9e+bqvFL9QXQ2osQuKUFjM2hGjKG2YclQnRKWQSt/nOTQ==", "optional": true, "requires": { - "commander": "~2.19.0", + "commander": "~2.20.3", "source-map": "~0.6.1" - }, - "dependencies": { - "commander": { - "version": "2.19.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.19.0.tgz", - "integrity": "sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg==", - "optional": true - } } }, "underscore": { @@ -1190,6 +1240,11 @@ "punycode": "^2.1.0" } }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, "utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", diff --git a/package.json b/package.json index b53f5ec..cbd84c8 100644 --- a/package.json +++ b/package.json @@ -9,18 +9,18 @@ "author": "", "license": "ISC", "dependencies": { - "axios": "^0.19.0", + "axios": "^0.19.2", "body-parser": "^1.19.0", "cookies": "^0.8.0", - "dotenv": "^6.1.0", - "express": "^4.16.3", - "express-handlebars": "^3.0.0", + "dotenv": "^6.2.0", + "express": "^4.17.1", + "express-handlebars": "^3.1.0", "https": "^1.0.0", "moment": "^2.24.0", - "mongodb": "^3.3.4", - "nodemailer": "^4.6.8", + "mongodb": "^3.5.2", + "nodemailer": "^4.7.0", "nodemailer-direct-transport": "^3.3.2", - "nodemailer-express-handlebars": "^3.0.0", + "nodemailer-express-handlebars": "^3.1.0", "request": "^2.88.0" } } diff --git a/views/account.hbs b/views/account.hbs index 225818e..12efeda 100644 --- a/views/account.hbs +++ b/views/account.hbs @@ -1,64 +1,78 @@
-
-
- Hi, {{account.username}}! +
+
+
+ Hi, {{account.username}}! +
+
+ You can manage your account here. +
+
+ {{account.code}} +
+
+ Log out +
-
- You can manage your account here. -
-
- {{account.code}} -
-
- Log out +
+
+ Current Rank +
+
+ {{rank}}(out of {{totalAccounts}}) +
+ Only the top 5 codes are visible on the front page. Keep boosting your code to stay on top! +
-
-
- Boost your code -
-
- Displays your code on the front page for a period of time. You can only - boost once every 12 hours. +
+
+
+ Boost your code +
+
+ Displays your code on the front page for a period of time. You can only + boost once every 12 hours. +
+
+ +
+ Last boost: {{account.lastBoost}} +
-
- +
+
+ Share PMReferrals.ca +
+
+ Share this link with others. It takes them to the front page. + The more people see it, the higher your code will rank. +
+
+ https://pmreferrals.ca/{{account.url}} +
+
{{{body}}} -
- PMReferrals.ca is a third-party tool and is not affiliated with Public Mobile. -
\ No newline at end of file From 92b99dea0a9d1cdb9a170ba4a020f8caf8d0128f Mon Sep 17 00:00:00 2001 From: Jeremy <23155614+jsbrn@users.noreply.github.com> Date: Sat, 25 Jan 2020 11:15:05 -0500 Subject: [PATCH 06/18] Fixed registration validation, plus some QoL stuff --- index.js | 26 +++++++++++++++++++++++--- views/home.hbs | 7 ++++--- views/login.hbs | 6 ++++-- views/register.hbs | 8 +++++--- 4 files changed, 36 insertions(+), 11 deletions(-) diff --git a/index.js b/index.js index 2501817..6efd151 100644 --- a/index.js +++ b/index.js @@ -239,11 +239,29 @@ app.post('/login', (request, response, next) => { app.post('/register', (request, response, next) => { var cookies = new Cookies(request, response); - database.get("accounts", {username: request.body.username, code: request.body.code}, {}, 1, (results) => { + + if (!request.body.password || !request.body.username || !request.body.code) { + response.json({success:false,reason:"Looks like you're missing something."}); + return; + } + + request.body.code = request.body.code.toUpperCase(); + + if (request.body.password.length < 6) { + response.json({success:false,reason:"Your password must be at least 6 characters long."}); + return; + } + + if (request.body.username.length < 4) { + response.json({success:false,reason:"Your username must be at least 4 characters long."}); + return; + } + + database.get("accounts", {$or: [{code: request.body.code}, {username: request.body.username}]}, {}, -1, (results) => { if (results.length == 0) { validator.verifyCode(request.body.code, (validator_results) => { if (!validator_results.valid) { - response.json({success: false, reason: "The code "+request.body.code+" is not valid."}); + response.json({success: false, reason: request.body.code+" is not a valid referral code."}); return; } else if (validator_results.error) { response.json({success: false, reason: "An unknown error occured."}); @@ -268,7 +286,9 @@ app.post('/register', (request, response, next) => { } }); } else { - response.json({success:false, reason: "Username already exists!"}); + response.json({success:false, reason: results[0].username === request.body.username + ? "That username has been taken." + : "This code has been registered already."}); } }, (err) => response.json({success:false, reason: "Database error"})); }); diff --git a/views/home.hbs b/views/home.hbs index 7ae9324..1814583 100644 --- a/views/home.hbs +++ b/views/home.hbs @@ -71,9 +71,10 @@
-
- PMReferrals.ca is a third-party tool and is not affiliated with Public Mobile. -
+
+ +
+ PMReferrals.ca is a third-party tool and is not affiliated with Public Mobile.
- - - \ No newline at end of file diff --git a/views/privacy.hbs b/views/privacy.hbs new file mode 100644 index 0000000..15a1759 --- /dev/null +++ b/views/privacy.hbs @@ -0,0 +1,28 @@ +
+
+

Privacy Statement

+

+ As somebody who is very privacy-oriented, I tried to design this site to collect as little information as possible. + I do not collect any emails, phone numbers or other identifiable information, because I don't need to. + Below is a summary of the (minimal) information PMReferrals collects and keeps track of about it's users. +

+
User Information
+

+ When you create an account, the website stores your username and a password hash (not your real password). + It also stores some meta data about your account, such as your "boost" score and session ID. + PMReferrals accounts do not require an email or phone number, and as such cannot be used to identify the user. +

+
Cookies
+

+ This website uses just one cookie, and it contains nothing but a randomly generated session ID to ensure + that you stay logged in. The session ID is randomized every time you log in, and read on each page load. + It expires one week after the most recent login. +

+
Tracking and Fingerprinting
+

+ The website does not currently use any fingerprinting techniques to identify anonymous users. + However, in the near future I will need to ensure that sharable links are not abused by the owner for a higher rank. + At that point I will disclose the techniques I decide to use to accomplish this. +

+
+
\ No newline at end of file diff --git a/views/register.hbs b/views/register.hbs index d8e774c..4473679 100644 --- a/views/register.hbs +++ b/views/register.hbs @@ -3,11 +3,17 @@ Sign up for PMReferrals.ca
- Add your referral code to our list and start lowering your phone bill! + + Add your referral code to our list and start lowering your phone bill! +
+ You can have a look at our privacy statement here. +
+ By registering, you confirm that you have read, understand and accept the statement as is. +
-
-
+
+
-
diff --git a/views/login.hbs b/views/login.hbs index e94030c..7fd041f 100644 --- a/views/login.hbs +++ b/views/login.hbs @@ -8,11 +8,6 @@
-
diff --git a/views/privacy.hbs b/views/privacy.hbs index 15a1759..c82e7d2 100644 --- a/views/privacy.hbs +++ b/views/privacy.hbs @@ -3,24 +3,31 @@

Privacy Statement

As somebody who is very privacy-oriented, I tried to design this site to collect as little information as possible. - I do not collect any emails, phone numbers or other identifiable information, because I don't need to. - Below is a summary of the (minimal) information PMReferrals collects and keeps track of about it's users. + I do not collect any emails, phone numbers or other identifiable information, because I don't need to. + Below is a summary of the (minimal) information PMReferrals tracks.

User Information

- When you create an account, the website stores your username and a password hash (not your real password). + When you create an account, the website stores your username and a password hash (not your real password). It also stores some meta data about your account, such as your "boost" score and session ID. PMReferrals accounts do not require an email or phone number, and as such cannot be used to identify the user.

+
User Activity
+

+ The website maintains an aggregated list of daily statistics regarding the number of codes viewed and submitted, + and the times those events occurred. These statistics don't contain any user information. +

Cookies

This website uses just one cookie, and it contains nothing but a randomly generated session ID to ensure - that you stay logged in. The session ID is randomized every time you log in, and read on each page load. - It expires one week after the most recent login. + that you stay logged in. The session ID is randomized every time you log in, and accessed on each page load + (the navbar depends on it). + The cookie expires one week after the most recent login.

Tracking and Fingerprinting

The website does not currently use any fingerprinting techniques to identify anonymous users. + It does not keep records of IP addresses. However, in the near future I will need to ensure that sharable links are not abused by the owner for a higher rank. At that point I will disclose the techniques I decide to use to accomplish this.

diff --git a/views/register.hbs b/views/register.hbs index 4473679..c8f3e6b 100644 --- a/views/register.hbs +++ b/views/register.hbs @@ -8,17 +8,12 @@
You can have a look at our privacy statement here.
- By registering, you confirm that you have read, understand and accept the statement as is. + By registering, you confirm that you have read and are OK with what it says.
- From c889ec43c930044384df6f4ec5e610501ba2eae0 Mon Sep 17 00:00:00 2001 From: Jeremy <23155614+jsbrn@users.noreply.github.com> Date: Sat, 25 Jan 2020 13:48:27 -0500 Subject: [PATCH 09/18] Reimplement logging, add new log events --- index.js | 60 ++++++++++++++++++++++++++++++++++++++++++----- views/account.hbs | 6 ++--- views/stats.hbs | 12 ++++++++-- 3 files changed, 66 insertions(+), 12 deletions(-) diff --git a/index.js b/index.js index 97a1877..661dfd9 100644 --- a/index.js +++ b/index.js @@ -163,7 +163,9 @@ app.get('/stats', (request, response) => { }).length; var viewCounts = new Array(); + var deletionCounts = new Array(); var submissionCounts = new Array(); + var boostCounts = new Array(); var dayLabels = new Array(); var days = request.query.days ? parseInt(request.query.days) : 14; @@ -181,6 +183,20 @@ app.get('/stats', (request, response) => { && d.isSame(l.date, 'day') }).length ); + boostCounts.push( + logs.filter((l) => { + return l.event_type === "boost" + //&& l.date < moment().subtract(1, 'hour') + && d.isSame(l.date, 'day') + }).length + ); + deletionCounts.push( + logs.filter((l) => { + return l.event_type === "delete" + && l.date < moment().subtract(1, 'hour') + && d.isSame(l.date, 'day') + }).length + ); submissionCounts.push( logs.filter((l) => { return l.event_type === "submit" @@ -206,13 +222,32 @@ app.get('/stats', (request, response) => { chartData: { "labels": dayLabels, "views": viewCounts, - "submissions": submissionCounts + "submissions": submissionCounts, + "boosts": boostCounts, + "deletions": deletionCounts } }); }); }); +app.get("/account/delete", (request, response) => { + database.get("accounts", {session: request.sessionId}, {}, -1, (results) => { + if (results.length == 0) return; + database.remove("accounts", {session: request.sessionId}, (deleted) => { + database.insert("logs", [{ + event_type: "delete", + code: results[0].code, + date: new Date() + }], (results) => { + var cookies = new Cookies(request, response); + cookies.set("userSessionId", ""); + response.redirect("/"); + }, (error) => {}); + }, (error) => {}); + }, (error) => {}); +}); + app.get('/logout', (request, response) => { var cookies = new Cookies(request, response); cookies.set("userSessionId", ""); @@ -227,7 +262,14 @@ app.post("/boost", (request, response) => { lastBoost: new Date(), boostPoints: results[0].boostPoints + 1, boostCooldown: 10 + (Math.random() * 4) - }, (results) => { + }, (updated) => { + database.insert("logs", [{ + event_type: "boost", + code: results[0].code, + date: new Date() + }], (inserted) => { + + }, (error) => {}); response.json({success: true}); }, (error) => {response.json({success: false, reason: "Database error"})}); } else { @@ -247,7 +289,7 @@ app.post('/login', (request, response, next) => { var sessionId = "X"+Math.floor((Math.random() * 100000000)); database.update("accounts", {username: request.body.username}, { session: sessionId, - disabled: !validator_results.valid, + disabled: !validator_results.valid && !validator_results.error, }, (results) => { cookies.set("userSessionId", sessionId, {maxAge: 1000*60*60*24*7}); response.json({success: true}); @@ -287,7 +329,7 @@ app.post('/register', (request, response, next) => { response.json({success: false, reason: request.body.code+" is not a valid referral code."}); return; } else if (validator_results.error) { - response.json({success: false, reason: "An unknown error occured."}); + response.json({success: false, reason: "Failed to contact the verification server."}); } else { var sessionId = "X"+Math.floor((Math.random() * 100000000)); database.insert("accounts", [{ @@ -303,8 +345,14 @@ app.post('/register', (request, response, next) => { session: sessionId, disabled: false }], (results) => { - cookies.set("userSessionId", sessionId); - response.json({success: true}); + database.insert("logs", [{ + event_type: "submit", + code: request.body.code, + date: new Date() + }], (results) => { + cookies.set("userSessionId", sessionId); + response.json({success: true}); + }, (error) => {}); }) } }); diff --git a/views/account.hbs b/views/account.hbs index 14ea964..c6590d5 100644 --- a/views/account.hbs +++ b/views/account.hbs @@ -3,7 +3,7 @@ {{#if account.disabled}}
It looks like your code is no longer a valid Public Mobile referral code. - It will no longer show up on the front page, regardless of rank. + It will not show up on the front page, regardless of rank. If you've switched Public Mobile accounts, you'll have to delete this code and register a new one.
{{/if}} @@ -20,9 +20,7 @@ {{account.code}}
diff --git a/views/stats.hbs b/views/stats.hbs index f21fb37..e4c369c 100644 --- a/views/stats.hbs +++ b/views/stats.hbs @@ -40,15 +40,23 @@ }, series: [ { - name: 'Codes viewed', + name: 'Clicks', data: [{{#each chartData.views}}{{this}},{{/each}}] }, + { + name: 'Boosts', + data: [{{#each chartData.boosts}}{{this}},{{/each}}] + }, { name: 'Submissions', data: [{{#each chartData.submissions}}{{this}},{{/each}}] }, + { + name: 'Deletions', + data: [{{#each chartData.deletions}}{{this}},{{/each}}] + }, ], - colors: ['#034045', '#00ff00'], + colors: ['#034045', '#daa520', '#00ff00', '#850101'], xaxis: { type: "datetime", categories: [{{#each chartData.labels}}"{{this}}",{{/each}}], From 4d4bd6852ef1a9e98ba58107c17226602955b034 Mon Sep 17 00:00:00 2001 From: Jeremy <23155614+jsbrn@users.noreply.github.com> Date: Sun, 26 Jan 2020 17:03:39 -0500 Subject: [PATCH 10/18] Don't reset boost cooldowns on weekly reset --- index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.js b/index.js index 661dfd9..10ca3e2 100644 --- a/index.js +++ b/index.js @@ -61,7 +61,7 @@ app.all("*", (request, response, next) => { if (results.length == 0) { //no record of resetting this week, so time to reset console.log("Time to reset scores (week "+week+")"); - database.update("accounts", {}, {boostPoints: 0, lastBoost: new Date()}, (results) => { + database.update("accounts", {}, {boostPoints: 0}, (results) => { database.update("meta", {}, {lastWeekReset: week}, (results) => {}, (error) => {}); next(); }, (error) => {}); From 36f261627fd4ac152aba0dcfde27b9c32dd4cb0f Mon Sep 17 00:00:00 2001 From: Jeremy <23155614+jsbrn@users.noreply.github.com> Date: Sun, 26 Jan 2020 18:45:03 -0500 Subject: [PATCH 11/18] Quality of life changes --- index.js | 2 +- views/account.hbs | 2 +- views/assets/stylesheets/custom.css | 8 ++++++++ views/home.hbs | 24 ++++++++++++++++++------ 4 files changed, 28 insertions(+), 8 deletions(-) diff --git a/index.js b/index.js index 10ca3e2..bedce0f 100644 --- a/index.js +++ b/index.js @@ -70,7 +70,7 @@ app.all("*", (request, response, next) => { }); app.get('/', (request, response, next) => { - database.get("accounts", {disabled: false}, {boostPoints: -1, lastBoost: -1}, 5, (accounts) => { + database.get("accounts", {disabled: false}, {boostPoints: -1, lastBoost: -1}, 10, (accounts) => { accounts.forEach(c => c.code = c.code.substring(0, 3)); response.render("home", { layout: "main.hbs", diff --git a/views/account.hbs b/views/account.hbs index c6590d5..599dce2 100644 --- a/views/account.hbs +++ b/views/account.hbs @@ -35,7 +35,7 @@
Your rank is determined by the number of boosts () you've collected during the week. - The referral codes with the highest boost counts are shown to visitors on the main page. Only the top 5 are visible. + The referral codes with the highest boost counts are shown to visitors on the main page. Only the top 10 are visible.

All scores reset at the start of every week.
diff --git a/views/assets/stylesheets/custom.css b/views/assets/stylesheets/custom.css index 0320484..9c43296 100644 --- a/views/assets/stylesheets/custom.css +++ b/views/assets/stylesheets/custom.css @@ -237,4 +237,12 @@ table { padding-top: 10px; padding-bottom: 5px; padding-left: 10px; +} + +#content-desktop {display: block;} +#content-mobile {display: none;} + +@media screen and (max-width: 768px) { + #content-desktop {display: none;} + #content-mobile {display: block;} } \ No newline at end of file diff --git a/views/home.hbs b/views/home.hbs index bb1ddd7..b9234d1 100644 --- a/views/home.hbs +++ b/views/home.hbs @@ -1,4 +1,7 @@
+
+ +
@@ -37,8 +40,8 @@
- This Week's Codes - + This Week's Codes +
{{#if empty}} @@ -46,7 +49,7 @@ {{else}} {{#each accounts as |account|}}
-
+
{{account.code}}### @@ -65,12 +68,21 @@
+{{#if loggedIn}} +{{else}} + \ No newline at end of file + +{{/if}} \ No newline at end of file From f09a06216bbeaed00bce0d33c124093a9fffa5bc Mon Sep 17 00:00:00 2001 From: Jeremy <23155614+jsbrn@users.noreply.github.com> Date: Sun, 26 Jan 2020 21:30:54 -0500 Subject: [PATCH 12/18] Fingerprinting middleware, stricter username requirements --- index.js | 67 ++++++++++++++++- package-lock.json | 177 +++++++++++++++++++++++++++++++++++++++++++++ package.json | 1 + views/login.hbs | 2 +- views/register.hbs | 4 +- 5 files changed, 245 insertions(+), 6 deletions(-) diff --git a/index.js b/index.js index bedce0f..d405b0d 100644 --- a/index.js +++ b/index.js @@ -13,6 +13,7 @@ const validator = require('./app/validator.js'); const hasher = require('password-hash'); const moment = require('moment'); var Cookies = require('cookies'); +var Fingerprint = require('express-fingerprint'); const bodyParser = require('body-parser'); /*Set the Handlebars options, including the Helpers*/ @@ -31,6 +32,16 @@ app.use('/images',express.static(path.join(__dirname, 'views/assets/images'))); app.use('/css',express.static(path.join(__dirname, 'views/assets/stylesheets'))); app.use('/scripts',express.static(path.join(__dirname, 'views/assets/scripts'))); +//fingerprint the visitor +app.use(Fingerprint({ + parameters:[ + // Defaults + Fingerprint.useragent, + Fingerprint.acceptHeaders, + Fingerprint.geoip + ] +})) + app.use(express.json()); /*HTTP REQUEST HANDLERS*/ @@ -54,6 +65,39 @@ app.all("*", (request, response, next) => { } }); +//verify that the fingerprint has not been seen before +//and record any unique fingerprints found +app.get("*", (request, response, next) => { + var cookies = new Cookies(request, response); + request.hasFingerprintCookie = cookies.get("fingerprintHash") != undefined; + request.hasSessionCookie = cookies.get("userSessionId") != undefined; + database.get("fingerprints", {ip: request.ip}, {}, -1, (results1) => { + request.seenIPBefore = results1.length > 0; + database.get("fingerprints", {hash: request.fingerprint.hash}, {}, -1, (results2) => { + request.seenFingerprintBefore = results2.length > 0; + request.seenBefore = + request.hasFingerprintCookie + || request.hasSessionCookie + || request.seenIPBefore + || (request.seenIPBefore && request.seenFingerprintBefore); + if (!request.seenFingerprintBefore || !request.seenIPBefore) + database.insert("fingerprints", [{ip: request.ip, hash: request.fingerprint.hash}], (insertion) => {}, (error) => {}); + cookies.set("fingerprintHash", request.fingerprint.hash, {expires: new Date('2050')}); + next(); + }, (error) => {}); + }, (error) => { next(); }); +}); + +//fingerprint debugging tool :) +app.get("/debug/fp", (request, response) => { + request.fingerprint.seenBefore = request.seenBefore; + request.fingerprint.hasFingerprintCookie = request.hasFingerprintCookie; + request.fingerprint.hasSessionCookie = request.hasSessionCookie; + request.fingerprint.seenIPBefore = request.seenIPBefore; + request.fingerprint.seenFingerprintBefore = request.seenFingerprintBefore; + response.json(request.fingerprint); +}); + //reset account scores once each week app.all("*", (request, response, next) => { var week = moment().week(); @@ -309,15 +353,32 @@ app.post('/register', (request, response, next) => { return; } - request.body.code = request.body.code.toUpperCase(); + request.body.code = request.body.code.trim().toUpperCase(); if (request.body.password.length < 6) { response.json({success:false,reason:"Your password must be at least 6 characters long."}); return; } - if (request.body.username.length < 4) { - response.json({success:false,reason:"Your username must be at least 4 characters long."}); + if (request.body.username.length < 4 || request.body.username.length > 32) { + response.json({success:false,reason:"Your username must be between 4 and 32 characters long."}); + return; + } + + var usernameCheck = /([A-Za-z0-9])+/.exec(request.body.username); + var validUsername = usernameCheck != null && usernameCheck.includes(request.body.username); + var passwordCheck = /([^\s])*/.exec(request.body.password); + var validPassword = passwordCheck != null && passwordCheck.includes(request.body.password); + if (!validUsername) { + response.json({success:false,reason:"Usernames can only have letters and numbers."}); + return; + } + if (!validPassword) { + response.json({success:false,reason:"Passwords cannot have whitespace."}); + return; + } + if (request.body.username === request.body.code) { + response.json({success:false,reason:"Your username cannot be your referral code."}); return; } diff --git a/package-lock.json b/package-lock.json index cdd69df..ed34247 100644 --- a/package-lock.json +++ b/package-lock.json @@ -62,6 +62,14 @@ "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" }, + "async": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", + "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", + "requires": { + "lodash": "^4.17.14" + } + }, "asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -85,6 +93,15 @@ "follow-redirects": "1.5.10" } }, + "babel-runtime": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", + "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", + "requires": { + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" + } + }, "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", @@ -194,11 +211,21 @@ "resolved": "https://registry.npmjs.org/bson/-/bson-1.1.3.tgz", "integrity": "sha512-TdiJxMVnodVS7r0BdL42y/pqC9cL2iKynVwA0Ho3qbsQYr428veL3l7BQyuqiw+Q5SqqoT0m4srSY/BlZ9AxXg==" }, + "buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=" + }, "caseless": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" }, + "colors": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", + "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==" + }, "combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", @@ -264,6 +291,11 @@ } } }, + "core-js": { + "version": "2.6.11", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.11.tgz", + "integrity": "sha512-5wjnpaT/3dV+XB4borEsnAYQchn00XSgTAWKDkEqv+K8KevjbzmofK6hfJ9TZIlpj2N0xQpazy7PiRQiWHqzWg==" + }, "core-util-is": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", @@ -391,6 +423,19 @@ } } }, + "express-fingerprint": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/express-fingerprint/-/express-fingerprint-1.1.3.tgz", + "integrity": "sha512-G8qdEE9T8V4VqcS6RUF1W8l+QXZdobFE5Fa8UoxqLoXRoJMNvXJZEn601kHZqqK6UDDW26QMFkcoQvCS8S7IzA==", + "requires": { + "async": "^2.6.2", + "babel-runtime": "^6.26.0", + "geoip-lite": "^1.3.7", + "murmurhash3js": "^3.0.1", + "traverse": "^0.6.6", + "useragent": "^2.3.0" + } + }, "express-handlebars": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/express-handlebars/-/express-handlebars-3.1.0.tgz", @@ -423,6 +468,14 @@ "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" }, + "fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=", + "requires": { + "pend": "~1.2.0" + } + }, "finalhandler": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", @@ -490,6 +543,20 @@ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" }, + "geoip-lite": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/geoip-lite/-/geoip-lite-1.4.0.tgz", + "integrity": "sha512-pQmZqkOAs6yRAEruVvX9Vbj1rdGHSc8QpbOA/FSZIhIsTsySOrufc3DPxjHimWo4zxIZMbdHwOiWvA6FB3bZhQ==", + "requires": { + "async": "^2.1.1", + "colors": "^1.1.2", + "iconv-lite": "^0.4.13", + "ip-address": "^5.8.9", + "lazy": "^1.0.11", + "rimraf": "^2.5.2", + "yauzl": "^2.9.2" + } + }, "getpass": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", @@ -616,6 +683,23 @@ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" }, + "ip-address": { + "version": "5.9.4", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-5.9.4.tgz", + "integrity": "sha512-dHkI3/YNJq4b/qQaz+c8LuarD3pY24JqZWfjB8aZx1gtpc2MDILu9L9jpZe1sHpzo/yWFweQVn+U//FhazUxmw==", + "requires": { + "jsbn": "1.1.0", + "lodash": "^4.17.15", + "sprintf-js": "1.1.2" + }, + "dependencies": { + "jsbn": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", + "integrity": "sha1-sBMHyym2GKHtJux56RH4A8TaAEA=" + } + } + }, "ipaddr.js": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.0.tgz", @@ -675,6 +759,25 @@ "tsscmp": "1.0.6" } }, + "lazy": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/lazy/-/lazy-1.0.11.tgz", + "integrity": "sha1-2qBoIGKCVCwIgojpdcKXwa53tpA=" + }, + "lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==" + }, + "lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "requires": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, "media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", @@ -757,6 +860,11 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" }, + "murmurhash3js": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/murmurhash3js/-/murmurhash3js-3.0.1.tgz", + "integrity": "sha1-Ppg+W0fCoG9DpxMXTn5DXKBEuZg=" + }, "negotiator": { "version": "0.6.2", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", @@ -848,6 +956,11 @@ "wordwrap": "~0.0.2" } }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" + }, "parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", @@ -868,6 +981,11 @@ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" }, + "pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=" + }, "performance-now": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", @@ -895,6 +1013,11 @@ "ipaddr.js": "1.9.0" } }, + "pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" + }, "psl": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/psl/-/psl-1.4.0.tgz", @@ -969,6 +1092,11 @@ "util-deprecate": "~1.0.1" } }, + "regenerator-runtime": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", + "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==" + }, "request": { "version": "2.88.0", "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", @@ -1035,6 +1163,14 @@ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-2.0.0.tgz", "integrity": "sha1-lICrIOlP+h2egKgEx+oUdhGWa1c=" }, + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "requires": { + "glob": "^7.1.3" + } + }, "safe-buffer": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", @@ -1125,6 +1261,11 @@ "memory-pager": "^1.0.2" } }, + "sprintf-js": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.2.tgz", + "integrity": "sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==" + }, "sshpk": { "version": "1.16.1", "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", @@ -1154,6 +1295,14 @@ "safe-buffer": "~5.1.0" } }, + "tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "requires": { + "os-tmpdir": "~1.0.2" + } + }, "toidentifier": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", @@ -1175,6 +1324,11 @@ } } }, + "traverse": { + "version": "0.6.6", + "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.6.6.tgz", + "integrity": "sha1-y99WD9e5r2MlAv7UD5GMFX6pcTc=" + }, "tsscmp": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/tsscmp/-/tsscmp-1.0.6.tgz", @@ -1245,6 +1399,15 @@ "punycode": "^2.1.0" } }, + "useragent": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/useragent/-/useragent-2.3.0.tgz", + "integrity": "sha512-4AoH4pxuSvHCjqLO04sU6U/uE65BYza8l/KKBS0b0hnUPWi+cQ2BpeTEwejCSx9SPV5/U03nniDTrWx5NrmKdw==", + "requires": { + "lru-cache": "4.1.x", + "tmp": "0.0.x" + } + }, "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -1284,6 +1447,20 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=" + }, + "yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=", + "requires": { + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" + } } } } diff --git a/package.json b/package.json index 630e49c..683ec3b 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,7 @@ "cookies": "^0.8.0", "dotenv": "^6.2.0", "express": "^4.17.1", + "express-fingerprint": "^1.1.3", "express-handlebars": "^3.1.0", "https": "^1.0.0", "moment": "^2.24.0", diff --git a/views/login.hbs b/views/login.hbs index 7fd041f..113fdd8 100644 --- a/views/login.hbs +++ b/views/login.hbs @@ -10,11 +10,11 @@
-
+
diff --git a/views/register.hbs b/views/register.hbs index c8f3e6b..a290ed3 100644 --- a/views/register.hbs +++ b/views/register.hbs @@ -17,10 +17,10 @@ -
-
+
+
From 59622716f62add43d78f233b294d004d1e5e2f22 Mon Sep 17 00:00:00 2001 From: Jeremy <23155614+jsbrn@users.noreply.github.com> Date: Sun, 26 Jan 2020 22:26:48 -0500 Subject: [PATCH 13/18] Minor changes --- index.js | 12 ++++++++++-- views/assets/images/eye.png | Bin 0 -> 731 bytes views/home.hbs | 8 +++----- 3 files changed, 13 insertions(+), 7 deletions(-) create mode 100644 views/assets/images/eye.png diff --git a/index.js b/index.js index d405b0d..a0510de 100644 --- a/index.js +++ b/index.js @@ -25,6 +25,7 @@ app.engine('.hbs', exphbs({ })); app.set('view engine', '.hbs'); app.set('views', path.join(__dirname, 'views')); +app.set('trust proxy', true); /*Set locations for getting static content*/ app.use('/assets',express.static(path.join(__dirname, 'views/assets'))); @@ -68,6 +69,7 @@ app.all("*", (request, response, next) => { //verify that the fingerprint has not been seen before //and record any unique fingerprints found app.get("*", (request, response, next) => { + request.ip = request.header('x-forwarded-for') || request.connection.remoteAddress; var cookies = new Cookies(request, response); request.hasFingerprintCookie = cookies.get("fingerprintHash") != undefined; request.hasSessionCookie = cookies.get("userSessionId") != undefined; @@ -98,6 +100,11 @@ app.get("/debug/fp", (request, response) => { response.json(request.fingerprint); }); +//ip debugging tool +app.get("/debug/ip", (request, response) => { + response.send(request.ip); +}); + //reset account scores once each week app.all("*", (request, response, next) => { var week = moment().week(); @@ -119,6 +126,7 @@ app.get('/', (request, response, next) => { response.render("home", { layout: "main.hbs", loggedIn: request.loggedIn, + seenBefore: request.seenBefore, accounts: accounts, bad_code: request.query.bad_code, successful_addition: request.query.success, @@ -377,7 +385,7 @@ app.post('/register', (request, response, next) => { response.json({success:false,reason:"Passwords cannot have whitespace."}); return; } - if (request.body.username === request.body.code) { + if (request.body.username.toUpperCase() === request.body.code) { response.json({success:false,reason:"Your username cannot be your referral code."}); return; } @@ -397,7 +405,7 @@ app.post('/register', (request, response, next) => { username: request.body.username, password: hasher.generate(request.body.password), code: request.body.code, - url: [...Array(8).keys()] + url: [...Array(5).keys()] .map(e => String.fromCharCode(Math.floor(Math.random() * (122-97)) + 97)) .reduce((total, curr) => { return total+""+curr; }), boostPoints: 0, diff --git a/views/assets/images/eye.png b/views/assets/images/eye.png new file mode 100644 index 0000000000000000000000000000000000000000..190959b4ca8f9a3f8d486674e6e0a3834cd4b606 GIT binary patch literal 731 zcmV<10wn#3P)|`_hO3Z@LEEh%MMGEGSgNTQoa`qyHRuMtLL$QZa(1PGWuRVEEksd4* zyx3MRO%Sq?kP?!Vgphr$N&H?&VhAagpy;6whJR-MdGpPi`QD@E{_>*E0semgjYcEm z@pubtHrqi_loB%6?RJk_tyZ8~t?s5$soYEeHk-|Zq{~omA}OPXg)c?Eqs) z%}^-x=}Z7-vw0pBzr^MngJdn}ETT>UXu)I+^v|_gZ7CX!exC{;7K8o}z6V`Fy@N0#K<`Jh@!Hg#@=z(FtU| zUazm=B(HM0+`V)<-5_yJr}HB|-mw#q6YU`O7TWoQMx#A~n*sNG?DGMrMyi%brP6Ku zxQZXCMx(J94u|)QM&mW1P`K*%`#r;icDwx zUM-PGw&8Zb{MH8`)kFN{a@iY?$43BMF84XqHsp{H3nHAx6tL+25CA7vi$o&Q5hvs; zrBHx$_-oeWxUcUEb7~pO2v)B_CakoW-)3J2JP(+S)owyluBiP$S_a9 zgmuh<4EY1O2fw+ClS5`A`MYd3>&s*^wGmBGEv3`xhBUnZup -
+
{{account.code}}### @@ -75,8 +75,7 @@ window.scrollTo(0, document.getElementById("codesDiv").getBoundingClientRect().top); }) -{{#if loggedIn}} -{{else}} + -{{/if}} \ No newline at end of file + \ No newline at end of file From bd7bfd09492d55b773cc4715f82520fc5aa18451 Mon Sep 17 00:00:00 2001 From: Jeremy <23155614+jsbrn@users.noreply.github.com> Date: Sun, 26 Jan 2020 23:20:21 -0500 Subject: [PATCH 14/18] Reward the users who share links to pmreferrals.ca --- index.js | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/index.js b/index.js index a0510de..d3c611f 100644 --- a/index.js +++ b/index.js @@ -185,7 +185,8 @@ app.get("/login", (request, response) => { app.get("/privacy", (request, response) => { response.render("privacy", { layout: "main.hbs", - title: "Privacy Statement" + title: "Privacy Statement", + loggedIn: request.loggedIn }); }); @@ -433,6 +434,23 @@ app.post('/register', (request, response, next) => { }, (err) => response.json({success:false, reason: "Database error"})); }); +//linkback program, match the url with the account to reward them for a successful share +app.get("/:accountURL", (request, response, next) => { + database.get("accounts", {url: request.params.accountURL}, {}, -1, (results) => { + if (results.length == 0) { + next(); + } else { + if (request.seenBefore) { + response.redirect("/"); + } else { + database.update("accounts", {url: request.params.accountURL}, {boostPoints: results[0].boostPoints + 2}, (updated) => { + response.redirect("/"); + }, (error) => {}); + } + } + }, (error) => { next(); }); +}); + //catchall and 404 app.get('*', (request, response) => { response.render("404", { From da6b847018e18bf46f8e9c1e42d777eb7b9cd524 Mon Sep 17 00:00:00 2001 From: Jeremy <23155614+jsbrn@users.noreply.github.com> Date: Sun, 26 Jan 2020 23:55:53 -0500 Subject: [PATCH 15/18] Ignore rewards if visitor is seen before --- views/account.hbs | 43 +++++++++++++++++++++++++++++-------------- views/privacy.hbs | 14 ++++++-------- 2 files changed, 35 insertions(+), 22 deletions(-) diff --git a/views/account.hbs b/views/account.hbs index 599dce2..078ac53 100644 --- a/views/account.hbs +++ b/views/account.hbs @@ -20,7 +20,9 @@ {{account.code}}
@@ -39,16 +41,14 @@

All scores reset at the start of every week.
-
-
-
-
Boost your code - - +1 +
+ + +1 +
Once a day you can boost your score by one point. @@ -62,23 +62,38 @@ {{/if}}
-
-
Share PMReferrals.ca - - +3 /click +
+ + +2 /click +
+
+
+ PMReferrals is only useful when people see it. Share this site with potential Public Mobile customers + by giving them this custom link. When they use it, your code will rank higher to all visitors. +
+
+ https://pmreferrals.ca/{{account.url}} +
+
+ + Report a bug + +
+ + +10 +
- Help spread Public Mobile far and wide! Share a custom link with others that takes them to the front page. - The more people click it, the higher your code will rank. + Found a bug or general problem with the site? + We'll reward you with 10 points if you submit it.
COMING SOON
-
diff --git a/views/stats.hbs b/views/stats.hbs index e4c369c..0c41318 100644 --- a/views/stats.hbs +++ b/views/stats.hbs @@ -47,6 +47,10 @@ name: 'Boosts', data: [{{#each chartData.boosts}}{{this}},{{/each}}] }, + { + name: 'Shares', + data: [{{#each chartData.shares}}{{this}},{{/each}}] + }, { name: 'Submissions', data: [{{#each chartData.submissions}}{{this}},{{/each}}] @@ -56,7 +60,7 @@ data: [{{#each chartData.deletions}}{{this}},{{/each}}] }, ], - colors: ['#034045', '#daa520', '#00ff00', '#850101'], + colors: ['#034045', '#daa520', '#add8e6', '#00ff00', '#850101'], xaxis: { type: "datetime", categories: [{{#each chartData.labels}}"{{this}}",{{/each}}], From 1399f02d8f2a2c7ef681e5ac064d09cde4752596 Mon Sep 17 00:00:00 2001 From: Jeremy <23155614+jsbrn@users.noreply.github.com> Date: Mon, 27 Jan 2020 08:18:21 -0500 Subject: [PATCH 18/18] Update readme.md --- README.md | 18 +++++++----------- views/account.hbs | 1 - 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index f13f6bc..8cc5c74 100644 --- a/README.md +++ b/README.md @@ -5,9 +5,10 @@ A handy free service to find a Public Mobile referral code to get the $10 credit **Features** * Instantly get a referral to use when signing up for Public Mobile account. -* Register your Public Mobile referral code to get randomly selected when other people request a referral. -* Codes are verified on Public Mobile's website before being accepted into the database. -* If a user closes their PM account, PMReferrals will delete the code the next time someone tries to use it. +* Register your Public Mobile referral code to start collecting anonymous referrals. +* Codes are ranked by a scoring system. Collect points by maintaining activity on the site, and sharing it with others. +* Points are reset each week. +* Codes are automatically verified on registration and login. Removed from the rankings if found to be invalid. **Contributing** @@ -34,18 +35,13 @@ MONGODB_PORT=27017 MONGODB_DATABASE=database_name MONGODB_SRV_RECORD=false -MOCK_CODE_VALIDATION=false - -EMAIL_ADDRESS=example@example.com -EMAIL_PASSWORD=password2 -SMTP_SERVER=mail.example.com -SMTP_PORT=465 +MESSAGE=PMReferrals is down for maintenance. +SUBMESSAGE=Come back in an hour! +MAINTENANCE=false BASE_URL=https://example.com ``` -When `MOCK_CODE_VALIDATION` is true, the codes will always be accepted. Email is not currently used by the application, so don't worry about configuring it. It used to be, in an older version. - **Bug Reports** If you are using the site and find a problem, please feel free to create a new issue on this repository. It will be super helpful as we try to build a useful tool for everyone. diff --git a/views/account.hbs b/views/account.hbs index e6bd324..629e754 100644 --- a/views/account.hbs +++ b/views/account.hbs @@ -75,7 +75,6 @@
https://pmreferrals.ca/{{account.url}}
-