## Predicates
```
pred org_is_enabled(org_id: Id<Org>);
pred user_in_org(user_id: Id<User>, org_id: Id<Org>);
pred user_in_role(user_id: Id<User>, role_id: Id<RoleId>);
pred is_org_owner(user_id: Id<User>, org_id: Id<Org>);
pred role_in_org(role_id: Id<Role>, org_id: Id<Org>);
pred key_in_role(key_id: Id<Key>, role_id: Id<Role>);
pred role_is_valid(role_id: Id<Role>);
pred role_exists(role_id: Id<Role>);
pred valid_role_in_org(role_id: Id<RoleId>, org_id: Id<Org>) {
role_exists(role_id) && role_is_valid(role_id) && role_in_org(role_id, org_id)
}
```
## Effects
### Orgs & Users
```
effect org_set_enabled(org: &Entity<Org>)
requires is_org_owner($sess_user.id, org.id) && org.id == $sess_org.id
routes PATCH /v0/org/<org_id>
effect org_set_policy(org: &Entity<Org>)
requires is_org_owner($sess_user.id, org.id) && org.id == $sess_org.id
routes PATCH /v0/org/<org_id>
effect org_set_name(org: &Entity<Org>)
requires is_org_owner($sess_user.id, org.id) && org.id == $sess_org.id
routes PATCH /v0/org/<org_id>
effect cognito_create_user -> Id<User>
requires org_is_enabled($sess_org.id) && is_org_owner($sess_user.id, $sess_org.id)
routes PATCH /v0/org/<org_id>/invite
effect dynamo_create_user
requires org_is_enabled($sess_org.id) && is_org_owner($sess_user.id, $sess_org.id)
routes PATCH /v0/org/<org_id>/invite
effect create_user_in_org(user_id: Id<User>, org_id: Id<Org>)
requires org_is_enabled(org_id) && is_org_owner($sess_user.id, org_id) && org_id == $sess_org.id
routes PATCH /v0/org/<org_id>/invite
```
### Keys
```
effect import_key(user_id: Id<User>, org_id: Id<Org>)
requires org_is_enabled(org_id) && user_in_org(user_id, org_id)
&& org_id == $sess_org.id && user_id == $sess_org.id
routes PUT /v0/org/<org_id>/keys
effect create_key(user_id: Id<User>, org_id: Id<Org>)
requires org_is_enabled(org_id) && user_in_org(user_id, org_id)
&& org_id == $sess_org.id && user_id == $sess_org.id
routes POST /v0/org/<org_id>/keys, POST /v1/org/<org_id>/eth2/stake
effect key_update_enabled(key: Relation<Key>)
requires org_is_enabled(key.from) && user_in_org($sess_user.id, key.from)
&& (is_org_owner($sess_user.id, key.from) || key.data.owner == $sess_user.id)
&& key.from == $sess_org.id
routes PATCH /v0/org/<org_id>/keys/<key_id>
effect key_update_owner(key: Relation<Key>, new_owner_id: Id<User>)
requires org_is_enabled(key.from) && user_in_org($sess_user.id, key.from)
&& (is_org_owner($sess_user.id, key.from) || key.data.owner == $sess_user.id)
&& key.from == $sess_org.id
&& user_in_org(new_owner_id, key.from)
routes PATCH /v0/org/<org_id>/keys/<key_id>
```
### Roles
```
effect create_role
requires org_is_enabled($sess_org.id) && user_in_org($sess_user.id, $sess_org.id)
routes POST /v0/org/<org_id>/roles
effect add_role_to_org(org_id: Id<Org>)
requires org_is_enabled($sess_org.id) && user_in_org($sess_user.id, $sess_org.id)
&& org_id == $sess_org.id
routes POST /v0/org/<org_id>/roles
effect add_user_to_role(role_id: Id<Role>, user_id: Id<User>)
requires org_is_enabled($sess_org.id) && user_in_org($sess_user.id, $sess_org.id)
&& user_in_org(user_id, $sess_org.id)
&& (user_id == $sess_user.id || is_org_owner($sess_user.id, $sess_org.id) || user_in_role($sess_user.id, role_id))
&& role_is_valid(role_id) && role_in_org(role_id, $sess_user.id)
routes POST /v0/org/<org_id>/roles, PUT /v0/org/<org_id>/roles/<role_id>/add_user/<user_id>
effect role_update_enabled(role_id: Id<Role>)
requires org_is_enabled($sess_org.id) && user_in_org($sess_user.id, $sess_org.id)
&& role_exists(role_id) && role_in_org(role_id, $sess_org.id)
&& (user_in_role($sess_user.id, $role_id) || is_org_owner($sess_user.id, $sess_org.id)
routes PATCH /v0/org/<org_id>/roles/<role_id>
effect delete_role(role_id: Id<Role>, org_id: Id<Org>)
requires org_is_enabled(org_id) && is_org_owner($sess_user.id, org_id)
&& valid_role_in_org(role_id, org_id)
routes DELETE /v0/org/<org_id>/roles/<role_id>
```
### Mfa
```
effect mfa_set_status(mfa: Relation<MfaRequest>)
requires org_is_enabled($sess_org.id) && user_in_org($sess_user.id, org_id)
&& valid_role_in_org(role_id, org_id)
&& (user_in_role($sess_user.id, mfa.from) || is_org_owner($sess_user.id, $sess_org.id)
&& allowed_approver($sess_user.id, mfa.data.to)
routes PATCH /v0/org/<org_id>/roles/<role_id>/mfa/<mfa_id>
effect mfa_set_approved(mfa: Relation<MfaRequest>, user_id: Id<User>)
requires org_is_enabled($sess_org.id) && user_in_org($sess_user.id, org_id)
&& valid_role_in_org(role_id, org_id)
&& (user_in_role($sess_user.id, mfa.from) || is_org_owner($sess_user.id, $sess_org.id)
&& allowed_approver($sess_user.id, mfa.data.to)
&& user_id = $sess_user.id
routes PATCH /v0/org/<org_id>/roles/<role_id>/mfa/<mfa_id>
```
### Keys in Role
```
effect add_keys_to_role_checked(org_id: Id<Org>, role_id: Id<Role>, policy: KeyInRole, keys: impl Iterator<Id<Key>>)
requires org_is_enabled(org_id) && user_in_org($sess_user.id, org_id)
&& valid_rules(policy.rules)
&& valid_role_in_org(role_id, org_id)
&& (is_org_owner($sess_user.id, org_id) || (user_in_role($sess_user.id, role_id) && for key_id in keys { is_key_owner($sess_user.id, key_id) } ))
&& org_id == $sess_org.id
effect remove_key_from_role(role_id: Id<Role>, key_id: Id<Key>)
requires org_is_enabled($sess_org.id) && user_in_org($sess_user.id, $sess_org.id)
&& valid_role_in_org(role_id, org_id)
&& key_in_role(key_id, role_id)
&& (is_org_owner($sess_user.id, $sess_org.id) || user_in_role($sess_user.id, role_id))
&& (is_org_owner($sess_user.id, $sess_org.id) || is_key_owner($sess_user.id, key_id))
routes DELETE /v0/org/<org_id>/roles/<role_id>/keys/<key_id>
```
### Tokens
```
effect create_session_token(role_id: Id<Role>)
requires org_is_enabled($sess_org.id) && user_in_org($sess_user.id, $sess_org.id)
&& valid_role_in_org(role_id, org_id)
&& (user_in_role($sess_user.id, role_id) || is_org_owner($sess_user.id, $sess_org.id))
route POST /v0/org/<org_id>/roles/<role_id>/tokens
effect revoke_all(role_id: Id<Role>)
requires org_is_enabled($sess_org.id) && user_in_org($sess_user.id, $sess_org.id)
&& valid_role_in_org(role_id, org_id)
&& (user_in_role($sess_user.id, role_id) || is_org_owner($sess_user.id, $sess_org.id))
routes DELETE /v0/org/<org_id>/roles/<role_id>/tokens
effect revoke(session: Session)
requires org_is_enabled($sess_org.id) && user_in_org($sess_user.id, $sess_org.id)
&& valid_role_in_org(role_id, org_id)
&& (user_in_role($sess_user.id, role_id) || is_org_owner($sess_user.id, $sess_org.id))
route DELETE /v0/org/<org_id>/roles/<role_id>/tokens/<session_id>
```
## Routes
### About me
```
[about_me] GET /v0/about_me
READS: $user.orgs
```
### Orgs
```
[get_org] GET /v0/org/<org_id>
ASSUMES: in_org($sess_user.id, $sess_org.id)
[update_org] PATCH /v0/org/<org_id>
ASSUMES: is_org_owner($sess_user.id, $sess_org.id)
EFFECT: org_set_enabled($sess_org); org_set_name($sess_org); org_set_rules($sess_org)
[invite] POST /v0/org/<org_id>/ivite
ASSUMES: org_is_enabled($sess_org.id) && user_in_org($sess_user.id, $sess_org.id)
EFFECT: let user_id = cognito_create_user in dynamo_create_user; create_user_in_org(user_id, $sess_org.id)
```
### Keys
```
[import_key] PUT /v0/org/<org_id>/keys
ASSUMES: org_is_enabled($sess_org.id) && user_in_org($sess_user.id, $sess_org.id)
EFFECT: import_key($sess_user.id, $sess_org.id)
[create_key] POST /v0/org/<org_id>/keys
ASSUMES: org_is_enabled($sess_org.id) && user_in_org($sess_user.id, $sess_org.id)
EFFECT: create_key($user, $org)
[list_keys] GET /v0/org/<org_id>/keys?<key_type>
ASSUMES: org_is_enabled($sess_org.id) && user_in_org($sess_user.id, $sess_org.id)
[get_key] GET /v0/org/<org_id>/keys/<key_id>
ASSUMES: org_is_enabled($sess_org.id) && user_in_org($sess_user.id, $sess_org.id)
ASSERT: user_in_org(key_id, $sess_org.id)
[update_key] PATCH /v0/org/<org_id>/keys/<key_id>
ASSUMES: org_is_enabled($sess_org.id) && user_in_org($sess_user.id, $sess_org.id)
ASSERT: is_org_owner($sess_user.id, $sess_org.id) || is_key_owner($sess_user.id, key_id) && if let Some(owner) = body.owner { user_in_org(owner, $sess_org.id) }
EFFECT: key_update_enabled(key_id); if let Some(owner) = body.owner { key_update_owner(key_id, owner) }
```
### Roles
```
[create_role] POST /v0/org/<org_id>/roles
ASSUMES: org_is_enabled($sess_org.id) && user_in_org($user.id, $sess_org.id)
EFFECT: let role_id = create_role in add_role_to_org($sess_org.id); add_user_to_role(role_id, $sess_org.id)
[list_roles] GET /v0/org/<org_id>/roles
ASSUMES: org_is_enabled($sess_org.id) && user_in_org($sess_user.id, $sess_org.id)
ASSERT: for role_id in $sess_org { is_org_owner($sess_user.id, $sess_org.id) || user_is_in_role($sess_user.id, role_id) }
[get_role] GET /v0/org/<org_id>/roles/<role_id>
ASSUMES: org_is_enabled($sess_org) && user_in_org($sess_user.id, $sess_org.id)
ASSERT: role_exists(role_id) && role_in_org(role_id, $sess_org.id) && (user_in_role($sess_user.id, role_id) || is_org_owner($sess_user.id, $sess_org.id))
[update_role] PUT /v0/org/<org_id>/roles/<role_id>
ASSUMES: org_is_enabled($sess_org) && in_org($sess_user.id, $sess_org.id)
ASSERT: role_exists(role_id) && role_in_org(role_id, $sess_org.id) && (user_in_role($sess_user.id, role_id) || is_org_owner($sess_user.id, $sess_org.id))
EFFECTS: role_update_enabled(role_id)
[delete_role] DELETE /v0/org/<org_id>/roles/<role_id>
ASSUMES: org_is_enabled($sess_org) && is_org_owner($sess_user.id, $sess_org.id)
ASSERT: let role = role_exists(role_id) in role_is_valid(role) && role_in_org(role_id, $sess_org.id)
EFFECTS: delete_role(role_id, $sess_org.id)
```
### MFA
```
[approve] PATCH /v0/org/<org_id>/roles/<role_id>/mfa/<mfa_id>
ASSUMES: org_is_enabled($sess_org) && user_in_org($sess_user.id, $sess_org.id)
ASSERT: (let role = role_exists(role_id) in role_is_valid(role) && role_in_org(role_id, $sess_org.id)) && (user_in_org($sess_user.id, role_id) || is_org_owner($sess_user.id, $sess_org.id))
ASSERT: (let mfa = mfa_exists(mfa_id) in $mfa.allowed_approvers.contains($user.id))
EFFECT: mfa_update_status(mfa), mfa_update_approve(mfa)
[get_mfa] PATCH /v0/org/<org_id>/roles/<role_id>/mfa/<mfa_id>
ASSUMES: org_is_enabled($sess_org) && user_in_org($sess_user.id, $sess_org.id)
ASSERT: (let role = role_exists(role_id) in role_is_valid(role) && role_in_org(role_id, $sess_org.id)) && (user_in_org($sess_user.id, role_id) || is_org_owner($sess_user.id, $sess_org.id))
ASSERT: (let mfa = mfa_exists(mfa_id) in mfa.allowed_approvers.contains($sess_user.id))
```
### Keys in Roles
```
[add_keys_to_role] PUT /v0/org/<org_id>/roles/<role_id>/add_keys
ASSUMES: org_is_enabled($sess_org) && user_in_org($user.id, $sess_org.id)
ASSERT: validate_policies($sess_org)
ASSERT: (let role = role_exists(role_id) in role_is_valid(role) && role_in_org(role_id, $sess_org.id))
&& (is_org_owner($sess_user.id, $sess_org.id) || (user_in_role($sess_org.id, $sess_user.id) && for key_id in body.keys() { is_key_owner($sess_user.id, key_id) })
EFFECT: add_keys_to_role_checked($sess_org.id, role_id, body.keys())
[remove_key_from_role] DELTE /v0/org/<org_id>/roles/<role_id>/keys/<key_id>
ASSUMES: org_is_enabled($sess_org) && user_in_org($sess_user.id, $sess_org.id)
ASSERT: (let $role = role_exists($role) in role_is_valid($role) && role_in_org($role.id, $org.id))
&& key_in_role($key_id, $role_id)
&& (user_in_role($sess_user.id, $role_id) || is_org_owner($user.id, $org.id))
&& (is_key_owner($sess_user.id, $key_id) || is_org_owner($user.id, $org.id))
EFFECT: delete_key_from_role($role_id, $key_id)
[add_user_to_role] PUT /v0/org/<org_id>/roles/<role_id>/add_user/<user_id>
ASSUMES: org_is_enabled($sess_org) AND user_in_org($sess_user.id, $sess_org.id)
ASSERT: user_in_org($user_id, $sess_org.id)
&& (let role = role_exists(role_id) in role_is_valid(role)) && (role_in_org(role_id, sess_org.id))
&& (user_in_role($sess_user.id, role_id) || is_org_owner($sess_user.id, $sess_org.id))
EFFECT: create_user_in_role(role_id, $sess_user.id)
```
### Tokens
```
[list] GET /v0/org/<org_id>/roles/<role_id>/tokens
ASSUMES: org_is_enabled($sess_org) AND user_in_org($)
ASSERT: (let $role = role_exists($role_id) in role_is_valid($role)) && (role_in_org($role_id, sess_org.id))
&& (user_in_role($sess_user.id, $role_id) || is_org_owner($sess_user.id, $sess_org.id))
[create] POST /v0/org/<org_id>/roles/<role_id>/tokens
ASSUMES: org_is_enabled($sess_org) AND user_in_org($sess_user.id, $sess_org.id)
ASSERT: (let $role = role_exists($role_id) in role_is_valid($role)) && (role_in_org($role_id, sess_org.id))
&& (user_in_role($sess_user.id, $role_id) || is_org_owner($sess_user.id, $sess_org.id))
EFFECT: create_session($role_id)
[revoke_all] DELETE /v0/org/<org_id>/roles/<role_id>/tokens
ASSUMES: org_is_enabled($sess_org) && user_in_org($sess_user.id, $sess_org.id)
ASSERT: (let $role = role_exists($role_id) in role_is_valid($role)) && (role_in_org($role_id, sess_org.id))
&& (user_in_role($sess_user.id, $role_id) || is_org_owner($sess_user.id, $sess_org.id))
EFFECT: revoke_all($role_id)
[revoke] DELETE /v0/org/<org_id>/roles/<role_id>/tokens/<session_id>
ASSUMES: org_is_enabled($sess_org) AND user_in_org($)
ASSERT: (let $role = role_exists($role_id) in role_is_valid($role)) && (role_in_org($role_id, sess_org.id))
&& (user_in_role($sess_user.id, $role_id) || is_org_owner($sess_user.id, $sess_org.id))
EFFECT: let $session = session_exists($session) in revoke_session($session)
```