Skip to content

Commit

Permalink
feat: add keeper user check
Browse files Browse the repository at this point in the history
Signed-off-by: gfanton <8671905+gfanton@users.noreply.github.com>
  • Loading branch information
gfanton committed Jul 1, 2024
1 parent ea1ff3f commit 4a3e5aa
Show file tree
Hide file tree
Showing 2 changed files with 137 additions and 0 deletions.
39 changes: 39 additions & 0 deletions gno.land/cmd/gnoland/testdata/addpkg_namespace.txtar
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
loadpkg gno.land/r/demo/users

adduser gui

gnoland start

## test address namespace

! gnokey maketx addpkg -pkgdir $WORK -pkgpath gno.land/r/$USER_ADDR_test1/one -gas-fee 1000000ugnot -gas-wanted 100000000 -broadcast -chainid=tendermint_test gui
stderr 'unauthorized user'

gnokey maketx addpkg -pkgdir $WORK -pkgpath gno.land/r/$USER_ADDR_gui/one -gas-fee 1000000ugnot -gas-wanted 100000000 -broadcast -chainid=tendermint_test gui
stdout 'OK!'

## test unregister namespace

! gnokey maketx addpkg -pkgdir $WORK -pkgpath gno.land/r/guiland/one -gas-fee 1000000ugnot -gas-wanted 100000000 -broadcast -chainid=tendermint_test test1
stderr 'unauthorized user'

## test register namespace

## XXX: THE FOLLOWING LINES REQUIRE BEING ABLE TO SET examples/gno.land/r/demo/users/users.admin=<test1_addr>
# gnokey maketx call -pkgpath gno.land/r/demo/users -func Invite -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test -args $USER_ADDR_gui test1
# stdout 'OK!'

# gnokey maketx call -pkgpath gno.land/r/demo/users -func Register -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test -args $USER_ADDR_test1 -args 'guiland' -args 'im gui' gui
# stdout 'OK!'

# gnokey maketx addpkg -pkgdir $WORK -pkgpath gno.land/r/guiland/one -gas-fee 1000000ugnot -gas-wanted 100000000 -broadcast -chainid=tendermint_test gui
# stdout 'OK!'

-- one.gno --
package one

func Render(path string) string {
return "# Hello One"
}


98 changes: 98 additions & 0 deletions gno.land/pkg/sdk/vm/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,13 @@ import (
"context"
"fmt"
"os"
"path/filepath"
"regexp"
"strings"

gno "github.com/gnolang/gno/gnovm/pkg/gnolang"
"github.com/gnolang/gno/gnovm/stdlibs"
"github.com/gnolang/gno/tm2/pkg/crypto"
"github.com/gnolang/gno/tm2/pkg/errors"
"github.com/gnolang/gno/tm2/pkg/sdk"
"github.com/gnolang/gno/tm2/pkg/sdk/auth"
Expand All @@ -23,6 +26,11 @@ import (
"go.opentelemetry.io/otel/metric"
)

var (
ErrInvalidRealm = errors.New("invalid realm")
ErrUnauthorizedUser = errors.New("unauthorized user")
)

const (
maxAllocTx = 500 * 1000 * 1000
maxAllocQuery = 1500 * 1000 * 1000 // higher limit for queries
Expand Down Expand Up @@ -135,6 +143,92 @@ func (vm *VMKeeper) getGnoStore(ctx sdk.Context) gno.Store {
}
}

// Namespace can be either a user or crypto address.
// XXX: Uppercase should be valid but transform into lowercase ?
var reNamespace = regexp.MustCompile(`^gno.land/(?:r|p)/([a-zA-Z]+[_a-zA-Z0-9]+)`)

// checkNamespacePermission check if
func (vm *VMKeeper) checkNamespacePermission(ctx sdk.Context, creator crypto.Address, pkgPath string) error {
const sysUsersPkg = "gno.land/r/demo/users"

store := vm.getGnoStore(ctx)

// if `sysUsersPkg` does not exists -> skip validation.
usersPkg := store.GetPackage(sysUsersPkg, false)
if usersPkg == nil {
return nil
}

// XXX: is this necessary ?
pkgPath = filepath.Clean(pkgPath) // cleanup pkgpath

match := reNamespace.FindStringSubmatch(pkgPath)
if len(match) != 2 {
return fmt.Errorf("%w: %q", ErrInvalidRealm, pkgPath)
}
username := match[1]

// Lowercase username
username = strings.ToLower(username)

// Allow user with their own address as namespace
if addr, err := crypto.AddressFromBech32(username); err == nil {
if addr.Compare(creator) == 0 {
return nil
}

return fmt.Errorf("%w: %q", ErrUnauthorizedUser, username)
}

// Parse and run the files, construct *PV.
pkgAddr := gno.DerivePkgAddr(pkgPath)
msgCtx := stdlibs.ExecContext{
ChainID: ctx.ChainID(),
Height: ctx.BlockHeight(),
Timestamp: ctx.BlockTime().Unix(),
OrigCaller: creator.Bech32(),
OrigSendSpent: new(std.Coins),
OrigPkgAddr: pkgAddr.Bech32(),
// XXX: should we remove the banker ?
Banker: NewSDKBanker(vm, ctx),
EventLogger: ctx.EventLogger(),
}

m := gno.NewMachineWithOptions(
gno.MachineOptions{
PkgPath: "",
Output: os.Stdout, // XXX
Store: store,
Context: msgCtx,
Alloc: store.GetAllocator(),
MaxCycles: vm.maxCycles,
GasMeter: ctx.GasMeter(),
})
defer m.Release()

// call $sysUsersPkg.GetUserByName("<user>")
// We only need to check by name here, as address have already been check
mpv := gno.NewPackageNode("main", "main", nil).NewPackage()
m.SetActivePackage(mpv)
m.RunDeclaration(gno.ImportD("users", sysUsersPkg))
x := gno.Call(
gno.Sel(gno.Nx("users"), "GetUserByName"),
gno.Str(username),
)

ret := m.Eval(x)
if len(ret) == 0 {
panic("invalid response length call")
}

// If value is nil, no user has been registered for this namespace
if user := ret[0]; user.V == nil {
return fmt.Errorf("%w: %q", ErrUnauthorizedUser, username)
}

return nil
}

// AddPackage adds a package with given fileset.
func (vm *VMKeeper) AddPackage(ctx sdk.Context, msg MsgAddPackage) (err error) {
creator := msg.Creator
Expand Down Expand Up @@ -177,6 +271,10 @@ func (vm *VMKeeper) AddPackage(ctx sdk.Context, msg MsgAddPackage) (err error) {
// - check if caller is in Admins or Editors.
// - check if namespace is not in pause.

if err := vm.checkNamespacePermission(ctx, creator, pkgPath); err != nil {
return err
}

err = vm.bank.SendCoins(ctx, creator, pkgAddr, deposit)
if err != nil {
return err
Expand Down

0 comments on commit 4a3e5aa

Please sign in to comment.