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}