Page MenuHomePhabricator

[keyserver/lib] Add keyserver support for creating roles
ClosedPublic

Authored by rohan on Jul 3 2023, 8:00 AM.
Tags
None
Referenced Files
F2057553: D8420.id28419.diff
Thu, Jun 20, 3:44 PM
F2057118: D8420.id28355.diff
Thu, Jun 20, 2:49 PM
Unknown Object (File)
Thu, Jun 20, 11:10 AM
Unknown Object (File)
Wed, Jun 19, 8:51 PM
Unknown Object (File)
Sat, Jun 15, 7:34 AM
Unknown Object (File)
Sat, Jun 15, 6:21 AM
Unknown Object (File)
Fri, Jun 14, 9:55 AM
Unknown Object (File)
Fri, Jun 14, 7:09 AM
Subscribers

Details

Summary

This diff adds the keyserver support for creating new roles with a set of permissions. configurableCommunityPermissions was introduced in the previous diff, and those are the user-selectable permissions that are provided here, and we introduce guaranteedCommunityPermissions here and merge the two arrays to derive a set of permissions for the new role. Generating thread updates will happen in a later diff

The reason I named things modifyRoles / RoleModification, as opposed to createRole / RoleCreation is because I plan to re-use this code as much as possible for the edit_roles flow. Because of this, I intended to name these functions / types as something that could be used both across creating roles and editing roles.

Only adding @ashoat as a reviewer here since it 1) directly addresses his feedback about introducing the guaranteedCommunityPermissions alongside its callsite, and 2) it involves community permissions and I'm not sure who has the most context on them.

Depends on D8391

ENG-4173

Test Plan

Between this diff and the last diff, I added a rough call to create a custom role when the client-side 'Create role' button is clicked, and confirmed that it saved in the DB. The next diff will add the logic to actually save a new role from the client.

Screenshot 2023-07-03 at 10.59.37 AM.png (52×1 px, 59 KB)

Diff Detail

Repository
rCOMM Comm
Lint
Lint Not Applicable
Unit
Tests Not Applicable

Event Timeline

rohan edited the test plan for this revision. (Show Details)
rohan requested review of this revision.Jul 3 2023, 8:18 AM

Support create_role action for now when creating a role (this will make it easier to re-use logic when working on the edit_role flow)

