Skip to content

Commit

Permalink
fix mozilla#242: use app.locals.breaches
Browse files Browse the repository at this point in the history
Update hibp module to match breached account website to
app.locals.breaches

Update /scan route to use app.locals.breaches

Update views to use new breach objects from app.locals.breaches

Drop Breach model and related scripts and db/utils code
  • Loading branch information
groovecoder committed Aug 1, 2018
1 parent e9dcd0f commit 111601b
Show file tree
Hide file tree
Showing 12 changed files with 19 additions and 282 deletions.
15 changes: 1 addition & 14 deletions db/migrations/initial_schema.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,10 @@ exports.up = knex => {
table.string("email");
table.string("verification_token").unique();
table.boolean("verified").defaultTo(false);
})
.createTable("breaches", table => {
table.increments("id").primary();
table.string("name").unique();
table.json("meta");
})
.createTable("breached_hashes", table => {
table.increments("id").primary();
table.integer("sha1_id").unsigned().references("id").inTable("email_hashes");
table.integer("breach_id").unsigned().references("id").inTable("breaches");
table.boolean("notified").defaultTo(false);
});
};

exports.down = knex => {
return knex.schema
.dropTableIfExists("breached_hashes")
.dropTableIfExists("email_hashes")
.dropTableIfExists("breaches");
.dropTableIfExists("email_hashes");
};
31 changes: 0 additions & 31 deletions db/models/breach.js

This file was deleted.

19 changes: 0 additions & 19 deletions db/models/emailhash.js
Original file line number Diff line number Diff line change
@@ -1,31 +1,12 @@
"use strict";

const Model = require("objection").Model;
const path = require("path");

class EmailHash extends Model {
// Table name is the only required property.
static get tableName() {
return "email_hashes";
}

static get relationMappings() {
return {
breaches: {
relation: Model.ManyToManyRelation,
modelClass: path.join(__dirname, "breach"),
join: {
from: "email_hashes.id",
through: {
from: "breached_hashes.sha1_id",
to: "breached_hashes.breach_id",
extra: ["notified"],
},
to: "breaches.id",
},
},
};
}
}

module.exports = EmailHash;
103 changes: 2 additions & 101 deletions db/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,39 +6,16 @@ const Knex = require("knex");
const knexConfig = require("./knexfile");
const { Model } = require("objection");

const Breach = require("./models/breach");
const EmailHash = require("./models/emailhash");

// FIXME: TODO: resolve circular depenency b/w db/utils and hibp
// const HIBP = require("../hibp");
const HIBP = require("../hibp");
const getSha1 = require("../sha1-utils");

const knex = Knex(knexConfig);
Model.knex(knex);


const DBUtils = {
async createBreach(name, meta) {
try {
return await Breach
.query()
.insert({ name, meta });
} catch(e) {
console.error(e);
if (e.code && e.code === "23505") {
// Duplicate error, silently log.
console.error(`Duplicate breach: ${name}`);
return;
}

throw e;
}
},

async deleteBreach(id) {
await Breach.query().deleteById(id);
},

async addUnverifiedEmailHash(email) {
return await EmailHash.query().insert(
{email: email, sha1: getSha1(email), verification_token: uuidv4(), verified: false}
Expand Down Expand Up @@ -110,8 +87,7 @@ const DBUtils = {
},

async verifySubscriber(emailHash) {
// FIXME: TODO: resolve circular depenency b/w db/utils and hibp
// await HIBP.subscribeHash(emailHash.sha1);
await HIBP.subscribeHash(emailHash.sha1);
return await emailHash.$query().patch({ verified: true }).returning("*");
},

Expand All @@ -127,85 +103,10 @@ const DBUtils = {
});
},

async getSubscribersForBreach(breach) {
return await breach
.$relatedQuery("email_hashes")
.whereNotNull("email")
.where("notified", false);
},

async getSubscribersByHashes(hashes) {
return await EmailHash.query().whereIn("sha1", hashes).andWhere("verified", "=", true);
},

async addBreachedHash(breachName, sha1) {
const addedEmailHash = await this._addEmailHash(sha1);

const breachesByName = await Breach
.query()
.where("name", breachName);

if (!breachesByName.length) {
return;
}

const breach = breachesByName[0];

const relatedSha1 = await breach
.$relatedQuery("email_hashes")
.where("sha1", sha1);

if (relatedSha1.length) {
// Already associated, nothing to do.
return;
}

return await breach
.$relatedQuery("email_hashes")
.relate(addedEmailHash.id);
},

async addBreachedEmail(breachName, email) {
return await this.addBreachedHash(breachName, getSha1(email));
},

async setBreachedHashNotified(breach, email) {
return await breach
.$relatedQuery("email_hashes")
.where("sha1", getSha1(email))
.patch({ notified: true });
},

async getBreachesForHash(sha1) {
return await this._getSha1EntryAndDo(sha1, async aEntry => {
return await aEntry
.$relatedQuery("breaches")
.orderBy("name");
}, async () => {
return [];
});
},

async getBreachesForHashPrefix(sha1Prefix) {
return await this._getSha1EntriesFromPrefixAndDo(sha1Prefix, async aEntries => {
return aEntries;
}, async () => {
return [];
});
},

getBreachesForEmail(email) {
return this.getBreachesForHash(getSha1(email));
},

async getBreachByName(breachName) {
return (await Breach.query().where("name", breachName))[0];
},

async getBreachesByNames(breachNames) {
return await Breach.query().where("name", "in", breachNames);
},

};

module.exports = DBUtils;
5 changes: 2 additions & 3 deletions hibp.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ const createDOMPurify = require("dompurify");
const { JSDOM } = require("jsdom");

const AppConstants = require("./app-constants");
const DBUtils = require("./db/utils");
const pkg = require("./package.json");


Expand Down Expand Up @@ -70,13 +69,13 @@ const HIBP = {
// ]
for (const breachedAccount of response.body) {
if (sha1.toUpperCase() === sha1Prefix + breachedAccount.hashSuffix) {
foundBreaches = await DBUtils.getBreachesByNames(breachedAccount.websites);
foundBreaches = allBreaches.filter(breach => breachedAccount.websites.includes(breach.Name));
}
}
} catch (error) {
console.error(error);
}
return foundBreaches.filter(({meta}) => meta.IsVerified && !meta.IsRetired && !meta.IsSensitive && !meta.IsSpamList);
return foundBreaches.filter(breach => breach.IsVerified && !breach.IsRetired && !breach.IsSensitive && !breach.IsSpamList);
},

async subscribeHash(sha1) {
Expand Down
2 changes: 1 addition & 1 deletion routes/scan.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ router.post("/", urlEncodedParser, async (req, res) => {
if (req.body.signup) {
signup = "checkboxChecked";
}
const foundBreaches = await HIBP.getBreachesForEmail(emailHash);
const foundBreaches = await HIBP.getBreachesForEmail(emailHash, req.app.locals.breaches);

res.render("scan", {
title: "Firefox Breach Alerts: Scan Results",
Expand Down
52 changes: 0 additions & 52 deletions scripts/add-breached-emails.js

This file was deleted.

48 changes: 0 additions & 48 deletions scripts/load-breaches.js

This file was deleted.

2 changes: 1 addition & 1 deletion views/email/breach_notification.hbs
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
{{!< email }}
Uh-oh, {{ email }} was involved in {{ breach.meta.Title }} data breach.
Uh-oh, {{ email }} was involved in {{ breach.Title }} data breach.
12 changes: 6 additions & 6 deletions views/partials/banner_breach.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,17 @@
<div class="account">
<div id="breach-title-wrapper">
<div class="image-wrap">
<img alt="{{ breach.meta.Title }}" src="img/logos/{{ breach.name }}.{{ breach.meta.LogoType }}">
<img alt="{{ breach.Title }}" src="img/logos/{{ breach.Name }}.{{ breach.LogoType }}">
</div>
<div id="breach-title-date">
<h3>{{ breach.meta.Title }} Breach</h3>
<span class="breach-info"><span class="medium">Breach Date</span> {{prettyDate breach.meta.BreachDate }}</span>
<h3>{{ breach.Title }} Breach</h3>
<span class="breach-info"><span class="medium">Breach Date</span> {{prettyDate breach.BreachDate }}</span>
</div>
</div>

<span class="breach-info"><span class="medium">Compromised Data</span> {{breachDataClasses breach.meta.DataClasses }}</span>
<span class="breach-info"><span class="medium">Compromised Accounts</span> {{localeString breach.meta.PwnCount }}</span>
<span class="breach-info">{{{ breach.meta.Description }}}</span>
<span class="breach-info"><span class="medium">Compromised Data</span> {{breachDataClasses breach.DataClasses }}</span>
<span class="breach-info"><span class="medium">Compromised Accounts</span> {{localeString breach.PwnCount }}</span>
<span class="breach-info">{{{ breach.Description }}}</span>
{{> hipb_attribution }}
</div>
{{/if}}
Loading

0 comments on commit 111601b

Please sign in to comment.