From c69dc9a98e22f7b7420dcb1586a6219f971c593e Mon Sep 17 00:00:00 2001 From: flifloo Date: Thu, 20 Aug 2020 22:46:46 +0200 Subject: [PATCH] Add reCaptcha --- app.js | 7 ++++++- config/config_exemple.json | 4 +++- middlewares/reCaptcha.js | 13 +++++++++++++ package-lock.json | 5 +++++ package.json | 1 + routes/login.js | 3 ++- routes/register.js | 5 +++-- views/layout.pug | 16 +++++++++------- views/login.pug | 2 +- views/mixin.pug | 16 ++++++++++++++++ views/register.pug | 2 +- 11 files changed, 60 insertions(+), 14 deletions(-) create mode 100644 middlewares/reCaptcha.js create mode 100644 views/mixin.pug diff --git a/app.js b/app.js index ba9893d..59af17e 100644 --- a/app.js +++ b/app.js @@ -4,6 +4,8 @@ let cookieParser = require("cookie-parser"); let session = require("express-session"); let logger = require("morgan"); let { I18n } = require("i18n"); +let Recaptcha = require("express-recaptcha").RecaptchaV3; +let config = process.env.NODE_ENV === "test" ? {} : require("./config/config.json"); let indexRouter = require("./routes/index"); let registerRouter = require("./routes/register"); @@ -17,7 +19,7 @@ let adminRouter = require("./routes/admin"); let app = express(); let sess = { - secret: process.env.NODE_ENV === "test" ? "Keyboard Cat" : require("./config/config.json").secret, + secret: process.env.NODE_ENV === "test" ? "Keyboard Cat" : config.secret, cookie: {} }; let i18n = new I18n({ @@ -27,6 +29,7 @@ let i18n = new I18n({ directory: __dirname + "/locales", objectNotation: true }); +let recaptcha = process.env.NODE_ENV === "test" ? null : new Recaptcha(config.siteKey, config.secretKey, {callback: "cb"}); if (app.get("env") === "production") { app.set("trust proxy", 1); @@ -36,6 +39,7 @@ if (app.get("env") === "production") { // view engine setup app.set("views", path.join(__dirname, "views")); app.set("view engine", "pug"); +app.set("recaptcha", recaptcha); app.use(logger("dev")); app.use(express.json()); @@ -48,6 +52,7 @@ if(process.env.NODE_ENV === "test") app.locals.test = true; app.use((req, res, next) => { res.locals.user = req.session.user; + res.locals.captcha = process.env.NODE_ENV === "test" ? undefined : recaptcha.render(); next(); }); diff --git a/config/config_exemple.json b/config/config_exemple.json index e6b8c52..f9a5ad2 100644 --- a/config/config_exemple.json +++ b/config/config_exemple.json @@ -6,5 +6,7 @@ "database": "database_development", "host": "127.0.0.1", "dialect": "mysql" - } + }, + "siteKey": "yjt,kugcjvhkyhgchkuyjgugjgcvkuh", + "secretKey": "yjt,vhjtfykjvhkhiuyhjvkjuiyvhjblhioguikjkly_lui" } diff --git a/middlewares/reCaptcha.js b/middlewares/reCaptcha.js new file mode 100644 index 0000000..0d745bf --- /dev/null +++ b/middlewares/reCaptcha.js @@ -0,0 +1,13 @@ +let error = require("../routes/utils/error"); + +module.exports = (req, res, next) => { + if(req.app.locals.test) + return next(); + req.app.get("recaptcha").middleware.verify(req, res, () => { + if (req.recaptcha.error) + error(req, res, "Strange behaviour detected !", 400, + req.app.get("env") !== "production" ? req.recaptcha.error : undefined); + else + next(); + }); +}; diff --git a/package-lock.json b/package-lock.json index 88ce433..27fc2ab 100644 --- a/package-lock.json +++ b/package-lock.json @@ -887,6 +887,11 @@ } } }, + "express-recaptcha": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/express-recaptcha/-/express-recaptcha-5.0.2.tgz", + "integrity": "sha512-111xDDJo1HPVwcU+hG1X3vOzRFWx/Yp9pyQ7qOVjkSfRXh2qeU9tLo1I0HBa1oLrB8rQlyxLUI9XXP5iUePnnw==" + }, "express-session": { "version": "1.17.1", "resolved": "https://registry.npmjs.org/express-session/-/express-session-1.17.1.tgz", diff --git a/package.json b/package.json index a85eb01..c0c465f 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ "cookie-parser": "~1.4.4", "debug": "~2.6.9", "express": "~4.16.1", + "express-recaptcha": "^5.0.2", "express-session": "^1.17.1", "http-errors": "~1.6.3", "i18n": "^0.12.0", diff --git a/routes/login.js b/routes/login.js index e047d36..bfb6ed1 100644 --- a/routes/login.js +++ b/routes/login.js @@ -1,6 +1,7 @@ const express = require("express"); const router = express.Router(); const models = require("../models"); +const reCaptcha = require("../middlewares/reCaptcha"); router.get("/", async (req, res) => { if (req.session.user) @@ -8,7 +9,7 @@ router.get("/", async (req, res) => { else res.render("login", { title: "SOD - Login" }); }) - .post("/", async (req, res) => { + .post("/", reCaptcha, async (req, res) => { if (!req.body.username || !req.body.password) res.redirect("/login"); else { diff --git a/routes/register.js b/routes/register.js index 3650c6b..0628b85 100644 --- a/routes/register.js +++ b/routes/register.js @@ -2,15 +2,16 @@ let express = require("express"); let router = express.Router(); let models = require("../models"); let userCreate = require("./utils/userCreate"); +let reCaptcha = require("../middlewares/reCaptcha"); -router.get("/", async (req, res) => { +router.get("/", async (req, res) => { if (req.session.user) res.redirect("/"); else res.render("register", {title: "SOD - register", departments: await models.Department.findAll()}); }) - .post("/", async (req, res) => { + .post("/", reCaptcha, async (req, res) => { let user = await userCreate(req, res); if (user) { req.session.user = user; diff --git a/views/layout.pug b/views/layout.pug index ff10c10..4191441 100644 --- a/views/layout.pug +++ b/views/layout.pug @@ -1,3 +1,5 @@ +include mixin + doctype html html head @@ -57,19 +59,19 @@ html a(href="https://www.linkedin.com/in/florian-charlaix" target="_blank") Florian Charlaix div#contact.popup.card.hide h1=__("layout.contact") - p.before-link=__("layout.orderIssue")+":" + p.before-link=__("layout.orderIssue") + ":" a(href="mailto: ") test@test.fr - p.before-link=__("layout.bio")+":" + p.before-link=__("layout.bio") + ":" a(href="mailto: ") - p.before-link=__("layout.chemistry")+":" + p.before-link=__("layout.chemistry") + ":" a(href="mailto: ") - p.before-link=__("layout.GC")+":" + p.before-link=__("layout.GC") + ":" a(href="mailto: ") - p.before-link=__("layout.GCPD")+":" + p.before-link=__("layout.GCPD") + ":" a(href="mailto: bde.gcgp.lyon1@gmail.com") bde.gcgp.lyon1@gmail.com - p.before-link=__("layout.GEA")+":" + p.before-link=__("layout.GEA") + ":" a(href="mailto: ") - p.before-link=__("layout.IT")+":" + p.before-link=__("layout.IT") + ":" a(href="mailto: contact@bde-info.org") contact@bde-info.org script(src="/javascripts/layout.js") diff --git a/views/login.pug b/views/login.pug index 1963a93..41f20e6 100644 --- a/views/login.pug +++ b/views/login.pug @@ -10,4 +10,4 @@ block content label(for="password")=__("password")+":" input#password(type="password" name="password" required) div.field - input(type="submit" value=__("login.submit")) + +submit(value=__("login.submit")) diff --git a/views/mixin.pug b/views/mixin.pug new file mode 100644 index 0000000..986f272 --- /dev/null +++ b/views/mixin.pug @@ -0,0 +1,16 @@ +mixin submit(value) + div.recaptcha.recaptcha-cb + input(type="submit" value!=value) + if !test + p !{captcha} + script. + function cb(token) { + document.querySelectorAll("div.recaptcha.recaptcha-cb").forEach(el => { + el.classList.remove("recaptcha-cb"); + let input = document.createElement("input"); + input.setAttribute("type", "hidden"); + input.setAttribute("name", "g-recaptcha-response"); + input.setAttribute("value", token); + el.appendChild(input); + }); + } diff --git a/views/register.pug b/views/register.pug index d2916ec..95e713e 100644 --- a/views/register.pug +++ b/views/register.pug @@ -22,7 +22,7 @@ block content label(for="password")=__("password")+":" input#password(type="password" name="password" required) div.field - input(type="submit" value=__("register.submit")) + +submit(value=__("register.submit")) datalist#department-list each department in departments