package server import ( "context" "fmt" "log" "net/http" "strings" "time" "github.com/gorilla/mux" "gitea.teamortix.com/team-ortix/coverage/db" ) const cookieName = "gitea_m_lord" // AuthorizationMiddleware is a middleware for requests to report endpoints to validate that users are authorized. // It automatically sets a refresh cookie to keep it updated. func AuthorizationMiddleware(resource func(http.ResponseWriter, *http.Request)) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) namespace := vars["namespace"] project := vars["project"] // It's a public repository :). if canAccessRepo(http.DefaultClient, namespace, project) { resource(w, r) return } cookie, err := r.Cookie(cookieName) if err != nil && err != http.ErrNoCookie { log.Printf("Could not get cookie: %v\n", err) http.Error(w, "could not process this request", http.StatusInternalServerError) return } // They don't have the cookie, so we redirect them to log in. if err == http.ErrNoCookie { url := db.GenerateNewToken(r.URL.String()) http.Redirect(w, r, url, http.StatusTemporaryRedirect) return } // Convert the cookie token to an OAuth token. client, newToken, err := db.Authorize(cookie.Value) if err != nil { url := db.GenerateNewToken(r.URL.String()) http.Redirect(w, r, url, http.StatusTemporaryRedirect) return } http.SetCookie(w, &http.Cookie{ Name: cookieName, Value: newToken, Expires: time.Now().Add(time.Hour * 24 * 7), }) // We can use the configured http client to check if they can access with credentials. if !canAccessRepo(client, namespace, project) { http.Error(w, "404 page not found", http.StatusNotFound) return } resource(w, r) }) } const repoURL = "https://gitea.teamortix.com/api/v1/repos/%s/%s" func canAccessRepo(client *http.Client, namespace, project string) bool { req, cancel := newClientWithTimeout(fmt.Sprintf(repoURL, namespace, project)) defer cancel() res, err := client.Do(req) if err != nil { log.Printf("could not do request: %s\n", err) return false } err = res.Body.Close() if err != nil { log.Printf("could close req body: %s\n", err) return false } if res.StatusCode != 200 { return false } return true } func newClientWithTimeout(url string) (*http.Request, context.CancelFunc) { ctx, cancel := context.WithTimeout( context.Background(), time.Second*5, ) r := strings.NewReader("") req, err := http.NewRequestWithContext(ctx, "GET", url, r) if err != nil { cancel() log.Fatalf("could not create new http request: %v", err) } return req, cancel }