mirror of
https://github.com/matrix-org/mjolnir.git
synced 2024-10-01 05:36:06 +00:00
DSL: Let's get back to a DSL in which we send rules through Matrix, instead of a JSON server.
This commit is contained in:
parent
1a0d3198ef
commit
7eb02d2e82
358
dsl.ts
358
dsl.ts
@ -1,184 +1,222 @@
|
|||||||
/**
|
/**
|
||||||
* A format for sending spam-checker rules from a rule server to
|
* A format of messages designed to allow communication with a configurable
|
||||||
* a synapse spam-checker.
|
* spamchecker designed around the Synapse Spamcheck API.
|
||||||
*
|
*
|
||||||
* The intended use is that the spam-checker will regularly
|
* - We call an implementation of the Synapse Spamcheck API that supports this
|
||||||
|
* protocol a *Checker*.
|
||||||
|
* - The Checker is configured to receive instructions in a set of rooms
|
||||||
|
* Room1, Room2, ... RoomN. This set of rooms does not change during the
|
||||||
|
* lifetime of the Checker.
|
||||||
|
* - Any member of Room1, ..., RoomN with authorization to send messages
|
||||||
|
* (aka a *Controller*) can send instructions to the Checker. We expect
|
||||||
|
* that the Controller will be an implementation of Mjölnir or Carlotta.
|
||||||
*
|
*
|
||||||
* GET https://example.org/mjolnir/rules?since=timestamp
|
* A the time of this writing, the Checker supports only simple rules.
|
||||||
*
|
*
|
||||||
* And receive an update of the rules since timestamp.
|
* - A number of string properties are exposed to rules.
|
||||||
|
* - A rule is a string property and a literal/regexp.
|
||||||
|
* - During execution, if the regexp appears in the value of the string
|
||||||
|
* property, the message/user account creation request is rejected.
|
||||||
|
* - Otherwise, it is accepted.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
interface Literal {}
|
/**
|
||||||
interface Regexp {}
|
* ------------------- Messages from controller ----------------------
|
||||||
|
*/
|
||||||
|
|
||||||
/// A list of additions/removal.
|
type MessageFromControllerContent = {
|
||||||
///
|
type: "org.matrix.spamcheck.control",
|
||||||
/// Additions are resolved *after* removals.
|
content:
|
||||||
///
|
/// Update matchers on a single property.
|
||||||
/// Type parameter `T` is used as a phantom type to distinguish between
|
StringRuleUpdate | ObjectRuleUpdate
|
||||||
/// literal strings (`Literal`) or regexp strings (`Regexp`).
|
/// Reset the Checker to remove all rules.
|
||||||
type Patch<T> = {
|
| ClearEverything
|
||||||
/// Remove some or all items.
|
/// Request a snapshot of the current list of rules from the Checker.
|
||||||
remove?: "clear" | string[],
|
| ShowMeTheseRules
|
||||||
|
};
|
||||||
|
|
||||||
/// Add items.
|
/**
|
||||||
add?: string[],
|
* ---------------- Properties that the Checker can match against -------
|
||||||
|
*/
|
||||||
|
|
||||||
|
enum StringProperty {
|
||||||
|
/// The following properties point to strings.
|
||||||
|
"org.matrix.spamcheck.user_may_invite.inviter_user_id",
|
||||||
|
"org.matrix.spamcheck.user_may_invite.new_member_user_id",
|
||||||
|
"org.matrix.spamcheck.user_may_invite.room_id",
|
||||||
|
"org.matrix.spamcheck.user_may_create_room.user_id",
|
||||||
|
"org.matrix.spamcheck.user_may_create_room_alias.user_id",
|
||||||
|
"org.matrix.spamcheck.user_may_create_room_alias.desired_alias",
|
||||||
|
"org.matrix.spamcheck.user_may_publish_room.publisher_user_id",
|
||||||
|
"org.matrix.spamcheck.user_may_publish_room.room_id",
|
||||||
|
"org.matrix.spamcheck.check_username_for_spam.user_id",
|
||||||
|
"org.matrix.spamcheck.check_username_for_spam.display_name",
|
||||||
|
"org.matrix.spamcheck.check_username_for_spam.avatar_url",
|
||||||
|
"org.matrix.spamcheck.check_registration_for_spam_deny.maybe_user_name",
|
||||||
|
"org.matrix.spamcheck.check_registration_for_spam_deny.maybe_email",
|
||||||
|
"org.matrix.spamcheck.check_registration_for_spam_deny.user_agent",
|
||||||
|
"org.matrix.spamcheck.check_registration_for_spam_deny.ip",
|
||||||
|
"org.matrix.spamcheck.check_registration_for_spam_deny.maybe_auth_provider_id",
|
||||||
|
"org.matrix.spamcheck.check_registration_for_spam_shadowban.maybe_user_name",
|
||||||
|
"org.matrix.spamcheck.check_registration_for_spam_shadowban.maybe_email",
|
||||||
|
"org.matrix.spamcheck.check_registration_for_spam_shadowban.user_agent",
|
||||||
|
"org.matrix.spamcheck.check_registration_for_spam_shadowban.ip",
|
||||||
|
"org.matrix.spamcheck.check_registration_for_spam_shadowban.maybe_auth_provider_id",
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ObjectProperty {
|
||||||
|
/// The following properties point to objects.
|
||||||
|
"org.matrix.spamcheck.check_event_for_spam.event",
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An update to an elementary spam rule, attempting to match a single value
|
* ---------------- Checker Matching primitives -------
|
||||||
* (e.g. a user_id) against a number of regexps.
|
|
||||||
*
|
|
||||||
* The rule will **reject** (i.e. consider as spam) if the value **contains**
|
|
||||||
* any of the regexps or literals.
|
|
||||||
*
|
|
||||||
* The rule will **accept** (i.e. let pass) otherwise.
|
|
||||||
*/
|
*/
|
||||||
type Update = {
|
|
||||||
/// Any number of literals to add/remove.
|
|
||||||
///
|
|
||||||
/// Whenever possible, prefer literals to regexps, as they are both
|
|
||||||
/// more faster and more memory-efficient.
|
|
||||||
literals?: Patch<Literal>,
|
|
||||||
|
|
||||||
/// Any number of regexps to add/remove.
|
type Matcher =
|
||||||
///
|
/// Matching against a literal string.
|
||||||
/// The regexps will be or-ed and compiled spamcheck-side.
|
|
||||||
///
|
|
||||||
/// These regexps MUST follow the specs of https://docs.python.org/3/library/re.html .
|
|
||||||
regexps?: Patch<Regexp>,
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An antispam rule for `user_may_invite`.
|
|
||||||
*/
|
|
||||||
type InviteUpdates = {
|
|
||||||
/// The full user id of the inviter.
|
|
||||||
inviter_user_id: Update,
|
|
||||||
|
|
||||||
/// The full user id if the potential new room member.
|
|
||||||
new_member_user_id: Update,
|
|
||||||
|
|
||||||
/// The room id.
|
|
||||||
room_id: Update,
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An antispam rule for `user_may_create_room`.
|
|
||||||
*/
|
|
||||||
type RoomCreateUpdates = {
|
|
||||||
/// The full user id of the room creator.
|
|
||||||
user_id: Update,
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An antispam rule for `user_may_create_room_alias`.
|
|
||||||
*/
|
|
||||||
type AliasCreateUpdates = {
|
|
||||||
/// The full user id of the alias creator.
|
|
||||||
user_id: Update,
|
|
||||||
|
|
||||||
/// The human-readable alias.
|
|
||||||
desired_alias: Update,
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An antispam rule for `user_may_publish_room`.
|
|
||||||
*/
|
|
||||||
type PublishRoomUpdates = {
|
|
||||||
/// The full user id of the publisher.
|
|
||||||
publisher_user_id: Update,
|
|
||||||
|
|
||||||
/// The room id.
|
|
||||||
room_id: Update,
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An antispam rule for `check_username_for_spam`.
|
|
||||||
*/
|
|
||||||
type CheckUsernameForSpamUpdates = {
|
|
||||||
/// The full user id of the user.
|
|
||||||
user_id: Update,
|
|
||||||
|
|
||||||
/// The display name of the user.
|
|
||||||
display_name: Update,
|
|
||||||
|
|
||||||
/// The URL towards the avatar of the user.
|
|
||||||
avatar_url: Update,
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An antispam rule for `check_registration_for_spam`.
|
|
||||||
*/
|
|
||||||
type CheckRegistrationForSpamUpdates = {
|
|
||||||
/// The username, if available.
|
|
||||||
maybe_user_name: Update,
|
|
||||||
|
|
||||||
/// The email used for registration, if available.
|
|
||||||
maybe_email: Update,
|
|
||||||
|
|
||||||
/// The list of user agents used during registration (possibly empty).
|
|
||||||
/// A registration will be considered spammy if any of the
|
|
||||||
/// user agents matches the rule.
|
|
||||||
user_agent: Update,
|
|
||||||
|
|
||||||
/// The list of IPs used during registration (possibly empty).
|
|
||||||
/// A registration will be considered spammy if any of the
|
|
||||||
/// IPs matches the rule.
|
|
||||||
ip: Update,
|
|
||||||
|
|
||||||
/// The auth provider, if available, e.g. "oidc", "saml", ...
|
|
||||||
maybe_auth_provider_id: Update
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An antispam rule for `check_event_for_spam`.
|
|
||||||
*/
|
|
||||||
type CheckEventForSpamUpdates = {
|
|
||||||
/// A path of fields within the event object.
|
|
||||||
///
|
///
|
||||||
/// e.g. `"content.formatted_body"` will return `event.content.formatted_body`.
|
/// If the string property contains this literal string, the rule **matches**
|
||||||
|
/// i.e. the spamcheck will **reject** the operation. Matches are case-insensitive.
|
||||||
///
|
///
|
||||||
/// If any of the fields is not present, the rule will **not** match (i.e. the
|
/// # Example
|
||||||
/// message will not be considered spam).
|
///
|
||||||
event: { [path: string]: Update },
|
/// If literal `hailhydra` is a matcher for string property
|
||||||
};
|
/// `org.matrix.spamcheck.check_registration_for_spam_deny.maybe_user_name`,
|
||||||
|
/// user won't be able to register an account with the name 'hailHydra'.
|
||||||
|
{ literal: string }
|
||||||
|
|
||||||
|
/// Matching against a regexp.
|
||||||
|
///
|
||||||
|
/// If the string property is matched by this regexp, the rule **matches**
|
||||||
|
/// i.e. the spamcheck will **reject** the operation. Matches are case-insensitive.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// If regexp `h[ae]il.*hydra` is a matcher for string property
|
||||||
|
/// `org.matrix.spamcheck.check_registration_for_spam_deny.maybe_user_name`,
|
||||||
|
/// user won't be able to register an account with the name 'hEil hYdra'.
|
||||||
|
| { regexp: string }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The complete list of rules for an instance of the spam-checker.
|
* ------------------- Snapshot of rules ----------------------
|
||||||
*/
|
*/
|
||||||
type GlobalUpdate = {
|
|
||||||
/// If the rules match, user cannot invite other user.
|
|
||||||
user_may_invite?: InviteUpdates,
|
|
||||||
|
|
||||||
/// If the rules match, user cannot create room.
|
/**
|
||||||
user_may_create_room?: RoomCreateUpdates,
|
* The current matchers on a property that points to an object.
|
||||||
|
*/
|
||||||
|
type StringPropertyMatchers = {
|
||||||
|
property: StringProperty,
|
||||||
|
matchers: Matcher[],
|
||||||
|
}
|
||||||
|
|
||||||
/// If the rules match, user cannot create an alias for the room.
|
/**
|
||||||
user_may_create_room_alias?: AliasCreateUpdates,
|
* The current matchers on a property that points to an object.
|
||||||
|
*/
|
||||||
|
type ObjectPropertyMatchers = {
|
||||||
|
property: ObjectProperty,
|
||||||
|
matchers: {
|
||||||
|
[path: string]: Matcher[]
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
/// If the rules match, user cannot make the room public.
|
/**
|
||||||
user_may_publish_room?: PublishRoomUpdates,
|
* A list of rules we wish to see.
|
||||||
|
*/
|
||||||
|
type RuleToShow =
|
||||||
|
/// All the matchers for a StringProperty.
|
||||||
|
StringProperty
|
||||||
|
/// All the matchers for a single path in a ObjectProperty.
|
||||||
|
| {
|
||||||
|
property: ObjectProperty,
|
||||||
|
path: string
|
||||||
|
}
|
||||||
|
/// All the matchers for all the paths in an ObjectProperty.
|
||||||
|
| ObjectProperty;
|
||||||
|
|
||||||
/// If the rules match, register user and immediately shadowban them.
|
/**
|
||||||
check_registration_for_spam_shadowban?: CheckRegistrationForSpamUpdates,
|
* Show current rules.
|
||||||
|
*/
|
||||||
|
type ShowMeTheseRules = {
|
||||||
|
"org.matrix.spamcheck.action": "snapshot",
|
||||||
|
|
||||||
/// If the rules of `check_registration_for_spam_shadowban` do NOT
|
/// The list of rules to show:
|
||||||
/// match but these rules match, deny registration.
|
|
||||||
check_registration_for_spam_deny?: CheckRegistrationForSpamUpdates,
|
|
||||||
|
|
||||||
/// If the rules match, deny registration, regardless of
|
|
||||||
/// the result of `check_registration_for_spam_shadowban`
|
|
||||||
/// and `check_registration_for_spam_deny`.
|
|
||||||
check_username_for_spam?: CheckUsernameForSpamUpdates,
|
|
||||||
|
|
||||||
/// If the rules match, event will bounce.
|
|
||||||
check_event_for_spam?: CheckEventForSpamUpdates,
|
|
||||||
|
|
||||||
/// The instant of the latest update, in milliseconds since the Unix epoch.
|
|
||||||
///
|
///
|
||||||
/// This value is meant to be passed as argument when requesting
|
/// `*` for all rules
|
||||||
/// more recent update.
|
property: RuleToShow[] | "*";
|
||||||
latest_update_ts: number,
|
}
|
||||||
};
|
|
||||||
|
/**
|
||||||
|
* A message with a snapshot of rules, as requested per `ShowMeTheseRules`.
|
||||||
|
*/
|
||||||
|
type RuleSnapshotMessage = {
|
||||||
|
type: "org.matrix.spamcheck.snapshot",
|
||||||
|
content: {
|
||||||
|
dump: (StringPropertyMatchers | ObjectPropertyMatchers)[]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const MESSAGE_RULE_DUMP_TYPE = "org.matrix.spamcheck.dump";
|
||||||
|
/**
|
||||||
|
* ------------------- Updating rules ----------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
/// A list of additions/removal.
|
||||||
|
///
|
||||||
|
/// Resolved in the following order:
|
||||||
|
///
|
||||||
|
/// 1. remove;
|
||||||
|
/// 2. add;
|
||||||
|
type Patch = {
|
||||||
|
/// Remove some or all items.
|
||||||
|
remove?: "org.matrix.spamcheck.clear" | Matcher[],
|
||||||
|
|
||||||
|
/// Add items.
|
||||||
|
add?: Matcher[],
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An update to a single rule, for a property that points to a string.
|
||||||
|
*/
|
||||||
|
type StringRuleUpdate = {
|
||||||
|
"org.matrix.spamcheck.action": "update",
|
||||||
|
|
||||||
|
/// The property affected by this rule change.
|
||||||
|
property: StringProperty,
|
||||||
|
|
||||||
|
/// Matchers to add/remove.
|
||||||
|
patch: Patch,
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An update to a single rule, for a property that points to an object.
|
||||||
|
*/
|
||||||
|
type ObjectRuleUpdate = {
|
||||||
|
"org.matrix.spamcheck.action": "update",
|
||||||
|
|
||||||
|
/// The property affected by this rule change.
|
||||||
|
///
|
||||||
|
/// This property points to an object `o`.
|
||||||
|
property: ObjectProperty,
|
||||||
|
|
||||||
|
/// The path to follow within object `o` to access
|
||||||
|
/// a string value.
|
||||||
|
///
|
||||||
|
/// If the path is not defined or the value is not
|
||||||
|
/// a string, the message is considered a non-match,
|
||||||
|
/// i.e. it can pass.
|
||||||
|
path: string,
|
||||||
|
|
||||||
|
/// Matchers to add/remove.
|
||||||
|
patch: Patch,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove all the rules.
|
||||||
|
*/
|
||||||
|
type ClearEverything = {
|
||||||
|
"org.matrix.spamcheck.action": "clear",
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user