forked from harness/harness
-
Notifications
You must be signed in to change notification settings - Fork 0
/
handler.go
224 lines (186 loc) · 6.1 KB
/
handler.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
package handler
import (
"fmt"
"log"
"net/http"
"net/url"
"github.com/drone/drone/pkg/database"
. "github.com/drone/drone/pkg/model"
)
// ErrorHandler wraps the default http.HandleFunc to handle an
// error as the return value.
type ErrorHandler func(w http.ResponseWriter, r *http.Request) error
func (h ErrorHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if err := h(w, r); err != nil {
log.Print(err)
}
}
// UserHandler wraps the default http.HandlerFunc to include
// the currently authenticated User in the method signature,
// in addition to handling an error as the return value.
type UserHandler func(w http.ResponseWriter, r *http.Request, user *User) error
func (h UserHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
user, err := readUser(r)
if err != nil {
redirectLogin(w, r)
return
}
if err = h(w, r, user); err != nil {
log.Print(err)
RenderError(w, err, http.StatusBadRequest)
}
}
// AdminHandler wraps the default http.HandlerFunc to include
// the currently authenticated User in the method signature,
// in addition to handling an error as the return value. It also
// verifies the user has Administrative privileges.
type AdminHandler func(w http.ResponseWriter, r *http.Request, user *User) error
func (h AdminHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
user, err := readUser(r)
if err != nil {
redirectLogin(w, r)
return
}
// User MUST have administrative privileges in order
// to execute the handler.
if user.Admin == false {
RenderNotFound(w)
return
}
if err = h(w, r, user); err != nil {
log.Print(err)
RenderError(w, err, http.StatusBadRequest)
}
}
// PublicHandler wraps the default http.HandlerFunc to include
// requested Repository in the method signature, in addition
// to handling an error as the return value.
type PublicHandler func(w http.ResponseWriter, r *http.Request, repo *Repo) error
func (h PublicHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// repository name from the URL parameters
hostParam := r.FormValue(":host")
userParam := r.FormValue(":owner")
nameParam := r.FormValue(":name")
repoName := fmt.Sprintf("%s/%s/%s", hostParam, userParam, nameParam)
repo, err := database.GetRepoSlug(repoName)
if err != nil || repo == nil {
RenderNotFound(w)
return
}
h(w, r, repo)
return
}
// RepoHandler wraps the default http.HandlerFunc to include
// the currently authenticated User and requested Repository
// in the method signature, in addition to handling an error
// as the return value.
type RepoHandler func(w http.ResponseWriter, r *http.Request, user *User, repo *Repo) error
func (h RepoHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// repository name from the URL parameters
hostParam := r.FormValue(":host")
userParam := r.FormValue(":owner")
nameParam := r.FormValue(":name")
repoName := fmt.Sprintf("%s/%s/%s", hostParam, userParam, nameParam)
repo, err := database.GetRepoSlug(repoName)
if err != nil || repo == nil {
RenderNotFound(w)
return
}
// retrieve the user from the database
user, err := readUser(r)
// if the user is not found, we can still
// serve the page assuming the repository
// is public.
switch {
case err != nil && repo.Private == true:
redirectLogin(w, r)
return
case err != nil && repo.Private == false:
h(w, r, nil, repo)
return
}
// The User must own the repository OR be a member
// of the Team that owns the repository OR the repo
// must not be private.
if repo.Private && user.ID != repo.UserID {
if member, _ := database.IsMember(user.ID, repo.TeamID); !member {
RenderNotFound(w)
return
}
}
if err = h(w, r, user, repo); err != nil {
log.Print(err)
RenderError(w, err, http.StatusBadRequest)
}
}
// RepoHandler wraps the default http.HandlerFunc to include
// the currently authenticated User and requested Repository
// in the method signature, in addition to handling an error
// as the return value.
type RepoAdminHandler func(w http.ResponseWriter, r *http.Request, user *User, repo *Repo) error
func (h RepoAdminHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
user, err := readUser(r)
if err != nil {
redirectLogin(w, r)
return
}
// repository name from the URL parameters
hostParam := r.FormValue(":host")
userParam := r.FormValue(":owner")
nameParam := r.FormValue(":name")
repoName := fmt.Sprintf("%s/%s/%s", hostParam, userParam, nameParam)
repo, err := database.GetRepoSlug(repoName)
if err != nil {
RenderNotFound(w)
return
}
// The User must own the repository OR be a member
// of the Team that owns the repository.
if admin, _ := database.IsRepoAdmin(user, repo); admin == false {
RenderNotFound(w)
return
}
if err = h(w, r, user, repo); err != nil {
log.Print(err)
RenderError(w, err, http.StatusBadRequest)
}
}
// helper function that reads the currently authenticated
// user from the given http.Request.
func readUser(r *http.Request) (*User, error) {
username := GetCookie(r, "_sess")
if len(username) == 0 {
return nil, fmt.Errorf("No user session")
}
// get the user from the database
user, err := database.GetUserEmail(username)
if err != nil || user == nil || user.ID == 0 {
return nil, err
}
return user, nil
}
// helper function that retrieves the repository based
// on the URL parameters
func readRepo(r *http.Request) (*Repo, error) {
// get the repo data from the URL parameters
hostParam := r.FormValue(":host")
userParam := r.FormValue(":owner")
nameParam := r.FormValue(":slug")
repoSlug := fmt.Sprintf("%s/%s/%s", hostParam, userParam, nameParam)
// get the repo from the database
return database.GetRepoSlug(repoSlug)
}
// helper function that sends the user to the login page.
func redirectLogin(w http.ResponseWriter, r *http.Request) {
v := url.Values{}
v.Add("return_to", r.URL.String())
http.Redirect(w, r, "/login?"+v.Encode(), http.StatusSeeOther)
}
func renderNotFound(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusNotFound)
RenderTemplate(w, "404.amber", nil)
}
func renderBadRequest(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusBadRequest)
RenderTemplate(w, "500.amber", nil)
}