authz_world.gno
3.34 Kb · 120 lines
1package chunk
2
3import (
4 "chain"
5 "strconv"
6
7 "gno.land/p/akkadia/v0/accesscontrol"
8 "gno.land/p/akkadia/v0/rbac"
9 "gno.land/r/akkadia/v0/admin"
10)
11
12const (
13 GrantMasterEvent = "GrantMaster"
14 RevokeMasterEvent = "RevokeMaster"
15)
16
17var (
18 worldAuthzRBAC = rbac.NewRBAC(32)
19)
20
21func init() {
22 initWorldAuthzDefinitions()
23}
24
25func initWorldAuthzDefinitions() {
26 worldAuthzRBAC = rbac.NewRBAC(32)
27 worldAuthzRBAC.AddRole(rbac.RoleSpec{Name: "master"})
28}
29
30// ==================== Admin Functions ====================
31
32// GrantMaster grants master role to a user for a world (admin only)
33func GrantMaster(cur realm, worldID uint32, user address) {
34 assertNotFrozen()
35 accesscontrol.AssertIsAdmin(0, cur, admin.IsAdmin)
36 worldStore.AssertExists(worldID)
37
38 if IsMaster(worldID, user) {
39 panic("user " + user.String() + " is already a master for world " + strconv.FormatUint(uint64(worldID), 10))
40 }
41
42 worldAuthzRBAC.AssignRole(formatWorldID(worldID), user, "master")
43
44 chain.Emit(
45 GrantMasterEvent,
46 "worldID", strconv.FormatUint(uint64(worldID), 10),
47 "user", user.String(),
48 )
49}
50
51// RevokeMaster revokes master role from a user for a world (admin only)
52func RevokeMaster(cur realm, worldID uint32, user address) {
53 assertNotFrozen()
54 accesscontrol.AssertIsAdmin(0, cur, admin.IsAdmin)
55 worldStore.AssertExists(worldID)
56
57 if !IsMaster(worldID, user) {
58 panic("user " + user.String() + " is not a master for world " + strconv.FormatUint(uint64(worldID), 10))
59 }
60
61 worldAuthzRBAC.UnassignRole(formatWorldID(worldID), user, "master")
62
63 chain.Emit(
64 RevokeMasterEvent,
65 "worldID", strconv.FormatUint(uint64(worldID), 10),
66 "user", user.String(),
67 )
68}
69
70// ==================== Query Functions ====================
71
72// IsMaster checks if a user is a master for a world
73func IsMaster(worldID uint32, user address) bool {
74 assertMigrationStateAvailable()
75 return worldAuthzRBAC.HasUserRole(formatWorldID(worldID), user, "master")
76}
77
78// HasWorldPermission checks if a user has world-level permission.
79func HasWorldPermission(worldID uint32, user address, _ string) bool {
80 assertMigrationStateAvailable()
81 if admin.IsAdmin(user) {
82 return true
83 }
84 return IsMaster(worldID, user)
85}
86
87// ListWorldMasters returns masters for a world by page.
88func ListWorldMasters(worldID uint32, page int, count int) []address {
89 assertMigrationStateAvailable()
90 assertListPageCount(page, count)
91 return worldAuthzRBAC.ListRoleUsers(formatWorldID(worldID), "master", page, count)
92}
93
94// GetWorldMasterSize returns the number of masters assigned to a world.
95func GetWorldMasterSize(worldID uint32) int {
96 assertMigrationStateAvailable()
97 return worldAuthzRBAC.RoleUserSize(formatWorldID(worldID), "master")
98}
99
100// ListMasterWorlds returns worlds where a user is a master by page.
101func ListMasterWorlds(user address, page int, count int) []uint32 {
102 assertMigrationStateAvailable()
103 assertListPageCount(page, count)
104 result := []uint32{}
105 worlds := worldAuthzRBAC.ListEntitiesByUserRole(user, "master", page, count)
106 for _, worldKey := range worlds {
107 worldID, err := strconv.ParseUint(worldKey, 10, 32)
108 if err != nil {
109 panic("invalid master worldID: " + worldKey)
110 }
111 result = append(result, uint32(worldID))
112 }
113 return result
114}
115
116// GetMasterWorldSize returns the number of worlds where user is a master.
117func GetMasterWorldSize(user address) int {
118 assertMigrationStateAvailable()
119 return worldAuthzRBAC.UserRoleEntitySize(user, "master")
120}