1package replica
2
3import (
4 "fmt"
5 "strings"
6
7 "golang.org/x/crypto/ssh"
8)
9
10func ParseAllowedSigners(data []byte) ([]ssh.PublicKey, error) {
11 var keys []ssh.PublicKey
12 for n, line := range strings.Split(string(data), "\n") {
13 line = strings.TrimSpace(line)
14 if line == "" || strings.HasPrefix(line, "#") {
15 continue
16 }
17 i := strings.IndexAny(line, " \t")
18 if i < 0 {
19 return nil, fmt.Errorf("replica: allowed signers line %d: no key", n+1)
20 }
21 key, _, options, _, err := ssh.ParseAuthorizedKey([]byte(strings.TrimSpace(line[i:])))
22 if err != nil {
23 return nil, fmt.Errorf("replica: allowed signers line %d: %w", n+1, err)
24 }
25 if signsGit(options) {
26 keys = append(keys, key)
27 }
28 }
29 if len(keys) == 0 {
30 return nil, ErrNoAllowedKeys
31 }
32 return keys, nil
33}
34
35func signsGit(options []string) bool {
36 for _, o := range options {
37 if o == "cert-authority" {
38 return false
39 }
40 if v, ok := strings.CutPrefix(o, "namespaces="); ok {
41 for _, ns := range strings.Split(strings.Trim(v, `"`), ",") {
42 if ns == Namespace {
43 return true
44 }
45 }
46 return false
47 }
48 }
49 return true
50}