diff --git a/distro-packages/Arch-Linux/skald-git/PKGBUILD b/distro-packages/Arch-Linux/skald-git/PKGBUILD index 4d41677..235704e 100644 --- a/distro-packages/Arch-Linux/skald-git/PKGBUILD +++ b/distro-packages/Arch-Linux/skald-git/PKGBUILD @@ -2,7 +2,7 @@ # shellcheck shell=bash disable=SC2034,SC2154 pkgname=skald-git -pkgver=0.0.0.r1552.ge31bffd +pkgver=0.0.0.r1553.g0c852e8 pkgrel=1 pkgdesc='Audio-only hall-based conferencing server' arch=('x86_64' 'aarch64') diff --git a/webserver/webserver.go b/webserver/webserver.go index 7845437..ec56d2a 100644 --- a/webserver/webserver.go +++ b/webserver/webserver.go @@ -689,17 +689,16 @@ func handleHallAction(w http.ResponseWriter, r *http.Request, hall string) { q := r.Form.Get("q") switch q { - case "delete": - filename := r.Form.Get("filename") - if hall == "" || filename == "" { - http.Error(w, "No filename provided", - http.StatusBadRequest) + case "confirm-delete": + filename, ok := recordingFilenameFromForm(w, r, hall) + if !ok { return } - if strings.ContainsRune(filename, '/') || - strings.ContainsRune(filename, filepath.Separator) { - http.Error(w, "Bad character in filename", - http.StatusBadRequest) + serveDeleteRecordingConfirmation(w, hall, filename) + return + case "delete": + filename, ok := recordingFilenameFromForm(w, r, hall) + if !ok { return } err := os.Remove( @@ -713,7 +712,7 @@ func handleHallAction(w http.ResponseWriter, r *http.Request, hall string) { httpError(w, err) return } - http.Redirect(w, r, "/recordings/"+hall+"/", + http.Redirect(w, r, recordingsHallPath(hall), http.StatusSeeOther) return default: @@ -721,6 +720,22 @@ func handleHallAction(w http.ResponseWriter, r *http.Request, hall string) { } } +func recordingFilenameFromForm(w http.ResponseWriter, r *http.Request, hall string) (string, bool) { + filename := r.Form.Get("filename") + if hall == "" || filename == "" { + http.Error(w, "No filename provided", + http.StatusBadRequest) + return "", false + } + if strings.ContainsRune(filename, '/') || + strings.ContainsRune(filename, filepath.Separator) { + http.Error(w, "Bad character in filename", + http.StatusBadRequest) + return "", false + } + return filename, true +} + func checkHallPermissions(w http.ResponseWriter, r *http.Request, hallname string) bool { user, pass, ok := r.BasicAuth() if !ok { @@ -758,6 +773,37 @@ func checkHallPermissions(w http.ResponseWriter, r *http.Request, hallname strin return true } +func recordingsHallPath(hall string) string { + parts := strings.Split(hall, "/") + for i, part := range parts { + parts[i] = url.PathEscape(part) + } + return "/recordings/" + strings.Join(parts, "/") + "/" +} + +func serveDeleteRecordingConfirmation(w http.ResponseWriter, hall string, filename string) { + hallPath := recordingsHallPath(hall) + escapedFilename := html.EscapeString(filename) + + w.Header().Set("content-type", "text/html; charset=utf-8") + w.Header().Set("cache-control", "no-cache") + + fmt.Fprintf(w, "\n
\n") + fmt.Fprintf(w, "Delete %v? This cannot be undone.
\n", escapedFilename) + fmt.Fprintf(w, + "\n", + hallPath, escapedFilename) + fmt.Fprintf(w, "\n", hallPath) + fmt.Fprintf(w, "\n") +} + func serveHallRecordings(w http.ResponseWriter, r *http.Request, f *os.File, hall string) { // read early, so we return permission errors to HEAD fis, err := f.Readdir(-1) @@ -793,11 +839,12 @@ func serveHallRecordings(w http.ResponseWriter, r *http.Request, f *os.File, hal fi.Size(), ) fmt.Fprintf(w, - "