fix: Use cached logos and fallback icons for breach email

This commit is contained in:
Florian Zia 2023-03-31 15:43:40 +02:00
Родитель 8df707bb8b
Коммит 6d760674cc
9 изменённых файлов: 129 добавлений и 35 удалений

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

@ -112,6 +112,7 @@ async function confirmed (req, res, next, client = FxAOAuthClient) {
const data = {
breachedEmail: email,
breachLogos: req.app.locals.breachLogoMap,
ctaHref: getEmailCtaHref(utmCampaignId, 'dashboard-cta'),
heading: getMessage('email-breach-summary'),
recipientEmail: email,

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

@ -20,7 +20,7 @@ import { getMessage } from '../utils/fluent.js'
import { generateToken } from '../utils/csrf.js'
import {
EmailTemplateType,
getNotifictionDummyData,
getNotificationDummyData,
getVerificationDummyData,
getMonthlyDummyData,
getSignupReportDummyData,
@ -41,7 +41,7 @@ function getTemplatesData () {
[EmailTemplateType.Notification]: {
label: 'Breach notification',
template: getPreviewTemplate(
getNotifictionDummyData(EMAIL_TEST_RECIPIENT),
getNotificationDummyData(EMAIL_TEST_RECIPIENT),
breachAlertEmailPartial
)
},

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

@ -151,6 +151,7 @@ async function notify (req, res) {
if (!notifiedRecipients.includes(breachedEmail)) {
const data = {
breachData: breachAlert,
breachLogos: req.app.locals.breachLogoMap,
breachedEmail,
ctaHref: getEmailCtaHref(utmCampaignId, 'dashboard-cta'),
heading: getMessage('email-spotted-new-breach'),

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

@ -5,30 +5,63 @@
/**
* @param {object} breach
* @param {Map<string, string>} logos Map of URLs to logos indexed by the domain name of the respective company
* @param {boolean} isEmail Is the icon being used in an email template?
* @returns {string} HTML for a breach logo (either an `img`, or a `span.breach-logo` containing the breached company's first letter)
*/
export function getBreachLogo (breach, logos) {
const logo = logos.has(breach.Domain)
? `<img src='${logos.get(breach.Domain)}' alt='' loading="lazy" class='breach-logo' height='32' />`
: `<span role="img" aria-hidden='true' class='breach-logo' style='background-color: var(${getColorForName(breach.Name)});'>${breach.Name.substring(0, 1)}</span>`
export function getBreachLogo (breach, logos, isEmail = false) {
const logoIsAvailable = logos?.has(breach.Domain)
return logo
if (logoIsAvailable) {
return `<img src='${logos.get(breach.Domain)}' alt='' loading="lazy" class='breach-logo' height='32' />`
}
const { className, variableName } = getColorForName(breach.Name)
const backgroundStyle = !isEmail
? `background-color: var(${variableName});`
: ''
const classNames = `breach-logo ${isEmail ? `breach-logo-email ${className}` : ''}`
return `<span role="img" aria-hidden='true' class='${classNames}' style='${backgroundStyle}'>${breach.Name.substring(0, 1)}</span>`
}
/**
* @param {string} name
* @returns string CSS variable for a string-specific color
* @returns {string} CSS variable for a string-specific color
*/
function getColorForName (name) {
const logoColors = [
'--blue-5',
'--purple-5',
'--green-05',
'--violet-5',
'--orange-5',
'--yellow-5',
'--red-5',
'--pink-5'
{
className: 'bg-blue-5',
variableName: '--blue-5'
},
{
className: 'bg-purple-5',
variableName: '--purple-5'
},
{
className: 'bg-green-05',
variableName: '--green-05'
},
{
className: 'bg-violet-5',
variableName: '--violet-5'
},
{
className: 'bg-orange-5',
variableName: '--orange-5'
},
{
className: 'bg-yellow-5',
variableName: '--yellow-5'
},
{
className: 'bg-red-5',
variableName: '--red-5'
},
{
className: 'bg-pink-5',
variableName: '--pink-5'
}
]
const charValue = name

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

@ -210,13 +210,17 @@ async function unsubscribeFromMonthlyReport (req) {
await updateMonthlyEmailOptout(urlQuery.token)
}
const breachDummyLogo = new Map([
['adobe.com', '/images/logo_cache/adobe.com.ico']
])
/**
* Dummy data for populating the breach notification email preview.
*
* @param {string} recipient
* @returns {object} Breach dummy data
*/
const getNotifictionDummyData = (recipient) => ({
const getNotificationDummyData = (recipient) => ({
breachData: {
Id: 1,
Name: 'Adobe',
@ -227,7 +231,6 @@ const getNotifictionDummyData = (recipient) => ({
ModifiedDate: '2023-01-01T00:00:00.000Z',
PwnCount: 123,
Description: 'Example description',
LogoPath: '/images/favicon-144.webp',
DataClasses: [
'email-addresses',
'password-hints',
@ -242,6 +245,7 @@ const getNotifictionDummyData = (recipient) => ({
IsMalware: false
},
breachedEmail: recipient,
breachLogos: breachDummyLogo,
ctaHref: getEmailCtaHref('email-test-notification', 'dashboard-cta'),
heading: getMessage('email-spotted-new-breach'),
recipientEmail: recipient,
@ -270,6 +274,7 @@ const getVerificationDummyData = (recipient) => ({
*/
const getMonthlyDummyData = (recipient) => ({
breachedEmail: 'breached@email.com',
breachLogos: breachDummyLogo,
ctaHref: `${SERVER_URL}/user/breaches`,
heading: getMessage('email-unresolved-heading'),
monitoredEmails: {
@ -294,7 +299,7 @@ const getMonthlyDummyData = (recipient) => ({
const getSignupReportDummyData = (recipient) => {
const unsafeBreachesForEmail = [
getNotifictionDummyData(recipient).breachData
getNotificationDummyData(recipient).breachData
]
const breachesCount = unsafeBreachesForEmail.length
const numPasswordsExposed = 1
@ -316,6 +321,7 @@ const getSignupReportDummyData = (recipient) => {
return {
breachedEmail: recipient,
breachLogos: breachDummyLogo,
ctaHref: getEmailCtaHref('email-test-notification', 'dashboard-cta'),
heading: unsafeBreachesForEmail.length
? getMessage('email-subject-found-breaches')
@ -331,7 +337,7 @@ export {
EmailTemplateType,
getEmailCtaHref,
getMonthlyDummyData,
getNotifictionDummyData,
getNotificationDummyData,
getSignupReportDummyData,
getUnsubscribeCtaHref,
getVerificationDummyData,

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

@ -202,6 +202,51 @@ const getStyles = () => `
background-image: url('${images.logoDark}')
}
}
.bg-blue-5 {
background-color: #aaf2ff;
}
.bg-purple-5 {
background-color: #e7dfff;
}
.bg-green-05 {
background-color: #e3fff3;
}
.bg-violet-5 {
background-color: #f7e2ff;
}
.bg-orange-5 {
background-color: #fff4de;
}
.bg-yellow-5 {
background-color: #ffc;
}
.bg-red-5 {
background-color: #ffdfe7;
}
.bg-pink-5 {
background-color: #ffdef0;
}
.breach-logo {
display: block;
height: 100%;
width: 100%;
}
.breach-logo-email {
border-radius: 50%;
display: block;
height: 100%;
width: 100%;
}
</style>
`

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

@ -22,7 +22,7 @@ const breachAlertCtaStyle = `
`
const breachAlertEmailPartial = data => {
const { breachData, breachedEmail, ctaHref } = data
const { breachData, breachedEmail, breachLogos, ctaHref } = data
return `
<tr>
@ -32,7 +32,7 @@ const breachAlertEmailPartial = data => {
'email-address': `<strong>${breachedEmail}</strong>`
})}
</p>
${breachCardPartial(breachData)}
${breachCardPartial(breachData, breachLogos)}
<a
href='${ctaHref}'
style='${breachAlertCtaStyle}'

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

@ -4,6 +4,7 @@
import { getLocale, getMessage } from '../../utils/fluent.js'
import { formatDate } from '../../utils/format-date.js'
import { getBreachLogo } from '../../utils/breach-logo.js'
const breachAlertTableStyle = `
margin: auto
@ -29,7 +30,14 @@ const breachAlertCardsTitleStyle = `
`
const breachAlertCardsTitleImageStyle = `
vertical-align: bottom;
display: inline-block;
font-weight: bold;
line-height: 2rem;
overflow: hidden;
margin-right: 0.5rem;
text-align: center;
vertical-align: middle;
width: 2rem;
`
const breachAlertLabelStyle = `
@ -50,9 +58,8 @@ const breachAlertValueStyle = `
padding-bottom: 15px;
`
const breachCardPartial = breachData => {
const breachCardPartial = (breachData, breachLogos) => {
const {
LogoPath,
AddedDate,
DataClasses,
Title
@ -64,15 +71,15 @@ const breachCardPartial = breachData => {
<td>
<table style='${breachAlertCardsContainerStyle}'>
<tr>
<td style='${breachAlertCardsTitleStyle}'>
<img
height='25'
src='${LogoPath}'
style='${breachAlertCardsTitleImageStyle}'
width='25'
>
${Title}
</td>
<td style='${breachAlertCardsTitleStyle}'>
<span
class='breachLogoWrapper'
style='${breachAlertCardsTitleImageStyle}'
>
${getBreachLogo(breachData, breachLogos, true)}
</span>
${Title}
</td>
</tr>
<tr>
<td style='padding: 24px;'>

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

@ -47,6 +47,7 @@ const ctaStyle = `
const signupReportEmailPartial = data => {
const {
breachedEmail,
breachLogos,
emailBreachStats,
unsafeBreachesForEmail
} = data
@ -90,7 +91,7 @@ const signupReportEmailPartial = data => {
${
unsafeBreachesForEmail?.length
? unsafeBreachesForEmail.map(unsafeBreach => (
breachCardPartial(unsafeBreach)
breachCardPartial(unsafeBreach, breachLogos)
)).join('')
: ''
}