repos / git-pr

a self-hosted git collaboration server
git clone https://github.com/picosh/git-pr.git

git-pr / util
Eric Bower  ·  2025-08-22

util.go

  1package util
  2
  3import (
  4	"crypto/ed25519"
  5	"crypto/rand"
  6	"fmt"
  7	"io"
  8	"os"
  9	"path/filepath"
 10	"strings"
 11
 12	"golang.org/x/crypto/ssh"
 13)
 14
 15func CreateTmpDir() string {
 16	tmp, err := os.MkdirTemp(os.TempDir(), "git-pr*")
 17	if err != nil {
 18		panic(err)
 19	}
 20	return tmp
 21}
 22
 23func CreateCfgFile(dataDir, cfgTmpl string, adminKey UserSSH) string {
 24	cfgPath := filepath.Join(dataDir, "git-pr.toml")
 25	cfgFi, err := os.Create(cfgPath)
 26	if err != nil {
 27		panic(err)
 28	}
 29	_, _ = fmt.Fprintf(cfgFi, cfgTmpl, dataDir, adminKey.Public())
 30	_ = cfgFi.Close()
 31	return cfgPath
 32}
 33
 34type UserSSH struct {
 35	username string
 36	signer   ssh.Signer
 37}
 38
 39func NewUserSSH(username string, signer ssh.Signer) *UserSSH {
 40	return &UserSSH{
 41		username: username,
 42		signer:   signer,
 43	}
 44}
 45
 46func (s UserSSH) Public() string {
 47	pubkey := s.signer.PublicKey()
 48	return string(ssh.MarshalAuthorizedKey(pubkey))
 49}
 50
 51func (s UserSSH) MustCmd(patch []byte, cmd string) string {
 52	res, err := s.Cmd(patch, cmd)
 53	if err != nil {
 54		panic(err)
 55	}
 56	return res
 57}
 58
 59func (s UserSSH) Cmd(patch []byte, cmd string) (string, error) {
 60	host := "localhost:2222"
 61
 62	config := &ssh.ClientConfig{
 63		User: s.username,
 64		Auth: []ssh.AuthMethod{
 65			ssh.PublicKeys(s.signer),
 66		},
 67		HostKeyCallback: ssh.InsecureIgnoreHostKey(),
 68	}
 69
 70	client, err := ssh.Dial("tcp", host, config)
 71	if err != nil {
 72		return "", err
 73	}
 74	defer func() {
 75		_ = client.Close()
 76	}()
 77
 78	session, err := client.NewSession()
 79	if err != nil {
 80		return "", err
 81	}
 82	defer func() {
 83		_ = session.Close()
 84	}()
 85
 86	stdinPipe, err := session.StdinPipe()
 87	if err != nil {
 88		return "", err
 89	}
 90
 91	stdoutPipe, err := session.StdoutPipe()
 92	if err != nil {
 93		return "", err
 94	}
 95
 96	if err := session.Start(cmd); err != nil {
 97		return "", err
 98	}
 99
100	if patch != nil {
101		_, err = stdinPipe.Write(patch)
102		if err != nil {
103			return "", err
104		}
105	}
106
107	_ = stdinPipe.Close()
108
109	if err := session.Wait(); err != nil {
110		return "", err
111	}
112
113	buf := new(strings.Builder)
114	_, err = io.Copy(buf, stdoutPipe)
115	if err != nil {
116		return "", err
117	}
118
119	return buf.String(), nil
120}
121
122func GenerateKeys() (UserSSH, UserSSH) {
123	_, adminKey, err := ed25519.GenerateKey(rand.Reader)
124	if err != nil {
125		panic(err)
126	}
127
128	adminSigner, err := ssh.NewSignerFromKey(adminKey)
129	if err != nil {
130		panic(err)
131	}
132
133	_, userKey, err := ed25519.GenerateKey(rand.Reader)
134	if err != nil {
135		panic(err)
136	}
137
138	userSigner, err := ssh.NewSignerFromKey(userKey)
139	if err != nil {
140		panic(err)
141	}
142
143	return UserSSH{
144			username: "admin",
145			signer:   adminSigner,
146		}, UserSSH{
147			username: "contributor",
148			signer:   userSigner,
149		}
150}