Skip to content

Commit

Permalink
Adds csrf
Browse files Browse the repository at this point in the history
  • Loading branch information
freetonik committed Jan 28, 2021
1 parent 4d81faa commit af840d2
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 57 deletions.
122 changes: 65 additions & 57 deletions app/brochure/routes/questions/index.js
@@ -1,44 +1,44 @@
var Express = require("express");
var Questions = new Express.Router();
var hbs = require("hbs");
var moment = require("moment");
const Express = require("express");
const Questions = new Express.Router();
const hbs = require("hbs");
const moment = require("moment");
const csrf = require("csurf")();

// Configure connection to Postgres
var Pool = require('pg').Pool;
const Pool = require('pg').Pool;
const pool = new Pool({
user: 'rakhim',
host: 'localhost',
database: 'blot_qa',
password: 'password',
port: 5432,
user: 'rakhim',
host: 'localhost',
database: 'blot_qa',
password: 'password',
port: 5432,
})

// Renders datetime in desired format
// Can be used like so: {{{formatDaytime D}}} where D is timestamp (e.g. from a DB)
hbs.registerHelper("formatDaytime", function(timestamp) {
try {
timestamp = moment.utc(timestamp).startOf("minute").fromNow();
} catch (e) {
timestamp = "";
}

return timestamp;
try {
timestamp = moment.utc(timestamp).startOf("minute").fromNow();
} catch (e) {
timestamp = "";
}
return timestamp;
});

Questions.use(Express.urlencoded({
extended: true
extended: true
}))

Questions.use(function(req, res, next) {
res.locals.base = "/questions";
next();
res.locals.base = "/questions";
next();
});

// Handle topic listing
// Topics are sorted by datetime of last reply, then by topic creation date
Questions.get("/", function(req, res) {
pool
.query(`SELECT i.*, last_reply_created_at, COUNT(r.parent_id) AS reply_count
pool
.query(`SELECT i.*, last_reply_created_at, COUNT(r.parent_id) AS reply_count
FROM items i
LEFT JOIN items r ON r.parent_id = i.id
LEFT JOIN (
Expand All @@ -49,60 +49,68 @@ Questions.get("/", function(req, res) {
WHERE i.is_topic = true
GROUP BY i.id, last_reply_created_at
ORDER BY last_reply_created_at, i.created_at DESC NULLS LAST`)
.then(topics => res.render("questions", { title: "Blot — QA", topics: topics.rows }))
.catch(err => {
throw err;
})
.then(topics => res.render("questions", { title: "Blot — QA", topics: topics.rows }))
.catch(err => {
throw err;
})
});

Questions.get("/new", function (req, res) {
// Handle topic viewing and creation
Questions
.route('/new')
.get(csrf, function (req, res) {
res.locals.csrf = req.csrfToken();
res.render("questions/new");
});

// Handle new topic
Questions.post('/new', function(req, res) {
var author = req.user.uid;
var title = req.body.title;
var body = req.body.body;
})
.post(csrf, function(req, res) {
const author = req.user.uid;
const title = req.body.title;
const body = req.body.body;
// Disallow empty title or body.
// TODO: show error message, do not lose form data
if (title.trim().length === 0 || body.trim().length === 0) res.redirect("/questions/new");
else {
pool.query('INSERT INTO items(id, author, title, body, is_topic) VALUES(DEFAULT, $1, $2, $3, true) RETURNING *', [author, title, body], (error, topic) => {
if (error) {throw error}
var newTopic = topic.rows[0];
res.redirect("/questions/" + newTopic.id);
})
pool.query('INSERT INTO items(id, author, title, body, is_topic) VALUES(DEFAULT, $1, $2, $3, true) RETURNING *', [author, title, body], (error, topic) => {
if (error) {throw error}
const newTopic = topic.rows[0];
res.redirect("/questions/" + newTopic.id);
})
}
});
});

// Handle new reply to topic
Questions.post('/:id/new', function(req, res) {
Questions
.route('/:id/new')
.post(csrf, function(req, res) {
const id = parseInt(req.params.id)
const author = req.user.uid;
const body = req.body.body;
if (body.trim().length === 0) res.redirect("/questions/" + id);
else {
pool
.query('INSERT INTO items(id, author, body, parent_id) VALUES(DEFAULT, $1, $2, $3) RETURNING *', [author, body, id])
.then(item => res.redirect("/questions/" + id))
.catch(err => {
throw err;
})
pool
.query('INSERT INTO items(id, author, body, parent_id) VALUES(DEFAULT, $1, $2, $3) RETURNING *', [author, body, id])
.then(item => res.redirect("/questions/" + id))
.catch(err => {
throw err;
})
}
});
});


Questions.get("/:id", function(req, res) {
Questions
.route('/:id')
.get(csrf, function(req, res) {
res.locals.csrf = req.csrfToken();
const id = parseInt(req.params.id)

pool.query('SELECT * FROM items WHERE id = $1 AND is_topic = true', [id], (error, topics) => {
if (error) {throw error}
pool.query('SELECT * FROM items WHERE parent_id = $1 AND is_topic = false', [id], (error, replies) => {
if (error) {throw error}
pool.query('SELECT * FROM items WHERE parent_id = $1 AND is_topic = false', [id], (error, replies) => {
if (error) {throw error}
var topic = topics.rows[0];
res.locals.breadcrumbs = res.locals.breadcrumbs.slice(0, -1);
res.render("questions/topic", {title: topic.title, topics: replies.rows, topic: topic});
})
const topic = topics.rows[0];
res.locals.breadcrumbs = res.locals.breadcrumbs.slice(0, -1);
res.render("questions/topic", {title: topic.title, topics: replies.rows, topic: topic});
})
})
});
});

module.exports = Questions;
1 change: 1 addition & 0 deletions app/brochure/views/questions/new.html
Expand Up @@ -40,6 +40,7 @@ <h1>New question</h1>

<div style="max-width: 637px;">
<form method="POST" action="/questions/new" id="new-question-form">
<input type="hidden" name="_csrf" value="{{csrf}}" />
<div>
<input type="text" name="title" id="title"></input>
</div>
Expand Down
1 change: 1 addition & 0 deletions app/brochure/views/questions/topic.html
Expand Up @@ -63,6 +63,7 @@ <h2>No replies yet</h2>
<br>
<div style="max-width: 637px;">
<form method="POST" action="/questions/{{topic.id}}/new" id="new-reply-form">
<input type="hidden" name="_csrf" value="{{csrf}}" />
<div>
<textarea type="text" name="body" id="body"></textarea>
</div>
Expand Down

0 comments on commit af840d2

Please sign in to comment.