💾 Archived View for gemini.rmf-dev.com › repo › Vaati › Gemigit › files › ca074e618760e5bff246766f16… captured on 2023-03-20 at 18:03:51. Gemini links have been rewritten to link to archived content

View Raw

More Information

⬅️ Previous capture (2023-01-29)

🚧 View Differences

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

0 package httpgit

1

2 import (

3 "gemigit/access"

4 "gemigit/config"

5 "gemigit/db"

6 "log"

7 "net/http"

8 "strconv"

9 "strings"

10 "time"

11

12 githttpxfer "github.com/nulab/go-git-http-xfer/githttpxfer"

13 )

14

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

16 ghx, err := githttpxfer.New(path, "git")

17 if err != nil {

18 log.Fatalln("GitHTTPXfer instance could not be created. ",

19 err.Error())

20 }

21

22 chain := newChain()

23 chain.use(logging)

24 chain.use(basicAuth)

25 handler := chain.build(ghx)

26

27 log.Println("Http server started on port", port)

28 if err := http.ListenAndServe(":"+strconv.Itoa(port), handler);

29 err != nil {

30 log.Fatalln("ListenAndServe: ", err.Error())

31 }

32 }

33

34 type middleware func(http.Handler) http.Handler

35

36 func newChain() *chain {

37 return &chain{[]middleware{}}

38 }

39

40 type chain struct {

41 middlewares []middleware

42 }

43

44 func (c *chain) use(m middleware) {

45 c.middlewares = append(c.middlewares, m)

46 }

47

48 func (c *chain) build(h http.Handler) http.Handler {

49 for i := range c.middlewares {

50 h = c.middlewares[len(c.middlewares)-1-i](h)

51 }

52 return h

53 }

54

55 func logging(next http.Handler) http.Handler {

56 return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {

57 t1 := time.Now()

58 next.ServeHTTP(w, r)

59 t2 := time.Now()

60 realIP := r.Header.Get("X-Real-IP")

61 log.Println("["+realIP+"]["+r.Method+"]",

62 r.URL.String(), t2.Sub(t1))

63 })

64 }

65

66 func basicAuth(next http.Handler) http.Handler {

67 return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {

68 readOnly := false

69 params := strings.Split(r.URL.Path[1:], "/")

70 if len(params) < 2 {

71 renderNotFound(w)

72 return

73 }

74 if strings.Contains(r.URL.Path, "git-upload-pack") ||

75 strings.Contains(r.URL.RawQuery, "git-upload-pack") {

76 readOnly = true

77 b, err := db.IsRepoPublic(params[1], params[0])

78 if err != nil {

79 renderNotFound(w)

80 return

81 }

82 if b {

83 next.ServeHTTP(w, r)

84 return

85 }

86 }

87

88 username, password, ok := r.BasicAuth()

89 if !ok {

90 renderUnauthorized(w)

91 return

92 }

93 if username == "root#" && password == config.Cfg.Git.Key {

94 next.ServeHTTP(w, r)

95 return

96 }

97 if config.Cfg.Ldap.Enabled {

98 err := access.Login(username, password)

99 if err != nil {

100 log.Println(err.Error())

101 renderUnauthorized(w)

102 return

103 }

104

105 } else {

106 err := db.CheckAuth(username, password)

107 if err != nil {

108 log.Println(err.Error())

109 renderUnauthorized(w)

110 return

111 }

112 }

113 var err error

114 if readOnly {

115 err = access.HasReadAccess(params[1], params[0],

116 username)

117 } else {

118 err = access.HasWriteAccess(params[1], params[0],

119 username)

120 }

121 if err != nil {

122 log.Println(err.Error())

123 renderUnauthorized(w)

124 return

125 }

126 next.ServeHTTP(w, r)

127 })

128 }

129

130 func renderNotFound(w http.ResponseWriter) {

131 w.WriteHeader(http.StatusNotFound)

132 w.Write([]byte(http.StatusText(http.StatusNotFound)))

133 w.Header().Set("Content-Type", "text/plain")

134 }

135

136 func renderUnauthorized(w http.ResponseWriter) {

137 w.Header().Set("WWW-Authenticate", "Basic realm=\"" +

138 "Please enter your username and password.\"")

139 w.WriteHeader(http.StatusUnauthorized)

140 w.Write([]byte(http.StatusText(http.StatusUnauthorized)))

141 w.Header().Set("Content-Type", "text/plain")

142 }

143