permissions.proto 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394
  1. syntax = "proto3";
  2. package chatto.admin.v1;
  3. import "buf/validate/validate.proto";
  4. import "chatto/api/v1/roles.proto";
  5. import "chatto/api/v1/pagination.proto";
  6. // Trinary permission decision used by permission matrices and write requests.
  7. enum PermissionDecision {
  8. // Unspecified decision; rejected for writes.
  9. PERMISSION_DECISION_UNSPECIFIED = 0;
  10. // Explicit allow.
  11. PERMISSION_DECISION_ALLOW = 1;
  12. // Explicit deny.
  13. PERMISSION_DECISION_DENY = 2;
  14. // No explicit decision; clears the permission state on writes.
  15. PERMISSION_DECISION_NONE = 3;
  16. }
  17. // Scope tier for permission matrices and write requests.
  18. enum PermissionScopeKind {
  19. // Unspecified scope; treated as server scope where older clients omit it.
  20. PERMISSION_SCOPE_KIND_UNSPECIFIED = 0;
  21. // Server tier.
  22. PERMISSION_SCOPE_KIND_SERVER = 1;
  23. // Room-group tier.
  24. PERMISSION_SCOPE_KIND_GROUP = 2;
  25. // Room tier.
  26. PERMISSION_SCOPE_KIND_ROOM = 3;
  27. // Server-wide direct-message tier.
  28. PERMISSION_SCOPE_KIND_DM = 4;
  29. }
  30. // Permission scope reference.
  31. message PermissionScope {
  32. // Scope tier.
  33. PermissionScopeKind kind = 1 [(buf.validate.field).enum.defined_only = true];
  34. // Scope ID for group or room scope. Empty for server or direct-message scope.
  35. string id = 2;
  36. }
  37. // Permission grants and denials at a single tier.
  38. message TierPermissions {
  39. // Explicitly granted permissions.
  40. repeated string permissions = 1;
  41. // Explicitly denied permissions.
  42. repeated string permission_denials = 2;
  43. }
  44. // One role's permission state at a single tier.
  45. message TierRole {
  46. reserved 1 to 5;
  47. reserved "role_name", "display_name", "description", "is_system", "position";
  48. // Explicit state at this tier.
  49. TierPermissions override = 6;
  50. // Allows inherited from broader tiers.
  51. repeated string inherited_allows = 7;
  52. // Denials inherited from broader tiers.
  53. repeated string inherited_denials = 8;
  54. // Public role metadata.
  55. chatto.api.v1.Role role = 9;
  56. }
  57. // Role permission matrix for one tier.
  58. message TierRoles {
  59. // Permissions configurable at this tier.
  60. repeated string applicable_permissions = 1;
  61. // Roles sorted by position.
  62. repeated TierRole roles = 2;
  63. }
  64. // Request a role-permission tier matrix.
  65. message GetRolePermissionTierMatrixRequest {
  66. // Target scope. Omit or use SERVER for server scope.
  67. PermissionScope scope = 1;
  68. }
  69. // Response containing a role-permission tier matrix.
  70. message GetRolePermissionTierMatrixResponse {
  71. // Requested matrix.
  72. TierRoles matrix = 1;
  73. }
  74. // Matrix column scope.
  75. message PermissionMatrixScope {
  76. // Stable scope ID for the server, direct messages, a group, or a room.
  77. string id = 1;
  78. // Human-readable label.
  79. string label = 2;
  80. // Scope tier.
  81. PermissionScopeKind kind = 3;
  82. // Parent group ID for room scopes.
  83. string parent_group_id = 4;
  84. }
  85. // Matrix cell for one permission and scope.
  86. message PermissionMatrixCell {
  87. // Permission identifier.
  88. string permission = 1;
  89. // Scope ID matching PermissionMatrixScope.id.
  90. string scope_id = 2;
  91. // Explicit decision at this scope.
  92. PermissionDecision override = 3;
  93. // Effective decision at this scope.
  94. PermissionDecision effective = 4;
  95. // Whether an explicit allow may currently be stored for this target. Absent
  96. // when no additional delegation ceiling applies.
  97. optional bool allow_permitted = 5;
  98. }
  99. // Permission matrix for one role within a scope page.
  100. message RolePermissionMatrix {
  101. // Role name.
  102. string role_name = 1;
  103. // Permissions rendered as rows.
  104. repeated string applicable_permissions = 2;
  105. // Scopes rendered as columns.
  106. repeated PermissionMatrixScope scopes = 3;
  107. // Sparse matrix cells.
  108. repeated PermissionMatrixCell cells = 4;
  109. }
  110. // Request one role's permission matrix.
  111. message GetRolePermissionMatrixRequest {
  112. // Stable role name.
  113. string role_name = 1 [(buf.validate.field).string.min_len = 1];
  114. // Include the direct-message scope column. Defaults to false so an older
  115. // client does not receive a scope kind that it cannot interpret.
  116. bool include_direct_message_scope = 2;
  117. // Scope page. Default 20 scopes, maximum 100. Offsets count scopes, not decisions.
  118. chatto.api.v1.PageRequest page = 3;
  119. // Optional exact scope filter. Missing or inaccessible scopes produce an empty page.
  120. // SERVER and DM require an empty ID; GROUP and ROOM require an ID.
  121. PermissionScope scope = 4;
  122. }
  123. // Response containing one role's permission matrix.
  124. message GetRolePermissionMatrixResponse {
  125. // Requested matrix.
  126. RolePermissionMatrix matrix = 1;
  127. // Total matching scopes and whether another scope page exists.
  128. chatto.api.v1.PageInfo page = 2;
  129. }
  130. // Permission matrix for one user within a scope page.
  131. message UserPermissionMatrix {
  132. // User ID.
  133. string user_id = 1;
  134. // Permissions rendered as rows.
  135. repeated string applicable_permissions = 2;
  136. // Scopes rendered as columns.
  137. repeated PermissionMatrixScope scopes = 3;
  138. // Sparse matrix cells.
  139. repeated PermissionMatrixCell cells = 4;
  140. }
  141. // One resource-oriented permission decision at a concrete scope.
  142. //
  143. // This is the row-oriented counterpart to PermissionMatrixCell. Prefer this
  144. // shape when building integrations that do not need matrix column joins.
  145. message ScopedPermissionDecision {
  146. // Permission identifier.
  147. string permission = 1;
  148. // Server, direct-message, group, or room scope for this decision.
  149. PermissionScope scope = 2;
  150. // Explicit decision stored at this scope.
  151. PermissionDecision override = 3;
  152. // Effective decision after inherited broader scopes are applied.
  153. PermissionDecision effective = 4;
  154. }
  155. // Stored permission decision returned after a write.
  156. message PermissionDecisionUpdate {
  157. // Permission identifier.
  158. string permission = 1;
  159. // Server, direct-message, group, or room scope for this decision.
  160. PermissionScope scope = 2;
  161. // Stored decision after the write. NONE means no explicit decision remains.
  162. PermissionDecision decision = 3;
  163. }
  164. // Request explicit/effective permission decisions for one role.
  165. message ListRolePermissionDecisionsRequest {
  166. // Stable role name.
  167. string role_name = 1 [(buf.validate.field).string.min_len = 1];
  168. // Include direct-message decisions. Defaults to false for older clients.
  169. bool include_direct_message_scope = 2;
  170. // Scope page. Default 20 scopes, maximum 100. Offsets count scopes, not decisions.
  171. chatto.api.v1.PageRequest page = 3;
  172. // Optional exact scope filter. Missing or inaccessible scopes produce an empty page.
  173. // SERVER and DM require an empty ID; GROUP and ROOM require an ID.
  174. PermissionScope scope = 4;
  175. }
  176. // Resource-oriented permission decisions for one role.
  177. message ListRolePermissionDecisionsResponse {
  178. // Stable role name.
  179. string role_name = 1;
  180. // Permission decisions keyed by permission and typed scope.
  181. repeated ScopedPermissionDecision decisions = 2;
  182. // Total matching scopes and whether another scope page exists.
  183. chatto.api.v1.PageInfo page = 3;
  184. // Scopes in this page, including scopes with no applicable decisions.
  185. repeated PermissionScope scopes = 4;
  186. }
  187. // Request explicit/effective permission decisions for one user.
  188. message ListUserPermissionDecisionsRequest {
  189. // User ID.
  190. string user_id = 1 [(buf.validate.field).string.min_len = 1];
  191. // Include direct-message decisions. Defaults to false for older clients.
  192. bool include_direct_message_scope = 2;
  193. // Scope page. Default 20 scopes, maximum 100. Offsets count scopes, not decisions.
  194. chatto.api.v1.PageRequest page = 3;
  195. // Optional exact scope filter. Missing or inaccessible scopes produce an empty page.
  196. // SERVER and DM require an empty ID; GROUP and ROOM require an ID.
  197. PermissionScope scope = 4;
  198. }
  199. // Resource-oriented permission decisions for one user.
  200. message ListUserPermissionDecisionsResponse {
  201. // User ID.
  202. string user_id = 1;
  203. // Permission decisions keyed by permission and typed scope.
  204. repeated ScopedPermissionDecision decisions = 2;
  205. // Total matching scopes and whether another scope page exists.
  206. chatto.api.v1.PageInfo page = 3;
  207. // Scopes in this page, including scopes with no applicable decisions.
  208. repeated PermissionScope scopes = 4;
  209. }
  210. // Level at which a permission explanation found a decision.
  211. enum PermissionDecisionLevel {
  212. // No decision level was reached.
  213. PERMISSION_DECISION_LEVEL_UNSPECIFIED = 0;
  214. // Server-level role or user decision.
  215. PERMISSION_DECISION_LEVEL_SERVER = 1;
  216. // Room-group-level role or user decision.
  217. PERMISSION_DECISION_LEVEL_GROUP = 2;
  218. // Room-level role or user decision.
  219. PERMISSION_DECISION_LEVEL_ROOM = 3;
  220. // Direct-message-level role or user decision.
  221. PERMISSION_DECISION_LEVEL_DM = 4;
  222. }
  223. // One explicit decision encountered while explaining a permission.
  224. message PermissionTraceEntry {
  225. // Level at which this decision was observed.
  226. PermissionDecisionLevel level = 1;
  227. // Role name, user ID, or policy marker that produced the decision.
  228. string role_name = 2;
  229. // Decision observed at this trace step.
  230. PermissionDecision decision = 3;
  231. // Whether this entry is the winning decision.
  232. bool applied = 4;
  233. }
  234. // Full decision trace for one permission and target user.
  235. message PermissionExplanation {
  236. // Permission identifier.
  237. string permission = 1;
  238. // Overall decision after resolving named subjects and the everyone baseline.
  239. PermissionDecision state = 2;
  240. // Level of the winning decision, when state is not NONE.
  241. PermissionDecisionLevel decided_at = 3;
  242. // Role name, user ID, or policy marker that produced the winning decision.
  243. string decided_by_role = 4;
  244. // Ordered decision trace. The first entry is the winning decision.
  245. repeated PermissionTraceEntry trace = 5;
  246. // Permission whose effective allow includes this permission. Empty when the
  247. // permission was resolved directly.
  248. string included_by_permission = 6;
  249. }
  250. // Request permission explanations for a user at a typed scope.
  251. message ExplainPermissionsRequest {
  252. // User whose permissions should be explained.
  253. string user_id = 1 [(buf.validate.field).string.min_len = 1];
  254. // Legacy room scope. Omit for server-scoped permissions. A request that
  255. // also supplies scope must identify the same room.
  256. string room_id = 2;
  257. // Optional typed target. Use DM with an empty ID for direct messages. Omit
  258. // for server scope. This field replaces room_id for new clients.
  259. PermissionScope scope = 3;
  260. }
  261. // Permission explanations for all permissions applicable at the requested scope.
  262. message ExplainPermissionsResponse {
  263. // Explanation rows sorted by permission metadata order.
  264. repeated PermissionExplanation explanations = 1;
  265. }
  266. // Request one user's permission matrix.
  267. message GetUserPermissionMatrixRequest {
  268. // User ID.
  269. string user_id = 1 [(buf.validate.field).string.min_len = 1];
  270. // Include the direct-message scope column. Defaults to false so an older
  271. // client does not receive a scope kind that it cannot interpret.
  272. bool include_direct_message_scope = 2;
  273. // Scope page. Default 20 scopes, maximum 100. Offsets count scopes, not decisions.
  274. chatto.api.v1.PageRequest page = 3;
  275. // Optional exact scope filter. Missing or inaccessible scopes produce an empty page.
  276. // SERVER and DM require an empty ID; GROUP and ROOM require an ID.
  277. PermissionScope scope = 4;
  278. }
  279. // Response containing one user's permission matrix.
  280. message GetUserPermissionMatrixResponse {
  281. // Requested matrix.
  282. UserPermissionMatrix matrix = 1;
  283. // Total matching scopes and whether another scope page exists.
  284. chatto.api.v1.PageInfo page = 2;
  285. }
  286. // Request to set one role permission state.
  287. message SetRolePermissionRequest {
  288. // Role name.
  289. string role_name = 1 [(buf.validate.field).string.min_len = 1];
  290. // Permission identifier.
  291. string permission = 2 [(buf.validate.field).string.min_len = 1];
  292. // New decision. NONE clears the explicit state.
  293. PermissionDecision decision = 3 [(buf.validate.field).enum = {
  294. defined_only: true
  295. not_in: [0]
  296. }];
  297. // Target scope. Omit or use SERVER for server scope.
  298. PermissionScope scope = 4;
  299. }
  300. // Result of setting one role permission state.
  301. message SetRolePermissionResponse {
  302. // Updated permission decision for the requested role/scope cell.
  303. PermissionDecisionUpdate decision = 1;
  304. }
  305. // Request to set one user permission state.
  306. message SetUserPermissionRequest {
  307. // Target user ID.
  308. string user_id = 1 [(buf.validate.field).string.min_len = 1];
  309. // Permission identifier.
  310. string permission = 2 [(buf.validate.field).string.min_len = 1];
  311. // New decision. NONE clears the explicit state.
  312. PermissionDecision decision = 3 [(buf.validate.field).enum = {
  313. defined_only: true
  314. not_in: [0]
  315. }];
  316. // Target scope. Omit or use SERVER for server scope.
  317. PermissionScope scope = 4;
  318. }
  319. // Result of setting one user permission state.
  320. message SetUserPermissionResponse {
  321. // Updated permission decision for the requested user/scope cell.
  322. PermissionDecisionUpdate decision = 1;
  323. }
  324. // Provides permission reads and admin permission writes.
  325. // Matrix and decision pages use the same scope order: SERVER, DM, then each GROUP
  326. // followed by its ROOM scopes. Groups and rooms within each group use ascending
  327. // resource IDs. Only requested scopes are evaluated.
  328. // Pages are live reads; layout or visibility changes can shift offsets. Keep the
  329. // same filters on each request and advance by the number of returned scopes.
  330. // A scope filter of DM selects DM even when include_direct_message_scope is false.
  331. service AdminPermissionService {
  332. // Gets the role-permission matrix for a single tier. Server scope requires
  333. // role.manage; group and room scopes require role.manage or effective
  334. // room.manage at the requested resource.
  335. rpc GetRolePermissionTierMatrix(GetRolePermissionTierMatrixRequest) returns (GetRolePermissionTierMatrixResponse);
  336. // Gets one page of a role's permission matrix. Requires role.manage. Returns
  337. // NOT_FOUND when the role does not exist.
  338. rpc GetRolePermissionMatrix(GetRolePermissionMatrixRequest) returns (GetRolePermissionMatrixResponse);
  339. // Lists one role's permission decisions as resource-oriented rows. Requires
  340. // role.manage. Returns NOT_FOUND when the role does not exist.
  341. rpc ListRolePermissionDecisions(ListRolePermissionDecisionsRequest) returns (ListRolePermissionDecisionsResponse);
  342. // Gets one page of a user's permission matrix. Human targets require
  343. // user.manage-permissions; bot targets require ownership or bot.manage.
  344. // Returns NOT_FOUND when the user does not exist.
  345. rpc GetUserPermissionMatrix(GetUserPermissionMatrixRequest) returns (GetUserPermissionMatrixResponse);
  346. // Lists one user's permission decisions as resource-oriented rows. Human
  347. // targets require user.manage-permissions; bot targets require ownership or
  348. // bot.manage. Returns NOT_FOUND when the user does not exist.
  349. rpc ListUserPermissionDecisions(ListUserPermissionDecisionsRequest) returns (ListUserPermissionDecisionsResponse);
  350. // Explains permission resolution for another user. Requires role.manage.
  351. rpc ExplainPermissions(ExplainPermissionsRequest) returns (ExplainPermissionsResponse);
  352. // Sets one role permission decision. Server scope requires role.manage;
  353. // group and room scopes also accept effective room.manage at that resource.
  354. rpc SetRolePermission(SetRolePermissionRequest) returns (SetRolePermissionResponse);
  355. // Sets one user permission decision. Human targets require
  356. // user.manage-permissions; bot targets require ownership or bot.manage and
  357. // accept only allow or clear within the bot owner's current authority.
  358. rpc SetUserPermission(SetUserPermissionRequest) returns (SetUserPermissionResponse);
  359. }