Skip to content

Commit

Permalink
feat: add validations for user invite permission
Browse files Browse the repository at this point in the history
This validation makes sure only owners can invite other owners.
  • Loading branch information
jeronimoalbi committed Nov 27, 2024
1 parent ec0cab0 commit 2986a17
Show file tree
Hide file tree
Showing 6 changed files with 105 additions and 6 deletions.
3 changes: 3 additions & 0 deletions examples/gno.land/r/demo/boards2/permission.gno
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ type (

// Permissioner define an interface to for permissioned execution.
Permissioner interface {
// HasRole checks if a user has a specific role assigned.
HasRole(std.Address, Role) bool

// HasPermission checks if a user has a specific permission.
HasPermission(std.Address, Permission) bool

Expand Down
9 changes: 5 additions & 4 deletions examples/gno.land/r/demo/boards2/permission_default.gno
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ type (
// PermissionsHandlerFunc defines a function to handle permission callbacks.
// Handlers are called by the `WithPermission()` method to execute callbacks
// when users have the permission assigned.
PermissionsHandlerFunc func(Args, *admindao.AdminDAO, func(Args))
PermissionsHandlerFunc func(Permissioner, Args, func(Args))

// DefaultPermissions manages users, roles and permissions.
DefaultPermissions struct {
Expand Down Expand Up @@ -132,7 +132,7 @@ func (dp *DefaultPermissions) HandleFunc(p Permission, fn PermissionsHandlerFunc
// WithPermission calls a callback when a user has a specific permission.
// It panics on error or when a handler panics.
// Callbacks are by default called when there is no handle registered for the permission.
func (dp DefaultPermissions) WithPermission(user std.Address, perm Permission, args Args, cb func(Args)) {
func (dp *DefaultPermissions) WithPermission(user std.Address, perm Permission, args Args, cb func(Args)) {
if !dp.HasPermission(user, perm) || !dp.dao.IsMember(user) {
panic("unauthorized")
}
Expand All @@ -144,7 +144,7 @@ func (dp DefaultPermissions) WithPermission(user std.Address, perm Permission, a
}

fn := h.(PermissionsHandlerFunc)
fn(args, dp.dao, cb)
fn(dp, args, cb)
}

func createDefaultPermissions() *DefaultPermissions {
Expand All @@ -156,13 +156,14 @@ func createDefaultPermissions() *DefaultPermissions {
perms := NewDefaultPermissions(
dao,
WithSuperRole(RoleOwner),
WithRole(RoleAdmin, PermissionBoardCreate),
WithRole(RoleAdmin, PermissionBoardCreate, PermissionMemberInvite),
// TODO: Finish assigning all roles and permissions
// WithRole(RoleModerator, permissions...),
WithUser(owner, RoleOwner),
)

perms.HandleFunc(PermissionBoardCreate, handleBoardCreate)
perms.HandleFunc(PermissionMemberInvite, handleMemberInvite)

return perms
}
16 changes: 14 additions & 2 deletions examples/gno.land/r/demo/boards2/permission_handlers.gno
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,10 @@ package boards2
import (
"std"

"gno.land/p/demo/boards2/admindao"
"gno.land/r/demo/users"
)

func handleBoardCreate(args Args, _ *admindao.AdminDAO, cb func(Args)) {
func handleBoardCreate(_ Permissioner, args Args, cb func(Args)) {
// TODO: This way of dealing with arguments is delicate, ideally types should be used
name := args[0].(string)
if std.Address(name).IsValid() {
Expand All @@ -24,3 +23,16 @@ func handleBoardCreate(args Args, _ *admindao.AdminDAO, cb func(Args)) {

cb(args)
}

func handleMemberInvite(p Permissioner, args Args, cb func(Args)) {
// Make sure that only owners invite other owners
role := args[1].(Role)
if role == RoleOwner {
caller := std.GetOrigCaller()
if !p.HasRole(caller, RoleOwner) {
panic("only owners are allowed to invite other owners")
}
}

cb(args)
}
24 changes: 24 additions & 0 deletions examples/gno.land/r/demo/boards2/z_1_a_filetest.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package main

import (
"std"

"gno.land/r/demo/boards2"
)

const (
owner = std.Address("g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5") // @test1
admin = std.Address("g1us8428u2a5satrlxzagqqa5m6vmuze025anjlj") // @test2
)

func init() {
std.TestSetOrigCaller(owner)
}

func main() {
boards2.InviteMember(admin, boards2.RoleAdmin)
println("ok")
}

// Output:
// ok
29 changes: 29 additions & 0 deletions examples/gno.land/r/demo/boards2/z_1_b_filetest.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package main

import (
"std"

"gno.land/r/demo/boards2"
)

const (
owner = std.Address("g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5") // @test1
admin = std.Address("g1us8428u2a5satrlxzagqqa5m6vmuze025anjlj") // @test2
user = std.Address("g1w4ek2u33ta047h6lta047h6lta047h6ldvdwpn")
)

func init() {
// Add an admin user
std.TestSetOrigCaller(owner)
boards2.InviteMember(admin, boards2.RoleAdmin)

// Next call will be done by the admin user
std.TestSetOrigCaller(admin)
}

func main() {
boards2.InviteMember(user, boards2.RoleOwner)
}

// Error:
// only owners are allowed to invite other owners
30 changes: 30 additions & 0 deletions examples/gno.land/r/demo/boards2/z_1_c_filetest.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package main

import (
"std"

"gno.land/r/demo/boards2"
)

const (
owner = std.Address("g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5") // @test1
admin = std.Address("g1us8428u2a5satrlxzagqqa5m6vmuze025anjlj") // @test2
user = std.Address("g1w4ek2u33ta047h6lta047h6lta047h6ldvdwpn")
)

func init() {
// Add an admin user
std.TestSetOrigCaller(owner)
boards2.InviteMember(admin, boards2.RoleAdmin)

// Next call will be done by the admin user
std.TestSetOrigCaller(admin)
}

func main() {
boards2.InviteMember(user, boards2.RoleAdmin)
println("ok")
}

// Output:
// ok

0 comments on commit 2986a17

Please sign in to comment.