• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

mozilla / blurts-server / #12632

pending completion
#12632

push

circleci

web-flow
Merge pull request #2854 from mozilla/MNTOR-741

MNTOR-741

282 of 1416 branches covered (19.92%)

Branch coverage included in aggregate %.

107 of 107 new or added lines in 9 files covered. (100.0%)

959 of 3912 relevant lines covered (24.51%)

2.04 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/src/utils/breaches.js
1
/* This Source Code Form is subject to the terms of the Mozilla Public
2
 * License, v. 2.0. If a copy of the MPL was not distributed with this
3
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4

5
import { getUserEmails } from '../db/tables/email_addresses.js'
6
import { getBreachesForEmail, getFilteredBreaches } from './hibp.js'
7
import { getSha1 } from './fxa.js'
8
import { filterBreachDataTypes } from './breach-resolution.js'
9

10
/**
11
 * TODO: deprecate
12
 * Get all emails and breaches for a user via app.locals
13
 * This function will be replaced after 'breaches" table is created
14
 * and all records can be retrieved from the one table
15
 *
16
 * @param {*} user
17
 * @param {*} allBreaches
18
 * @returns
19
 */
20
async function getAllEmailsAndBreaches (user, allBreaches) {
21
  const monitoredEmails = await getUserEmails(user.id)
×
22
  const verifiedEmails = []
×
23
  const unverifiedEmails = []
×
24
  verifiedEmails.push(await bundleVerifiedEmails({ user, email: user.primary_email, recordId: user.id, recordVerified: user.primary_verified, allBreaches }))
×
25
  for (const email of monitoredEmails) {
×
26
    if (email.verified) {
×
27
      verifiedEmails.push(await bundleVerifiedEmails({ user, email: email.email, recordId: email.id, recordVerified: email.verified, allBreaches }))
×
28
    } else {
29
      unverifiedEmails.push(email)
×
30
    }
31
  }
32

33
  // get new breaches since last shown
34
  for (const emailEntry of verifiedEmails) {
×
35
    const newBreachesForEmail = emailEntry.breaches.filter(breach => breach.AddedDate >= user.breaches_last_shown)
×
36

37
    for (const newBreachForEmail of newBreachesForEmail) {
×
38
      newBreachForEmail.NewBreach = true // add "NewBreach" property to the new breach.
×
39
      emailEntry.hasNewBreaches = newBreachesForEmail.length // add the number of new breaches to the email
×
40
    }
41
  }
42

43
  return { verifiedEmails, unverifiedEmails }
×
44
}
45

46
function addRecencyIndex (foundBreaches) {
47
  const annotatedBreaches = []
×
48
  // slice() the array to make a copy so before reversing so we don't
49
  // reverse foundBreaches in-place
50
  const oldestToNewestFoundBreaches = foundBreaches.slice().reverse()
×
51
  oldestToNewestFoundBreaches.forEach((annotatingBreach, index) => {
×
52
    const foundBreach = foundBreaches.find(foundBreach => foundBreach.Name === annotatingBreach.Name)
×
53
    annotatedBreaches.push(Object.assign({ recencyIndex: index }, foundBreach))
×
54
  })
55
  return annotatedBreaches.reverse()
×
56
}
57

58
async function bundleVerifiedEmails (options) {
59
  const { user, email, recordId, recordVerified, allBreaches } = options
×
60
  const lowerCaseEmailSha = getSha1(email.toLowerCase())
×
61

62
  // find all breaches relevant to the current email
63
  const foundBreaches = await getBreachesForEmail(lowerCaseEmailSha, allBreaches, true, false)
×
64

65
  // TODO: remove after migration MNTOR-978
66
  // adding index to breaches based on recency
67
  const foundBreachesWithRecency = addRecencyIndex(foundBreaches)
×
68

69
  // get v2 "breach_resolution" object
70
  const breachResolutionV2 = user.breach_resolution
×
71
    ? user.breach_resolution[email] ? user.breach_resolution[email] : {}
×
72
    : []
73

74
  const useBreachId = user.breach_resolution?.useBreachId
×
75

76
  for (const breach of foundBreachesWithRecency) {
×
77
    // if breach resolution json has `useBreachId` boolean, that means the migration has taken place
78
    // we will use breach id as the key. Otherwise, we fallback to using recency index for backwards compatibility
79
    if (useBreachId) {
×
80
      breach.IsResolved = breachResolutionV2[breach.Id]?.isResolved
×
81
      breach.ResolutionsChecked = breachResolutionV2[breach.Id]?.resolutionsChecked || []
×
82
    } else {
83
      // TODO: remove after MNTOR-978
84
      breach.IsResolved = breachResolutionV2[breach.recencyIndex]?.isResolved
×
85
      breach.ResolutionsChecked = breachResolutionV2[breach.recencyIndex]?.resolutionsChecked || []
×
86
    }
87

88
    // filter breach types based on the 13 types we care about
89
    breach.DataClasses = filterBreachDataTypes(breach.DataClasses)
×
90
  }
91

92
  // filter out irrelevant breaches based on HIBP
93
  const filteredAnnotatedFoundBreaches = getFilteredBreaches(foundBreachesWithRecency)
×
94

95
  const emailEntry = {
×
96
    email,
97
    breaches: filteredAnnotatedFoundBreaches,
98
    primary: email === user.primary_email,
99
    id: recordId,
100
    verified: recordVerified
101
  }
102

103
  return emailEntry
×
104
}
105

106
export { getAllEmailsAndBreaches }
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc