51 lines
1.9 KiB
JavaScript
51 lines
1.9 KiB
JavaScript
import nodemailer from 'nodemailer'
|
|
import * as auth from './auth.js'
|
|
|
|
const normalize = value => String(value || '').trim().toLowerCase()
|
|
const enabled = value => ['1', 'true', 'yes', 'on'].includes(normalize(value))
|
|
|
|
export function isReviewUser(user) {
|
|
if (!user) return false
|
|
const email = normalize(user.email)
|
|
return normalize(user.accountType) === 'playstore_review' ||
|
|
Boolean(email && email === normalize(process.env.PLAYSTORE_REVIEW_EMAIL))
|
|
}
|
|
|
|
function addresses(values) {
|
|
return values.flat(Infinity).filter(Boolean).flatMap(value => {
|
|
if (typeof value === 'object') return [normalize(value.address)]
|
|
return String(value).split(',').map(part => normalize(part.match(/<([^>]+)>/)?.[1] || part))
|
|
})
|
|
}
|
|
|
|
export async function shouldSuppressMail(event, emails = []) {
|
|
if (enabled(process.env.MAIL_DELIVERY_DISABLED)) return true
|
|
|
|
// Use the authenticated account, never a client-provided demo flag.
|
|
if (event) {
|
|
const token = auth.getTokenFromEvent(event)
|
|
if (token && isReviewUser(await auth.getUserFromToken(token))) return true
|
|
}
|
|
|
|
const targets = addresses(emails)
|
|
if (!targets.length) return false
|
|
if (targets.includes(normalize(process.env.PLAYSTORE_REVIEW_EMAIL))) return true
|
|
const users = await auth.readUsers()
|
|
return users.some(user => isReviewUser(user) && targets.includes(normalize(user.email)))
|
|
}
|
|
|
|
// All SMTP entry points go through this gate, including newsletter batches.
|
|
// Create the real transport lazily so suppressed mail cannot open a connection.
|
|
export function createMailTransport(event, options) {
|
|
let transport
|
|
return {
|
|
async sendMail(mail) {
|
|
if (await shouldSuppressMail(event, [mail.to, mail.cc, mail.bcc, mail.replyTo])) {
|
|
return { suppressed: true, messageId: null, accepted: [], rejected: [] }
|
|
}
|
|
transport ||= nodemailer.createTransport(options)
|
|
return transport.sendMail(mail)
|
|
}
|
|
}
|
|
}
|