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.

pkgpath.gno

3.31 Kb · 110 lines
  1package gnopm
  2
  3import "strings"
  4
  5// Parsing a gno package path far enough to know who owns it.
  6//
  7// A path is "<domain>/<kind>/<namespace>/<name...>", optionally ending in a
  8// "/vN" version element: "gno.land/p/moul/md/v1", "gno.land/r/sys/users",
  9// "gno.land/r/g1abc.../scratch/v0". The namespace is the third element and it
 10// is the whole reason this file exists: it decides whether a claim comes from
 11// the party that controls the path or from a stranger, which is the strongest
 12// signal the registry can offer about a claim it can never itself verify.
 13
 14// SplitPkgPath breaks a package path into its domain, kind ("p" or "r"),
 15// namespace and the remainder. ok is false for anything that is not shaped like
 16// a publishable gno path.
 17func SplitPkgPath(s string) (domain, kind, ns, rest string, ok bool) {
 18	if !ValidPkgPath(s) {
 19		return "", "", "", "", false
 20	}
 21	parts := strings.Split(s, "/")
 22	return parts[0], parts[1], parts[2], strings.Join(parts[3:], "/"), true
 23}
 24
 25// Namespace returns the owning namespace of a package path, or "" if the path
 26// is not one.
 27func Namespace(s string) string {
 28	_, _, ns, _, ok := SplitPkgPath(s)
 29	if !ok {
 30		return ""
 31	}
 32	return ns
 33}
 34
 35// Version returns the trailing "vN" element of a package path, or "" when the
 36// path carries none. Absent is legal and is not an error: gnoweb serves
 37// gno.land/u/<name> by calling the realm at exactly /r/<name>/home, so that one
 38// path can never carry a version.
 39func Version(s string) string {
 40	parts := strings.Split(s, "/")
 41	if len(parts) < 4 {
 42		return ""
 43	}
 44	last := parts[len(parts)-1]
 45	if len(last) < 2 || last[0] != 'v' {
 46		return ""
 47	}
 48	for i := 1; i < len(last); i++ {
 49		if last[i] < '0' || last[i] > '9' {
 50			return ""
 51		}
 52	}
 53	return last
 54}
 55
 56// ValidPkgPath reports whether s is shaped like a publishable gno package path.
 57//
 58// It does NOT say the path exists on any chain, and cannot: a realm has no way
 59// to ask whether some other path was ever deployed. That gap is the registry's
 60// central honesty problem and is documented on Registry.
 61func ValidPkgPath(s string) bool {
 62	if s == "" || len(s) > MaxPkgPathLen {
 63		return false
 64	}
 65	if strings.HasPrefix(s, "/") || strings.HasSuffix(s, "/") || strings.Contains(s, "//") {
 66		return false
 67	}
 68	parts := strings.Split(s, "/")
 69	if len(parts) < 4 {
 70		return false
 71	}
 72	// The domain, which is a host and so must carry a dot.
 73	if !strings.Contains(parts[0], ".") {
 74		return false
 75	}
 76	if parts[1] != "p" && parts[1] != "r" {
 77		return false
 78	}
 79	for _, p := range parts {
 80		if p == "" || p == "." || p == ".." {
 81			return false
 82		}
 83		for i := 0; i < len(p); i++ {
 84			if !pathByteOK(p[i]) {
 85				return false
 86			}
 87		}
 88	}
 89	return true
 90}
 91
 92// AddressNamespace reports whether ns is shaped like a gno bech32 address, the
 93// namespace every account owns without registering anything. A caller still
 94// has to check it is the claimant's own address; this only says which of the
 95// two ownership rules applies.
 96func AddressNamespace(ns string) bool {
 97	if len(ns) != 40 || !strings.HasPrefix(ns, "g1") {
 98		return false
 99	}
100	for i := 2; i < len(ns); i++ {
101		if !strings.ContainsRune(bech32Charset, rune(ns[i])) {
102			return false
103		}
104	}
105	return true
106}
107
108// bech32Charset is bech32's data alphabet: lowercase alphanumerics minus the
109// four characters it drops to avoid transcription errors (1, b, i, o).
110const bech32Charset = "023456789acdefghjklmnpqrstuvwxyz"