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 }()
22}
23
24// Fetch registers Git fetch functionality for the given repo and key.
25func (cfg *Config) Fetch(repo string, pk ssh.PublicKey) {
26 if cfg.Cfg.Callbacks != nil {
27 cfg.Cfg.Callbacks.Fetch(repo)
28 }
29}
30
31// AuthRepo grants repo authorization to the given key.
32func (cfg *Config) AuthRepo(repo string, pk ssh.PublicKey) gm.AccessLevel {
33 return cfg.accessForKey(repo, pk)
34}
35
36// PasswordHandler returns whether or not password access is allowed.
37func (cfg *Config) PasswordHandler(ctx ssh.Context, password string) bool {
38 return (cfg.AnonAccess != "no-access") && cfg.AllowKeyless
39}
40
41// PublicKeyHandler returns whether or not the given public key may access the
42// repo.
43func (cfg *Config) PublicKeyHandler(ctx ssh.Context, pk ssh.PublicKey) bool {
44 return cfg.accessForKey("", pk) != gm.NoAccess
45}
46
47func (cfg *Config) accessForKey(repo string, pk ssh.PublicKey) gm.AccessLevel {
48 private := cfg.isPrivate(repo)
49 if repo == "config" {
50 private = true
51 }
52 for _, u := range cfg.Users {
53 for _, k := range u.PublicKeys {
54 apk, _, _, _, err := ssh.ParseAuthorizedKey([]byte(strings.TrimSpace(k)))
55 if err != nil {
56 log.Printf("error: malformed authorized key: '%s'", k)
57 return gm.NoAccess
58 }
59 if ssh.KeysEqual(pk, apk) {
60 if u.Admin {
61 return gm.AdminAccess
62 }
63 for _, r := range u.CollabRepos {
64 if repo == r {
65 return gm.ReadWriteAccess
66 }
67 }
68 if !private {
69 return gm.ReadOnlyAccess
70 }
71 }
72 }
73 }
74 if private && (cfg.AnonAccess != "read-write") {
75 return gm.NoAccess
76 }
77 switch cfg.AnonAccess {
78 case "no-access":
79 return gm.NoAccess
80 case "read-only":
81 return gm.ReadOnlyAccess
82 case "read-write":
83 return gm.ReadWriteAccess
84 default:
85 return gm.NoAccess
86 }
87}