Page MenuHomePhabricator

D9662.diff
No OneTemporary

D9662.diff

diff --git a/lib/permissions/minimally-encoded-thread-permissions.js b/lib/permissions/minimally-encoded-thread-permissions.js
--- a/lib/permissions/minimally-encoded-thread-permissions.js
+++ b/lib/permissions/minimally-encoded-thread-permissions.js
@@ -2,38 +2,59 @@
import invariant from 'invariant';
+import { parseThreadPermissionString } from './prefixes.js';
import type {
ThreadPermission,
ThreadPermissionsInfo,
} from '../types/thread-permission-types.js';
import { entries } from '../utils/objects.js';
-const minimallyEncodedThreadPermissions = Object.freeze({
+// `baseRolePermissionEncoding` maps permission names to indices.
+// These indices represent the 6-bit basePermission part of the 10-bit role
+// permission encoding created by `rolePermissionToBitmaskHex`.
+// The 6-bit basePermission allows for up to 2^6 = 64 different permissions.
+// If more than 64 permissions are needed, the encoding in
+// `rolePermissionToBitmaskHex` will need to be updated to accommodate this.
+const baseRolePermissionEncoding = Object.freeze({
// TODO (atul): Update flow to `194.0.0` for bigint support
// $FlowIssue bigint-unsupported
- know_of: BigInt(1) << BigInt(0),
- visible: BigInt(1) << BigInt(1),
- voiced: BigInt(1) << BigInt(2),
- edit_entries: BigInt(1) << BigInt(3),
- edit_thread: BigInt(1) << BigInt(4), // EDIT_THREAD_NAME
- edit_thread_description: BigInt(1) << BigInt(5),
- edit_thread_color: BigInt(1) << BigInt(6),
- delete_thread: BigInt(1) << BigInt(7),
- create_subthreads: BigInt(1) << BigInt(8), // CREATE_SUBCHANNELS
- create_sidebars: BigInt(1) << BigInt(9),
- join_thread: BigInt(1) << BigInt(10),
- edit_permissions: BigInt(1) << BigInt(11),
- add_members: BigInt(1) << BigInt(12),
- remove_members: BigInt(1) << BigInt(13),
- change_role: BigInt(1) << BigInt(14),
- leave_thread: BigInt(1) << BigInt(15),
- react_to_message: BigInt(1) << BigInt(16),
- edit_message: BigInt(1) << BigInt(17),
- edit_thread_avatar: BigInt(1) << BigInt(18),
- manage_pins: BigInt(1) << BigInt(19),
- manage_invite_links: BigInt(1) << BigInt(20),
+ know_of: BigInt(0),
+ visible: BigInt(1),
+ voiced: BigInt(2),
+ edit_entries: BigInt(3),
+ edit_thread: BigInt(4), // EDIT_THREAD_NAME
+ edit_thread_description: BigInt(5),
+ edit_thread_color: BigInt(6),
+ delete_thread: BigInt(7),
+ create_subthreads: BigInt(8), // CREATE_SUBCHANNELS
+ create_sidebars: BigInt(9),
+ join_thread: BigInt(10),
+ edit_permissions: BigInt(11),
+ add_members: BigInt(12),
+ remove_members: BigInt(13),
+ change_role: BigInt(14),
+ leave_thread: BigInt(15),
+ react_to_message: BigInt(16),
+ edit_message: BigInt(17),
+ edit_thread_avatar: BigInt(18),
+ manage_pins: BigInt(19),
+ manage_invite_links: BigInt(20),
});
+// `minimallyEncodedThreadPermissions` is used to map each permission
+// to its respective bitmask where the index from `baseRolePermissionEncoding`
+// is used to set a specific bit in the bitmask. This is used in the
+// `permissionsToBitmaskHex` function where each permission is represented as a
+// single bit and the final bitmask is the union of all granted permissions.
+const minimallyEncodedThreadPermissions = Object.fromEntries(
+ Object.keys(baseRolePermissionEncoding).map((key, idx) => [
+ key,
+ BigInt(1) << BigInt(idx),
+ ]),
+);
+
+// This function converts a set of permissions to a hex-encoded bitmask.
+// Each permission is represented as a single bit in the bitmask.
const permissionsToBitmaskHex = (
permissions: ThreadPermissionsInfo,
): string => {
@@ -70,8 +91,39 @@
return (permissionsBitmask & permissionBitmask) !== BigInt(0);
};
-export {
- minimallyEncodedThreadPermissions,
- permissionsToBitmaskHex,
- hasPermission,
+const propagationPrefixes = Object.freeze({
+ '': BigInt(0),
+ 'descendant_': BigInt(1),
+ 'child_': BigInt(2),
+});
+const filterPrefixes = Object.freeze({
+ '': BigInt(0),
+ 'open_': BigInt(1),
+ 'toplevel_': BigInt(2),
+ 'opentoplevel_': BigInt(3),
+});
+
+// Role Permission Bitmask Structure
+// [9 8 7 6 5 4 3 2 1 0] - bit positions
+// [b b b b b b p p f f] - symbol representation
+// b = basePermission (6 bits)
+// p = propagationPrefix (2 bits)
+// f = filterPrefix (2 bits)
+const rolePermissionToBitmaskHex = (threadRolePermission: string): string => {
+ const parsed = parseThreadPermissionString(threadRolePermission);
+ const basePermissionBits =
+ baseRolePermissionEncoding[parsed.permission] & BigInt(63);
+ const propagationPrefixBits =
+ propagationPrefixes[parsed.propagationPrefix ?? ''] & BigInt(3);
+ const filterPrefixBits =
+ filterPrefixes[parsed.filterPrefix ?? ''] & BigInt(3);
+
+ const bitmask =
+ (basePermissionBits << BigInt(4)) |
+ (propagationPrefixBits << BigInt(2)) |
+ filterPrefixBits;
+
+ return bitmask.toString(16).padStart(3, '0');
};
+
+export { permissionsToBitmaskHex, hasPermission, rolePermissionToBitmaskHex };
diff --git a/lib/permissions/minimally-encoded-thread-permissions.test.js b/lib/permissions/minimally-encoded-thread-permissions.test.js
--- a/lib/permissions/minimally-encoded-thread-permissions.test.js
+++ b/lib/permissions/minimally-encoded-thread-permissions.test.js
@@ -3,6 +3,7 @@
import {
hasPermission,
permissionsToBitmaskHex,
+ rolePermissionToBitmaskHex,
} from './minimally-encoded-thread-permissions.js';
describe('minimallyEncodedThreadPermissions', () => {
@@ -51,3 +52,39 @@
expect(hasPermission(permissionsBitmask, 'edit_message')).toBe(true);
});
});
+
+describe('rolePermissionToBitmaskHex', () => {
+ it('should encode `child_opentoplevel_visible` successfully', () => {
+ expect(rolePermissionToBitmaskHex('child_opentoplevel_visible')).toBe(
+ '01b',
+ );
+ });
+
+ it('should encode `child_opentoplevel_know_of` successfully', () => {
+ expect(rolePermissionToBitmaskHex('child_opentoplevel_know_of')).toBe(
+ '00b',
+ );
+ });
+
+ it('should encode `child_toplevel_visible` successfully', () => {
+ expect(rolePermissionToBitmaskHex('child_toplevel_visible')).toBe('01a');
+ });
+
+ it('should encode `child_toplevel_know_of` successfully', () => {
+ expect(rolePermissionToBitmaskHex('child_toplevel_know_of')).toBe('00a');
+ });
+
+ it('should encode `child_opentoplevel_join_thread` successfully', () => {
+ expect(rolePermissionToBitmaskHex('child_opentoplevel_join_thread')).toBe(
+ '0ab',
+ );
+ });
+
+ it('should encode `child_visible` successfully', () => {
+ expect(rolePermissionToBitmaskHex('child_visible')).toBe('018');
+ });
+
+ it('should encode `child_know_of` successfully', () => {
+ expect(rolePermissionToBitmaskHex('child_know_of')).toBe('008');
+ });
+});

File Metadata

Mime Type
text/plain
Expires
Mon, Dec 2, 7:14 PM (21 h, 43 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2608637
Default Alt Text
D9662.diff (6 KB)

Event Timeline