Page MenuHomePhabricator

[keyserver] Prevent the only admin role from being changed on the keyserver
ClosedPublic

Authored by rohan on Jun 13 2023, 1:45 PM.
Tags
None
Referenced Files
Unknown Object (File)
Mon, Dec 2, 6:50 AM
Unknown Object (File)
Mon, Dec 2, 12:31 AM
Unknown Object (File)
Sun, Dec 1, 6:22 AM
Unknown Object (File)
Sun, Dec 1, 3:34 AM
Unknown Object (File)
Tue, Nov 26, 9:11 AM
Unknown Object (File)
Tue, Nov 26, 9:07 AM
Unknown Object (File)
Tue, Nov 26, 4:19 AM
Unknown Object (File)
Sat, Nov 23, 4:15 PM
Subscribers

Details

Summary

Although we will handle this on the client-side, we should also make sure the keyserver supports the use case where we throw a server error if the sole admin of a community tries to change their own role.

Depends on D8140

Test Plan

Please see the video below

Diff Detail

Repository
rCOMM Comm
Lint
No Lint Coverage
Unit
No Test Coverage

Event Timeline

rohan requested review of this revision.Jun 13 2023, 2:04 PM

Adding @ashoat as blocking here to take another look

keyserver/src/updaters/thread-updaters.js
106–108 ↗(On Diff #27707)

Can we add a comment explaining the reasoning for this "block" of code?

ashoat requested changes to this revision.Jun 15 2023, 6:36 AM
ashoat added a subscriber: atul.
ashoat added inline comments.
keyserver/src/updaters/thread-updaters.js
98 ↗(On Diff #27722)

The fact that we're only checking memberIDs[0] seems problematic. What if there is 1 admin and 1 member, and the admin creates a new role and tries to assign both the member and the admin to the new role? It seems like if the member is the first ID, then we won't bother checking the admin at all

107 ↗(On Diff #27722)

I'm not sure relying on the name here is a good approach. If we take this approach, we'll need another task (or two) to make sure that it's not possible to rename a role to "Admins", and that it's not possible to rename the "Admins" role.

I wonder if we could add an isAdmin parameter to RoleInfo, similar to how we have isDefault today. This would require changes to the MySQL database: probably a new admin_role column on threads, similar to how we have the default_role column now.

I vaguely recall chatting with @atul recently about some other reason that it would be good to have this parameter, but I don't recall the exact details (I think it was related to permissions?)

This revision now requires changes to proceed.Jun 15 2023, 6:36 AM
keyserver/src/updaters/thread-updaters.js
98 ↗(On Diff #27722)

That's fair, I only considered the client-side of changing roles where it's one at a time at the moment (haven't checked the new role creation flow) - a better approach would to check 1) the number of admin roles in the change request and 2) the number of current admins in the community. Then we can throw an error if all admins are losing their role

107 ↗(On Diff #27722)

If we take this approach, we'll need another task (or two) to make sure that it's not possible to rename a role to "Admins", and that it's not possible to rename the "Admins" role.

The first could probably be addressed in the role creation stack when I work on that by adding a unique key on the role names (we'd probably want this anyways so we don't have several roles with the same name with different permissions).

The second I believe is already covered as an edge case in the designs.

I wonder if we could add an isAdmin parameter to RoleInfo, similar to how we have isDefault today. This would require changes to the MySQL database: probably a new admin_role column on threads, similar to how we have the default_role column now.

I'm open to looking into this, just wanted to gauge if it would be better to handle now or towards the end of roles since I already plan to prevent duplicate role names and prevent the admin role from being renamed

keyserver/src/updaters/thread-updaters.js
107 ↗(On Diff #27722)

I'm open to looking into this, just wanted to gauge if it would be better to handle now or towards the end of roles since I already plan to prevent duplicate role names and prevent the admin role from being renamed

Not sure, that's a good question...

I'd like to hear from @atul RE this:

I vaguely recall chatting with @atul recently about some other reason that it would be good to have this parameter, but I don't recall the exact details (I think it was related to permissions?)

If that's not an urgent thing we want to address, then I'm open to sequencing this later. But it does feel to me that determining whether a role is an admin role based on the name is a bit "sketchy"...

Address feedback on considering multiple member role changes (tested these changes).

Waiting on the discussion about checking "Admins" to determine whether that should be changed

keyserver/src/updaters/thread-updaters.js
105–114

This could probably be simplified into something like the below, but I preferred the loop to keep readability

const changedAdminsCount = memberIDs.filter(
  memberID =>
    threadInfo.members.find(member => member.id === memberID)?.role ===
    adminRoleID,
).length;
ashoat added 1 blocking reviewer(s): atul.

Resigning since I'm going to be out-of-office starting tomorrow, and I want to avoid blocking this diff. Instead, going to set @atul as blocking to confirm that my concerns are addressed, and so that he responds to the question above

keyserver/src/updaters/thread-updaters.js
95 ↗(On Diff #27896)

Should we handle the possiblity of threadInfo being undefined?

108 ↗(On Diff #27896)
  1. adminRoleID can be falsey if there is no admin role
  2. memberRole can be falsey if a new user is being added

I think this could break your logic

I vaguely recall chatting with @atul recently about some other reason that it would be good to have this parameter, but I don't recall the exact details (I think it was related to permissions?)

I believe this was so we could avoid storing computed permissions for other users in ThreadStore?

In D8200#243739, @atul wrote:

I vaguely recall chatting with @atul recently about some other reason that it would be good to have this parameter, but I don't recall the exact details (I think it was related to permissions?)

I believe this was so we could avoid storing computed permissions for other users in ThreadStore?

Ah, so the thinking was that we would only include permissions blobs for admins and the viewer, and skip permissions blobs for other users?

@rohan, maybe you can create a follow-up task to address this before landing?

Ah, so the thinking was that we would only include permissions blobs for admins and the viewer, and skip permissions blobs for other users?

@rohan, maybe you can create a follow-up task to address this before landing?

https://linear.app/comm/issue/ENG-4154/modify-threadstore-permission-blobs

keyserver/src/updaters/thread-updaters.js
95 ↗(On Diff #27896)

We could by throwing a invalid_parameters error here, in the event that a threadID not associated to a thread is for some reason passed in

108 ↗(On Diff #27896)

adminRoleID can be falsey if there is no admin role

That's fair

memberRole can be falsey if a new user is being added

I feel like that makes sense. If a new user is added and they don't have a role, that just leaves an undefined value in memberRoles. When we calculate changedAdminsCount and iterate through memberRoles, this instance of undefined === adminRoleID would just be false and it makes sense since they aren't an admin losing their role.

Am I missing something there?

keyserver/src/updaters/thread-updaters.js
108 ↗(On Diff #27896)

I'm not objecting to them being undefined – I'm pointing out that if both of these things happen, changedAdminsCount can be artificially inflated by undefined === undefined

keyserver/src/updaters/thread-updaters.js
108 ↗(On Diff #27896)

Ah I misunderstood your original comment. Makes sense! The best solution I think would be just to wrap this all in an if (adminRoleID) { ... }

This revision is now accepted and ready to land.Jun 20 2023, 12:36 PM
This revision was landed with ongoing or failed builds.Jun 21 2023, 8:41 AM
This revision was automatically updated to reflect the committed changes.