landingpage/http.go

120 lines
3.2 KiB
Go
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package main
import (
"io"
"log"
"net/http"
"net/http/httputil"
"net/url"
"os"
"path"
"regexp"
"strings"
)
var regexASCII = regexp.MustCompile(`\[\d+m`)
func httpIndex(w http.ResponseWriter, r *http.Request) {
if r.URL.Path != "/" && r.URL.Path != "/auth/authorize" {
http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
return
}
data, _ := os.ReadFile(wwwRoot + "/index.html")
w.Write(data)
}
func httpUnauthorized(w http.ResponseWriter, r *http.Request) {
http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
}
func httpBad(w http.ResponseWriter, r *http.Request) {
http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
}
func httpLogs(w http.ResponseWriter, r *http.Request) {
response, err := http.Get("http://observer/logs")
if err != nil || response.StatusCode >= 300 {
log.Printf("Observer /logs fails: %s", err)
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
}
defer response.Body.Close()
data, err := io.ReadAll(response.Body)
if err != nil {
log.Printf("Issue with fetch the logs: %s", err)
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
}
logs := regexASCII.ReplaceAllLiteralString(string(data), "")
w.Write([]byte(logs))
}
func httpSupervisorProxy(w http.ResponseWriter, r *http.Request) {
log.Printf("Proxy request: %s", r.URL.Path)
// Base Supervisor URL
supervisorHost := "supervisor"
if development && os.Getenv("SUPERVISOR_HOST") != "" {
supervisorHost = os.Getenv("SUPERVISOR_HOST")
}
u, err := url.Parse("http://" + supervisorHost + "/")
if err != nil {
// Handle error in parsing URL
w.Write([]byte(err.Error()))
return
}
// Strip "/supervisor/" from the path
trimmedPath := strings.TrimPrefix(r.URL.Path, "/supervisor/")
// Split the path into parts, the first part is the subpath (e.g., resolution or network)
parts := strings.SplitN(trimmedPath, "/", 2)
if len(parts) < 2 {
http.Error(w, "Bad request: missing path", http.StatusBadRequest)
log.Printf("Invalid path: %s", r.URL.Path)
return
}
// Extract subpath (e.g., resolution or network)
subPath := parts[0]
// The remainder path (after the subpath) to be sanitized
remainderPath := "/" + parts[1]
// Clean the remainder path to avoid path traversal attacks
cleanPath := path.Clean(remainderPath)
// Ensure it's under the intended subpath (e.g., /resolution or /network)
if cleanPath != remainderPath {
http.Error(w, "Forbidden: Invalid path", http.StatusForbidden)
log.Printf("Blocked path traversal attempt: %s", cleanPath)
return
}
// Update the request path to be forwarded
r.URL.Path = "/" + subPath + cleanPath
// Create the reverse proxy
proxy := httputil.NewSingleHostReverseProxy(u)
// Add authorization header
r.Header.Add("Authorization", "Bearer "+os.Getenv("SUPERVISOR_TOKEN"))
if cleanPath == "/logs" {
// for logs download add text/plain headers
r.Header.Add("Accept", "text/plain")
} else if cleanPath == "/logs/follow" {
// Set FlushInterval to enable streaming
proxy.FlushInterval = -1
}
// Forward the request
proxy.ServeHTTP(w, r)
}