Merge pull request #146 from mozilla/hash-email-on-client-143

fix #143: hash email client-side before scanning
This commit is contained in:
Lesley Norton 2018-06-06 13:54:46 -05:00 коммит произвёл GitHub
Родитель 3fff9d2706 f7d4a907f5
Коммит 237706c39d
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
11 изменённых файлов: 55 добавлений и 107 удалений

Просмотреть файл

@ -5,17 +5,15 @@ const got = require("got");
const AppConstants = require("./app-constants");
const DBUtils = require("./db/utils");
const pkg = require("./package.json");
const getSha1 = require("./sha1-utils");
const HIBP_USER_AGENT = `${pkg.name}/${pkg.version}`;
const HIBP = {
async getBreachesForEmail(email) {
async getBreachesForEmail(sha1) {
let foundBreaches = [];
const sha1 = getSha1(email);
const sha1Prefix = sha1.slice(0, 6);
const url = `${AppConstants.HIBP_STAGE_API_ROOT}/breachedaccount/range/${sha1Prefix}?code=${encodeURIComponent(AppConstants.HIBP_STAGE_API_TOKEN)}`;
const headers = {

Просмотреть файл

@ -2,6 +2,7 @@
"use strict";
/*
function doXHR(aURL, aBodyObj, aAlertText, aDebug=true) {
return new Promise((resolve) => {
const xhr = new XMLHttpRequest();
@ -25,42 +26,21 @@ function doXHR(aURL, aBodyObj, aAlertText, aDebug=true) {
});
}
// eslint-disable-next-line no-unused-vars
function addUser() {
doXHR("/user/add",
{ email: document.getElementById("addUserField").value })
.then(function() {
alert("A verification link has been emailed to the specified address.");
});
function isValidEmail(val) {
// https://stackoverflow.com/a/46181
const re = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
return re.test(String(val).toLowerCase());
}
// eslint-disable-next-line no-unused-vars
function removeUser() {
doXHR("/user/remove",
{ email: document.getElementById("removeUserField").value });
function enableBtnIfEmailValid(e) {
const emailBtn = document.getElementById("subscribe-email-btn");
if (isValidEmail(e.target.value)) {
emailBtn.disabled = false;
} else {
emailBtn.disabled = true;
}
}
// eslint-disable-next-line no-unused-vars
// function doOauth() {
// window.open("/oauth/init");
// }
// function isValidEmail(val) {
// // https://stackoverflow.com/a/46181
// const re = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
// return re.test(String(val).toLowerCase());
// }
// function enableBtnIfEmailValid(e) {
// const emailBtn = document.getElementById("subscribe-email-btn");
// if (isValidEmail(e.target.value)) {
// emailBtn.disabled = false;
// } else {
// emailBtn.disabled = true;
// }
// }
*/
function showFalseDoor(){
const falseDoorBlurb = "<div class='section-container'><h4>Thank you for trying Firefox Monitor</h4><p>FireFox Monitor is a concept we are testing. We hope to provide the service to everyone soon.</p><p>Stay up-to-date with Firefox Monitor and other new features when you sign up for the <a href='https://www.mozilla.org/newsletter/firefox/'>Firefox newsletter.</a></p><button class='button' id='close-false-door'>Close</button></div>";
@ -75,9 +55,25 @@ function showFalseDoor(){
}
async function sha1(message) {
const msgBuffer = new TextEncoder("utf-8").encode(message);
const hashBuffer = await crypto.subtle.digest("SHA-1", msgBuffer);
const hashArray = Array.from(new Uint8Array(hashBuffer));
const hashHex = hashArray.map(b => ("00" + b.toString(16)).slice(-2)).join("");
return hashHex;
}
async function hashEmailAndSend(emailFormSubmitEvent) {
emailFormSubmitEvent.preventDefault();
const emailForm = emailFormSubmitEvent.target;
for (const emailInput of emailForm.querySelectorAll("input[type=email]")) {
emailForm.querySelector("input[name=emailHash]").value = await sha1(emailInput.value);
emailInput.value = "";
}
emailForm.submit();
}
document.querySelector(".email-scan").addEventListener("submit", hashEmailAndSend);
$(document).foundation();
document.querySelector("#sign-up").addEventListener("click", showFalseDoor);

Просмотреть файл

@ -1,17 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>blurts-server testing UI</title>
<script src="/js/test.js"></script>
</head>
<body>
<input type="text" id="addUserField" /><input type="submit" value="Add User" onclick="addUser()" /><br/>
<input type="submit" value="Add User Using FxA" onclick="doOauth()"/><br/>
<input type="text" id="removeUserField" /><input type="submit" value="Remove User" onclick="removeUser()" /><br/>
<br/>
<h1>Response dump:</h1>
<div id="responseDump" />
</body>
</html>

Просмотреть файл

@ -1,24 +0,0 @@
"use strict";
const express = require("express");
const bodyParser = require("body-parser");
const DBUtils = require("../db/utils");
const router = express.Router();
const urlEncodedParser = bodyParser.urlencoded({ extended: false });
router.get("/api/v3/breachedaccount/range/:hashPrefix", urlEncodedParser, async (req, res) => {
const hashPrefix = req.params.hashPrefix;
const foundEntries = await DBUtils.getBreachesForHashPrefix(hashPrefix);
if (!foundEntries.length) {
res.status(404).send("Not Found");
} else {
res.render("range", {foundEntries});
}
});
module.exports = router;

Просмотреть файл

@ -12,25 +12,24 @@ const urlEncodedParser = bodyParser.urlencoded({ extended: false });
router.post("/", urlEncodedParser, async (req, res) => {
const email = req.body.email;
const emailHash = req.body.emailHash;
let foundBreaches = [];
if (!req.session.scanResults) {
req.session.scanResults = {};
}
if (email) {
if (req.session.scanResults[email]) {
foundBreaches = req.session.scanResults[email];
if (emailHash) {
if (req.session.scanResults[emailHash]) {
foundBreaches = req.session.scanResults[emailHash];
} else {
foundBreaches = await HIBP.getBreachesForEmail(email);
req.session.scanResults[email] = foundBreaches;
foundBreaches = await HIBP.getBreachesForEmail(emailHash);
req.session.scanResults[emailHash] = foundBreaches;
}
}
res.render("scan", {
title: "Firefox Breach Alerts: Scan Results",
email: email,
foundBreaches: foundBreaches,
});
});

Просмотреть файл

@ -7,15 +7,14 @@ const hbs = require("express-hbs");
const helmet = require("helmet");
const sessions = require("client-sessions");
const EmailUtils = require("./email-utils");
// const EmailUtils = require("./email-utils");
const HBSHelpers = require("./hbs-helpers");
const DockerflowRoutes = require("./routes/dockerflow");
const HIBPRoutes = require("./routes/hibp-stubs");
const HomeRoutes = require("./routes/home");
const OAuthRoutes = require("./routes/oauth");
const ScanRoutes = require("./routes/scan");
const UserRoutes = require("./routes/user");
// const OAuthRoutes = require("./routes/oauth");
// const UserRoutes = require("./routes/user");
const app = express();
@ -70,15 +69,14 @@ app.use(sessions({
app.use("/", HomeRoutes);
app.use("/", DockerflowRoutes);
app.use("/hibp", HIBPRoutes);
app.use("/oauth", OAuthRoutes);
app.use("/scan", ScanRoutes);
app.use("/user", UserRoutes);
// app.use("/oauth", OAuthRoutes);
// app.use("/user", UserRoutes);
EmailUtils.init().then(() => {
// EmailUtils.init().then(() => {
const listener = app.listen(AppConstants.PORT, () => {
console.info(`Listening on ${listener.address().port}`);
});
}).catch(error => {
/* }).catch(error => {
console.error(error);
});
}); */

Просмотреть файл

@ -13,9 +13,10 @@
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec volutpat hendrerit !nibus.
</p>
<br>
<form action="/scan" method="post">
<form action="/scan" class="email-scan" method="post">
<div class="input-group">
<input class="input-group-field email-to-hash" type="email" name="email">
<input class="input-group-field email-to-hash" type="email">
<input type="hidden" name="emailHash">
<div class="input-group-button">
<input id="submit-email" type="submit" class="button" value="Scan">
</div>

Просмотреть файл

@ -9,7 +9,7 @@
<link rel="stylesheet" href="/css/app.css">
<script type="text/javascript" src="/js/vendor/jquery.js" defer></script>
<script type="text/javascript" src="/js/vendor/foundation.min.js" defer></script>
<script type="text/javascript" src="/js/test.js" defer></script>
<script type="text/javascript" src="/js/monitor.js" defer></script>
</head>
<body>
<header class ="top-bar">

Просмотреть файл

@ -5,9 +5,10 @@
{{else}}
<p class="demi">The first step to keeping your online accounts safe is knowing what youre up against. Enter your email to find out if your accounts have been compromised.</p>
{{/if}}
<form action="/scan" method="post">
<form action="/scan" class="email-scan" method="post">
<div class="input-group">
<input class="input-group-field email-to-hash" type="email" name="email" placeholder="Enter Email Address">
<input class="input-group-field email-to-hash" type="email" placeholder="Enter Email Address">
<input type="hidden" name="emailHash">
<div class="input-group-button">
<img src="img/Search.svg" alt="search icon" />
<input id="submit-email" type="submit" class="button" value="Search">

Просмотреть файл

@ -16,10 +16,11 @@
<span class="bold">Subscribe</span> for alerts from Firefox Monitor to learn sooner about your compromised accounts.
</li>
<li>
<form action="/scan" method="post">
<form action="/scan" class="email-scan" method="post">
<label class="medium">Scan another email address</label>
<div class="input-group">
<input class="input-group-field email-to-hash" type="email" name="email" placeholder="Enter Email">
<input class="input-group-field email-to-hash" type="email" placeholder="Enter Email">
<input type="hidden" name="emailHash">
<div class="input-group-button">
<img src="img/Search.svg" alt="search icon" />
<input id="submit-email" type="submit" class="button" value="">

Просмотреть файл

@ -1,5 +0,0 @@
{{#if foundEntries }}
{{#each foundEntries }}
{{ sha1 }}:{{#each breaches }}{{ name }}{{#unless @last}},{{/unless}}{{/each}}
{{/each }}
{{/if }}