wip: Add endpoints
This commit is contained in:
Родитель
654cbc5d4c
Коммит
70b05456b5
|
@ -17,7 +17,7 @@
|
|||
"@maxmind/geoip2-node": "^3.1.0",
|
||||
"@sentry/node": "7.36.0",
|
||||
"@sentry/tracing": "^7.36.0",
|
||||
"body-parser": "^1.20.1",
|
||||
"body-parser": "^1.20.2",
|
||||
"client-oauth2": "4.3.3",
|
||||
"connect-redis": "6.1.3",
|
||||
"cookie-parser": "^1.4.6",
|
||||
|
@ -2775,12 +2775,12 @@
|
|||
"dev": true
|
||||
},
|
||||
"node_modules/body-parser": {
|
||||
"version": "1.20.1",
|
||||
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz",
|
||||
"integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==",
|
||||
"version": "1.20.2",
|
||||
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz",
|
||||
"integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==",
|
||||
"dependencies": {
|
||||
"bytes": "3.1.2",
|
||||
"content-type": "~1.0.4",
|
||||
"content-type": "~1.0.5",
|
||||
"debug": "2.6.9",
|
||||
"depd": "2.0.0",
|
||||
"destroy": "1.2.0",
|
||||
|
@ -2788,7 +2788,7 @@
|
|||
"iconv-lite": "0.4.24",
|
||||
"on-finished": "2.4.1",
|
||||
"qs": "6.11.0",
|
||||
"raw-body": "2.5.1",
|
||||
"raw-body": "2.5.2",
|
||||
"type-is": "~1.6.18",
|
||||
"unpipe": "1.0.0"
|
||||
},
|
||||
|
@ -5257,6 +5257,29 @@
|
|||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz",
|
||||
"integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg=="
|
||||
},
|
||||
"node_modules/express/node_modules/body-parser": {
|
||||
"version": "1.20.1",
|
||||
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz",
|
||||
"integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==",
|
||||
"dependencies": {
|
||||
"bytes": "3.1.2",
|
||||
"content-type": "~1.0.4",
|
||||
"debug": "2.6.9",
|
||||
"depd": "2.0.0",
|
||||
"destroy": "1.2.0",
|
||||
"http-errors": "2.0.0",
|
||||
"iconv-lite": "0.4.24",
|
||||
"on-finished": "2.4.1",
|
||||
"qs": "6.11.0",
|
||||
"raw-body": "2.5.1",
|
||||
"type-is": "~1.6.18",
|
||||
"unpipe": "1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.8",
|
||||
"npm": "1.2.8000 || >= 1.4.16"
|
||||
}
|
||||
},
|
||||
"node_modules/express/node_modules/cookie": {
|
||||
"version": "0.5.0",
|
||||
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz",
|
||||
|
@ -5265,6 +5288,20 @@
|
|||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/express/node_modules/raw-body": {
|
||||
"version": "2.5.1",
|
||||
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz",
|
||||
"integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==",
|
||||
"dependencies": {
|
||||
"bytes": "3.1.2",
|
||||
"http-errors": "2.0.0",
|
||||
"iconv-lite": "0.4.24",
|
||||
"unpipe": "1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/extend": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
|
||||
|
@ -9700,9 +9737,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/raw-body": {
|
||||
"version": "2.5.1",
|
||||
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz",
|
||||
"integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==",
|
||||
"version": "2.5.2",
|
||||
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz",
|
||||
"integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==",
|
||||
"dependencies": {
|
||||
"bytes": "3.1.2",
|
||||
"http-errors": "2.0.0",
|
||||
|
@ -13886,12 +13923,12 @@
|
|||
"dev": true
|
||||
},
|
||||
"body-parser": {
|
||||
"version": "1.20.1",
|
||||
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz",
|
||||
"integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==",
|
||||
"version": "1.20.2",
|
||||
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz",
|
||||
"integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==",
|
||||
"requires": {
|
||||
"bytes": "3.1.2",
|
||||
"content-type": "~1.0.4",
|
||||
"content-type": "~1.0.5",
|
||||
"debug": "2.6.9",
|
||||
"depd": "2.0.0",
|
||||
"destroy": "1.2.0",
|
||||
|
@ -13899,7 +13936,7 @@
|
|||
"iconv-lite": "0.4.24",
|
||||
"on-finished": "2.4.1",
|
||||
"qs": "6.11.0",
|
||||
"raw-body": "2.5.1",
|
||||
"raw-body": "2.5.2",
|
||||
"type-is": "~1.6.18",
|
||||
"unpipe": "1.0.0"
|
||||
}
|
||||
|
@ -15667,10 +15704,40 @@
|
|||
"vary": "~1.1.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"body-parser": {
|
||||
"version": "1.20.1",
|
||||
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz",
|
||||
"integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==",
|
||||
"requires": {
|
||||
"bytes": "3.1.2",
|
||||
"content-type": "~1.0.4",
|
||||
"debug": "2.6.9",
|
||||
"depd": "2.0.0",
|
||||
"destroy": "1.2.0",
|
||||
"http-errors": "2.0.0",
|
||||
"iconv-lite": "0.4.24",
|
||||
"on-finished": "2.4.1",
|
||||
"qs": "6.11.0",
|
||||
"raw-body": "2.5.1",
|
||||
"type-is": "~1.6.18",
|
||||
"unpipe": "1.0.0"
|
||||
}
|
||||
},
|
||||
"cookie": {
|
||||
"version": "0.5.0",
|
||||
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz",
|
||||
"integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw=="
|
||||
},
|
||||
"raw-body": {
|
||||
"version": "2.5.1",
|
||||
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz",
|
||||
"integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==",
|
||||
"requires": {
|
||||
"bytes": "3.1.2",
|
||||
"http-errors": "2.0.0",
|
||||
"iconv-lite": "0.4.24",
|
||||
"unpipe": "1.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -18997,9 +19064,9 @@
|
|||
"integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="
|
||||
},
|
||||
"raw-body": {
|
||||
"version": "2.5.1",
|
||||
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz",
|
||||
"integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==",
|
||||
"version": "2.5.2",
|
||||
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz",
|
||||
"integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==",
|
||||
"requires": {
|
||||
"bytes": "3.1.2",
|
||||
"http-errors": "2.0.0",
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
"@maxmind/geoip2-node": "^3.1.0",
|
||||
"@sentry/node": "7.36.0",
|
||||
"@sentry/tracing": "^7.36.0",
|
||||
"body-parser": "^1.20.1",
|
||||
"body-parser": "^1.20.2",
|
||||
"client-oauth2": "4.3.3",
|
||||
"connect-redis": "6.1.3",
|
||||
"cookie-parser": "^1.4.6",
|
||||
|
|
|
@ -32,6 +32,7 @@ function getTemplatesData () {
|
|||
return {
|
||||
[EmailTemplateType.Verification]: {
|
||||
label: 'Email verification',
|
||||
data: getVerificationDummyData(EMAIL_TEST_RECIPIENT), // TODO: Remove - only for dev testing
|
||||
template: getPreviewTemplate(
|
||||
getVerificationDummyData(EMAIL_TEST_RECIPIENT),
|
||||
verifyPartial
|
||||
|
@ -39,6 +40,7 @@ function getTemplatesData () {
|
|||
},
|
||||
[EmailTemplateType.Notification]: {
|
||||
label: 'Breach notification',
|
||||
data: getNotifictionDummyData(EMAIL_TEST_RECIPIENT), // TODO: Remove - only for dev testing
|
||||
template: getPreviewTemplate(
|
||||
getNotifictionDummyData(EMAIL_TEST_RECIPIENT),
|
||||
breachAlertEmailPartial
|
||||
|
@ -46,6 +48,7 @@ function getTemplatesData () {
|
|||
},
|
||||
[EmailTemplateType.Monthly]: {
|
||||
label: 'Monthly unresolved breaches',
|
||||
data: getMonthlyDummyData(EMAIL_TEST_RECIPIENT), // TODO: Remove - only for dev testing
|
||||
template: getPreviewTemplate(
|
||||
getMonthlyDummyData(EMAIL_TEST_RECIPIENT),
|
||||
monthlyUnresolvedEmailPartial
|
||||
|
@ -53,6 +56,7 @@ function getTemplatesData () {
|
|||
},
|
||||
[EmailTemplateType.SignupReport]: {
|
||||
label: 'Signup report',
|
||||
data: getSignupReportDummyData(EMAIL_TEST_RECIPIENT), // TODO: Remove - only for dev testing
|
||||
template: getPreviewTemplate(
|
||||
getSignupReportDummyData(EMAIL_TEST_RECIPIENT),
|
||||
signupReportEmailPartial
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
import bodyParser from 'body-parser'
|
||||
import { Router } from 'express'
|
||||
|
||||
import { asyncMiddleware } from '../middleware/util.js'
|
||||
|
@ -11,8 +12,14 @@ import { dashboardPage } from '../controllers/dashboard.js'
|
|||
import { breachesPage } from '../controllers/breaches.js'
|
||||
import { dataRemovalPage } from '../controllers/data-removal.js'
|
||||
import { settingsPage } from '../controllers/settings.js'
|
||||
import {
|
||||
getUnsubscribeUrl,
|
||||
getMonthlyUnsubscribeUrl,
|
||||
postUnsubscribe
|
||||
} from '../utils/email.js'
|
||||
|
||||
const router = Router()
|
||||
const urlEncodedParser = bodyParser.urlencoded({ extended: false })
|
||||
|
||||
// dashboard page
|
||||
router.get('/dashboard', requireSessionUser, dashboardPage)
|
||||
|
@ -29,4 +36,18 @@ router.get('/settings', requireSessionUser, settingsPage)
|
|||
// sign the user out
|
||||
router.get('/logout', asyncMiddleware(logout))
|
||||
|
||||
// unsubscribe from emails
|
||||
router.use('/unsubscribe', urlEncodedParser)
|
||||
router.get('/unsubscribe', urlEncodedParser, asyncMiddleware(getUnsubscribeUrl))
|
||||
router.get(
|
||||
'/unsubscribe-monthly',
|
||||
urlEncodedParser,
|
||||
asyncMiddleware(getMonthlyUnsubscribeUrl)
|
||||
)
|
||||
router.post(
|
||||
'/unsubscribe',
|
||||
requireSessionUser,
|
||||
asyncMiddleware(postUnsubscribe)
|
||||
)
|
||||
|
||||
export default router
|
||||
|
|
|
@ -109,6 +109,7 @@ function getVerificationUrl (subscriber) {
|
|||
}
|
||||
|
||||
function getUnsubscribeUrl (subscriber, emailType) {
|
||||
console.log('getUnsubscribeUrl')
|
||||
// TODO: email unsubscribe is broken for most emails
|
||||
const token = Object.hasOwn(subscriber, 'verification_token')
|
||||
? subscriber.verification_token
|
||||
|
@ -125,6 +126,7 @@ function getUnsubscribeUrl (subscriber, emailType) {
|
|||
}
|
||||
|
||||
function getMonthlyUnsubscribeUrl (subscriber, campaign, content) {
|
||||
console.log('getMonthlyUnsubscribeUrl')
|
||||
// TODO: create new subscriptions section in settings to manage
|
||||
// all emails and avoid one-off routes like this
|
||||
if (!subscriber.primary_verification_token) {
|
||||
|
@ -138,6 +140,10 @@ function getMonthlyUnsubscribeUrl (subscriber, campaign, content) {
|
|||
return appendUtmParams(url, campaign, content)
|
||||
}
|
||||
|
||||
function postUnsubscribe () {
|
||||
console.log('postUnsubscribe')
|
||||
}
|
||||
|
||||
/**
|
||||
* Dummy data for populating the breach notification email preview
|
||||
*
|
||||
|
@ -175,7 +181,7 @@ const getNotifictionDummyData = (recipient) => ({
|
|||
recipientEmail: recipient,
|
||||
subscriberId: 123,
|
||||
supportedLocales: ['en'],
|
||||
unsubscribeUrl: SERVER_URL,
|
||||
unsubscribeUrl: getUnsubscribeUrl(recipient, 'email-type'),
|
||||
utmCampaign: ''
|
||||
})
|
||||
|
||||
|
@ -186,12 +192,12 @@ const getNotifictionDummyData = (recipient) => ({
|
|||
* @returns {object} Email verification dummy data
|
||||
*/
|
||||
const getVerificationDummyData = (recipient) => ({
|
||||
recipientEmail: recipient,
|
||||
ctaHref: SERVER_URL,
|
||||
utmCampaign: 'email_verify',
|
||||
unsubscribeUrl: SERVER_URL,
|
||||
heading: getMessage('email-verify-heading'),
|
||||
subheading: getMessage('email-verify-subhead')
|
||||
recipientEmail: recipient,
|
||||
subheading: getMessage('email-verify-subhead'),
|
||||
unsubscribeUrl: getUnsubscribeUrl(recipient, 'email-type'),
|
||||
utmCampaign: 'email_verify'
|
||||
})
|
||||
|
||||
/**
|
||||
|
@ -201,13 +207,9 @@ const getVerificationDummyData = (recipient) => ({
|
|||
* @returns {object} Monthly unresolved breaches dummy data
|
||||
*/
|
||||
const getMonthlyDummyData = (recipient) => ({
|
||||
recipientEmail: recipient,
|
||||
ctaHref: SERVER_URL,
|
||||
utmCampaign: '',
|
||||
unsubscribeUrl: SERVER_URL,
|
||||
heading: getMessage('email-unresolved-heading'),
|
||||
subheading: getMessage('email-unresolved-subhead'),
|
||||
breachedEmail: 'breached@email.com',
|
||||
ctaHref: SERVER_URL,
|
||||
heading: getMessage('email-unresolved-heading'),
|
||||
monitoredEmails: {
|
||||
count: 2
|
||||
},
|
||||
|
@ -215,7 +217,11 @@ const getMonthlyDummyData = (recipient) => ({
|
|||
count: 3,
|
||||
numResolved: 2,
|
||||
numUnresolved: 1
|
||||
}
|
||||
},
|
||||
recipientEmail: recipient,
|
||||
subheading: getMessage('email-unresolved-subhead'),
|
||||
unsubscribeUrl: getMonthlyUnsubscribeUrl(recipient, 'campaign', 'content'),
|
||||
utmCampaign: ''
|
||||
})
|
||||
|
||||
/**
|
||||
|
@ -257,7 +263,7 @@ const getSignupReportDummyData = (recipient) => {
|
|||
recipientEmail: recipient,
|
||||
subscriberId: 123,
|
||||
unsafeBreachesForEmail,
|
||||
unsubscribeUrl: SERVER_URL,
|
||||
unsubscribeUrl: getUnsubscribeUrl(recipient, 'email-type'),
|
||||
utmCampaign: ''
|
||||
}
|
||||
}
|
||||
|
@ -273,5 +279,6 @@ export {
|
|||
getVerificationDummyData,
|
||||
getVerificationUrl,
|
||||
initEmail,
|
||||
postUnsubscribe,
|
||||
sendEmail
|
||||
}
|
||||
|
|
|
@ -52,6 +52,13 @@ export const emailPreview = (data) => {
|
|||
<custom-select name='email-template'>
|
||||
${getPreviewOptions(currentTemplateKey, emailTemplates)}
|
||||
</custom-select>
|
||||
<pre>
|
||||
${JSON.stringify(
|
||||
data.email.data[currentTemplateKey].data,
|
||||
null,
|
||||
2
|
||||
)}
|
||||
</pre>
|
||||
|
||||
${
|
||||
isAdminPreview
|
||||
|
|
Загрузка…
Ссылка в новой задаче