💾 Archived View for gemini.rmf-dev.com › repo › Vaati › Gemigit › files › 2d02fe7c1b740dff30b5a7bbc8… captured on 2024-02-05 at 09:49:12. Gemini links have been rewritten to link to archived content

View Raw

More Information

⬅️ Previous capture (2023-12-28)

-=-=-=-=-=-=-

Go Back

0 package sshgit

1

2 import (

3 "github.com/gliderlabs/ssh"

4 "gemigit/access"

5 "gemigit/config"

6 "gemigit/db"

7 "log"

8 "strconv"

9 "strings"

10 "os/exec"

11 "os"

12 gossh "golang.org/x/crypto/ssh"

13 )

14

15 func handle(s ssh.Session) {

16

17 invalidPath := []byte("Invalid path\n")

18 notFound := []byte("Repository not found\n")

19 forbidden := []byte("Access forbidden\n")

20 readCommand := s.Command()[0] == "git-upload-pack"

21 writeCommand := s.Command()[0] == "git-receive-pack"

22

23 if (!readCommand && !writeCommand) {

24 s.Stderr().Write([]byte("invalid command\n"))

25 return

26 }

27 if len(s.Command()) < 2 {

28 s.Stderr().Write(invalidPath)

29 return

30 }

31 arg := s.Command()[1]

32 if arg[0] != '/' {

33 s.Stderr().Write(invalidPath)

34 return

35 }

36 arg = arg[1:]

37 if arg[len(arg) - 1] == '/' {

38 arg = arg[:len(arg) - 1]

39 }

40 args := strings.Split(arg, "/")

41 if len(args) != 2 {

42 s.Stderr().Write(invalidPath)

43 return

44 }

45 owner := args[0]

46 repo := args[1]

47 username := s.User()

48 password := s.Context().Value("password").(string)

49 readOnly := readCommand

50

51 public := false

52 if config.Cfg.Git.Public {

53 var err error

54 public, err = db.IsRepoPublic(repo, owner)

55 if err != nil {

56 s.Stderr().Write(notFound)

57 log.Println(err.Error())

58 return

59 }

60 }

61

62 if !public || !readOnly {

63 pass, err := db.CanUsePassword(repo, owner, username)

64 if err != nil {

65 log.Println(err.Error())

66 s.Stderr().Write(forbidden)

67 return

68 }

69 err = access.Login(username, password, true, pass, !readOnly)

70 if err != nil {

71 log.Println(err.Error())

72 s.Stderr().Write([]byte(err.Error() + "\n"))

73 return

74 }

75 if readOnly {

76 err = access.HasReadAccess(repo, owner, username)

77 } else {

78 err = access.HasWriteAccess(repo, owner, username)

79 }

80 if err != nil {

81 log.Println(err.Error())

82 s.Stderr().Write(forbidden)

83 return

84 }

85 }

86

87 var command string

88 if writeCommand {

89 command = "git-receive-pack"

90 } else {

91 command = "git-upload-pack"

92 }

93 cmd := exec.Command(command,

94 config.Cfg.Git.Path + "/" + owner + "/" + repo)

95 cmd.Stdin = s

96 cmd.Stdout = s

97 if err := cmd.Run(); err != nil {

98 log.Println(err)

99 return

100 }

101 }

102

103 func Listen(path string, address string, port int) {

104 var server ssh.Server

105 server.Handle(handle)

106 server.KeyboardInteractiveHandler = func(ctx ssh.Context,

107 challenge gossh.KeyboardInteractiveChallenge) bool {

108 if ctx.User() == "anon" {

109 ctx.SetValue("password", "")

110 return true

111 }

112 answers, err := challenge("", "",

113 []string{"password:"}, []bool{false})

114 if err != nil {

115 log.Println(err)

116 return false

117 }

118 ctx.SetValue("password", answers[0])

119 return true

120 }

121

122 server.Addr = config.Cfg.Git.SSH.Address + ":" +

123 strconv.Itoa(config.Cfg.Git.SSH.Port)

124 server.PasswordHandler = ssh.PasswordHandler(

125 func(ctx ssh.Context, password string) bool {

126 ctx.SetValue("password", password)

127 return true

128 })

129 data, err := os.ReadFile(config.Cfg.Gemini.Key)

130 if err != nil {

131 log.Fatalln(err)

132 return

133 }

134 key, err := gossh.ParsePrivateKey(data)

135 if err != nil {

136 log.Fatalln(err)

137 return

138 }

139 server.AddHostKey(key)

140 log.Println("SSH server started on port", config.Cfg.Git.SSH.Port)

141 if err := server.ListenAndServe(); err != nil {

142 log.Fatalln(err)

143 }

144 }

145