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