nestedpkg.gno

2.76 Kb ยท 89 lines
 1// Package nestedpkg provides helpers for package-path based access control.
 2// It is useful for upgrade patterns relying on namespaces.
 3package nestedpkg
 4
 5// To test this from a realm and have std.CurrentRealm/PreviousRealm work correctly,
 6// this file is tested from gno.land/r/demo/tests/nestedpkg_test.gno
 7// XXX: move test to ths directory once we support testing a package and
 8// specifying values for both PreviousRealm and CurrentRealm.
 9
10import (
11	"std"
12	"strings"
13)
14
15// IsCallerSubPath checks if the caller realm is located in a subfolder of the current realm.
16func IsCallerSubPath() bool {
17	var (
18		cur  = std.CurrentRealm().PkgPath() + "/"
19		prev = std.PreviousRealm().PkgPath() + "/"
20	)
21	return strings.HasPrefix(prev, cur)
22}
23
24// AssertCallerIsSubPath panics if IsCallerSubPath returns false.
25func AssertCallerIsSubPath() {
26	var (
27		cur  = std.CurrentRealm().PkgPath() + "/"
28		prev = std.PreviousRealm().PkgPath() + "/"
29	)
30	if !strings.HasPrefix(prev, cur) {
31		panic("call restricted to nested packages. current realm is " + cur + ", previous realm is " + prev)
32	}
33}
34
35// IsCallerParentPath checks if the caller realm is located in a parent location of the current realm.
36func IsCallerParentPath() bool {
37	var (
38		cur  = std.CurrentRealm().PkgPath() + "/"
39		prev = std.PreviousRealm().PkgPath() + "/"
40	)
41	return strings.HasPrefix(cur, prev)
42}
43
44// AssertCallerIsParentPath panics if IsCallerParentPath returns false.
45func AssertCallerIsParentPath() {
46	var (
47		cur  = std.CurrentRealm().PkgPath() + "/"
48		prev = std.PreviousRealm().PkgPath() + "/"
49	)
50	if !strings.HasPrefix(cur, prev) {
51		panic("call restricted to parent packages. current realm is " + cur + ", previous realm is " + prev)
52	}
53}
54
55// IsSameNamespace checks if the caller realm and the current realm are in the same namespace.
56func IsSameNamespace() bool {
57	var (
58		cur  = nsFromPath(std.CurrentRealm().PkgPath()) + "/"
59		prev = nsFromPath(std.PreviousRealm().PkgPath()) + "/"
60	)
61	return cur == prev
62}
63
64// AssertIsSameNamespace panics if IsSameNamespace returns false.
65func AssertIsSameNamespace() {
66	var (
67		cur  = nsFromPath(std.CurrentRealm().PkgPath()) + "/"
68		prev = nsFromPath(std.PreviousRealm().PkgPath()) + "/"
69	)
70	if cur != prev {
71		panic("call restricted to packages from the same namespace. current realm is " + cur + ", previous realm is " + prev)
72	}
73}
74
75// nsFromPath extracts the namespace from a package path.
76func nsFromPath(pkgpath string) string {
77	parts := strings.Split(pkgpath, "/")
78
79	// Specifically for gno.land, potential paths are in the form of DOMAIN/r/NAMESPACE/...
80	// XXX: Consider extra checks.
81	// XXX: Support non gno.land domains, where p/ and r/ won't be enforced.
82	if len(parts) >= 3 {
83		return parts[2]
84	}
85	return ""
86}
87
88// XXX: Consider adding IsCallerDirectlySubPath
89// XXX: Consider adding IsCallerDirectlyParentPath