Support m->d redacting messages and reactions
This commit is contained in:
		| @@ -70,4 +70,10 @@ CREATE TABLE IF NOT EXISTS "emoji" ( | ||||
| 	"mxc_url"	TEXT NOT NULL, | ||||
| 	PRIMARY KEY("id") | ||||
| ) WITHOUT ROWID; | ||||
| CREATE TABLE IF NOT EXISTS "reaction" ( | ||||
| 	"hashed_event_id"	INTEGER NOT NULL, | ||||
| 	"message_id"	TEXT NOT NULL, | ||||
| 	"encoded_emoji"	TEXT NOT NULL, | ||||
| 	PRIMARY KEY ("hashed_event_id") | ||||
| ) WITHOUT ROWID; | ||||
| COMMIT; | ||||
|   | ||||
							
								
								
									
										6
									
								
								db/orm-utils.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								db/orm-utils.d.ts
									
									
									
									
										vendored
									
									
								
							| @@ -69,6 +69,12 @@ export type Models = { | ||||
| 		animated: number | ||||
| 		mxc_url: string | ||||
| 	} | ||||
|  | ||||
| 	reaction: { | ||||
| 		hashed_event_id: number | ||||
| 		message_id: string | ||||
| 		encoded_emoji: string | ||||
| 	} | ||||
| } | ||||
|  | ||||
| export type Prepared<Row> = { | ||||
|   | ||||
| @@ -5,6 +5,8 @@ const Ty = require("../../types") | ||||
|  | ||||
| const passthrough = require("../../passthrough") | ||||
| const {discord, sync, db, select} = passthrough | ||||
| /** @type {import("../converters/utils")} */ | ||||
| const utils = sync.require("../converters/utils") | ||||
|  | ||||
| /** | ||||
|  * @param {Ty.Event.Outer<Ty.Event.M_Reaction>} event | ||||
| @@ -48,7 +50,9 @@ async function addReaction(event) { | ||||
| 		console.log("add reaction from matrix:", emoji, encoded, encodedTrimmed, "chosen:", discordPreferredEncoding) | ||||
| 	} | ||||
|  | ||||
| 	return discord.snow.channel.createReaction(channelID, messageID, discordPreferredEncoding) // acting as the discord bot itself | ||||
| 	await discord.snow.channel.createReaction(channelID, messageID, discordPreferredEncoding) // acting as the discord bot itself | ||||
|  | ||||
| 	db.prepare("REPLACE INTO reaction (hashed_event_id, message_id, encoded_emoji) VALUES (?, ?, ?)").run(utils.getEventIDHash(event.event_id), messageID, discordPreferredEncoding) | ||||
| } | ||||
|  | ||||
| module.exports.addReaction = addReaction | ||||
|   | ||||
							
								
								
									
										39
									
								
								m2d/actions/redact.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								m2d/actions/redact.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,39 @@ | ||||
| // @ts-check | ||||
|  | ||||
| const assert = require("assert").strict | ||||
| const Ty = require("../../types") | ||||
|  | ||||
| const passthrough = require("../../passthrough") | ||||
| const {discord, sync, db, select, from} = passthrough | ||||
| /** @type {import("../converters/utils")} */ | ||||
| const utils = sync.require("../converters/utils") | ||||
|  | ||||
| /** | ||||
|  * @param {Ty.Event.Outer_M_Room_Redaction} event | ||||
|  */ | ||||
| async function deleteMessage(event) { | ||||
| 	const row = from("event_message").join("message_channel", "message_id").select("channel_id", "message_id").and("WHERE event_id = ?").get(event.event_id) | ||||
| 	if (!row) return | ||||
| 	return discord.snow.channel.deleteMessage(row.channel_id, row.message_id, event.content.reason) | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * @param {Ty.Event.Outer_M_Room_Redaction} event | ||||
|  */ | ||||
| async function removeReaction(event) { | ||||
| 	const hash = utils.getEventIDHash(event.redacts) | ||||
| 	const row = from("reaction").join("message_channel", "message_id").select("channel_id", "message_id", "encoded_emoji").and("WHERE hashed_event_id = ?").get(hash) | ||||
| 	if (!row) return | ||||
| 	return discord.snow.channel.deleteReactionSelf(row.channel_id, row.message_id, row.encoded_emoji) | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Try everything that could possibly be redacted. | ||||
|  * @param {Ty.Event.Outer_M_Room_Redaction} event | ||||
|  */ | ||||
| async function handle(event) { | ||||
| 	await deleteMessage(event) | ||||
| 	await removeReaction(event) | ||||
| } | ||||
|  | ||||
| module.exports.handle = handle | ||||
| @@ -38,7 +38,7 @@ function getPublicUrlForMxc(mxc) { | ||||
| /** | ||||
|  * Event IDs are really big and have more entropy than we need. | ||||
|  * If we want to store the event ID in the database, we can store a more compact version by hashing it with this. | ||||
|  * Choosing a 64-bit non-cryptographic hash as only a 32-bit hash will see birthday collisions unreasonably frequently: https://en.wikipedia.org/wiki/Birthday_attack#Mathematics | ||||
|  * I choose a 64-bit non-cryptographic hash as only a 32-bit hash will see birthday collisions unreasonably frequently: https://en.wikipedia.org/wiki/Birthday_attack#Mathematics | ||||
|  * xxhash outputs an unsigned 64-bit integer. | ||||
|  * Converting to a signed 64-bit integer with no bit loss so that it can be stored in an SQLite integer field as-is: https://www.sqlite.org/fileformat2.html#record_format | ||||
|  * This should give very efficient storage with sufficient entropy. | ||||
|   | ||||
| @@ -12,6 +12,8 @@ const {discord, db, sync, as} = require("../passthrough") | ||||
| const sendEvent = sync.require("./actions/send-event") | ||||
| /** @type {import("./actions/add-reaction")} */ | ||||
| const addReaction = sync.require("./actions/add-reaction") | ||||
| /** @type {import("./actions/redact")} */ | ||||
| const redact = sync.require("./actions/redact") | ||||
| /** @type {import("./converters/utils")} */ | ||||
| const utils = sync.require("./converters/utils") | ||||
| /** @type {import("../matrix/api")}) */ | ||||
| @@ -101,6 +103,15 @@ async event => { | ||||
| 	} | ||||
| })) | ||||
|  | ||||
| sync.addTemporaryListener(as, "type:m.room.redaction", guard("m.room.redaction", | ||||
| /** | ||||
|  * @param {Ty.Event.Outer_M_Room_Redaction} event it is a m.room.redaction because that's what this listener is filtering for | ||||
|  */ | ||||
| async event => { | ||||
| 	if (utils.eventSenderIsFromDiscord(event.sender)) return | ||||
| 	await redact.handle(event) | ||||
| })) | ||||
|  | ||||
| sync.addTemporaryListener(as, "type:m.room.avatar", guard("m.room.avatar", | ||||
| /** | ||||
|  * @param {Ty.Event.StateOuter<Ty.Event.M_Room_Avatar>} event | ||||
|   | ||||
							
								
								
									
										6
									
								
								types.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								types.d.ts
									
									
									
									
										vendored
									
									
								
							| @@ -173,6 +173,12 @@ export namespace Event { | ||||
| 			key: string // the unicode emoji, mxc uri, or reaction text | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	export type Outer_M_Room_Redaction = Outer<{ | ||||
| 		reason?: string | ||||
| 	}> & { | ||||
| 		redacts: string | ||||
| 	} | ||||
| } | ||||
|  | ||||
| export namespace R { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Cadence Ember
					Cadence Ember