--- a/access/access.go Sun Apr 28 02:00:26 2019 -0300
+++ b/access/access.go Mon Apr 29 01:48:57 2019 -0300
@@ -51,7 +51,7 @@
+ global [numPerms][]_key // parse calls inderectly UnmarshalYAML, it's caller's duty to control the access to a.
@@ -79,23 +79,23 @@
groups := make(map[string][]_key)
- for i, v := range dummy.Groups {
- if isPublic([]byte(i)) {
- log.Errorf("access: %q group is reserved, ignored", i)
+ for name, v := range dummy.Groups { + if isPublic([]byte(name)) { + log.Errorf("access: %q group is reserved, ignored", name) - if _, exists := groups[i]; exists {
- log.Errorf("access: group %q registered twice", i)
+ if _, exists := groups[name]; exists { + log.Errorf("access: group %q registered twice", name) for _, keyFile := range v {
- k, err := loadKey(keyFile)
+ k, err := loadKeys(keyFile) - if _, ok := groups[i]; !ok {
- // if group "i" fail to load every key, this stops
+ if _, ok := groups[name]; !ok { + // if group "name" fail to load every key, this stops // setPath routines to load group names as keys
@@ -103,9 +103,11 @@
keys = append(keys, _key{fprint: v})
- groups[i] = append(groups[i], keys...)
+ groups[name] = append(groups[name], keys...) + gperms := [numPerms][]string{dummy.Global.Init, dummy.Global.Read, dummy.Global.Write} + a.setGlobals(groups, gperms) for i, v := range dummy.Patterns {
globs, err := filepath.Glob(filepath.Join(reposDir, i))
@@ -113,11 +115,9 @@
log.Errorf("malformed pattern %q: %v", i, err)
for _, path := range globs {
- a.setPathInit(path, v.Init, groups)
- a.setPathRead(path, v.Read, groups)
- a.setPathWrite(path, v.Write, groups)
+ perms := [numPerms][]string{v.Init, v.Read, v.Write} + a.setPath(path, perms, groups) @@ -136,75 +136,80 @@
-func (a *Access) setPathInit(path string, init []string, groups map[string][]_key) {
- for _, key := range init {
- if _, ok := groups[key]; ok {
- // set permissions on groups key
- for i := range groups[key] {
+func (a *Access) setPath(path string, perms [numPerms][]string, groups map[string][]_key) { + for p, yamlPerm := range perms { + // casting p is not required as of current Go tip (1.13) + // see: http://golang.org/issues/19113 + perm := Perm(1 << uint32(p)) - a.addToPath(path, Init, k)
+ if len(yamlPerm) == 0 { + a.addToPath(path, perm, a.global[0]...) - ks, err := loadKey(key)
+ for _, keyOrGroup := range yamlPerm { + // if it's a group, just copy what we already loaded + if _, ok := groups[keyOrGroup]; ok { + // set permissions on groups key + for i := range groups[keyOrGroup] { + k := groups[keyOrGroup][i] + a.addToPath(path, perm, k) + // this is likely to change, it's here just to remember later. + if keyOrGroup == "public" { + a.addToPath(path, perm, a.global[p]...) + ks, err := loadKeys(keyOrGroup) + keys := make([]_key, 0, len(ks)) + keys = append(keys, _key{fprint: v}) + a.addToPath(path, perm, keys...) - keys := make([]_key, 0, len(ks))
- keys = append(keys, _key{fprint: v})
- a.addToPath(path, Init, keys...)
-func (a *Access) setPathRead(path string, read []string, groups map[string][]_key) {
- for _, key := range read {
- if _, ok := groups[key]; ok {
- // set permissions on groups key
- for i := range groups[key] {
- a.addToPath(path, Read, k)
+func (a *Access) setGlobals(groups map[string][]_key, perms [numPerms][]string) { + for p, keyOrGroup := range perms { + // casting p is not required as of current Go tip (1.13) + // see: http://golang.org/issues/19113 + perm.set(Perm(1 << uint32(p))) + for _, name := range keyOrGroup { + // if it's a group, just copy what we already loaded + if _, found := groups[name]; found { + keys := make([]_key, 0, len(groups[name])+1) + for _, v := range groups[name] { + a.global[p] = append(a.global[p], keys...)
- ks, err := loadKey(key)
- keys := make([]_key, 0, len(ks))
- keys = append(keys, _key{fprint: v})
+ // this is likely to change, it's here just to remember later. + a.global[p] = append(a.global[p], _key{fprint: "public", p: perm}) + k, err := loadKeys(name) + keys := make([]_key, 0, len(k)) + keys = append(keys, _key{fprint: v, p: perm}) + a.global[p] = append(a.global[p], keys...) - a.addToPath(path, Read, keys...)
-func (a *Access) setPathWrite(path string, write []string, groups map[string][]_key) {
- for _, key := range write {
- if _, ok := groups[key]; ok {
- // set permissions on groups key
- for i := range groups[key] {
- a.addToPath(path, Write, k)
- ks, err := loadKey(key)
- keys := make([]_key, 0, len(ks))
- keys = append(keys, _key{fprint: v})
- a.addToPath(path, Write, keys...)
@@ -252,12 +257,12 @@
-// loadKey reads repoPath/hgkeeper/keys/name and tries to
-// parse as an authorized keys format, and returns its fingerprint
-func loadKey(name string) ([]string, error) {
- f, err := os.Open(filepath.Join(keysDir, name))
+// loadKeys reads file trying to parse it as an authorized key +// format, returning the finger prints of all keys found +func loadKeys(file string) ([]string, error) { + f, err := os.Open(filepath.Join(keysDir, file)) - return nil, fmt.Errorf("loadKey %q: %v", name, err)
+ return nil, fmt.Errorf("loadKeys %q: %v", file, err) keys := make([]string, 0, 20)
@@ -271,7 +276,7 @@
pub, _, _, _, err := ssh.ParseAuthorizedKey([]byte(key))
- log.Errorf("loadKey %q:%d: %v", name, line, err)
+ log.Errorf("loadKeys %q:%d: %v", file, line, err) keys = append(keys, ssh.FingerprintSHA256(pub))
--- a/access/permissions.go Sun Apr 28 02:00:26 2019 -0300
+++ b/access/permissions.go Mon Apr 29 01:48:57 2019 -0300
@@ -8,6 +8,7 @@
// String returns a textual representation of the perm.
--- a/go.mod Sun Apr 28 02:00:26 2019 -0300
+++ b/go.mod Mon Apr 29 01:48:57 2019 -0300
@@ -4,7 +4,10 @@
github.com/alecthomas/kong v0.1.16
github.com/go-yaml/yaml v2.1.0+incompatible
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51
+ github.com/kr/pretty v0.1.0 // indirect github.com/sirupsen/logrus v1.4.1
github.com/stretchr/testify v1.3.0
golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a
+ gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect + gopkg.in/yaml.v2 v2.2.2 // indirect --- a/go.sum Sun Apr 28 02:00:26 2019 -0300
+++ b/go.sum Mon Apr 29 01:48:57 2019 -0300
@@ -8,7 +8,13 @@
github.com/go-yaml/yaml v2.1.0+incompatible/go.mod h1:w2MrLa16VYP0jy6N7M5kHaCkaLENm+P+Tv+MfurjSw0=
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
+github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
+github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/sirupsen/logrus v1.4.1 h1:GL2rEmy6nsikmW0r8opw9JIRScdMF5hA8cOYLH7In1k=
@@ -23,3 +29,8 @@
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e h1:nFYrTHrdrAOpShe27kaFHjsqYSEQ0KWqdWLu3xuZJts=
golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=