From 445632bf1545e9e93615c8b8f7686bbb5e173160 Mon Sep 17 00:00:00 2001 From: Atul Madhugiri Date: Tue, 31 Oct 2023 18:56:49 -0400 Subject: [PATCH] [lib] Introduce `decodeRolePermissionBitmask` Summary: To reverse `rolePermissionToBitmaskHex` introduced in D9662. --- Depends on D9662 Test Plan: Unit tests, will add a few more. Reviewers: ashoat, ginsu, tomek, rohan Reviewed By: ashoat Subscribers: wyilio Differential Revision: https://phab.comm.dev/D9663 --- .../minimally-encoded-thread-permissions.js | 47 ++++++++++++++++++- ...nimally-encoded-thread-permissions.test.js | 37 +++++++++++++++ 2 files changed, 83 insertions(+), 1 deletion(-) diff --git a/lib/permissions/minimally-encoded-thread-permissions.js b/lib/permissions/minimally-encoded-thread-permissions.js index b3dee9d7fb..3bd0f8085c 100644 --- a/lib/permissions/minimally-encoded-thread-permissions.js +++ b/lib/permissions/minimally-encoded-thread-permissions.js @@ -126,4 +126,49 @@ const rolePermissionToBitmaskHex = (threadRolePermission: string): string => { return bitmask.toString(16).padStart(3, '0'); }; -export { permissionsToBitmaskHex, hasPermission, rolePermissionToBitmaskHex }; +const inverseBaseRolePermissionEncoding = new Map( + Object.entries(baseRolePermissionEncoding).map(([key, value]) => [ + value, + key, + ]), +); + +// $FlowIssue bigint-unsupported +const inversePropagationPrefixes: Map = new Map( + Object.entries(propagationPrefixes).map(([key, value]) => [value, key]), +); +// $FlowIssue bigint-unsupported +const inverseFilterPrefixes: Map = new Map( + Object.entries(filterPrefixes).map(([key, value]) => [value, key]), +); +const decodeRolePermissionBitmask = (bitmask: string): string => { + const bitmaskInt = BigInt(`0x${bitmask}`); + const basePermission = (bitmaskInt >> BigInt(4)) & BigInt(63); + const propagationPrefix = (bitmaskInt >> BigInt(2)) & BigInt(3); + const filterPrefix = bitmaskInt & BigInt(3); + + const basePermissionString = + inverseBaseRolePermissionEncoding.get(basePermission); + const propagationPrefixString = + inversePropagationPrefixes.get(propagationPrefix) ?? ''; + const filterPrefixString = inverseFilterPrefixes.get(filterPrefix) ?? ''; + + invariant( + basePermissionString !== null && + basePermissionString !== undefined && + propagationPrefixString !== null && + propagationPrefixString !== undefined && + filterPrefixString !== null && + filterPrefixString !== undefined, + 'invalid bitmask', + ); + + return `${propagationPrefixString}${filterPrefixString}${basePermissionString}`; +}; + +export { + permissionsToBitmaskHex, + hasPermission, + rolePermissionToBitmaskHex, + decodeRolePermissionBitmask, +}; diff --git a/lib/permissions/minimally-encoded-thread-permissions.test.js b/lib/permissions/minimally-encoded-thread-permissions.test.js index 090c5c125d..93bf0524f4 100644 --- a/lib/permissions/minimally-encoded-thread-permissions.test.js +++ b/lib/permissions/minimally-encoded-thread-permissions.test.js @@ -1,6 +1,7 @@ // @flow import { + decodeRolePermissionBitmask, hasPermission, permissionsToBitmaskHex, rolePermissionToBitmaskHex, @@ -88,3 +89,39 @@ describe('rolePermissionToBitmaskHex', () => { expect(rolePermissionToBitmaskHex('child_know_of')).toBe('008'); }); }); + +describe('decodeRolePermissionBitmask', () => { + it('should decode `01b` to `child_opentoplevel_visible` successfully', () => { + expect(decodeRolePermissionBitmask('01b')).toBe( + 'child_opentoplevel_visible', + ); + }); + + it('should decode `00b` to `child_opentoplevel_know_of` successfully', () => { + expect(decodeRolePermissionBitmask('00b')).toBe( + 'child_opentoplevel_know_of', + ); + }); + + it('should decode `01a` to `child_toplevel_visible` successfully', () => { + expect(decodeRolePermissionBitmask('01a')).toBe('child_toplevel_visible'); + }); + + it('should decode `00a` to `child_toplevel_know_of` successfully', () => { + expect(decodeRolePermissionBitmask('00a')).toBe('child_toplevel_know_of'); + }); + + it('should decode `0ab` to `child_opentoplevel_join_thread` successfully', () => { + expect(decodeRolePermissionBitmask('0ab')).toBe( + 'child_opentoplevel_join_thread', + ); + }); + + it('should decode `018` to `child_visible` successfully', () => { + expect(decodeRolePermissionBitmask('018')).toBe('child_visible'); + }); + + it('should decode `008` to `child_know_of` successfully', () => { + expect(decodeRolePermissionBitmask('008')).toBe('child_know_of'); + }); +});