fixing some functions

This commit is contained in:
2026-06-04 17:32:11 +07:00
parent 2a79993f43
commit b933cbe9ee
6 changed files with 847 additions and 20 deletions
+110 -19
View File
@@ -16,6 +16,47 @@ import (
"github.com/sirupsen/logrus"
)
const (
acmeChallengePrefix = "/.well-known/acme-challenge/"
acmeWellknownPrefix = "/.well-known/acme-wellknown/"
)
// IsAcmeWellKnownPath reports whether path is an ACME HTTP-01 challenge URL.
func IsAcmeWellKnownPath(path string) bool {
return strings.HasPrefix(path, acmeChallengePrefix) || strings.HasPrefix(path, acmeWellknownPrefix)
}
func acmeTokenFromPath(path string) (token string, layout string, ok bool) {
switch {
case strings.HasPrefix(path, acmeChallengePrefix):
layout = acmeChallengePrefix
token = strings.TrimPrefix(path, acmeChallengePrefix)
case strings.HasPrefix(path, acmeWellknownPrefix):
layout = acmeWellknownPrefix
token = strings.TrimPrefix(path, acmeWellknownPrefix)
default:
return "", "", false
}
if token == "" || strings.Contains(token, "..") {
return "", "", false
}
return token, layout, true
}
func acmeFilePaths(wellKnownDir, token string) []string {
return []string{
filepath.Join(wellKnownDir, "acme-challenge", token),
filepath.Join(wellKnownDir, token),
}
}
func defaultAcmeWritePath(wellKnownDir, token, layout string) string {
if layout == acmeWellknownPrefix {
return filepath.Join(wellKnownDir, token)
}
return filepath.Join(wellKnownDir, "acme-challenge", token)
}
// stripHostPort возвращает только имя хоста, если в строке был порт.
func stripHostPort(host string) string {
h, _, err := net.SplitHostPort(host)
@@ -143,9 +184,15 @@ type reverseProxiesHandler struct {
func (rph reverseProxiesHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
logrus.Infof("Incoming request: %s %s from %s (Host: %s)", r.Method, r.URL.Path, r.RemoteAddr, r.Host)
if strings.HasPrefix(r.URL.Path, "/.well-known/acme-wellknown/") {
logrus.Infof("Handling .well-known/acme-wellknown request: %s", r.URL.Path)
rph.handleWellKnown(w, r)
if strings.HasPrefix(r.URL.Path, acmeChallengePrefix) || strings.HasPrefix(r.URL.Path, acmeWellknownPrefix) {
token, layout, ok := acmeTokenFromPath(r.URL.Path)
if !ok {
logrus.Warnf("Invalid .well-known path: %s", r.URL.Path)
http.Error(w, "Invalid path", http.StatusBadRequest)
return
}
logrus.Infof("Handling ACME well-known request: %s (layout=%s)", r.URL.Path, layout)
rph.handleWellKnown(w, r, token, layout)
return
}
@@ -194,7 +241,7 @@ func (rph reverseProxiesHandler) getHostList() []string {
return hosts
}
func (rph reverseProxiesHandler) handleWellKnown(w http.ResponseWriter, r *http.Request) {
func (rph reverseProxiesHandler) handleWellKnown(w http.ResponseWriter, r *http.Request, token, layout string) {
// Проверяем и при необходимости монтируем NFS перед обработкой
if err := nfs.EnsureMounted(); err != nil {
logrus.Errorf("Failed to ensure NFS is mounted: %v", err)
@@ -202,23 +249,18 @@ func (rph reverseProxiesHandler) handleWellKnown(w http.ResponseWriter, r *http.
return
}
path := strings.TrimPrefix(r.URL.Path, "/.well-known/acme-wellknown/")
if path == "" || strings.Contains(path, "..") {
logrus.Warnf("Invalid .well-known path: %s", r.URL.Path)
http.Error(w, "Invalid path", http.StatusBadRequest)
return
}
fullPath := filepath.Join(rph.WellKnownDir, path)
logrus.Infof("Well-known request: method=%s, path=%s, fullPath=%s", r.Method, path, fullPath)
paths := acmeFilePaths(rph.WellKnownDir, token)
logrus.Infof("Well-known request: method=%s, token=%s, layout=%s, paths=%v",
r.Method, token, layout, paths)
switch r.Method {
case "GET", "HEAD":
data, err := ioutil.ReadFile(fullPath)
data, _, err := readFirstExisting(paths)
if err != nil {
if os.IsNotExist(err) {
http.NotFound(w, r)
return
}
logrus.Errorf("Error reading file %s: %v", fullPath, err)
logrus.Errorf("Error reading ACME challenge files %v: %v", paths, err)
http.Error(w, "Internal server error", http.StatusInternalServerError)
return
}
@@ -234,14 +276,18 @@ func (rph reverseProxiesHandler) handleWellKnown(w http.ResponseWriter, r *http.
http.Error(w, "Bad request", http.StatusBadRequest)
return
}
dir := filepath.Dir(fullPath)
writePath := existingAcmePath(paths)
if writePath == "" {
writePath = defaultAcmeWritePath(rph.WellKnownDir, token, layout)
}
dir := filepath.Dir(writePath)
if err := os.MkdirAll(dir, 0755); err != nil {
logrus.Errorf("Error creating directory %s: %v", dir, err)
http.Error(w, "Internal server error", http.StatusInternalServerError)
return
}
if err := ioutil.WriteFile(fullPath, data, 0644); err != nil {
logrus.Errorf("Error writing file %s: %v", fullPath, err)
if err := ioutil.WriteFile(writePath, data, 0644); err != nil {
logrus.Errorf("Error writing file %s: %v", writePath, err)
http.Error(w, "Internal server error", http.StatusInternalServerError)
return
}
@@ -252,12 +298,12 @@ func (rph reverseProxiesHandler) handleWellKnown(w http.ResponseWriter, r *http.
w.Write([]byte("File created successfully"))
}
case "DELETE":
if err := os.Remove(fullPath); err != nil {
if err := removeFirstExisting(paths); err != nil {
if os.IsNotExist(err) {
http.NotFound(w, r)
return
}
logrus.Errorf("Error deleting file %s: %v", fullPath, err)
logrus.Errorf("Error deleting ACME challenge files %v: %v", paths, err)
http.Error(w, "Internal server error", http.StatusInternalServerError)
return
}
@@ -267,3 +313,48 @@ func (rph reverseProxiesHandler) handleWellKnown(w http.ResponseWriter, r *http.
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
}
}
func readFirstExisting(paths []string) ([]byte, string, error) {
var lastErr error
for _, path := range paths {
data, err := ioutil.ReadFile(path)
if err == nil {
return data, path, nil
}
if !os.IsNotExist(err) {
return nil, "", err
}
lastErr = err
}
if lastErr == nil {
lastErr = os.ErrNotExist
}
return nil, "", lastErr
}
func existingAcmePath(paths []string) string {
for _, path := range paths {
if _, err := os.Stat(path); err == nil {
return path
}
}
return ""
}
func removeFirstExisting(paths []string) error {
var lastErr error
for _, path := range paths {
err := os.Remove(path)
if err == nil {
return nil
}
if !os.IsNotExist(err) {
return err
}
lastErr = err
}
if lastErr == nil {
lastErr = os.ErrNotExist
}
return lastErr
}