Skip to content

Commit

Permalink
fix mozilla#961: add csrf tokens to all preferences forms
Browse files Browse the repository at this point in the history
  • Loading branch information
groovecoder committed May 23, 2019
1 parent 403a1c3 commit f3d81c4
Show file tree
Hide file tree
Showing 8 changed files with 20 additions and 14 deletions.
2 changes: 2 additions & 0 deletions controllers/user.js
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,7 @@ async function getRemoveFxm(req, res) {
title: req.fluentFormat("remove-fxm"),
subscriber: sessionUser,
whichPartial: "subpages/remove_fxm",
csrfToken: req.csrfToken(),
});
}

Expand Down Expand Up @@ -313,6 +314,7 @@ async function getPreferences(req, res) {
res.render("dashboards", {
title: "Firefox Monitor",
whichPartial: "dashboards/preferences",
csrfToken: req.csrfToken(),
verifiedEmails, unverifiedEmails,
});
}
Expand Down
18 changes: 10 additions & 8 deletions routes/user.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

const express = require("express");
const bodyParser = require("body-parser");
const csrf = require("csurf");

const { asyncMiddleware } = require("../middleware");
const {
Expand All @@ -13,20 +14,21 @@ const {
const router = express.Router();
const jsonParser = bodyParser.json();
const urlEncodedParser = bodyParser.urlencoded({ extended: false });
const csrfProtection = csrf();


router.get("/dashboard", asyncMiddleware(getDashboard));
router.get("/preferences", asyncMiddleware(getPreferences));
router.get("/preferences", csrfProtection, asyncMiddleware(getPreferences));
router.get("/logout", logout);
router.post("/email", urlEncodedParser, asyncMiddleware(add));
router.post("/remove-email", urlEncodedParser, asyncMiddleware(removeEmail));
router.post("/resend-email", jsonParser, asyncMiddleware(resendEmail));
router.post("/update-comm-option", jsonParser, asyncMiddleware(updateCommunicationOptions));
router.post("/email", urlEncodedParser, csrfProtection, asyncMiddleware(add));
router.post("/remove-email", urlEncodedParser, csrfProtection, asyncMiddleware(removeEmail));
router.post("/resend-email", jsonParser, csrfProtection, asyncMiddleware(resendEmail));
router.post("/update-comm-option", jsonParser, csrfProtection, asyncMiddleware(updateCommunicationOptions));
router.get("/verify", jsonParser, asyncMiddleware(verify));
router.use("/unsubscribe", urlEncodedParser);
router.get("/unsubscribe", asyncMiddleware(getUnsubscribe));
router.post("/unsubscribe", asyncMiddleware(postUnsubscribe));
router.get("/remove-fxm", urlEncodedParser, asyncMiddleware(getRemoveFxm));
router.post("/remove-fxm", jsonParser, asyncMiddleware(postRemoveFxm));
router.post("/unsubscribe", csrfProtection, asyncMiddleware(postUnsubscribe));
router.get("/remove-fxm", urlEncodedParser, csrfProtection, asyncMiddleware(getRemoveFxm));
router.post("/remove-fxm", jsonParser, csrfProtection, asyncMiddleware(postRemoveFxm));

module.exports = router;
2 changes: 1 addition & 1 deletion tests/controllers/user.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -351,7 +351,7 @@ test("user/remove-fxm GET request with invalid session returns error", async ()

test("user/remove-fxm GET request with valid session returns 200 and renders remove_fxm", async () => {
// Set up mocks
const req = { fluentFormat: jest.fn(), session: { user: TEST_SUBSCRIBERS.firefox_account }};
const req = { fluentFormat: jest.fn(), csrfToken: jest.fn(), session: { user: TEST_SUBSCRIBERS.firefox_account }};
const resp = httpMocks.createResponse();
resp.render = jest.fn();

Expand Down
4 changes: 2 additions & 2 deletions views/partials/dashboards/preferences.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
<section>
{{#each communicationOptions}}
<label class="radio-container">
<input class="radio-comm-option" data-comm-option="{{ optionId }}" data-form-action="update-comm-option" type="radio" {{ optionChecked }} name="1">
<input class="radio-comm-option" data-comm-option="{{ optionId }}" data-form-action="update-comm-option" data-csrf-token="{{ ../csrfToken }}" type="radio" {{ optionChecked }} name="1">
<span class="radio-label">{{{ labelString }}}</span>
<span class="checkmark"></span>
</label>
Expand All @@ -33,7 +33,7 @@
</div>
<div class="pref">
<h4 class="email-pref add-new">{{ getString "add-new-email" }}</h4>
{{> forms/add-another-email-form }}
{{> forms/add-another-email-form csrfToken=../csrfToken}}
</div>
<div class="pref remove">
<a href="/user/remove-fxm"><h3 class="remove-fxm subhead">{{ getString "remove-fxm" }}{{> svg/arrow-head-right }}</h3></a>
Expand Down
4 changes: 2 additions & 2 deletions views/partials/email-card.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
{{else}}
<!-- show resend-email link for unverified emails -->
<div class="button-resend-wrapper flx">
<button class="resend-email" data-email-id="{{ id }}" data-form-action="resend-email">{{ getString "resend-verification" }}</button>
<button class="resend-email" data-email-id="{{ id }}" data-form-action="resend-email" data-csrf-token="{{ csrfToken }}">{{ getString "resend-verification" }}</button>
<span class="sending hide"> {{getString "signup-modal-sent"}}</span>
</div>
{{/if}}
Expand All @@ -34,7 +34,7 @@
{{#if primary}}
<a href="{{ getFxaUrl }}" class="change-primary-email flx hide-mobile">{{ getString "link-change-primary" }}</a>
{{else}}
{{> forms/remove-email-form }}
{{> forms/remove-email-form csrfToken=../../../csrfToken }}
{{/if}}
{{else}} <!-- user breaches dashboard / show toggle -->
{{#ifCompare breaches.length ">" 0}}
Expand Down
1 change: 1 addition & 0 deletions views/partials/forms/add-another-email-form.hbs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<form action="/user/email" method="post" id="add-another-email-form" class="form-group add-new-email-form" data-event-category="Add Another Email Form">
<input type="hidden" name="_csrf" value="{{ csrfToken }}">
<div class="input-group">
<input id="email-add" class="input-group-field email-add" type="email" name="email" placeholder="{{ getString "scan-placeholder"}}" aria-label="{{ getString "scan-placeholder"}}" autocomplete="off">
{{> forms/error-message }}
Expand Down
1 change: 1 addition & 0 deletions views/partials/forms/remove-email-form.hbs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<form action="/user/remove-email" method="POST" class="remove-email svg-wrap" aria-label="{{ getString "stop-monitor-this" }}">
<input type="hidden" name="emailId" value="{{ id }}" />
<input type="hidden" name="_csrf" value="{{ csrfToken }}">
<input class="remove-email-submit" type="submit" value="" />{{> svg/trash-can}}
</form>
2 changes: 1 addition & 1 deletion views/partials/subpages/remove_fxm.hbs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<section id="unsubscribe" class="half">
<h3 class="pref-section-headline remove">{{ getString "remove-fxm" }}</h3>
<p class="subhead">{{ getString "remove-fxm-blurb" }}</p>
<button class="remove-fxm flx" data-form-action="remove-fxm" data-primary-token="{{ primaryToken }}" data-primary-hash="{{ primaryHash }}" href="#">{{ getString "remove-fxm" }}{{> svg/arrow-head-right }}</button>
<button class="remove-fxm flx" data-form-action="remove-fxm" data-csrf-token="{{ csrfToken }}" data-primary-token="{{ primaryToken }}" data-primary-hash="{{ primaryHash }}" href="#">{{ getString "remove-fxm" }}{{> svg/arrow-head-right }}</button>
</section>

0 comments on commit f3d81c4

Please sign in to comment.