krz/gitbay

A CLI-first git forge.

clone: git clone https://gitbay.org/krz/gitbay.git

main: internal/policy/names.go · raw

 1// Package policy holds access-control and naming rules.
 2package policy
 3
 4import (
 5	"fmt"
 6	"regexp"
 7)
 8
 9// reservedNames are forbidden as usernames and org names because they are, or
10// will be, top-level web routes (the UI serves /<owner>/<name>). Any change to
11// the httpd mux's top-level routes must be reflected here; the httpd package
12// asserts this in its tests.
13var reservedNames = map[string]bool{
14	"admin":    true,
15	"api":      true,
16	"archive":  true,
17	"explore":  true,
18	"login":    true,
19	"logout":   true,
20	"new":      true,
21	"raw":      true,
22	"register": true,
23	"settings": true,
24	"static":   true,
25}
26
27// namePat matches valid user, org, and repo names: lowercase alphanumerics,
28// dot, dash, underscore; must start with an alphanumeric. Dots are further
29// restricted by ValidateName to avoid "." / ".." and ".git" suffixes.
30var namePat = regexp.MustCompile(`^[a-z0-9][a-z0-9._-]{0,62}$`)
31
32// ValidateOwnerName checks a username or org name.
33func ValidateOwnerName(name string) error {
34	if err := ValidateName(name); err != nil {
35		return err
36	}
37	if reservedNames[name] {
38		return fmt.Errorf("name %q is reserved", name)
39	}
40	return nil
41}
42
43// ValidateName checks a repo name (reserved words are allowed for repos;
44// routes are namespaced under the owner).
45func ValidateName(name string) error {
46	if !namePat.MatchString(name) {
47		return fmt.Errorf("invalid name %q: lowercase letters, digits, '.', '-', '_' only; must start with a letter or digit; max 63 chars", name)
48	}
49	if name == "." || name == ".." {
50		return fmt.Errorf("invalid name %q", name)
51	}
52	if len(name) > 4 && name[len(name)-4:] == ".git" {
53		return fmt.Errorf("invalid name %q: must not end in .git", name)
54	}
55	return nil
56}
57
58// Reserved reports whether name is a reserved route word. Exported so the
59// httpd tests can assert route/reserved-list agreement.
60func Reserved(name string) bool { return reservedNames[name] }