This commit is contained in:
julien 2025-07-03 14:35:39 +02:00
parent 86fbed85a9
commit 94b9e74b08

View File

@ -4,18 +4,18 @@ import (
"app/shelfly/internal/download"
"app/shelfly/internal/library"
"app/shelfly/internal/login"
"app/shelfly/internal/models"
"app/shelfly/internal/users"
"app/shelfly/renders"
"encoding/base64"
"fmt"
"golang.org/x/crypto/bcrypt"
"log"
"net/http"
"os"
"path/filepath"
"strings"
"time"
"golang.org/x/crypto/bcrypt"
"app/shelfly/internal/models"
"github.com/gorilla/mux"
"golang.org/x/net/webdav"
@ -35,6 +35,7 @@ func checkUserCredentials(db *gorm.DB, email string, password string) bool {
err := bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(password))
return err == nil
}
type spaHandler struct {
staticPath string
indexPath string
@ -97,55 +98,55 @@ func RoutesPublic(r *mux.Router, bd *gorm.DB) {
http.Error(w, "Erreur lors de la génération de la playlist", http.StatusInternalServerError)
}
})
r.PathPrefix("/webdav/").Handler(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
authHeader := req.Header.Get("Authorization")
if authHeader == "" {
w.Header().Set("WWW-Authenticate", `Basic realm="Restricted"`)
http.Error(w, "Unauthorized", http.StatusUnauthorized)
return
}
r.PathPrefix("/webdav/").Handler(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
authHeader := req.Header.Get("Authorization")
if authHeader == "" {
w.Header().Set("WWW-Authenticate", `Basic realm="Restricted"`)
http.Error(w, "Unauthorized", http.StatusUnauthorized)
return
}
// Authentification HTTP Basic en base de données
email, password, ok := req.BasicAuth()
if !ok {
w.Header().Set("WWW-Authenticate", `Basic realm="Restricted"`)
http.Error(w, "Unauthorized", http.StatusUnauthorized)
return
}
log.Printf("✅ email saisi: %s", email)
log.Printf("✅ password saisi: %s", password)
// Authentification HTTP Basic en base de données
email, password, ok := req.BasicAuth()
if !ok {
w.Header().Set("WWW-Authenticate", `Basic realm="Restricted"`)
http.Error(w, "Unauthorized", http.StatusUnauthorized)
return
}
log.Printf("✅ email saisi: %s", email)
log.Printf("✅ password saisi: %s", password)
var user models.User
result := bd.Where("email = ?", email).First(&user)
if result.Error != nil {
w.Header().Set("WWW-Authenticate", `Basic realm="Restricted"`)
http.Error(w, "Unauthorized", http.StatusUnauthorized)
return
}
var user models.User
result := bd.Where("email = ?", email).First(&user)
if result.Error != nil {
w.Header().Set("WWW-Authenticate", `Basic realm="Restricted"`)
http.Error(w, "Unauthorized", http.StatusUnauthorized)
return
}
err := bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(password))
if err != nil {
w.Header().Set("WWW-Authenticate", `Basic realm="Restricted"`)
http.Error(w, "Unauthorized", http.StatusUnauthorized)
return
}
err := bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(password))
if err != nil {
w.Header().Set("WWW-Authenticate", `Basic realm="Restricted"`)
http.Error(w, "Unauthorized", http.StatusUnauthorized)
return
}
// ✅ Ici on autorise TOUTES les méthodes WebDAV (lecture/écriture/suppression)
log.Printf("✅ WebDAV FULL ACCESS for user: %s", email)
// ✅ Ici on autorise TOUTES les méthodes WebDAV (lecture/écriture/suppression)
log.Printf("✅ WebDAV FULL ACCESS for user: %s", email)
// Headers WebDAV que certains clients attendent
w.Header().Set("DAV", "1,2")
w.Header().Set("MS-Author-Via", "DAV")
// Headers WebDAV que certains clients attendent
w.Header().Set("DAV", "1,2")
w.Header().Set("MS-Author-Via", "DAV")
// Handler WebDAV complet
webdavHandler := &webdav.Handler{
Prefix: "/webdav/",
FileSystem: webdav.Dir("/app/upload"),
LockSystem: webdav.NewMemLS(),
}
// Handler WebDAV complet
webdavHandler := &webdav.Handler{
Prefix: "/webdav/",
FileSystem: webdav.Dir("/app/upload"),
LockSystem: webdav.NewMemLS(),
}
webdavHandler.ServeHTTP(w, req)
}))
webdavHandler.ServeHTTP(w, req)
}))
// WebDAV sécurisé
// username := "tonuser" // ton login
@ -223,16 +224,39 @@ func RoutesProtected(r *mux.Router, bd *gorm.DB) {
r.HandleFunc("/validate-path", download.PathValidationHandler)
r.HandleFunc("/folders", renders.StreamHandler)
r.HandleFunc("/folders/detail", renders.DetailHandler).Methods("GET")
r.HandleFunc("/folders/detail", renders.DetailHandler).Methods("GET")
r.HandleFunc("/api/paths/{id:[0-9]+}/media", renders.PathMedia(bd)).Methods("GET")
// r.HandleFunc("/stream/{partID:[0-9]+}", renders.Stream(bd)).Methods("GET")
r.HandleFunc("/media/{partID:[0-9]+}", renders.MediaDetail(bd)).Methods("GET")
r.HandleFunc("/hls/{partID:[0-9]+}/{file}", renders.HLSStream(bd)).Methods("GET")
r.HandleFunc("/hls/{partID:[0-9]+}/", renders.HLSStream(bd)).Methods("GET")
r.HandleFunc("/api/paths/{id:[0-9]+}/media", renders.PathMedia(bd)).Methods("GET")
// r.HandleFunc("/stream/{partID:[0-9]+}", renders.Stream(bd)).Methods("GET")
r.HandleFunc("/media/{partID:[0-9]+}", renders.MediaDetail(bd)).Methods("GET")
r.HandleFunc("/hls/{partID:[0-9]+}/{file}", renders.HLSStream(bd)).Methods("GET")
r.HandleFunc("/hls/{partID:[0-9]+}/", renders.HLSStream(bd)).Methods("GET")
//API Scan folder
// —————— JSON API routes ——————
r.HandleFunc("/api/dashboard", renders.DashboardJSON(db)).Methods("GET")
r.HandleFunc("/api/menu-library", renders.MenuLibraryJSON(db)).Methods("GET")
r.HandleFunc("/api/settings", renders.SettingsJSON()).Methods("GET")
r.HandleFunc("/api/library", renders.LibraryJSON()).Methods("GET")
r.HandleFunc("/api/godownloader/download", renders.GoDownloadJSON()).Methods("GET")
r.HandleFunc("/api/godownloader/linkcollectors", renders.GoDownloadLinkCollectorsJSON()).Methods("GET")
r.HandleFunc("/api/godownloader/settings/delete", renders.GoDownloadSettingDeleteJSON(db)).Methods("POST")
r.HandleFunc("/api/godownloader/settings/toggle", renders.GoDownloadSettingToggleActiveJSON(db)).Methods("POST")
r.HandleFunc("/api/godownloader/settings", renders.GoDownloadSettingJSON(db)).Methods("GET", "POST")
r.HandleFunc("/api/godownloader/settings/table", renders.GoDownloadPartialTableJSON(db)).Methods("GET")
r.HandleFunc("/api/godownloader2", renders.GoDownload2JSON(db)).Methods("GET")
r.HandleFunc("/api/add-job", renders.HandleAddJobJSON(db)).Methods("POST")
r.HandleFunc("/api/jobs/list", renders.HandleListJobsPartialJSON(db)).Methods("GET")
r.HandleFunc("/api/add-jobs-multiple", renders.HandleAddJobsMultipleJSON(db)).Methods("POST")
r.HandleFunc("/api/stream", renders.StreamHandlerJSON()).Methods("GET")
r.HandleFunc("/api/pathmedia/{id}", renders.PathMediaJSON(db)).Methods("GET")
r.HandleFunc("/api/media/detail/{partID}", renders.MediaDetailJSON(db)).Methods("GET")
}
// func RoutesProtected(r *mux.Router, db *gorm.DB) {
// // —————— HTML routes ——————
// r.HandleFunc("/login", Login).Methods("GET")
@ -289,9 +313,9 @@ r.HandleFunc("/hls/{partID:[0-9]+}/", renders.HLSStream(bd)).Methods("GET")
// r.HandleFunc("/api/stream", StreamHandlerJSON()).Methods("GET")
// r.HandleFunc("/api/pathmedia/{id}", PathMediaJSON(db)).Methods("GET")
// r.HandleFunc("/api/media/detail/{partID}", MediaDetailJSON(db)).Methods("GET")
// }
// r.HandleFunc("/api/pathmedia/{id}", PathMediaJSON(db)).Methods("GET")
// r.HandleFunc("/api/media/detail/{partID}", MediaDetailJSON(db)).Methods("GET")
// }
func StreamHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "text/event-stream")
w.Header().Set("Cache-Control", "no-cache")