keyserver/src/creators/role-creator.js
90–95 ↗(On Diff #28364)

The idea here is since we type each permission as a string and not a ThreadPermission (see D8391 for the comment why), I want to validate that each permission passed in is indeed a valid permission. So I use the existing threadPermissions, and ensure for each permission to be associated with the new role, it includes one of the threadPermissions.

So know_of and descendant_know_of, for example, will include 'know_of', however something like random_permission will be detected and throw the ServerError

ashoat requested changes to this revision.Jul 4 2023, 12:35 PM
ashoat added inline comments.
keyserver/src/creators/role-creator.js
90 ↗(On Diff #28364)

No reason to recreate this on every invocation. Can we just export this from lib/types/thread-permission-types.js? Or perhaps even better would be to export a Set constructed from the array?

90–95 ↗(On Diff #28364)

Should we do this check before we create the ID?

92 ↗(On Diff #28364)

It appears like you're making it possible to set any "base" threadPermissions constant, and preventing the client for setting anything with a prefix. It also doesn't seem like you're blocking any of the threadPermissions, including the deprecated ones

See my final inline comment for my overall thoughts on this API design

110 ↗(On Diff #28364)

If we're not supporting edit_role yet, can you throw a new ServerError('unimplemented') or something for that case? Or is it be implemented in the following diff?

lib/types/thread-types.js
437 ↗(On Diff #28364)

I think putting threadPermissions here is the wrong API. You're hijacking an enum made for something else. The "user-facing permissions" are a fairly different concept from the threadPermissions in the database, and I think it would be better for readability / maintability / input validation if you just created a separate enum for them

This revision now requires changes to proceed.Jul 4 2023, 12:35 PM
keyserver/src/creators/role-creator.js
90 ↗(On Diff #28364)

Sure that makes sense

90–95 ↗(On Diff #28364)

Yeah that makes sense

92 ↗(On Diff #28364)

My approach was to make it possible to set any base threadPermission and any threadPermission with a prefix (see the comment in D8391)

type ConfigurableCommunityPermission = {
  // Type the permissions as `string`, as opposed to `ThreadPermission`,
  // because we open up the permissions to include an optional prefix
  // (i.e. `descendant_`) to propagate certain permissions down the community.
  +permissions: $ReadOnlyArray<string>,
  +title: string,
  +description: string,
};

Once your feedback is addressed on changing configurableCommunityPermissions, I'll check on improving the validation.

I responded to the overall API design comment in your last inline comment

110 ↗(On Diff #28364)

edit_role will be implemented later during that flow, so I can just throw a ServerError for now

lib/types/thread-types.js
437 ↗(On Diff #28364)

The permissions here specifically are the selected permissions passed in from the client-side create roles screen, where the user selects the EnumSettingsOption corresponding to what permissions they want associated for the role (i.e. selecting "Allows members to edit their sent messages" and "Allows members to add reactions to messages" will mean this permissions array is ['edit_message', 'descendant_edit_message', 'react_to_message', 'descendant_react_to_message'].

Separately, my understanding is we want to use the existing thread permissions to build out community roles. The 'user-facing' permissions, to me, were just the way we present the different permissions to users (and how we group different permissions like all of the edit_thread_... permissions). The readability of this will be better when your feedback in D8391 is addressed. On the back-end, it's still the same permissions system of using the thread permissions, but trying to propagate them across the entire community for that one role.

Let me know if I'm misunderstanding your comment however

lib/types/thread-types.js
437 ↗(On Diff #28364)

I don't think we should allow the client this much leeway. It should not be able to pick arbitrary combinations of permissions and prefixes. We need to lock it down to only accept the predetermined combos of permissions that we are showing in the UI.

The best way to address this would be to introduce a different enum to track the various predetermined combos of permissions, and to use that for client/server communication. The mapping from the new enum to the combos of permissions would be done on the keyserver side, and could not be gamed by the client.

Rebase on changing configurableCommunityPermissions

rohan planned changes to this revision.Jul 5 2023, 8:54 AM

Address feedback:

  1. Export the keys from the configurableCommunityPermissions enum (valid, configurable thread permissions) to validate the permissions passed in to the keyserver instead of using threadPermissions.
  2. Validate the input before creating a new ID
  3. Throw a ServerError if action === 'edit_role' since we don't support that flow yet
  4. General rebase on D8391 to use the newer 'API' for configurable role permissions
ashoat requested changes to this revision.Jul 5 2023, 10:55 AM
ashoat added inline comments.
lib/types/thread-types.js
434–439 ↗(On Diff #28420)

I think this API still needs to be updated so that keyserver / client communication uses a new enum containing a list of user-facing per-community permissions. More details in my comment in D8391:

After our discussion over chat, I think the new conclusion is that the client code for creating / managing roles shouldn't think about threadPermissions at all, and should instead use a new enum that reflects the list of user-facing permissions. The keyserver will handle converting from the new enum of user-facing permissions to threadPermissions... so some version of this data structure will likely still be necessary, but it will probably be keyserver-specific, and the format of the data structure might be different given differing requirements. Does that sound right to you @rohan?

This revision now requires changes to proceed.Jul 5 2023, 10:55 AM

Update the API to address client/keyserver communication feedback

Generally looks good! If you apply the changes in D8391, this should be basically be ready to go

lib/types/thread-permission-types.js
322 ↗(On Diff #28428)

Thinking about naming here... guaranteed isn't too bad, but how would you feel about universalCommunityPermissions?

lib/utils/objects.js
119–121 ↗(On Diff #28428)

Think we can skip this function if we change the format back (see this comment)

This revision is now accepted and ready to land.Jul 6 2023, 12:29 PM
rohan marked 2 inline comments as done.

Rebase on D8391 and simplify retrieving the mapping of user-surfaced permission to permission strings

Use internal_error instead of invalid_parameters

Revert the previous change, amended the wrong diff

Change descendant_voiced to descendant_open_voiced for universalCommunityPermissions. Explanation is in D8391

diff --git a/lib/types/thread-permission-types.js b/lib/types/thread-permission-types.js
index cd543207a..eece33e4f 100644
--- a/lib/types/thread-permission-types.js
+++ b/lib/types/thread-permission-types.js
@@ -363,8 +363,10 @@ export const universalCommunityPermissions: $ReadOnlyArray<string> = [
     threadPermissionFilterPrefixes.OPEN +
     threadPermissions.KNOW_OF,
 
-  // voiced
-  threadPermissionPropagationPrefixes.DESCENDANT + threadPermissions.VOICED,
+  // descendant_open_voiced
+  threadPermissionPropagationPrefixes.DESCENDANT +
+    threadPermissionFilterPrefixes.OPEN +
+    threadPermissions.VOICED,
 
   // visible | descendant_open_visible
   threadPermissions.VISIBLE,

Testing follow-up:

If a role is created for a COMMUNITY_ANNOUNCEMENT_ROOT, no changes are made. However, if the community is just a normal COMMUNITY_ROOT, we want to add in the voiced permission for all roles.