214 lines
5.0 KiB
Go
214 lines
5.0 KiB
Go
// backend/server_folders_proxy.go
|
|
|
|
package main
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"net/url"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
type serverFoldersAgentConfig struct {
|
|
MilestoneHost string
|
|
Scheme string
|
|
Port string
|
|
Token string
|
|
}
|
|
|
|
func (s *Server) handleProxyListServerFolders(w http.ResponseWriter, r *http.Request) {
|
|
s.proxyServerFoldersRequest(w, r, http.MethodGet)
|
|
}
|
|
|
|
func (s *Server) handleProxyCreateServerFolder(w http.ResponseWriter, r *http.Request) {
|
|
s.proxyServerFoldersRequest(w, r, http.MethodPost)
|
|
}
|
|
|
|
func (s *Server) proxyServerFoldersRequest(w http.ResponseWriter, r *http.Request, method string) {
|
|
config, err := s.getServerFoldersAgentConfig(r.Context())
|
|
if err != nil {
|
|
writeError(w, http.StatusBadGateway, "Server-Folders-Agent-Konfiguration konnte nicht geladen werden")
|
|
return
|
|
}
|
|
|
|
targetURL, err := serverFoldersAgentURL(config, forwardedServerFoldersQuery(r.URL.Query()))
|
|
if err != nil {
|
|
writeError(w, http.StatusBadGateway, err.Error())
|
|
return
|
|
}
|
|
|
|
var body []byte
|
|
if method == http.MethodPost {
|
|
body, err = io.ReadAll(io.LimitReader(r.Body, 1<<20))
|
|
if err != nil {
|
|
writeError(w, http.StatusBadRequest, "Request konnte nicht gelesen werden")
|
|
return
|
|
}
|
|
}
|
|
|
|
request, err := http.NewRequestWithContext(
|
|
r.Context(),
|
|
method,
|
|
targetURL,
|
|
bytes.NewReader(body),
|
|
)
|
|
if err != nil {
|
|
writeError(w, http.StatusBadGateway, "Proxy-Request konnte nicht erstellt werden")
|
|
return
|
|
}
|
|
|
|
request.Header.Set("Accept", "application/json")
|
|
|
|
if method == http.MethodPost {
|
|
request.Header.Set("Content-Type", "application/json")
|
|
}
|
|
|
|
if config.Token != "" {
|
|
request.Header.Set("X-Server-Folders-Token", config.Token)
|
|
}
|
|
|
|
client := &http.Client{
|
|
Timeout: 20 * time.Second,
|
|
}
|
|
|
|
response, err := client.Do(request)
|
|
if err != nil {
|
|
writeError(w, http.StatusBadGateway, "Server-Folders-Agent ist nicht erreichbar")
|
|
return
|
|
}
|
|
defer response.Body.Close()
|
|
|
|
responseBody, err := io.ReadAll(io.LimitReader(response.Body, 4<<20))
|
|
if err != nil {
|
|
writeError(w, http.StatusBadGateway, "Antwort vom Server-Folders-Agent konnte nicht gelesen werden")
|
|
return
|
|
}
|
|
|
|
contentType := response.Header.Get("Content-Type")
|
|
if strings.TrimSpace(contentType) == "" {
|
|
contentType = "application/json"
|
|
}
|
|
|
|
w.Header().Set("Content-Type", contentType)
|
|
w.WriteHeader(response.StatusCode)
|
|
_, _ = w.Write(responseBody)
|
|
}
|
|
|
|
func (s *Server) getServerFoldersAgentConfig(ctx context.Context) (serverFoldersAgentConfig, error) {
|
|
var config serverFoldersAgentConfig
|
|
|
|
err := s.db.QueryRow(
|
|
ctx,
|
|
`
|
|
SELECT
|
|
host,
|
|
COALESCE(server_folders_agent_scheme, 'http'),
|
|
COALESCE(server_folders_agent_port, '8099'),
|
|
COALESCE(pgp_sym_decrypt(server_folders_agent_token_encrypted, $1), '')
|
|
FROM milestone_settings
|
|
WHERE id = 1
|
|
LIMIT 1
|
|
`,
|
|
s.milestoneEncryptionKey(),
|
|
).Scan(
|
|
&config.MilestoneHost,
|
|
&config.Scheme,
|
|
&config.Port,
|
|
&config.Token,
|
|
)
|
|
if err != nil {
|
|
return config, err
|
|
}
|
|
|
|
config.Scheme = normalizeServerFoldersAgentScheme(config.Scheme)
|
|
if config.Scheme == "" {
|
|
config.Scheme = "http"
|
|
}
|
|
|
|
config.Port = normalizeServerFoldersAgentPort(config.Port)
|
|
if config.Port == "" {
|
|
config.Port = "8099"
|
|
}
|
|
|
|
config.MilestoneHost = strings.TrimSpace(config.MilestoneHost)
|
|
config.Token = strings.TrimSpace(config.Token)
|
|
|
|
return config, nil
|
|
}
|
|
|
|
func serverFoldersAgentURL(config serverFoldersAgentConfig, rawQuery string) (string, error) {
|
|
if strings.TrimSpace(config.MilestoneHost) == "" {
|
|
return "", fmt.Errorf("Milestone Host fehlt")
|
|
}
|
|
|
|
normalizedMilestoneHost := strings.TrimSpace(config.MilestoneHost)
|
|
if !strings.Contains(normalizedMilestoneHost, "://") {
|
|
normalizedMilestoneHost = "http://" + normalizedMilestoneHost
|
|
}
|
|
|
|
parsedMilestoneURL, err := url.Parse(normalizedMilestoneHost)
|
|
if err != nil || parsedMilestoneURL.Hostname() == "" {
|
|
return "", fmt.Errorf("Milestone Host ist ungültig")
|
|
}
|
|
|
|
agentURL := url.URL{
|
|
Scheme: config.Scheme,
|
|
Host: parsedMilestoneURL.Hostname() + ":" + config.Port,
|
|
Path: "/server-folders",
|
|
RawQuery: rawQuery,
|
|
}
|
|
|
|
return agentURL.String(), nil
|
|
}
|
|
|
|
func forwardedServerFoldersQuery(values url.Values) string {
|
|
// rootType=storage/archive wird bewusst weitergeleitet.
|
|
// Nur Verbindungs-/Auth-Parameter werden entfernt.
|
|
nextValues := url.Values{}
|
|
|
|
for key, value := range values {
|
|
switch strings.ToLower(strings.TrimSpace(key)) {
|
|
case "schema", "scheme", "agentschema", "agentscheme", "port", "agentport", "token", "agenttoken":
|
|
continue
|
|
default:
|
|
for _, item := range value {
|
|
nextValues.Add(key, item)
|
|
}
|
|
}
|
|
}
|
|
|
|
return nextValues.Encode()
|
|
}
|
|
|
|
func normalizeServerFoldersAgentScheme(value string) string {
|
|
value = strings.TrimSpace(strings.ToLower(value))
|
|
|
|
switch value {
|
|
case "", "http", "https":
|
|
return value
|
|
default:
|
|
return ""
|
|
}
|
|
}
|
|
|
|
func normalizeServerFoldersAgentPort(value string) string {
|
|
value = strings.TrimSpace(value)
|
|
value = strings.TrimPrefix(value, ":")
|
|
|
|
if value == "" {
|
|
return ""
|
|
}
|
|
|
|
for _, char := range value {
|
|
if char < '0' || char > '9' {
|
|
return ""
|
|
}
|
|
}
|
|
|
|
return value
|
|
}
|