authz_admin.gno
9.63 Kb ยท 362 lines
1package personal_world
2
3import (
4 "chain"
5 "strconv"
6 "strings"
7)
8
9const (
10 CreatePermissionEvent = "CreatePermission"
11 DeletePermissionEvent = "DeletePermission"
12 CreateRoleEvent = "CreateRole"
13 UpdateRoleEvent = "UpdateRole"
14 UpdateRolePropertyEvent = "UpdateRoleProperty"
15 DeleteRoleEvent = "DeleteRole"
16 AddPermissionEvent = "AddPermission"
17 RemovePermissionEvent = "RemovePermission"
18 AddGrantableEvent = "AddGrantable"
19 RemoveGrantableEvent = "RemoveGrantable"
20 GrantRoleEvent = "GrantRole"
21 RevokeRoleEvent = "RevokeRole"
22)
23
24var (
25 // Permission registry: permission name -> description
26 permissionMap = make(map[string]string)
27
28 // Role registry: role name -> role info (name, maxAssign)
29 roleMap = make(map[string]map[string]string)
30
31 // Role permissions: role name -> permission -> bool
32 rolePermissions = make(map[string]map[string]bool)
33
34 // Grantable map: granterRole -> grantableRole -> bool
35 grantableMap = make(map[string]map[string]bool)
36)
37
38func init() {
39 // Initialize core permissions
40 permissionMap["role:grant"] = "Grant Role"
41 permissionMap["role:revoke"] = "Revoke Role"
42 permissionMap["world:update"] = "Update World"
43 permissionMap["world:expand"] = "Expand World"
44 permissionMap["world:delete"] = "Delete World"
45 permissionMap["block:install"] = "Install Block"
46 permissionMap["block:uninstall"] = "Uninstall Block"
47
48 // Initialize default "editor" role (MaxAssign = 5)
49 roleMap["editor"] = map[string]string{
50 "name": "editor",
51 "maxAssign": "5",
52 }
53 rolePermissions["editor"] = map[string]bool{
54 "block:install": true,
55 "block:uninstall": true,
56 }
57}
58
59// ==================== Permission Management (Admin Only) ====================
60
61// CreatePermission creates a new permission definition
62func CreatePermission(cur realm, name string, description string) {
63 caller := validateUser()
64 assertIsAdmin(caller)
65
66 if _, found := permissionMap[name]; found {
67 panic("permission already exists: " + name)
68 }
69
70 permissionMap[name] = description
71 chain.Emit(CreatePermissionEvent, "name", name, "description", description)
72}
73
74// DeletePermission deletes a permission and removes it from all roles
75func DeletePermission(cur realm, name string) {
76 caller := validateUser()
77 assertIsAdmin(caller)
78
79 if _, found := permissionMap[name]; !found {
80 panic("permission not found: " + name)
81 }
82
83 // Remove from all roles
84 for roleName := range roleMap {
85 if perms, found := rolePermissions[roleName]; found {
86 delete(perms, name)
87 }
88 }
89
90 delete(permissionMap, name)
91 chain.Emit(DeletePermissionEvent, "name", name)
92}
93
94// AddPermissionToRole adds a permission to an existing role
95func AddPermissionToRole(cur realm, roleName string, permissionName string) {
96 caller := validateUser()
97 assertIsAdmin(caller)
98
99 if _, found := roleMap[roleName]; !found {
100 panic("role not found: " + roleName)
101 }
102
103 if _, found := permissionMap[permissionName]; !found {
104 panic("permission not found: " + permissionName)
105 }
106
107 perms := rolePermissions[roleName]
108 if perms == nil {
109 perms = make(map[string]bool)
110 rolePermissions[roleName] = perms
111 }
112
113 if perms[permissionName] {
114 panic("permission '" + permissionName + "' already in role '" + roleName + "'")
115 }
116
117 perms[permissionName] = true
118 chain.Emit(AddPermissionEvent, "role", roleName, "permission", permissionName)
119}
120
121// RemovePermissionFromRole removes a permission from a role
122func RemovePermissionFromRole(cur realm, roleName string, permissionName string) {
123 caller := validateUser()
124 assertIsAdmin(caller)
125
126 if _, found := roleMap[roleName]; !found {
127 panic("role not found: " + roleName)
128 }
129
130 if _, found := permissionMap[permissionName]; !found {
131 panic("permission not found: " + permissionName)
132 }
133
134 perms := rolePermissions[roleName]
135 if perms == nil || !perms[permissionName] {
136 panic("permission '" + permissionName + "' not in role '" + roleName + "'")
137 }
138
139 delete(perms, permissionName)
140 chain.Emit(RemovePermissionEvent, "role", roleName, "permission", permissionName)
141}
142
143// ==================== Role Management (Admin Only) ====================
144
145// CreateRole creates a new role with permissions
146// permissions is a comma-separated string of permission names
147// maxAssign: 0 = unlimited assignments
148func CreateRole(cur realm, roleName string, maxAssign int, permissions string) {
149 caller := validateUser()
150 assertIsAdmin(caller)
151
152 if _, found := roleMap[roleName]; found {
153 panic("role already exists: " + roleName)
154 }
155
156 if maxAssign < 0 {
157 panic("maxAssign must be non-negative")
158 }
159
160 // Parse and validate permissions
161 perms := make(map[string]bool)
162 if len(permissions) > 0 {
163 permList := strings.Split(permissions, ",")
164 for _, perm := range permList {
165 perm = strings.TrimSpace(perm)
166 if len(perm) == 0 {
167 continue
168 }
169
170 if _, found := permissionMap[perm]; !found {
171 panic("permission not found: " + perm)
172 }
173
174 perms[perm] = true
175 }
176 }
177
178 roleMap[roleName] = map[string]string{
179 "name": roleName,
180 "maxAssign": strconv.Itoa(maxAssign),
181 }
182 rolePermissions[roleName] = perms
183
184 chain.Emit(CreateRoleEvent, "name", roleName, "permissions", permissions)
185}
186
187// UpdateRole updates a role's maxAssign and permissions
188// permissions is a comma-separated string of permission names (replaces all existing permissions)
189// maxAssign: 0 = unlimited assignments
190func UpdateRole(cur realm, roleName string, maxAssign int, permissions string) {
191 caller := validateUser()
192 assertIsAdmin(caller)
193
194 if _, found := roleMap[roleName]; !found {
195 panic("role not found: " + roleName)
196 }
197
198 if maxAssign < 0 {
199 panic("maxAssign must be non-negative")
200 }
201
202 // Parse and validate permissions
203 perms := make(map[string]bool)
204 if len(permissions) > 0 {
205 permList := strings.Split(permissions, ",")
206 for _, perm := range permList {
207 perm = strings.TrimSpace(perm)
208 if len(perm) == 0 {
209 continue
210 }
211
212 if _, found := permissionMap[perm]; !found {
213 panic("permission not found: " + perm)
214 }
215
216 perms[perm] = true
217 }
218 }
219
220 roleMap[roleName]["maxAssign"] = strconv.Itoa(maxAssign)
221 rolePermissions[roleName] = perms
222
223 chain.Emit(UpdateRoleEvent, "name", roleName, "maxAssign", strconv.Itoa(maxAssign), "permissions", permissions)
224}
225
226// UpdateRoleProperty updates a single property of a role
227func UpdateRoleProperty(cur realm, roleName string, key string, value string) {
228 caller := validateUser()
229 assertIsAdmin(caller)
230
231 if key == "name" {
232 panic("reserved key: name")
233 }
234
235 roleInfo, found := roleMap[roleName]
236 if !found {
237 panic("role not found: " + roleName)
238 }
239
240 roleInfo[key] = value
241
242 chain.Emit(UpdateRolePropertyEvent, "name", roleName, "key", key, "value", value)
243}
244
245// DeleteRole deletes a role and removes all its assignments
246func DeleteRole(cur realm, roleName string) {
247 caller := validateUser()
248 assertIsAdmin(caller)
249
250 if _, found := roleMap[roleName]; !found {
251 panic("role not found: " + roleName)
252 }
253
254 // Remove role from all worlds
255 for worldID := range worldAuthorization {
256 for addr := range worldAuthorization[worldID] {
257 delete(worldAuthorization[worldID][addr], roleName)
258
259 if len(worldAuthorization[worldID][addr]) == 0 {
260 delete(worldAuthorization[worldID], addr)
261 }
262 }
263
264 if len(worldAuthorization[worldID]) == 0 {
265 delete(worldAuthorization, worldID)
266 }
267 }
268
269 // Remove from grantable map
270 delete(grantableMap, roleName)
271 for _, grantables := range grantableMap {
272 delete(grantables, roleName)
273 }
274
275 delete(roleMap, roleName)
276 delete(rolePermissions, roleName)
277 chain.Emit(DeleteRoleEvent, "name", roleName)
278}
279
280// ==================== Grantable Management (Admin Only) ====================
281
282// AddGrantable allows granterRole to grant grantableRole to users
283func AddGrantable(cur realm, granterRole, grantableRole string) {
284 caller := validateUser()
285 assertIsAdmin(caller)
286
287 if _, found := roleMap[granterRole]; !found {
288 panic("granter role not found: " + granterRole)
289 }
290
291 if _, found := roleMap[grantableRole]; !found {
292 panic("grantable role not found: " + grantableRole)
293 }
294
295 if _, found := grantableMap[granterRole]; !found {
296 grantableMap[granterRole] = make(map[string]bool)
297 }
298
299 grantableMap[granterRole][grantableRole] = true
300 chain.Emit(AddGrantableEvent, "granterRole", granterRole, "grantableRole", grantableRole)
301}
302
303// RemoveGrantable removes the ability for granterRole to grant grantableRole
304func RemoveGrantable(cur realm, granterRole, grantableRole string) {
305 caller := validateUser()
306 assertIsAdmin(caller)
307
308 if _, found := roleMap[granterRole]; !found {
309 panic("granter role not found: " + granterRole)
310 }
311
312 if _, found := roleMap[grantableRole]; !found {
313 panic("grantable role not found: " + grantableRole)
314 }
315
316 grantables, found := grantableMap[granterRole]
317 if !found || !grantables[grantableRole] {
318 panic("role hierarchy not found: " + granterRole + " -> " + grantableRole)
319 }
320
321 delete(grantables, grantableRole)
322 if len(grantables) == 0 {
323 delete(grantableMap, granterRole)
324 }
325
326 chain.Emit(RemoveGrantableEvent, "granterRole", granterRole, "grantableRole", grantableRole)
327}
328
329// ==================== Query Functions ====================
330
331// GetPermissions returns all available permissions
332func GetPermissions() map[string]string {
333 return permissionMap
334}
335
336// GetRoleInfo returns detailed information about a role
337func GetRoleInfo(roleName string) map[string]string {
338 if roleInfo, found := roleMap[roleName]; found {
339 return roleInfo
340 }
341 return nil
342}
343
344// ListRoles returns all available role names
345func ListRoles() []string {
346 result := []string{}
347 for roleName := range roleMap {
348 result = append(result, roleName)
349 }
350 return result
351}
352
353// ListGrantables returns roles that granterRole can grant
354func ListGrantables(granterRole string) []string {
355 result := []string{}
356 if grantables, found := grantableMap[granterRole]; found {
357 for role := range grantables {
358 result = append(result, role)
359 }
360 }
361 return result
362}