Skip to content Search Apps Documentation Source Content File Folder Download Copy Actions State String Boolean Number Struct Map Slice Pointer Function Closure Reference Nil Package Type Interface Unknown

Community realm. Read the code first. Community realm, deployed by its author. Read the code before you interact or send coins.

nestedpkg.gno

3.36 Kb · 107 lines
  1// Package nestedpkg provides helpers for package-path based access control.
  2// It is useful for upgrade patterns relying on namespaces.
  3//
  4// SECURITY: every exported helper takes `rlm realm` and reads both
  5// `rlm.PkgPath()` and `rlm.Previous().PkgPath()` to make an
  6// authorization decision. To close Class-2 designation forgery (a
  7// hostile realm stashes a captured realm value and passes it back to
  8// spoof identity), every helper gates on `rlm.IsCurrent()` first. The
  9// Is* predicates return false on stale rlm (fail-closed); the Assert*
 10// helpers panic. See docs/resources/gno-security.md.
 11package nestedpkg
 12
 13import "strings"
 14
 15// IsCallerSubPath checks if the caller realm is located in a subfolder of the current realm.
 16func IsCallerSubPath(_ int, rlm realm) bool {
 17	if !rlm.IsCurrent() {
 18		return false
 19	}
 20	var (
 21		curPath  = rlm.PkgPath() + "/"
 22		prevPath = rlm.Previous().PkgPath() + "/"
 23	)
 24	return strings.HasPrefix(prevPath, curPath)
 25}
 26
 27// AssertCallerIsSubPath panics if IsCallerSubPath returns false.
 28func AssertCallerIsSubPath(_ int, rlm realm) {
 29	if !rlm.IsCurrent() {
 30		panic("unauthorized: rlm is not the caller's live cur")
 31	}
 32	var (
 33		curPath  = rlm.PkgPath() + "/"
 34		prevPath = rlm.Previous().PkgPath() + "/"
 35	)
 36	if !strings.HasPrefix(prevPath, curPath) {
 37		panic("call restricted to nested packages. current realm is " + curPath + ", previous realm is " + prevPath)
 38	}
 39}
 40
 41// IsCallerParentPath checks if the caller realm is located in a parent location of the current realm.
 42func IsCallerParentPath(_ int, rlm realm) bool {
 43	if !rlm.IsCurrent() {
 44		return false
 45	}
 46	var (
 47		curPath  = rlm.PkgPath() + "/"
 48		prevPath = rlm.Previous().PkgPath() + "/"
 49	)
 50	return strings.HasPrefix(curPath, prevPath)
 51}
 52
 53// AssertCallerIsParentPath panics if IsCallerParentPath returns false.
 54func AssertCallerIsParentPath(_ int, rlm realm) {
 55	if !rlm.IsCurrent() {
 56		panic("unauthorized: rlm is not the caller's live cur")
 57	}
 58	var (
 59		curPath  = rlm.PkgPath() + "/"
 60		prevPath = rlm.Previous().PkgPath() + "/"
 61	)
 62	if !strings.HasPrefix(curPath, prevPath) {
 63		panic("call restricted to parent packages. current realm is " + curPath + ", previous realm is " + prevPath)
 64	}
 65}
 66
 67// IsSameNamespace checks if the caller realm and the current realm are in the same namespace.
 68func IsSameNamespace(_ int, rlm realm) bool {
 69	if !rlm.IsCurrent() {
 70		return false
 71	}
 72	var (
 73		curNs  = nsFromPath(rlm.PkgPath()) + "/"
 74		prevNs = nsFromPath(rlm.Previous().PkgPath()) + "/"
 75	)
 76	return curNs == prevNs
 77}
 78
 79// AssertIsSameNamespace panics if IsSameNamespace returns false.
 80func AssertIsSameNamespace(_ int, rlm realm) {
 81	if !rlm.IsCurrent() {
 82		panic("unauthorized: rlm is not the caller's live cur")
 83	}
 84	var (
 85		curNs  = nsFromPath(rlm.PkgPath()) + "/"
 86		prevNs = nsFromPath(rlm.Previous().PkgPath()) + "/"
 87	)
 88	if curNs != prevNs {
 89		panic("call restricted to packages from the same namespace. current realm is " + curNs + ", previous realm is " + prevNs)
 90	}
 91}
 92
 93// nsFromPath extracts the namespace from a package path.
 94func nsFromPath(pkgpath string) string {
 95	parts := strings.Split(pkgpath, "/")
 96
 97	// Specifically for gno.land, potential paths are in the form of DOMAIN/r/NAMESPACE/...
 98	// XXX: Consider extra checks.
 99	// XXX: Support non gno.land domains, where p/ and r/ won't be enforced.
100	if len(parts) >= 3 {
101		return parts[2]
102	}
103	return ""
104}
105
106// XXX: Consider adding IsCallerDirectlySubPath
107// XXX: Consider adding IsCallerDirectlyParentPath