Allow the redact command to take globs

This commit is contained in:
Travis Ralston 2019-12-09 19:43:41 -07:00
parent 7de3744875
commit 6753e7f780
2 changed files with 64 additions and 32 deletions

View File

@ -19,6 +19,7 @@ import { Mjolnir } from "../Mjolnir";
import { LogLevel, LogService } from "matrix-bot-sdk";
import { logMessage } from "../LogProxy";
import config from "../config";
import { isTrueJoinEvent } from "../utils";
export class FirstMessageIsImage implements IProtection {
@ -36,14 +37,7 @@ export class FirstMessageIsImage implements IProtection {
if (!this.justJoined[roomId]) this.justJoined[roomId] = [];
if (event['type'] === 'm.room.member') {
const membership = event['content']['membership'] || 'join';
let prevMembership = "leave";
if (event['unsigned'] && event['unsigned']['prev_content']) {
prevMembership = event['unsigned']['prev_content']['membership'] || 'leave';
}
// We look at the previous membership to filter out profile changes
if (membership === 'join' && prevMembership !== "join") {
if (isTrueJoinEvent(event)) {
this.justJoined[roomId].push(event['state_key']);
LogService.info("FirstMessageIsImage", `Tracking ${event['state_key']} in ${roomId} as just joined`);
}

View File

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import { MatrixClient } from "matrix-bot-sdk";
import { LogService, MatrixClient, MatrixGlob } from "matrix-bot-sdk";
export function setToArray<T>(set: Set<T>): T[] {
const arr: T[] = [];
@ -24,7 +24,27 @@ export function setToArray<T>(set: Set<T>): T[] {
return arr;
}
export function isTrueJoinEvent(event: any): boolean {
const membership = event['content']['membership'] || 'join';
let prevMembership = "leave";
if (event['unsigned'] && event['unsigned']['prev_content']) {
prevMembership = event['unsigned']['prev_content']['membership'] || 'leave';
}
// We look at the previous membership to filter out profile changes
return membership === 'join' && prevMembership !== "join";
}
/**
* Gets all the events sent by a user (or users if using wildcards) in a given room ID, since
* the time they joined.
* @param {MatrixClient} client The client to use.
* @param {string} sender The sender. Can include wildcards to match multiple people.
* @param {string} roomId The room ID to search in.
* @returns {Promise<any>} Resolves to the events sent by the user(s) prior to join.
*/
export async function getMessagesByUserSinceLastJoin(client: MatrixClient, sender: string, roomId: string): Promise<any[]> {
const limit = 1000; // maximum number of events to process, regardless of outcome
const filter = {
room: {
rooms: [roomId],
@ -33,7 +53,6 @@ export async function getMessagesByUserSinceLastJoin(client: MatrixClient, sende
rooms: [roomId],
},
timeline: {
senders: [sender],
rooms: [roomId],
types: ["m.room.message"],
},
@ -56,6 +75,22 @@ export async function getMessagesByUserSinceLastJoin(client: MatrixClient, sende
},
};
let isGlob = true;
if (!sender.includes("*")) {
isGlob = false;
filter.room.timeline['senders'] = [sender];
}
const matcher = new MatrixGlob(sender);
function testUser(userId: string): boolean {
if (isGlob) {
return matcher.test(userId);
} else {
return userId === sender;
}
}
function initialSync() {
const qs = {
filter: JSON.stringify(filter),
@ -69,6 +104,7 @@ export async function getMessagesByUserSinceLastJoin(client: MatrixClient, sende
from: from,
dir: "b",
};
LogService.info("utils", "Backfilling with token: " + token);
return client.doRequest("GET", `/_matrix/client/r0/rooms/${encodeURIComponent(roomId)}/messages`, qs);
}
@ -76,35 +112,37 @@ export async function getMessagesByUserSinceLastJoin(client: MatrixClient, sende
const response = await initialSync();
if (!response) return [];
let token = response['next_batch'];
const messages = [];
const stopProcessingMembers = [];
let processed = 0;
const timeline = (((response['rooms'] || {})['join'] || {})[roomId] || {})['timeline'] || {};
const syncedMessages = timeline['events'] || [];
token = timeline['prev_batch'] || token;
for (const event of syncedMessages) {
if (event['sender'] === sender) messages.push(event);
if (event['type'] === 'm.room.member' && event['state_key'] === sender) {
if (event['content'] && event['content']['membership'] === 'join') {
return messages; // we're done!
}
}
}
while (token) {
const bfMessages = await backfill(token);
token = bfMessages['end'];
let token = timeline['prev_batch'] || response['next_batch'];
let bfMessages = {chunk: syncedMessages, end: token};
do {
for (const event of (bfMessages['chunk'] || [])) {
if (event['sender'] === sender) messages.push(event);
if (event['type'] === 'm.room.member' && event['state_key'] === sender) {
if (event['content'] && event['content']['membership'] === 'join') {
return messages; // we're done!
}
if (processed >= limit) return messages; // we're done even if we don't want to be
processed++;
if (stopProcessingMembers.includes(event['sender'])) continue;
if (testUser(event['sender'])) messages.push(event);
if (event['type'] === 'm.room.member' && testUser(event['state_key']) && isTrueJoinEvent(event)) {
stopProcessingMembers.push(event['sender']);
if (!isGlob) return messages; // done!
}
}
}
if (token) {
bfMessages = await backfill(token);
let lastToken = token;
token = bfMessages['end'];
if (lastToken === token) {
LogService.warn("utils", "Backfill returned same end token - returning");
return messages;
}
}
} while (token);
return messages;
}