Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat!: rename "Capability" to "Role", attach ID #462

Merged
merged 5 commits into from
Feb 7, 2024

Conversation

EvanHahn
Copy link
Contributor

This change makes several improvements to the concept formerly known as "capabilities":

  • Capability is now called Role across the project, resulting in many simple renames.

  • Roles have an attached roleId property, which they didn't before.

  • The creator role and "no role" role now have role IDs.1

  • The RoleId type now includes all possible role types, now including the creator role and the "no role" role. I created narrower types such as RoleIdAssignableToOthers and RoleIdAssignableToAnyone, which don't include those.

This should help the front-end know what role someone is (for example, digidem/comapeo-mobile#79 (comment)).

Footnotes

  1. I generated these with crypto.randomBytes(8).toString('hex').

This change makes several improvements to the concept formerly known as
"capabilities":

- `Capability` is now called `Role` across the project, resulting in
  many simple renames.

- `Role`s have an attached `roleId` property, which they didn't before.

- The creator role and "no role" role now have role IDs.[^1]

- The `RoleId` type now includes all possible role types, now including
  the creator role and the "no role" role. I created narrower types such
  as `RoleIdAssignableToOthers` and `RoleIdAssignableToAnyone`, which
  don't include those.

This should help the front-end know what role someone is (for example,
<digidem/comapeo-mobile#79 (comment)>).

[^1]: I generated these with `crypto.randomBytes(8).toString('hex')`.
src/roles.js Outdated
*/
function isKnownRoleId(roleId) {
return roleId in DEFAULT_CAPABILITIES
return roleId in ROLES
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Highlighting this: DEFAULT_CAPABILITIES didn't have the creator or "no role" capabilities before. ROLES does have those. I think this is fine based on usage but want to make sure.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should avoid allowing the creator role id, maybe not in this function but instead where it is used on line 288? We will later validate role assignments, but I think it's safer that we don't allow a role record to define a role to be the project creator, since we're not allowing the project creator role to be assigned, just implicit.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in f24c85e.

src/types.ts Show resolved Hide resolved
@EvanHahn EvanHahn marked this pull request as ready for review January 31, 2024 22:08
@EvanHahn EvanHahn requested a review from gmaclennan January 31, 2024 22:08
Copy link
Member

@gmaclennan gmaclennan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good. Happy for my comments to be addressed in a follow-up so that this can get merged sooner, since it touches quite a few files and I don't want to create complex merge operations in the future.

src/roles.js Outdated
*/
function isKnownRoleId(roleId) {
return roleId in DEFAULT_CAPABILITIES
return roleId in ROLES
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should avoid allowing the creator role id, maybe not in this function but instead where it is used on line 288? We will later validate role assignments, but I think it's safer that we don't allow a role record to define a role to be the project creator, since we're not allowing the project creator role to be assigned, just implicit.

src/types.ts Show resolved Hide resolved
* @param {string} [opts.roleName]
* @param {string} [opts.roleDescription]
* @param {number} [opts.timeout]
*
* @returns {Promise<import('./generated/rpc.js').InviteResponse_Decision>}
*/
async invite(deviceId, { roleId, roleName, roleDescription, timeout }) {
if (!DEFAULT_CAPABILITIES[roleId]) {
if (!ROLES[roleId]) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this needs to be stricter now, since we do not want to allow inviting someone as a project creator. This should be the "assignable to others" role list, although we should probably exclude the blocked role from that, but maybe as a to-do because I think some tests invite as blocked, just because I was lazy.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in f24c85e.

src/roles.js Outdated
Comment on lines 49 to 56
/**
* @typedef {Extract<RoleId,
* typeof COORDINATOR_ROLE_ID |
* typeof MEMBER_ROLE_ID |
* typeof BLOCKED_ROLE_ID |
* typeof LEFT_ROLE_ID
* >} RoleIdAssignableToAnyone
*/
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think better to have both of these as runtime checks to e.g.

const ROLE_ID_ASSIGNABLE_TO_ANYONE = /** @type {const} */ ([
  COORDINATOR_ROLE_ID,
  MEMBER_ROLE_ID,
  BLOCKED_ROLE_ID,
  LEFT_ROLE_ID,
])
/** @typedef {typeof ROLE_ID_ASSIGNABLE_TO_ANYONE} RoleIdAssignableToAnyone */

and when used as a type we should also add an assertion.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in f24c85e.

@@ -163,10 +163,10 @@ export class MemberApi extends TypedEmitter {

/**
* @param {string} deviceId
* @param {import('./capabilities.js').RoleId} roleId
* @param {import('./roles.js').RoleIdAssignableToOthers} roleId
* @returns {Promise<void>}
*/
async assignRole(deviceId, roleId) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we add a TODO note here or open an issue to have stricter runtime checks here.
I also wonder if "assigning a blocked role" is confusing for the API consumer, and we should expose that separately as $member.block(deviceId) and limit assignRole() to just assignable roles within the project (currently participant and coordinator).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also in the future we might want to add options to how we block users (which internally we might implement as different roles, or additional fields on membership records - maybe the latter better for many scenarios), for example:

  1. Removed with "self-destruct", e.g. when a device discovers it is removed it deletes all data including its own. Would be useful for compromised phones.
  2. Removed with removed encryption keys and keeping own data (but deleting others) - useful for when removing a device that we know has important data on it, that we want to sync off it in the future, without allowing that device to access it. Device would need to self-delete its encryption keys when it finds out it is blocked this way.
  3. Removed with ignore all data from device - would re-index and ignore all edits or created data from the removed device.

Having a separate API to remove devices would be helpful for implementing these.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a stricter runtime check in f24c85e. Let me know if you still want me to add a TODO/issue.

src/roles.js Outdated Show resolved Hide resolved
src/roles.js Outdated Show resolved Hide resolved
@EvanHahn EvanHahn requested a review from gmaclennan February 6, 2024 18:02
@EvanHahn
Copy link
Contributor Author

EvanHahn commented Feb 6, 2024

I believe I've addressed all comments. I've requested another review but will plan to merge tomorrow barring objections.

@EvanHahn EvanHahn merged commit 0edb56e into main Feb 7, 2024
7 checks passed
@EvanHahn EvanHahn deleted the role-slash-capability-improvements branch February 7, 2024 13:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants