Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Towards computing opinions #339

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 28 additions & 7 deletions src/Mjolnir.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import {
TextualMessageEventContent
} from "matrix-bot-sdk";

import { ALL_RULE_TYPES as ALL_BAN_LIST_RULE_TYPES, RULE_ROOM, RULE_SERVER, RULE_USER } from "./models/ListRule";
import { ALL_RULE_TYPES as ALL_BAN_LIST_RULE_TYPES, EntityType, RULE_ROOM, RULE_SERVER, RULE_USER } from "./models/PolicyRule";
import { applyServerAcls } from "./actions/ApplyAcl";
import { RoomUpdateError } from "./models/RoomUpdateError";
import { COMMAND_PREFIX, handleCommand } from "./commands/CommandHandler";
Expand All @@ -50,7 +50,7 @@ import RuleServer from "./models/RuleServer";
import { RoomMemberManager } from "./RoomMembers";
import { ProtectedRoomActivityTracker } from "./queues/ProtectedRoomActivityTracker";
import { ThrottlingQueue } from "./queues/ThrottlingQueue";
import PolicyList, { ListRuleChange } from "./models/PolicyList";
import PolicyList, { PolicyRuleChange } from "./models/PolicyList";

const levelToFn = {
[LogLevel.DEBUG.toString()]: LogService.debug,
Expand Down Expand Up @@ -355,7 +355,7 @@ export class Mjolnir {
this.currentState = STATE_SYNCING;
if (config.syncOnStartup) {
await this.logMessage(LogLevel.INFO, "Mjolnir@startup", "Syncing lists...");
await this.syncLists(config.verboseLogging);
await this.syncPolicyLists(config.verboseLogging);
await this.registerProtections();
}

Expand Down Expand Up @@ -434,7 +434,7 @@ export class Mjolnir {
const rooms = (additionalProtectedRooms?.rooms ?? []);
rooms.push(roomId);
await this.client.setAccountData(PROTECTED_ROOMS_EVENT_TYPE, { rooms: rooms });
await this.syncLists(config.verboseLogging);
await this.syncPolicyLists(config.verboseLogging);
}

public async removeProtectedRoom(roomId: string) {
Expand Down Expand Up @@ -482,7 +482,7 @@ export class Mjolnir {
this.applyUnprotectedRooms();

if (withSync) {
await this.syncLists(config.verboseLogging);
await this.syncPolicyLists(config.verboseLogging);
}
}

Expand Down Expand Up @@ -882,7 +882,7 @@ export class Mjolnir {
* Sync all the rooms with all the watched lists, banning and applying any changed ACLS.
* @param verbose Whether to report any errors to the management room.
*/
public async syncLists(verbose = true) {
public async syncPolicyLists(verbose = true) {
for (const list of this.policyLists) {
const changes = await list.updateList();
await this.printBanlistChanges(changes, list, true);
Expand Down Expand Up @@ -1052,7 +1052,7 @@ export class Mjolnir {
* @param ignoreSelf Whether to exclude changes that have been made by Mjolnir.
* @returns true if the message was sent, false if it wasn't (because there there were no changes to report).
*/
private async printBanlistChanges(changes: ListRuleChange[], list: PolicyList, ignoreSelf = false): Promise<boolean> {
private async printBanlistChanges(changes: PolicyRuleChange[], list: PolicyList, ignoreSelf = false): Promise<boolean> {
if (ignoreSelf) {
const sender = await this.client.getUserId();
changes = changes.filter(change => change.sender !== sender);
Expand Down Expand Up @@ -1194,4 +1194,25 @@ export class Mjolnir {
await protection.handleReport(this, roomId, reporterId, event, reason);
}
}

/**
* Return the composite opinion for an entity.
*
* In the current implementation, we return the first opinion found in the list
* of policies. Future versions will support additional mechanisms for composing
* opinions.
*
* @param entity
* @param type
* @returns The opinion or null if no list defines an opinion on this entity.
*/
public opinionForEntity(entity: string, type: EntityType): number | null {
for (let policyList of this.policyLists) {
let opinion = policyList.opinionForEntity(entity, type);
if (opinion !== null) {
return opinion;
}
}
return null;
}
}
3 changes: 2 additions & 1 deletion src/actions/ApplyAcl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { Mjolnir } from "../Mjolnir";
import config from "../config";
import { LogLevel, UserID } from "matrix-bot-sdk";
import { ERROR_KIND_FATAL, ERROR_KIND_PERMISSION } from "../ErrorCache";
import { Recommendation } from "../models/PolicyRule";

/**
* Applies the server ACLs represented by the ban lists to the provided rooms, returning the
Expand All @@ -36,7 +37,7 @@ export async function applyServerAcls(lists: PolicyList[], roomIds: string[], mj
// Construct a server ACL first
const acl = new ServerAcl(serverName).denyIpAddresses().allowServer("*");
for (const list of lists) {
for (const rule of list.serverRules) {
for (const rule of list.getServerRules(Recommendation.Ban)) {
acl.denyServer(rule.entity);
}
}
Expand Down
3 changes: 2 additions & 1 deletion src/actions/ApplyBan.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { Mjolnir } from "../Mjolnir";
import config from "../config";
import { LogLevel } from "matrix-bot-sdk";
import { ERROR_KIND_FATAL, ERROR_KIND_PERMISSION } from "../ErrorCache";
import { Recommendation } from "../models/PolicyRule";

/**
* Applies the member bans represented by the ban lists to the provided rooms, returning the
Expand Down Expand Up @@ -57,7 +58,7 @@ export async function applyUserBans(lists: PolicyList[], roomIds: string[], mjol

let banned = false;
for (const list of lists) {
for (const userRule of list.userRules) {
for (const userRule of list.getUserRules(Recommendation.Ban)) {
if (userRule.isMatch(member.userId)) {
// User needs to be banned

Expand Down
10 changes: 5 additions & 5 deletions src/commands/DumpRulesCommand.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ limitations under the License.

import { RichReply } from "matrix-bot-sdk";
import { Mjolnir } from "../Mjolnir";
import { EntityType } from "../models/ListRule";
import { EntityType } from "../models/PolicyRule";
import { htmlEscape } from "../utils";

/**
Expand All @@ -33,7 +33,7 @@ export async function execRulesMatchingCommand(roomId: string, event: any, mjoln
let html = "";
let text = "";
for (const list of mjolnir.lists) {
const matches = list.rulesMatchingEntity(entity)
const matches = list.rulesMatchingEntity(entity, "*");

if (matches.length === 0) {
continue;
Expand Down Expand Up @@ -90,19 +90,19 @@ export async function execDumpRulesCommand(roomId: string, event: any, mjolnir:
html += `<a href="${list.roomRef}">${list.roomId}</a>${shortcodeInfo}:<br/><ul>`;
text += `${list.roomRef}${shortcodeInfo}:\n`;

for (const rule of list.serverRules) {
for (const rule of list.getServerRules("*")) {
hasRules = true;
html += `<li>server (<code>${rule.recommendation}</code>): <code>${htmlEscape(rule.entity)}</code> (${htmlEscape(rule.reason)})</li>`;
text += `* server (${rule.recommendation}): ${rule.entity} (${rule.reason})\n`;
}

for (const rule of list.userRules) {
for (const rule of list.getUserRules("*")) {
hasRules = true;
html += `<li>user (<code>${rule.recommendation}</code>): <code>${htmlEscape(rule.entity)}</code> (${htmlEscape(rule.reason)})</li>`;
text += `* user (${rule.recommendation}): ${rule.entity} (${rule.reason})\n`;
}

for (const rule of list.roomRules) {
for (const rule of list.getRoomRules("*")) {
hasRules = true;
html += `<li>room (<code>${rule.recommendation}</code>): <code>${htmlEscape(rule.entity)}</code> (${htmlEscape(rule.reason)})</li>`;
text += `* room (${rule.recommendation}): ${rule.entity} (${rule.reason})\n`;
Expand Down
2 changes: 1 addition & 1 deletion src/commands/ImportCommand.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ limitations under the License.

import { Mjolnir } from "../Mjolnir";
import { RichReply } from "matrix-bot-sdk";
import { EntityType, Recommendation } from "../models/ListRule";
import { EntityType, Recommendation } from "../models/PolicyRule";

// !mjolnir import <room ID> <shortcode>
export async function execImportCommand(roomId: string, event: any, mjolnir: Mjolnir, parts: string[]) {
Expand Down
6 changes: 3 additions & 3 deletions src/commands/StatusCommand.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,10 +71,10 @@ async function showMjolnirStatus(roomId: string, event: any, mjolnir: Mjolnir) {
text += `Protected rooms: ${Object.keys(mjolnir.protectedRooms).length}\n`;

// Append list information
html += "<b>Subscribed ban lists:</b><br><ul>";
text += "Subscribed ban lists:\n";
html += "<b>Subscribed policy lists:</b><br><ul>";
text += "Subscribed policy lists:\n";
for (const list of mjolnir.lists) {
const ruleInfo = `rules: ${list.serverRules.length} servers, ${list.userRules.length} users, ${list.roomRules.length} rooms`;
const ruleInfo = `rules: ${list.getServerRules("*").length} servers, ${list.getUserRules("*").length} users, ${list.getRoomRules("*").length} rooms`;
html += `<li><a href="${list.roomRef}">${list.roomId}</a> (${ruleInfo})</li>`;
text += `* ${list.roomRef} (${ruleInfo})\n`;
}
Expand Down
2 changes: 1 addition & 1 deletion src/commands/SyncCommand.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,5 @@ import { Mjolnir } from "../Mjolnir";

// !mjolnir sync
export async function execSyncCommand(roomId: string, event: any, mjolnir: Mjolnir) {
return mjolnir.syncLists();
return mjolnir.syncPolicyLists();
}
4 changes: 2 additions & 2 deletions src/commands/UnbanBanCommand.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ limitations under the License.
import { Mjolnir } from "../Mjolnir";
import PolicyList from "../models/PolicyList";
import { extractRequestError, LogLevel, LogService, MatrixGlob, RichReply } from "matrix-bot-sdk";
import { Recommendation, RULE_ROOM, RULE_SERVER, RULE_USER, USER_RULE_TYPES } from "../models/ListRule";
import { Recommendation, RULE_ROOM, RULE_SERVER, RULE_USER, USER_RULE_TYPES } from "../models/PolicyRule";
import config from "../config";
import { DEFAULT_LIST_EVENT_TYPE } from "./SetDefaultBanListCommand";

Expand Down Expand Up @@ -163,7 +163,7 @@ export async function execUnbanCommand(roomId: string, event: any, mjolnir: Mjol

if (unbannedSomeone) {
await mjolnir.logMessage(LogLevel.DEBUG, "UnbanBanCommand", `Syncing lists to ensure no users were accidentally unbanned`);
await mjolnir.syncLists(config.verboseLogging);
await mjolnir.syncPolicyLists(config.verboseLogging);
}
}

Expand Down
Loading