Search Apps Documentation Source Content File Folder Download Copy Actions Download

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}