mirror of
https://github.com/lawrencehook/remove-youtube-suggestions.git
synced 2026-07-25 06:54:31 +00:00
Migrate SES sends from v1 to SESv2 to avoid fast-xml-parser conflict
The fast-xml-parser >=5.3.8 override (added for CVE) is incompatible with @aws-sdk/client-ses, whose XML response parser registers entities named "#xD" and "#10" — names that 5.x rejects with [EntityReplacer] Invalid character '#' in entity name. SESv2 uses REST/JSON, sidestepping the parser entirely. validateEmail already used SESv2; this consolidates the three send functions onto the same client and drops @aws-sdk/client-ses. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Generated
-65
@@ -8,7 +8,6 @@
|
||||
"name": "rys-premium-server",
|
||||
"version": "1.0.0",
|
||||
"dependencies": {
|
||||
"@aws-sdk/client-ses": "^3.1000.0",
|
||||
"@aws-sdk/client-sesv2": "^3.1000.0",
|
||||
"better-sqlite3": "^11.0.0",
|
||||
"cors": "^2.8.5",
|
||||
@@ -151,57 +150,6 @@
|
||||
"node": ">=14.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@aws-sdk/client-ses": {
|
||||
"version": "3.1035.0",
|
||||
"resolved": "https://registry.npmjs.org/@aws-sdk/client-ses/-/client-ses-3.1035.0.tgz",
|
||||
"integrity": "sha512-fpyLQVNuBXwkSvySrBsi6P/qS/ZhNhSifY25Hiluo0EP6Zec7OM8SGWR5ECq9M3I87MyHvp1GrzuoWg+9/Fk5g==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@aws-crypto/sha256-browser": "5.2.0",
|
||||
"@aws-crypto/sha256-js": "5.2.0",
|
||||
"@aws-sdk/core": "^3.974.4",
|
||||
"@aws-sdk/credential-provider-node": "^3.972.35",
|
||||
"@aws-sdk/middleware-host-header": "^3.972.10",
|
||||
"@aws-sdk/middleware-logger": "^3.972.10",
|
||||
"@aws-sdk/middleware-recursion-detection": "^3.972.11",
|
||||
"@aws-sdk/middleware-user-agent": "^3.972.34",
|
||||
"@aws-sdk/region-config-resolver": "^3.972.13",
|
||||
"@aws-sdk/types": "^3.973.8",
|
||||
"@aws-sdk/util-endpoints": "^3.996.8",
|
||||
"@aws-sdk/util-user-agent-browser": "^3.972.10",
|
||||
"@aws-sdk/util-user-agent-node": "^3.973.20",
|
||||
"@smithy/config-resolver": "^4.4.17",
|
||||
"@smithy/core": "^3.23.16",
|
||||
"@smithy/fetch-http-handler": "^5.3.17",
|
||||
"@smithy/hash-node": "^4.2.14",
|
||||
"@smithy/invalid-dependency": "^4.2.14",
|
||||
"@smithy/middleware-content-length": "^4.2.14",
|
||||
"@smithy/middleware-endpoint": "^4.4.31",
|
||||
"@smithy/middleware-retry": "^4.5.4",
|
||||
"@smithy/middleware-serde": "^4.2.19",
|
||||
"@smithy/middleware-stack": "^4.2.14",
|
||||
"@smithy/node-config-provider": "^4.3.14",
|
||||
"@smithy/node-http-handler": "^4.6.0",
|
||||
"@smithy/protocol-http": "^5.3.14",
|
||||
"@smithy/smithy-client": "^4.12.12",
|
||||
"@smithy/types": "^4.14.1",
|
||||
"@smithy/url-parser": "^4.2.14",
|
||||
"@smithy/util-base64": "^4.3.2",
|
||||
"@smithy/util-body-length-browser": "^4.2.2",
|
||||
"@smithy/util-body-length-node": "^4.2.3",
|
||||
"@smithy/util-defaults-mode-browser": "^4.3.48",
|
||||
"@smithy/util-defaults-mode-node": "^4.2.53",
|
||||
"@smithy/util-endpoints": "^3.4.2",
|
||||
"@smithy/util-middleware": "^4.2.14",
|
||||
"@smithy/util-retry": "^4.3.3",
|
||||
"@smithy/util-utf8": "^4.2.2",
|
||||
"@smithy/util-waiter": "^4.2.16",
|
||||
"tslib": "^2.6.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@aws-sdk/client-sesv2": {
|
||||
"version": "3.1035.0",
|
||||
"resolved": "https://registry.npmjs.org/@aws-sdk/client-sesv2/-/client-sesv2-3.1035.0.tgz",
|
||||
@@ -1330,19 +1278,6 @@
|
||||
"node": ">=18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@smithy/util-waiter": {
|
||||
"version": "4.2.16",
|
||||
"resolved": "https://registry.npmjs.org/@smithy/util-waiter/-/util-waiter-4.2.16.tgz",
|
||||
"integrity": "sha512-GtclrKoZ3Lt7jPQ7aTIYKfjY92OgceScftVnkTsG8e1KV8rkvZgN+ny6YSRhd9hxB8rZtwVbmln7NTvE5O3GmQ==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@smithy/types": "^4.14.1",
|
||||
"tslib": "^2.6.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@smithy/uuid": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@smithy/uuid/-/uuid-1.1.2.tgz",
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
"test": "node --test --test-concurrency=1 tests/*.test.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@aws-sdk/client-ses": "^3.1000.0",
|
||||
"@aws-sdk/client-sesv2": "^3.1000.0",
|
||||
"better-sqlite3": "^11.0.0",
|
||||
"cors": "^2.8.5",
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
const { SESClient, SendEmailCommand } = require('@aws-sdk/client-ses');
|
||||
const { SESv2Client, GetEmailAddressInsightsCommand } = require('@aws-sdk/client-sesv2');
|
||||
const {
|
||||
SESv2Client,
|
||||
SendEmailCommand,
|
||||
GetEmailAddressInsightsCommand,
|
||||
} = require('@aws-sdk/client-sesv2');
|
||||
const config = require('../config');
|
||||
|
||||
const sesClient = new SESClient({ region: config.AWS_REGION });
|
||||
const sesV2Client = new SESv2Client({ region: config.AWS_REGION });
|
||||
|
||||
async function sendMagicLinkEmail(email, magicLinkUrl, { isPremium = false } = {}) {
|
||||
@@ -10,21 +12,22 @@ async function sendMagicLinkEmail(email, magicLinkUrl, { isPremium = false } = {
|
||||
? ' <span style="font-size: 12px; font-weight: 500; color: #0600fb; letter-spacing: 0.02em;">Premium</span>'
|
||||
: '';
|
||||
const params = {
|
||||
Source: config.EMAIL_FROM,
|
||||
FromEmailAddress: config.EMAIL_FROM,
|
||||
Destination: {
|
||||
ToAddresses: [email],
|
||||
},
|
||||
Message: {
|
||||
Subject: {
|
||||
Data: 'Sign in to RYS',
|
||||
Charset: 'UTF-8',
|
||||
},
|
||||
Body: {
|
||||
Text: {
|
||||
Data: `Here's your sign-in link for RYS:\n\n${magicLinkUrl}\n\nLink expires in 15 minutes. If you didn't request this, just ignore it.\n\n— Lawrence`,
|
||||
Content: {
|
||||
Simple: {
|
||||
Subject: {
|
||||
Data: 'Sign in to RYS',
|
||||
Charset: 'UTF-8',
|
||||
},
|
||||
Html: {
|
||||
Body: {
|
||||
Text: {
|
||||
Data: `Here's your sign-in link for RYS:\n\n${magicLinkUrl}\n\nLink expires in 15 minutes. If you didn't request this, just ignore it.\n\n— Lawrence`,
|
||||
Charset: 'UTF-8',
|
||||
},
|
||||
Html: {
|
||||
Data: `
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
@@ -58,33 +61,35 @@ async function sendMagicLinkEmail(email, magicLinkUrl, { isPremium = false } = {
|
||||
</body>
|
||||
</html>
|
||||
`.trim(),
|
||||
Charset: 'UTF-8',
|
||||
Charset: 'UTF-8',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const command = new SendEmailCommand(params);
|
||||
return sesClient.send(command);
|
||||
return sesV2Client.send(command);
|
||||
}
|
||||
|
||||
async function sendWelcomeEmail(email) {
|
||||
const params = {
|
||||
Source: config.EMAIL_FROM,
|
||||
FromEmailAddress: config.EMAIL_FROM,
|
||||
Destination: {
|
||||
ToAddresses: [email],
|
||||
},
|
||||
Message: {
|
||||
Subject: {
|
||||
Data: 'Welcome to RYS Premium',
|
||||
Charset: 'UTF-8',
|
||||
},
|
||||
Body: {
|
||||
Text: {
|
||||
Data: `Welcome to RYS Premium!\n\nThank you for subscribing. Your premium features are now active.\n\n— Lawrence`,
|
||||
Content: {
|
||||
Simple: {
|
||||
Subject: {
|
||||
Data: 'Welcome to RYS Premium',
|
||||
Charset: 'UTF-8',
|
||||
},
|
||||
Html: {
|
||||
Body: {
|
||||
Text: {
|
||||
Data: `Welcome to RYS Premium!\n\nThank you for subscribing. Your premium features are now active.\n\n— Lawrence`,
|
||||
Charset: 'UTF-8',
|
||||
},
|
||||
Html: {
|
||||
Data: `
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
@@ -112,35 +117,37 @@ async function sendWelcomeEmail(email) {
|
||||
</body>
|
||||
</html>
|
||||
`.trim(),
|
||||
Charset: 'UTF-8',
|
||||
Charset: 'UTF-8',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const command = new SendEmailCommand(params);
|
||||
return sesClient.send(command);
|
||||
return sesV2Client.send(command);
|
||||
}
|
||||
|
||||
const FEEDBACK_URL = 'https://docs.google.com/forms/d/1AzQQxTWgG6M5N87jinvXKQkGS6Mehzg19XV4mjteTK0';
|
||||
|
||||
async function sendCancellationEmail(email) {
|
||||
const params = {
|
||||
Source: config.EMAIL_FROM,
|
||||
FromEmailAddress: config.EMAIL_FROM,
|
||||
Destination: {
|
||||
ToAddresses: [email],
|
||||
},
|
||||
Message: {
|
||||
Subject: {
|
||||
Data: 'Your RYS Premium subscription has been canceled',
|
||||
Charset: 'UTF-8',
|
||||
},
|
||||
Body: {
|
||||
Text: {
|
||||
Data: `Your RYS Premium subscription has been canceled.\n\nThe free version of RYS is still yours to use anytime.\n\nIf you have a moment, we'd love to hear what we could do better: ${FEEDBACK_URL}\n\nThanks for giving Premium a try.\n\n— Lawrence`,
|
||||
Content: {
|
||||
Simple: {
|
||||
Subject: {
|
||||
Data: 'Your RYS Premium subscription has been canceled',
|
||||
Charset: 'UTF-8',
|
||||
},
|
||||
Html: {
|
||||
Body: {
|
||||
Text: {
|
||||
Data: `Your RYS Premium subscription has been canceled.\n\nThe free version of RYS is still yours to use anytime.\n\nIf you have a moment, we'd love to hear what we could do better: ${FEEDBACK_URL}\n\nThanks for giving Premium a try.\n\n— Lawrence`,
|
||||
Charset: 'UTF-8',
|
||||
},
|
||||
Html: {
|
||||
Data: `
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
@@ -180,14 +187,15 @@ async function sendCancellationEmail(email) {
|
||||
</body>
|
||||
</html>
|
||||
`.trim(),
|
||||
Charset: 'UTF-8',
|
||||
Charset: 'UTF-8',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const command = new SendEmailCommand(params);
|
||||
return sesClient.send(command);
|
||||
return sesV2Client.send(command);
|
||||
}
|
||||
|
||||
async function validateEmail(email) {
|
||||
|
||||
Reference in New Issue
Block a user