feat: add sanitize-html for improved email content sanitization
This commit is contained in:
@@ -39,6 +39,7 @@
|
|||||||
"mailparser": "^3.9.8",
|
"mailparser": "^3.9.8",
|
||||||
"morgan": "^1.10.0",
|
"morgan": "^1.10.0",
|
||||||
"multer": "^2.1.1",
|
"multer": "^2.1.1",
|
||||||
|
"sanitize-html": "^2.17.3",
|
||||||
"signale": "^1.4.0",
|
"signale": "^1.4.0",
|
||||||
"stripe": "^20.0.0"
|
"stripe": "^20.0.0"
|
||||||
},
|
},
|
||||||
@@ -52,6 +53,7 @@
|
|||||||
"@types/mailparser": "^3.4.6",
|
"@types/mailparser": "^3.4.6",
|
||||||
"@types/morgan": "^1.9.9",
|
"@types/morgan": "^1.9.9",
|
||||||
"@types/multer": "^2.0.0",
|
"@types/multer": "^2.0.0",
|
||||||
|
"@types/sanitize-html": "^2.16.1",
|
||||||
"@types/signale": "^1.4.7",
|
"@types/signale": "^1.4.7",
|
||||||
"concurrently": "^9.2.1",
|
"concurrently": "^9.2.1",
|
||||||
"tsx": "^4.20.6"
|
"tsx": "^4.20.6"
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import type {Prisma} from '@plunk/db';
|
|||||||
import {EmailSourceType, EmailStatus} from '@plunk/db';
|
import {EmailSourceType, EmailStatus} from '@plunk/db';
|
||||||
import type {Request, Response} from 'express';
|
import type {Request, Response} from 'express';
|
||||||
import {simpleParser} from 'mailparser';
|
import {simpleParser} from 'mailparser';
|
||||||
|
import sanitizeHtml from 'sanitize-html';
|
||||||
import signale from 'signale';
|
import signale from 'signale';
|
||||||
import type Stripe from 'stripe';
|
import type Stripe from 'stripe';
|
||||||
|
|
||||||
@@ -157,19 +158,31 @@ export class Webhooks {
|
|||||||
// Parse email content if available
|
// Parse email content if available
|
||||||
let htmlBody: string | undefined;
|
let htmlBody: string | undefined;
|
||||||
|
|
||||||
if (body.content) {
|
if (body.content && typeof body.content === 'string') {
|
||||||
try {
|
try {
|
||||||
const isBase64 = body.receipt?.action?.encoding === 'BASE64';
|
const isBase64 = body.receipt?.action?.encoding === 'BASE64';
|
||||||
const emailBuffer = isBase64
|
const emailBuffer = isBase64
|
||||||
? Buffer.from(body.content as string, 'base64')
|
? Buffer.from(body.content, 'base64')
|
||||||
: Buffer.from(body.content as string);
|
: Buffer.from(body.content);
|
||||||
|
|
||||||
const parsed = await simpleParser(emailBuffer);
|
const parsed = await simpleParser(emailBuffer);
|
||||||
htmlBody =
|
const raw =
|
||||||
(parsed.html ? String(parsed.html) : undefined) ??
|
(parsed.html ? String(parsed.html) : undefined) ??
|
||||||
parsed.textAsHtml ??
|
parsed.textAsHtml ??
|
||||||
parsed.text ??
|
parsed.text ??
|
||||||
undefined;
|
undefined;
|
||||||
|
|
||||||
|
if (raw) {
|
||||||
|
htmlBody = sanitizeHtml(raw, {
|
||||||
|
allowedTags: sanitizeHtml.defaults.allowedTags.concat(['img']),
|
||||||
|
allowedAttributes: {
|
||||||
|
...sanitizeHtml.defaults.allowedAttributes,
|
||||||
|
img: ['src', 'alt', 'width', 'height'],
|
||||||
|
'*': ['style'],
|
||||||
|
},
|
||||||
|
allowedSchemes: ['http', 'https', 'mailto'],
|
||||||
|
});
|
||||||
|
}
|
||||||
} catch (parseError) {
|
} catch (parseError) {
|
||||||
signale.error('[WEBHOOK] Failed to parse email content:', parseError);
|
signale.error('[WEBHOOK] Failed to parse email content:', parseError);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7086,6 +7086,15 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"@types/sanitize-html@npm:^2.16.1":
|
||||||
|
version: 2.16.1
|
||||||
|
resolution: "@types/sanitize-html@npm:2.16.1"
|
||||||
|
dependencies:
|
||||||
|
htmlparser2: "npm:^10.1"
|
||||||
|
checksum: 10c0/4e0d326a5243edb49780105d3b9a246e6672d998e20aefbc29e5d840bf51a0b03825a20901851ed8f333b4a52ea58b2ac634132792d3c1b0ce91fded9ffe8315
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"@types/send@npm:*":
|
"@types/send@npm:*":
|
||||||
version: 1.2.1
|
version: 1.2.1
|
||||||
resolution: "@types/send@npm:1.2.1"
|
resolution: "@types/send@npm:1.2.1"
|
||||||
@@ -8072,6 +8081,7 @@ __metadata:
|
|||||||
"@types/mailparser": "npm:^3.4.6"
|
"@types/mailparser": "npm:^3.4.6"
|
||||||
"@types/morgan": "npm:^1.9.9"
|
"@types/morgan": "npm:^1.9.9"
|
||||||
"@types/multer": "npm:^2.0.0"
|
"@types/multer": "npm:^2.0.0"
|
||||||
|
"@types/sanitize-html": "npm:^2.16.1"
|
||||||
"@types/signale": "npm:^1.4.7"
|
"@types/signale": "npm:^1.4.7"
|
||||||
"@zootools/email-spell-checker": "npm:^1.12.0"
|
"@zootools/email-spell-checker": "npm:^1.12.0"
|
||||||
bcrypt: "npm:^6.0.0"
|
bcrypt: "npm:^6.0.0"
|
||||||
@@ -8091,6 +8101,7 @@ __metadata:
|
|||||||
mailparser: "npm:^3.9.8"
|
mailparser: "npm:^3.9.8"
|
||||||
morgan: "npm:^1.10.0"
|
morgan: "npm:^1.10.0"
|
||||||
multer: "npm:^2.1.1"
|
multer: "npm:^2.1.1"
|
||||||
|
sanitize-html: "npm:^2.17.3"
|
||||||
signale: "npm:^1.4.0"
|
signale: "npm:^1.4.0"
|
||||||
stripe: "npm:^20.0.0"
|
stripe: "npm:^20.0.0"
|
||||||
tsx: "npm:^4.20.6"
|
tsx: "npm:^4.20.6"
|
||||||
@@ -9606,7 +9617,7 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"deepmerge@npm:^4.3.1":
|
"deepmerge@npm:^4.2.2, deepmerge@npm:^4.3.1":
|
||||||
version: 4.3.1
|
version: 4.3.1
|
||||||
resolution: "deepmerge@npm:4.3.1"
|
resolution: "deepmerge@npm:4.3.1"
|
||||||
checksum: 10c0/e53481aaf1aa2c4082b5342be6b6d8ad9dfe387bc92ce197a66dea08bd4265904a087e75e464f14d1347cf2ac8afe1e4c16b266e0561cc5df29382d3c5f80044
|
checksum: 10c0/e53481aaf1aa2c4082b5342be6b6d8ad9dfe387bc92ce197a66dea08bd4265904a087e75e464f14d1347cf2ac8afe1e4c16b266e0561cc5df29382d3c5f80044
|
||||||
@@ -9835,7 +9846,7 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"domutils@npm:^3.0.1, domutils@npm:^3.1.0":
|
"domutils@npm:^3.0.1, domutils@npm:^3.1.0, domutils@npm:^3.2.2":
|
||||||
version: 3.2.2
|
version: 3.2.2
|
||||||
resolution: "domutils@npm:3.2.2"
|
resolution: "domutils@npm:3.2.2"
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -10101,6 +10112,13 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"entities@npm:^7.0.1":
|
||||||
|
version: 7.0.1
|
||||||
|
resolution: "entities@npm:7.0.1"
|
||||||
|
checksum: 10c0/b4fb9937bb47ecb00aaaceb9db9cdd1cc0b0fb649c0e843d05cf5dbbd2e9d2df8f98721d8b1b286445689c72af7b54a7242fc2d63ef7c9739037a8c73363e7ca
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"env-paths@npm:^2.2.0":
|
"env-paths@npm:^2.2.0":
|
||||||
version: 2.2.1
|
version: 2.2.1
|
||||||
resolution: "env-paths@npm:2.2.1"
|
resolution: "env-paths@npm:2.2.1"
|
||||||
@@ -12261,6 +12279,18 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"htmlparser2@npm:^10.1, htmlparser2@npm:^10.1.0":
|
||||||
|
version: 10.1.0
|
||||||
|
resolution: "htmlparser2@npm:10.1.0"
|
||||||
|
dependencies:
|
||||||
|
domelementtype: "npm:^2.3.0"
|
||||||
|
domhandler: "npm:^5.0.3"
|
||||||
|
domutils: "npm:^3.2.2"
|
||||||
|
entities: "npm:^7.0.1"
|
||||||
|
checksum: 10c0/36394e29b80cfcc5e78e0fa4d3aa21fdaac3e6778d23e5c933e625c290987cd9a724a2eb0753ab60ed0c69dfaba0ab115f0ee50fb112fd8f0c4d522e7e0089a2
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"htmlparser2@npm:^5.0.0":
|
"htmlparser2@npm:^5.0.0":
|
||||||
version: 5.0.1
|
version: 5.0.1
|
||||||
resolution: "htmlparser2@npm:5.0.1"
|
resolution: "htmlparser2@npm:5.0.1"
|
||||||
@@ -12762,6 +12792,13 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"is-plain-object@npm:^5.0.0":
|
||||||
|
version: 5.0.0
|
||||||
|
resolution: "is-plain-object@npm:5.0.0"
|
||||||
|
checksum: 10c0/893e42bad832aae3511c71fd61c0bf61aa3a6d853061c62a307261842727d0d25f761ce9379f7ba7226d6179db2a3157efa918e7fe26360f3bf0842d9f28942c
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"is-promise@npm:^4.0.0":
|
"is-promise@npm:^4.0.0":
|
||||||
version: 4.0.0
|
version: 4.0.0
|
||||||
resolution: "is-promise@npm:4.0.0"
|
resolution: "is-promise@npm:4.0.0"
|
||||||
@@ -15618,6 +15655,13 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"parse-srcset@npm:^1.0.2":
|
||||||
|
version: 1.0.2
|
||||||
|
resolution: "parse-srcset@npm:1.0.2"
|
||||||
|
checksum: 10c0/2f268e3d110d4c53d06ed2a8e8ee61a7da0cee13bf150819a6da066a8ca9b8d15b5600d6e6cae8be940e2edc50ee7c1e1052934d6ec858324065ecef848f0497
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"parse5-htmlparser2-tree-adapter@npm:^7.0.0":
|
"parse5-htmlparser2-tree-adapter@npm:^7.0.0":
|
||||||
version: 7.1.0
|
version: 7.1.0
|
||||||
resolution: "parse5-htmlparser2-tree-adapter@npm:7.1.0"
|
resolution: "parse5-htmlparser2-tree-adapter@npm:7.1.0"
|
||||||
@@ -15933,6 +15977,17 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"postcss@npm:^8.3.11":
|
||||||
|
version: 8.5.14
|
||||||
|
resolution: "postcss@npm:8.5.14"
|
||||||
|
dependencies:
|
||||||
|
nanoid: "npm:^3.3.11"
|
||||||
|
picocolors: "npm:^1.1.1"
|
||||||
|
source-map-js: "npm:^1.2.1"
|
||||||
|
checksum: 10c0/48138207cf5ef5581be1bfe2cb65ccfe0ac75e43888ba045afc8ed6043d7b56aeb3b9a9fe5b353ff554be943cd0cc15d826ccb991525159175971e5ee8ab0237
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"postcss@npm:^8.4.23, postcss@npm:^8.4.33, postcss@npm:^8.4.41, postcss@npm:^8.5.6":
|
"postcss@npm:^8.4.23, postcss@npm:^8.4.33, postcss@npm:^8.4.41, postcss@npm:^8.5.6":
|
||||||
version: 8.5.6
|
version: 8.5.6
|
||||||
resolution: "postcss@npm:8.5.6"
|
resolution: "postcss@npm:8.5.6"
|
||||||
@@ -17160,6 +17215,20 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"sanitize-html@npm:^2.17.3":
|
||||||
|
version: 2.17.3
|
||||||
|
resolution: "sanitize-html@npm:2.17.3"
|
||||||
|
dependencies:
|
||||||
|
deepmerge: "npm:^4.2.2"
|
||||||
|
escape-string-regexp: "npm:^4.0.0"
|
||||||
|
htmlparser2: "npm:^10.1.0"
|
||||||
|
is-plain-object: "npm:^5.0.0"
|
||||||
|
parse-srcset: "npm:^1.0.2"
|
||||||
|
postcss: "npm:^8.3.11"
|
||||||
|
checksum: 10c0/8afa59bed125b38bf4b437f9b5a3289a4307f42d720e45105de5a0b3d665be70e27d1722d223121993be2e54a2b99304cd9c54317fb2d251fd7f4abf06b68d27
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"sax@npm:^1.2.4":
|
"sax@npm:^1.2.4":
|
||||||
version: 1.4.3
|
version: 1.4.3
|
||||||
resolution: "sax@npm:1.4.3"
|
resolution: "sax@npm:1.4.3"
|
||||||
|
|||||||
Reference in New Issue
Block a user