m->d fix a few markdown escaping problems
This commit is contained in:
		
							parent
							
								
									d255f2ab22
								
							
						
					
					
						commit
						5185ae45ab
					
				
					 2 changed files with 105 additions and 10 deletions
				
			
		| 
						 | 
					@ -22,13 +22,48 @@ const BLOCK_ELEMENTS = [
 | 
				
			||||||
	"TFOOT", "TH", "THEAD", "TR", "UL"
 | 
						"TFOOT", "TH", "THEAD", "TR", "UL"
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** @type {[RegExp, string][]} */
 | 
				
			||||||
 | 
					const markdownEscapes = [
 | 
				
			||||||
 | 
						[/\\/g, '\\\\'],
 | 
				
			||||||
 | 
						[/\*/g, '\\*'],
 | 
				
			||||||
 | 
						[/^-/g, '\\-'],
 | 
				
			||||||
 | 
						[/^\+ /g, '\\+ '],
 | 
				
			||||||
 | 
						[/^(=+)/g, '\\$1'],
 | 
				
			||||||
 | 
						[/^(#{1,6}) /g, '\\$1 '],
 | 
				
			||||||
 | 
						[/`/g, '\\`'],
 | 
				
			||||||
 | 
						[/^~~~/g, '\\~~~'],
 | 
				
			||||||
 | 
						[/\[/g, '\\['],
 | 
				
			||||||
 | 
						[/\]/g, '\\]'],
 | 
				
			||||||
 | 
						[/^>/g, '\\>'],
 | 
				
			||||||
 | 
						[/_/g, '\\_'],
 | 
				
			||||||
 | 
						[/^(\d+)\. /g, '$1\\. ']
 | 
				
			||||||
 | 
					 ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const turndownService = new TurndownService({
 | 
					const turndownService = new TurndownService({
 | 
				
			||||||
	hr: "----",
 | 
						hr: "----",
 | 
				
			||||||
	headingStyle: "atx",
 | 
						headingStyle: "atx",
 | 
				
			||||||
	preformattedCode: true,
 | 
						preformattedCode: true,
 | 
				
			||||||
	codeBlockStyle: "fenced"
 | 
						codeBlockStyle: "fenced",
 | 
				
			||||||
})
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Markdown characters in the HTML content need to be escaped, though take care not to escape the middle of bare links
 | 
				
			||||||
 | 
					 * @param {string} string
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					// @ts-ignore bad type from turndown
 | 
				
			||||||
 | 
					turndownService.escape = function (string) {
 | 
				
			||||||
 | 
						const escapedWords = string.split(" ").map(word => {
 | 
				
			||||||
 | 
							if (word.match(/^https?:\/\//)) {
 | 
				
			||||||
 | 
								return word
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								return markdownEscapes.reduce(function (accumulator, escape) {
 | 
				
			||||||
 | 
									return accumulator.replace(escape[0], escape[1])
 | 
				
			||||||
 | 
							 	}, word)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
						return escapedWords.join(" ")
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
turndownService.remove("mx-reply")
 | 
					turndownService.remove("mx-reply")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
turndownService.addRule("strikethrough", {
 | 
					turndownService.addRule("strikethrough", {
 | 
				
			||||||
| 
						 | 
					@ -67,7 +102,6 @@ turndownService.addRule("spoiler", {
 | 
				
			||||||
turndownService.addRule("inlineLink", {
 | 
					turndownService.addRule("inlineLink", {
 | 
				
			||||||
	filter: function (node, options) {
 | 
						filter: function (node, options) {
 | 
				
			||||||
		return (
 | 
							return (
 | 
				
			||||||
			options.linkStyle === "inlined" &&
 | 
					 | 
				
			||||||
			node.nodeName === "A" &&
 | 
								node.nodeName === "A" &&
 | 
				
			||||||
			node.getAttribute("href")
 | 
								node.getAttribute("href")
 | 
				
			||||||
		)
 | 
							)
 | 
				
			||||||
| 
						 | 
					@ -275,8 +309,9 @@ async function eventToMessage(event, guild, di) {
 | 
				
			||||||
				content = `* ${displayName} ${content}`
 | 
									content = `* ${displayName} ${content}`
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			// Markdown needs to be escaped
 | 
								// Markdown needs to be escaped, though take care not to escape the middle of links
 | 
				
			||||||
			content = content.replace(/([*_~`#])/g, `\\$1`)
 | 
								// @ts-ignore bad type from turndown
 | 
				
			||||||
 | 
								content = turndownService.escape(content)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	} else if (event.type === "m.room.message" && (event.content.msgtype === "m.file" || event.content.msgtype === "m.video" || event.content.msgtype === "m.audio" || event.content.msgtype === "m.image")) {
 | 
						} else if (event.type === "m.room.message" && (event.content.msgtype === "m.file" || event.content.msgtype === "m.video" || event.content.msgtype === "m.audio" || event.content.msgtype === "m.image")) {
 | 
				
			||||||
		content = ""
 | 
							content = ""
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -64,11 +64,11 @@ test("event2message: body is used when there is no formatted_body", async t => {
 | 
				
			||||||
	)
 | 
						)
 | 
				
			||||||
})
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
test("event2message: any markdown in body is escaped", async t => {
 | 
					test("event2message: any markdown in body is escaped, except strikethrough", async t => {
 | 
				
			||||||
	t.deepEqual(
 | 
						t.deepEqual(
 | 
				
			||||||
		await eventToMessage({
 | 
							await eventToMessage({
 | 
				
			||||||
			content: {
 | 
								content: {
 | 
				
			||||||
				body: "testing **special** ~~things~~ which _should_ *not* `trigger` @any <effects>",
 | 
									body: "testing **special** ~~things~~ which _should_ *not* `trigger` @any <effects>, except strikethrough",
 | 
				
			||||||
				msgtype: "m.text"
 | 
									msgtype: "m.text"
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			event_id: "$g07oYSZFWBkxohNEfywldwgcWj1hbhDzQ1sBAKvqOOU",
 | 
								event_id: "$g07oYSZFWBkxohNEfywldwgcWj1hbhDzQ1sBAKvqOOU",
 | 
				
			||||||
| 
						 | 
					@ -85,7 +85,67 @@ test("event2message: any markdown in body is escaped", async t => {
 | 
				
			||||||
			messagesToEdit: [],
 | 
								messagesToEdit: [],
 | 
				
			||||||
			messagesToSend: [{
 | 
								messagesToSend: [{
 | 
				
			||||||
				username: "cadence [they]",
 | 
									username: "cadence [they]",
 | 
				
			||||||
				content: "testing \\*\\*special\\*\\* \\~\\~things\\~\\~ which \\_should\\_ \\*not\\* \\`trigger\\` @any <effects>",
 | 
									content: "testing \\*\\*special\\*\\* ~~things~~ which \\_should\\_ \\*not\\* \\`trigger\\` @any <effects>, except strikethrough",
 | 
				
			||||||
 | 
									avatar_url: undefined
 | 
				
			||||||
 | 
								}]
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test("event2message: links in formatted body are not broken", async t => {
 | 
				
			||||||
 | 
						t.deepEqual(
 | 
				
			||||||
 | 
							await eventToMessage({
 | 
				
			||||||
 | 
								type: "m.room.message",
 | 
				
			||||||
 | 
								sender: "@cadence:cadence.moe",
 | 
				
			||||||
 | 
								content: {
 | 
				
			||||||
 | 
									msgtype: "m.text",
 | 
				
			||||||
 | 
									body: "kyuugryphon I wonder what the midjourney text description of this photo is https://upload.wikimedia.org/wikipedia/commons/f/f3/After_gay_pride%2C_rainbow_flags_flying_along_Beach_Street_%2814853144744%29.jpg",
 | 
				
			||||||
 | 
									format: "org.matrix.custom.html",
 | 
				
			||||||
 | 
									formatted_body: "<a href=\"https://matrix.to/#/@_ooye_kyuugryphon:cadence.moe\">kyuugryphon</a> I wonder what the midjourney text description of this photo is https://upload.wikimedia.org/wikipedia/commons/f/f3/After_gay_pride%2C_rainbow_flags_flying_along_Beach_Street_%2814853144744%29.jpg"
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								origin_server_ts: 1693739630700,
 | 
				
			||||||
 | 
								unsigned: {
 | 
				
			||||||
 | 
									age: 39,
 | 
				
			||||||
 | 
									transaction_id: "m1693739630587.160"
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								event_id: "$zANQGOdnHKZj48lrajojsejH86KNYST26imgb2Sw1Jg",
 | 
				
			||||||
 | 
								room_id: "!kLRqKKUQXcibIMtOpl:cadence.moe"
 | 
				
			||||||
 | 
							}),
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								messagesToDelete: [],
 | 
				
			||||||
 | 
								messagesToEdit: [],
 | 
				
			||||||
 | 
								messagesToSend: [{
 | 
				
			||||||
 | 
									username: "cadence [they]",
 | 
				
			||||||
 | 
									content: "<@111604486476181504> I wonder what the midjourney text description of this photo is https://upload.wikimedia.org/wikipedia/commons/f/f3/After_gay_pride%2C_rainbow_flags_flying_along_Beach_Street_%2814853144744%29.jpg",
 | 
				
			||||||
 | 
									avatar_url: undefined
 | 
				
			||||||
 | 
								}]
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test("event2message: links in plaintext body are not broken", async t => {
 | 
				
			||||||
 | 
						t.deepEqual(
 | 
				
			||||||
 | 
							await eventToMessage({
 | 
				
			||||||
 | 
								type: "m.room.message",
 | 
				
			||||||
 | 
								sender: "@cadence:cadence.moe",
 | 
				
			||||||
 | 
								content: {
 | 
				
			||||||
 | 
									msgtype: "m.text",
 | 
				
			||||||
 | 
									body: "I wonder what the midjourney text description of this photo is https://upload.wikimedia.org/wikipedia/commons/f/f3/After_gay_pride%2C_rainbow_flags_flying_along_Beach_Street_%2814853144744%29.jpg",
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								origin_server_ts: 1693739630700,
 | 
				
			||||||
 | 
								unsigned: {
 | 
				
			||||||
 | 
									age: 39,
 | 
				
			||||||
 | 
									transaction_id: "m1693739630587.160"
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								event_id: "$zANQGOdnHKZj48lrajojsejH86KNYST26imgb2Sw1Jg",
 | 
				
			||||||
 | 
								room_id: "!kLRqKKUQXcibIMtOpl:cadence.moe"
 | 
				
			||||||
 | 
							}),
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								messagesToDelete: [],
 | 
				
			||||||
 | 
								messagesToEdit: [],
 | 
				
			||||||
 | 
								messagesToSend: [{
 | 
				
			||||||
 | 
									username: "cadence [they]",
 | 
				
			||||||
 | 
									content: "I wonder what the midjourney text description of this photo is https://upload.wikimedia.org/wikipedia/commons/f/f3/After_gay_pride%2C_rainbow_flags_flying_along_Beach_Street_%2814853144744%29.jpg",
 | 
				
			||||||
				avatar_url: undefined
 | 
									avatar_url: undefined
 | 
				
			||||||
			}]
 | 
								}]
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					@ -99,7 +159,7 @@ test("event2message: basic html is converted to markdown", async t => {
 | 
				
			||||||
				msgtype: "m.text",
 | 
									msgtype: "m.text",
 | 
				
			||||||
				body: "wrong body",
 | 
									body: "wrong body",
 | 
				
			||||||
				format: "org.matrix.custom.html",
 | 
									format: "org.matrix.custom.html",
 | 
				
			||||||
				formatted_body: "this <strong>is</strong> a <em><strong>test</strong> <u>of</u></em> <del>formatting</del>"
 | 
									formatted_body: "this <strong>is</strong> a <em><strong>test</strong> <u>of</u></em> <del><em>formatting</em></del>"
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			event_id: "$g07oYSZFWBkxohNEfywldwgcWj1hbhDzQ1sBAKvqOOU",
 | 
								event_id: "$g07oYSZFWBkxohNEfywldwgcWj1hbhDzQ1sBAKvqOOU",
 | 
				
			||||||
			origin_server_ts: 1688301929913,
 | 
								origin_server_ts: 1688301929913,
 | 
				
			||||||
| 
						 | 
					@ -115,7 +175,7 @@ test("event2message: basic html is converted to markdown", async t => {
 | 
				
			||||||
			messagesToEdit: [],
 | 
								messagesToEdit: [],
 | 
				
			||||||
			messagesToSend: [{
 | 
								messagesToSend: [{
 | 
				
			||||||
				username: "cadence [they]",
 | 
									username: "cadence [they]",
 | 
				
			||||||
				content: "this **is** a _**test** __of___ ~~formatting~~",
 | 
									content: "this **is** a _**test** __of___ ~~_formatting_~~",
 | 
				
			||||||
				avatar_url: undefined
 | 
									avatar_url: undefined
 | 
				
			||||||
			}]
 | 
								}]
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					@ -449,7 +509,7 @@ test("event2message: m.emote plaintext works", async t => {
 | 
				
			||||||
			messagesToEdit: [],
 | 
								messagesToEdit: [],
 | 
				
			||||||
			messagesToSend: [{
 | 
								messagesToSend: [{
 | 
				
			||||||
				username: "cadence [they]",
 | 
									username: "cadence [they]",
 | 
				
			||||||
				content: "\\* cadence [they] tests an m.emote message",
 | 
									content: "\\* cadence \\[they\\] tests an m.emote message",
 | 
				
			||||||
				avatar_url: undefined
 | 
									avatar_url: undefined
 | 
				
			||||||
			}]
 | 
								}]
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue