Coder Social home page Coder Social logo

matrix-protection-suite's Introduction

matrix-protection-suite

The matrix protection suite is a library that provides interfaces and models for interacting with matrix policy lists. These models are not attached to any single client backend.

The aim of the project is to extract components from Draupnir and Mjolnir into a complete library that can be used in any application, from other bots, to widgets, and web apps.

Currently anything involving policy lists has a well fleshed interface, and are less likely to change than other components while this library matures.

This library was generated from a template.

matrix-protection-suite's People

Contributors

gnuxie avatar mikaela avatar dependabot[bot] avatar pre-commit-ci[bot] avatar

Stargazers

jjj333_p avatar Erlend Sogge Heggen avatar

Watchers

 avatar  avatar jjj333_p avatar

Forkers

mikaela

matrix-protection-suite's Issues

`Context` object in Protections only exists because different consequence providers can't be configured to be given to different protections.

If protections need additional authority than provided by the consequence provider, then they should be able to get a consequence provider with a different interface and be configured to handle that. https://github.com/Gnuxie/matrix-protection-suite/blob/main/src/Protection/ProtectionsConfig/ProtectionsConfig.ts#L51

It's important that we remove the context object as soon as we have the config support for matching up different providers to different protections. https://github.com/Gnuxie/matrix-protection-suite/blob/main/src/Protection/ProtectionsConfig/MjolnirProtectionsConfig.ts#L45-L46. This is the only way to make a safe "dry run" mode of Draupnir.

Room state concepts need more consideration.

Something that we've missed for years is that if you manage to find a state event in the timeline, and it's for a brand new type+key combination, then you can always treat it like a state delta. It's not possible for the event to be stale state from your and your server's perspective.

To be able to represent this, we need new state change concepts, changing Added to Introduced and Reintroduced.
Where Introduced means that we haven't seen an event of that type+key combination before.

Events that have been Introduced can then be directly inserted by revision issuers into the next revision.

Batching of revisions is something that is inherited from Mjolnir to make sure that server ACL application wouldn't flood a room with m.room.server_acl events if using a script to bulk add policies to a policy room. I'm now of the opinion that batching should be controlled protection side. However, revision issuers should at least perform some batching so that introduced events received within the same sync response end up within the same revision.

Revision issuers should take a ULID before beginning the process of fetching state and revision issuers should then give this ULID to the next revision. This ensures that consumers of revisions that make assumptions and pre-empt the state of the room can invalidate their predictions by comparing the ULID of the revision to the ULID associated with their predictions and whether they came true or not.

(For onlookers, we only use ULIDs within the same process)

Preemption can only be done in cases where the state is a certainty, e.g. introduced state. We can't use ULID's like this because introduced state can revise a revision while a request is being sent across the network.

Why `TrackedStateEvent` might not be worth it.

Currently the RoomStateRevision can be configured to store a minimal representation of events provided they fit the TrackedStateEvent interface. This can be done by setting events as InformOnly within a StateTrackingMeta object and then giving StateTrackingMeta object to the RoomStateRevision either at initialization or later. In theory this will mean that the RoomStateRevision will use up less memory because events will be stored with most keys redacted. However, this does mean that PolicyListRevisions and RoomMembershipRevisions cannot be instantiated from a RoomStateRevision, only a blank revision that is incrementally built by listening to a RoomStateRevisionIssuer. It's also unclear whether there is going to be much benefit from the reduced memory footprint of some events, given that for Draupnir, all rooms protected will need their membership tracked. Which preserves the event content and most top level fields.

It's going to be expensive to run Draupnir to protected a room with 100k members, and this sort of saving is going to be linear. If we needed to think seriously about this for whatever reason, homeservers probably will reach the limit first. Telegram for instance only supports 200k members per group.

Let's pretend the average membership event will be 2000bytes for Draupnir to hold in memory (my estimates are more in the region of 800bytes, but lets up it just to be conservative, and the real serialized size is probably less still, in the region of 500-600bytes per event). And now let's say there's a million of them. That would mean there only needs to be 2GB to represent them. Which is quite reasonable. Even if we double or quadruple that.

So I think it's fair to say for simplicity, we're not going to have to worry about this quite yet and if we did, we would need to change the architecture of MPS regardless of the linear savings for TrackedStateEvent. We'd reach the point where we have to be able to change the cached membership to be a partial understanding of room state based on who is active in the room at around the same time in either case.

`MembershipChangeType` `Rejoined` is probably error prone

Given a user rejecting an invite or being kicked on knock for the first time and later joining again probably shouldn't be classified as rejoined as they never did really join the room. Of course, this relies on transitions being skipped from our perspective due to downtime and not chasing up the chain of events, because normally the user would be classified as renocked or reinvited.

Do we need to add attribution text to our files that reference the repository?

e.g. we have attribution text for mjolnir

// SPDX-FileAttributionText: <text>
// This modified file incorporates work from mjolnir
// https://github.com/matrix-org/mjolnir
// </text>

We aren't legally obligated to do this, but we do do this because it's the right thing to do.
We want to try enforce that other projects do the same to us when they copy from us, and it seems like the only way to do that is by adding attribution text the same way that is self referential. Which is interesting, since that text can't say modified but has to say modified when it has been copied? Maybe incorporates is enough.

There should be a way to go from changes and a revision to the revision issuer

async function groupRulesByIssuer(policyRoomManager: PolicyRoomManager, changesByList: ChangesByRoomID): Promise<ActionResult<GroupedChanges[]>> {
    for (const [roomID, changes] of changesByList) {
        const issuer = await policyRoomManager.getPolicyRoomRevisionIssuer(MatrixRoomReference.fromRoomID(roomID));
    }
}

This kind of code shouldn't be happening... We can't avoid aggregating changes into other revisions, so maybe this needs to happen at the rule level?

Draupnir Account data & state migration is verified.

It doesn't seem like any "migration" actually happens.

`MembershipChangeType` doesn't account for skipped transititions

For example leave->leave implies a user temporarily rejoined the room, so it's wrong to classify it as NoChange since we might want to warn protections about the rejoin even if we don't have a record of it (because of downtime). Of course, all of these special cases have to have to be its own enum variant

Ensure `PolicyListRevisionIssuer`s and their dependents are intialized in a consistent way

This can be done by enforcing that the initial data that is used to build a revision (e.g. when fetching state for the first time) is done so from calling reviseFromChanges/reviseFromState on an empty revision (blankRevision). Then adding a flag to the revision event (or an event that can be subscribed to with once (i don't think the latter is necessary given everything will need to subscribe to this events, and only client code will need to distinguish between the two).

`SetRoomState`/`SetRoomMembership` 'revision' event consistency

So I was wondering if I needed to create a new listener specifically for when the ProtectedRoomsManagergets a call to addRoom. Instead of just abusing the existing 'revision' event in the setRoomState and membership objects.

When a new policy list is added to the PolicyListsConfig, the issuer manager creates a revision that incorporates all these new changes. But that's because the revision represents the final result of all config and fancy filtering.

So the thing is the protection handles for handleStateChange and handleMembershipChange are called when the setRoomState emits the revision event.

Startup time is much worse 0.19.0

by about a minute, it's something to do with the way the set membreship and set room state are intiailised in the ProtectedRoomsManager

Why we are not using a bundler (rollup to be removed shortly)

I haven't seen a compelling argument to use one. People have suggested that bundling libraries means that the packages are smaller and there is better compatbility with supporting both CommonJS, ESM and even UMD. But It's not actually clear to me whether this is a real problem for more recent npm packages anyway?
If you are going to write a web app where the size of the depenencies will matter, you will have a bundler anyway? If your dependencies are themselves bundled, their dependencies probably will not be de-duplicated by your own bundler. So I don't really buy this argument. It seems like there is just an obsession to save bytes for no purpose and to create tooling that doesn't actually match up with npm. https://cmdcolin.github.io/posts/2022-05-27-youmaynotneedabundler.

For our project, we tried to use rollup and add typebox as an external peer dependency using @rollup/plugin-node-resolve. However, this will not work when you try to use the bundled library in another project that has a subdependency that is installed first which doesn't use the same version of typebox as you. And there doesn't seem to be an obvious way to fix that at all. The tooling is inadequate and a waste of time. And is probably quite damaging in other ways (dependants not being able to override dependencies and all).

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.