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

mozilla / blurts-server / #11898

pending completion
#11898

push

circleci

web-flow
Merge pull request #2770 from mozilla/license

Add license headers in source files

282 of 1138 branches covered (24.78%)

Branch coverage included in aggregate %.

959 of 3049 relevant lines covered (31.45%)

2.55 hits per line

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

0.0
/src/controllers/auth.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 { URL } from 'url'
6
import { randomBytes } from 'crypto'
7

8
import AppConstants from '../app-constants.js'
9
import { getSubscriberByEmail, updateFxAData, removeFxAData } from '../db/tables/subscribers.js'
10
import { addSubscriber } from '../db/tables/email_addresses.js'
11
// import { sendEmail, getEmailCtaHref, getUnsubscribeUrl } from '../email-utils'
12
import { getProfileData, FxAOAuthClient } from '../utils/fxa.js'
13
// import { getBreachesForEmail } from '../utils/hibp.js'
14
import { fluentError } from '../utils/fluent.js'
15
import mozlog from '../utils/log.js'
16
const { SERVER_URL } = AppConstants
×
17

18
const log = mozlog('controllers.auth')
×
19

20
function init (req, res, next, client = FxAOAuthClient) {
×
21
  // Set a random state string in a cookie so that we can verify
22
  // the user when they're redirected back to us after auth.
23
  const state = randomBytes(40).toString('hex')
×
24
  req.session.state = state
×
25
  const url = new URL(client.code.getUri({ state }))
×
26
  const fxaParams = new URL(req.url, SERVER_URL)
×
27

28
  req.session.utmContents = {}
×
29
  url.searchParams.append('prompt', 'login')
×
30
  url.searchParams.append('max_age', 0)
×
31
  url.searchParams.append('access_type', 'offline')
×
32
  url.searchParams.append('action', 'email')
×
33

34
  for (const param of fxaParams.searchParams.keys()) {
×
35
    url.searchParams.append(param, fxaParams.searchParams.get(param))
×
36
  }
37

38
  res.redirect(url)
×
39
}
40

41
async function confirmed (req, res, next, client = FxAOAuthClient) {
×
42
  if (!req.session.state) {
×
43
    log.error('oauth-invalid-session', 'req.session.state missing')
×
44
    throw fluentError('oauth-invalid-session')
×
45
  }
46

47
  if (req.session.state !== req.query.state) {
×
48
    log.error('oauth-invalid-session', 'req.session does not match req.query')
×
49
    throw fluentError('oauth-invalid-session')
×
50
  }
51

52
  const fxaUser = await client.code.getToken(req.originalUrl, { state: req.session.state })
×
53
  // Clear the session.state to clean up and avoid any replays
54
  req.session.state = null
×
55
  log.debug('fxa-confirmed-fxaUser', fxaUser)
×
56
  const fxaProfileData = await getProfileData(fxaUser.accessToken)
×
57
  log.debug('fxa-confirmed-profile-data', fxaProfileData)
×
58
  const email = JSON.parse(fxaProfileData).email
×
59

60
  const existingUser = await getSubscriberByEmail(email)
×
61
  req.session.user = existingUser
×
62

63
  const returnURL = new URL('user/breaches', SERVER_URL)
×
64
  const originalURL = new URL(req.originalUrl, SERVER_URL)
×
65

66
  for (const [key, value] of originalURL.searchParams.entries()) {
×
67
    if (key.startsWith('utm_')) returnURL.searchParams.append(key, value)
×
68
  }
69

70
  // Check if user is signing up or signing in,
71
  // then add new users to db and send email.
72
  if (!existingUser) {
×
73
    // req.session.newUser determines whether or not we show "fxa_new_user_bar" in template
74
    req.session.newUser = true
×
75
    const signupLanguage = req.locale
×
76
    const verifiedSubscriber = await addSubscriber(email, signupLanguage, fxaUser.accessToken, fxaUser.refreshToken, fxaProfileData)
×
77

78
    // TODO:
79
    // duping some of user/verify for now
80
    // let unsafeBreachesForEmail = []
81

82
    // unsafeBreachesForEmail = await getBreachesForEmail(
83
    //   sha1(email),
84
    //   req.app.locals.breaches,
85
    //   true
86
    // )
87

88
    // const utmID = 'report'
89
    // const reportSubject = unsafeBreachesForEmail.length ? req.fluentFormat('email-subject-found-breaches') : req.fluentFormat('email-subject-no-breaches')
90

91
    // await sendEmail(
92
    //   email,
93
    //   reportSubject,
94
    //   'email-2022',
95
    //   {
96
    //     supportedLocales: req.supportedLocales,
97
    //     breachedEmail: email,
98
    //     recipientEmail: email,
99
    //     date: req.fluentFormat(new Date()),
100
    //     unsafeBreachesForEmail,
101
    //     ctaHref: getEmailCtaHref(utmID, 'dashboard-cta'),
102
    //     utmCampaign: utmID,
103
    //     unsubscribeUrl: getUnsubscribeUrl(verifiedSubscriber, utmID),
104
    //     whichPartial: 'email_partials/report',
105
    //     heading: req.fluentFormat('email-breach-summary')
106
    //   }
107
    // )
108
    req.session.user = verifiedSubscriber
×
109

110
    return res.redirect(returnURL.pathname + returnURL.search)
×
111
  }
112
  // Update existing user's FxA data
113
  await updateFxAData(existingUser, fxaUser.accessToken, fxaUser.refreshToken, fxaProfileData)
×
114

115
  res.redirect(returnURL.pathname + returnURL.search)
×
116
}
117

118
/**
119
 * Controller to trigger a logout for user
120
 * @param {object} req contains session.user
121
 * @param {object} res redirects to homepage
122
 */
123
async function logout (req, res) {
124
  const subscriber = req.session?.user
×
125
  log.info('logout', subscriber?.primary_email)
×
126

127
  // delete oauth session info in database
128
  await removeFxAData(subscriber)
×
129

130
  // clear session cache
131
  req.session.destroy(s => {
×
132
    delete req.session
×
133
    res.redirect('/')
×
134
  })
135
}
136

137
export { init, confirmed, logout }
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