203 lines
5.5 KiB
Go
203 lines
5.5 KiB
Go
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)
|
|
}
|
|
}
|
|
|
|
// 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 user.ID != repo.UserID {
|
|
if admin, _ := database.IsMemberAdmin(user.ID, repo.TeamID); 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)
|
|
}
|