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 @@ -133,10 +133,15 @@ 'toplevel_': BigInt(2), 'opentoplevel_': BigInt(3), }); +const membershipPrefixes = Object.freeze({ + '': BigInt(0), + 'member_': BigInt(1), +}); // 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 +// [10 9 8 7 6 5 4 3 2 1 0] - bit positions +// [m b b b b b b p p f f] - symbol representation +// m = membershipPrefix (1 bit) // b = basePermission (6 bits) // p = propagationPrefix (2 bits) // f = filterPrefix (2 bits) @@ -148,8 +153,11 @@ propagationPrefixes[parsed.propagationPrefix ?? ''] & BigInt(3); const filterPrefixBits = filterPrefixes[parsed.filterPrefix ?? ''] & BigInt(3); + const membershipPrefixesBits = + membershipPrefixes[parsed.membershipPrefix ?? ''] & BigInt(1); const bitmask = + (membershipPrefixesBits << BigInt(10)) | (basePermissionBits << BigInt(4)) | (propagationPrefixBits << BigInt(2)) | filterPrefixBits; @@ -167,18 +175,24 @@ const inverseFilterPrefixes: Map = invertObjectToMap(filterPrefixes); +const inverseMembershipPrefixes: Map = + invertObjectToMap(membershipPrefixes); + const tHexEncodedRolePermission: TRegex = tRegex(/^[0-9a-fA-F]{3,}$/); 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 membershipPrefix = (bitmaskInt >> BigInt(10)) & BigInt(1); const basePermissionString = inverseBaseRolePermissionEncoding.get(basePermission); const propagationPrefixString = inversePropagationPrefixes.get(propagationPrefix) ?? ''; const filterPrefixString = inverseFilterPrefixes.get(filterPrefix) ?? ''; + const membershipPrefixString = + inverseMembershipPrefixes.get(membershipPrefix) ?? ''; invariant( basePermissionString !== null && @@ -186,11 +200,18 @@ propagationPrefixString !== null && propagationPrefixString !== undefined && filterPrefixString !== null && - filterPrefixString !== undefined, + filterPrefixString !== undefined && + membershipPrefixString !== null && + membershipPrefixString !== undefined, 'invalid bitmask', ); - return `${propagationPrefixString}${filterPrefixString}${basePermissionString}`; + return ( + propagationPrefixString + + filterPrefixString + + basePermissionString + + membershipPrefixString + ); }; const threadRolePermissionsBlobToBitmaskArray = (