1package config
2
3import (
4 "log"
5 "strings"
6
7 gm "github.com/charmbracelet/wish/git"
8 "github.com/gliderlabs/ssh"
9 gossh "golang.org/x/crypto/ssh"
10)
11
12// Push registers Git push functionality for the given repo and key.
13func (cfg *Config) Push(repo string, pk ssh.PublicKey) {
14 go func() {
15 err := cfg.Reload()
16 if err != nil {
17 log.Printf("error reloading after push: %s", err)
18 }
19 if cfg.Cfg.Callbacks != nil {
20 cfg.Cfg.Callbacks.Push(repo)
21 }
22 r, err := cfg.Source.GetRepo(repo)
23 if err != nil {
24 log.Printf("error getting repo after push: %s", err)
25 return
26 }
27 err = r.UpdateServerInfo()
28 if err != nil {
29 log.Printf("error updating server info after push: %s", err)
30 }
31 }()
32}
33
34// Fetch registers Git fetch functionality for the given repo and key.
35func (cfg *Config) Fetch(repo string, pk ssh.PublicKey) {
36 if cfg.Cfg.Callbacks != nil {
37 cfg.Cfg.Callbacks.Fetch(repo)
38 }
39}
40
41// AuthRepo grants repo authorization to the given key.
42func (cfg *Config) AuthRepo(repo string, pk ssh.PublicKey) gm.AccessLevel {
43 return cfg.accessForKey(repo, pk)
44}
45
46// PasswordHandler returns whether or not password access is allowed.
47func (cfg *Config) PasswordHandler(ctx ssh.Context, password string) bool {
48 return (cfg.AnonAccess != "no-access") && cfg.AllowKeyless
49}
50
51// KeyboardInteractiveHandler returns whether or not keyboard interactive is allowed.
52func (cfg *Config) KeyboardInteractiveHandler(ctx ssh.Context, _ gossh.KeyboardInteractiveChallenge) bool {
53 return (cfg.AnonAccess != "no-access") && cfg.AllowKeyless
54}
55
56// PublicKeyHandler returns whether or not the given public key may access the
57// repo.
58func (cfg *Config) PublicKeyHandler(ctx ssh.Context, pk ssh.PublicKey) bool {
59 return cfg.accessForKey("", pk) != gm.NoAccess
60}
61
62func (cfg *Config) accessForKey(repo string, pk ssh.PublicKey) gm.AccessLevel {
63 private := cfg.isPrivate(repo)
64 for _, u := range cfg.Users {
65 for _, k := range u.PublicKeys {
66 apk, _, _, _, err := ssh.ParseAuthorizedKey([]byte(strings.TrimSpace(k)))
67 if err != nil {
68 log.Printf("error: malformed authorized key: '%s'", k)
69 return gm.NoAccess
70 }
71 if ssh.KeysEqual(pk, apk) {
72 if u.Admin {
73 return gm.AdminAccess
74 }
75 for _, r := range u.CollabRepos {
76 if repo == r {
77 return gm.ReadWriteAccess
78 }
79 }
80 if !private {
81 return gm.ReadOnlyAccess
82 }
83 }
84 }
85 }
86 if private && len(cfg.Users) > 0 {
87 return gm.NoAccess
88 }
89 switch cfg.AnonAccess {
90 case "no-access":
91 return gm.NoAccess
92 case "read-only":
93 return gm.ReadOnlyAccess
94 case "read-write":
95 return gm.ReadWriteAccess
96 case "admin-access":
97 return gm.AdminAccess
98 default:
99 return gm.NoAccess
100 }
101}