Checkpoint audio-only Skald fork work

This commit is contained in:
Storm Dragon
2026-05-18 13:06:57 -04:00
parent a8ada950d5
commit 965347cad4
48 changed files with 1080 additions and 3651 deletions
+16 -16
View File
@@ -50,7 +50,7 @@ func checkPasswordAdmin(w http.ResponseWriter, r *http.Request, hallname, user s
desc, err := hall.GetDescription(hallname)
if err != nil {
internalError(w,
"Get description for group %v: %v",
"Get description for hall %v: %v",
hallname, err,
)
return false
@@ -168,15 +168,15 @@ func apiHandler(w http.ResponseWriter, r *http.Request) {
return
}
w.Header().Set("cache-control", "no-cache")
sendJSON(w, r, stats.GetGroups())
sendJSON(w, r, stats.GetHalls())
case ".halls":
apiGroupHandler(w, r, rest)
apiHallHandler(w, r, rest)
default:
http.NotFound(w, r)
}
}
func apiGroupHandler(w http.ResponseWriter, r *http.Request, pth string) {
func apiHallHandler(w http.ResponseWriter, r *http.Request, pth string) {
first, kind, rest := splitPath(pth)
g := ""
if first != "" {
@@ -193,12 +193,12 @@ func apiGroupHandler(w http.ResponseWriter, r *http.Request, pth string) {
methodNotAllowed(w, "HEAD, GET")
return
}
groups, err := hall.GetDescriptionNames()
halls, err := hall.GetDescriptionNames()
if err != nil {
httpError(w, err)
return
}
sendJSON(w, r, groups)
sendJSON(w, r, halls)
return
}
@@ -562,7 +562,7 @@ func tokensHandler(w http.ResponseWriter, r *http.Request, g, pth string) {
}
if g != "" {
// check that the group exists
// check that the hall exists
_, err := hall.GetDescription(g)
if err != nil {
httpError(w, err)
@@ -592,7 +592,7 @@ func tokensHandler(w http.ResponseWriter, r *http.Request, g, pth string) {
if done {
return
}
if newtoken.Token != "" || newtoken.Group != "" {
if newtoken.Token != "" || newtoken.Hall != "" {
http.Error(w, "overspecified token",
http.StatusBadRequest)
return
@@ -601,7 +601,7 @@ func tokensHandler(w http.ResponseWriter, r *http.Request, g, pth string) {
rand.Read(buf)
newtoken.Token =
base64.RawURLEncoding.EncodeToString(buf)
newtoken.Group = g
newtoken.Hall = g
t, err := token.Update(&newtoken, "")
if err != nil {
httpError(w, err)
@@ -626,13 +626,13 @@ func tokensHandler(w http.ResponseWriter, r *http.Request, g, pth string) {
httpError(w, err)
return
}
if old.Group != g {
if old.Hall != g {
http.NotFound(w, r)
return
}
tok := old.Clone()
tok.Token = ""
tok.Group = ""
tok.Hall = ""
w.Header().Set("etag", etag)
done := checkPreconditions(w, r, etag)
if done {
@@ -649,8 +649,8 @@ func tokensHandler(w http.ResponseWriter, r *http.Request, g, pth string) {
httpError(w, err)
return
}
if old.Group != g {
http.Error(w, "token exists in different group",
if old.Hall != g {
http.Error(w, "token exists in different hall",
http.StatusConflict)
return
}
@@ -665,12 +665,12 @@ func tokensHandler(w http.ResponseWriter, r *http.Request, g, pth string) {
if done {
return
}
if newtoken.Group != "" || newtoken.Token != "" {
if newtoken.Hall != "" || newtoken.Token != "" {
http.Error(w, "overspecified token",
http.StatusBadRequest)
return
}
newtoken.Group = g
newtoken.Hall = g
newtoken.Token = t
_, err = token.Update(&newtoken, etag)
if err != nil {
@@ -689,7 +689,7 @@ func tokensHandler(w http.ResponseWriter, r *http.Request, g, pth string) {
httpError(w, err)
return
}
if old.Group != g {
if old.Hall != g {
http.NotFound(w, r)
return
}
+19 -19
View File
@@ -37,7 +37,7 @@ func setupTest(dir, datadir string) error {
hall.Directory = dir
hall.DataDirectory = datadir
config := `{
"writableGroups": true,
"writableHalls": true,
"users": {
"root": {
"password": "pw",
@@ -114,9 +114,9 @@ func TestApi(t *testing.T) {
return d.Decode(value)
}
var groups []string
err = getJSON("/skald-api/v0/.halls/", &groups)
if err != nil || len(groups) != 0 {
var halls []string
err = getJSON("/skald-api/v0/.halls/", &halls)
if err != nil || len(halls) != 0 {
t.Errorf("Get halls: %v", err)
}
@@ -161,9 +161,9 @@ func TestApi(t *testing.T) {
t.Errorf("Delete hall (bad ETag): %v %v", err, resp.StatusCode)
}
err = getJSON("/skald-api/v0/.halls/", &groups)
if err != nil || len(groups) != 1 || groups[0] != "test" {
t.Errorf("Get halls: %v %v", err, groups)
err = getJSON("/skald-api/v0/.halls/", &halls)
if err != nil || len(halls) != 1 || halls[0] != "test" {
t.Errorf("Get halls: %v %v", err, halls)
}
resp, err = do("PUT", "/skald-api/v0/.halls/test/.keys",
@@ -176,8 +176,8 @@ func TestApi(t *testing.T) {
t.Errorf("Set key: %v %v", err, resp.StatusCode)
}
err = getJSON("/skald-api/v0/.halls/test/.users/", &groups)
if err != nil || len(groups) != 0 {
err = getJSON("/skald-api/v0/.halls/test/.users/", &halls)
if err != nil || len(halls) != 0 {
t.Errorf("Get users: %v", err)
}
@@ -301,9 +301,9 @@ func TestApi(t *testing.T) {
}
resp, err = do("POST", "/skald-api/v0/.halls/test/.tokens/",
"application/json", "", "", `{"group":"bad"}`)
"application/json", "", "", `{"hall":"bad"}`)
if err != nil || resp.StatusCode != http.StatusBadRequest {
t.Errorf("Create token (bad group): %v %v", err, resp.StatusCode)
t.Errorf("Create token (bad hall): %v %v", err, resp.StatusCode)
}
resp, err = do("POST", "/skald-api/v0/.halls/test/.tokens/",
@@ -313,7 +313,7 @@ func TestApi(t *testing.T) {
}
resp, err = do("POST", "/skald-api/v0/.halls/.tokens/",
"application/json", "", "", "{\"includeSubgroups\": true}")
"application/json", "", "", "{\"includeSubhalls\": true}")
if err != nil || resp.StatusCode != http.StatusCreated {
t.Errorf("Create global token: %v %v", err, resp.StatusCode)
}
@@ -343,8 +343,8 @@ func TestApi(t *testing.T) {
t.Errorf("Get token: %v %v", err, resp.StatusCode)
}
if tok.Token != "" || tok.Group != "" {
t.Errorf("Get token: %v %v", tok.Token, tok.Group)
if tok.Token != "" || tok.Hall != "" {
t.Errorf("Get token: %v %v", tok.Token, tok.Hall)
}
e := time.Now().Add(time.Hour)
@@ -363,11 +363,11 @@ func TestApi(t *testing.T) {
}
tok.Token = ""
tok.Group = "test"
tok.Hall = "test"
resp, err = do("PUT", tokenpath,
"application/json", "", "", marshalToString(tok))
if err != nil || resp.StatusCode != http.StatusBadRequest {
t.Errorf("Update token with group: %v %v", err, resp.StatusCode)
t.Errorf("Update token with hall: %v %v", err, resp.StatusCode)
}
err = getJSON(tokenpath, &tok)
@@ -384,13 +384,13 @@ func TestApi(t *testing.T) {
tokenpath2 := "/skald-api/v0/.halls/test2/.tokens/" + tokname
resp, err = do("GET", tokenpath2, "", "", "", "")
if err != nil || resp.StatusCode != http.StatusNotFound {
t.Errorf("Get token in bad group: %v %v", err, resp.StatusCode)
t.Errorf("Get token in bad hall: %v %v", err, resp.StatusCode)
}
resp, err = do("PUT", tokenpath2,
"application/json", "", "", "{}")
if err != nil || resp.StatusCode != http.StatusConflict {
t.Errorf("Put token in bad group: %v %v", err, resp.StatusCode)
t.Errorf("Put token in bad hall: %v %v", err, resp.StatusCode)
}
resp, err = do("DELETE", tokenpath, "", "", "", "")
@@ -416,7 +416,7 @@ func TestApi(t *testing.T) {
_, err = hall.GetDescription("test")
if !errors.Is(err, os.ErrNotExist) {
t.Errorf("Group exists after delete")
t.Errorf("Hall exists after delete")
}
}
+25 -25
View File
@@ -35,7 +35,7 @@ var Insecure bool
func Serve(address string, dataDir string) error {
http.Handle("/", &fileHandler{http.Dir(StaticRoot)})
http.HandleFunc("/hall/", groupHandler)
http.HandleFunc("/hall/", hallHandler)
http.HandleFunc("/recordings",
func(w http.ResponseWriter, r *http.Request) {
http.Redirect(w, r,
@@ -321,14 +321,14 @@ func splitPath(pth string) (string, string, string) {
return pth[:index], pth[index+1 : index+1+index2], pth[index+1+index2:]
}
func groupHandler(w http.ResponseWriter, r *http.Request) {
func hallHandler(w http.ResponseWriter, r *http.Request) {
if redirect(w, r) {
return
}
dir, kind, rest := splitPath(r.URL.Path)
if kind == ".status" && rest == "" {
groupStatusHandler(w, r)
hallStatusHandler(w, r)
return
} else if kind == ".status.json" && rest == "" {
http.Redirect(w, r, dir+"/"+".status",
@@ -409,10 +409,10 @@ func baseURL(r *http.Request) (*url.URL, error) {
return &base, nil
}
func groupStatusHandler(w http.ResponseWriter, r *http.Request) {
func hallStatusHandler(w http.ResponseWriter, r *http.Request) {
pth, kind, rest := splitPath(r.URL.Path)
if kind != ".status" || rest != "" {
internalError(w, "groupStatusHandler: this shouldn't happen")
internalError(w, "hallStatusHandler: this shouldn't happen")
return
}
name := parseHallName("/hall/", pth)
@@ -447,7 +447,7 @@ func groupStatusHandler(w http.ResponseWriter, r *http.Request) {
func publicHandler(w http.ResponseWriter, r *http.Request) {
base, err := baseURL(r)
if err != nil {
log.Printf("couldn't determine group base: %v", err)
log.Printf("couldn't determine hall base: %v", err)
httpError(w, err)
return
}
@@ -608,13 +608,13 @@ func recordingsHandler(w http.ResponseWriter, r *http.Request) {
return
}
var group, filename string
var hall, filename string
if fi.IsDir() {
for len(p) > 0 && p[len(p)-1] == '/' {
p = p[:len(p)-1]
}
group = parseHallName("/", p)
if group == "" {
hall = parseHallName("/", p)
if hall == "" {
http.Error(w, "Bad hall name", http.StatusBadRequest)
return
}
@@ -623,31 +623,31 @@ func recordingsHandler(w http.ResponseWriter, r *http.Request) {
http.Error(w, "Bad hall name", http.StatusBadRequest)
return
}
group, filename = path.Split(p)
group = parseHallName("/", group)
if group == "" {
hall, filename = path.Split(p)
hall = parseHallName("/", hall)
if hall == "" {
http.Error(w, "Bad hall name", http.StatusBadRequest)
return
}
}
u := "/recordings/" + group + "/" + filename
u := "/recordings/" + hall + "/" + filename
if r.URL.Path != u {
http.Redirect(w, r, u, http.StatusPermanentRedirect)
return
}
ok := checkGroupPermissions(w, r, group)
ok := checkHallPermissions(w, r, hall)
if !ok {
failAuthentication(w, "recordings/"+group)
failAuthentication(w, "recordings/"+hall)
return
}
if filename == "" {
if r.Method == "POST" {
handleGroupAction(w, r, group)
handleHallAction(w, r, hall)
} else {
serveGroupRecordings(w, r, f, group)
serveHallRecordings(w, r, f, hall)
}
return
}
@@ -658,7 +658,7 @@ func recordingsHandler(w http.ResponseWriter, r *http.Request) {
http.ServeContent(w, r, fi.Name(), fi.ModTime(), f)
}
func handleGroupAction(w http.ResponseWriter, r *http.Request, group string) {
func handleHallAction(w http.ResponseWriter, r *http.Request, hall string) {
if r.Method != "POST" {
methodNotAllowed(w, "POST")
return
@@ -675,7 +675,7 @@ func handleGroupAction(w http.ResponseWriter, r *http.Request, group string) {
switch q {
case "delete":
filename := r.Form.Get("filename")
if group == "" || filename == "" {
if hall == "" || filename == "" {
http.Error(w, "No filename provided",
http.StatusBadRequest)
return
@@ -688,7 +688,7 @@ func handleGroupAction(w http.ResponseWriter, r *http.Request, group string) {
}
err := os.Remove(
filepath.Join(diskwriter.Directory,
filepath.Join(group,
filepath.Join(hall,
path.Clean("/"+filename),
),
),
@@ -697,7 +697,7 @@ func handleGroupAction(w http.ResponseWriter, r *http.Request, group string) {
httpError(w, err)
return
}
http.Redirect(w, r, "/recordings/"+group+"/",
http.Redirect(w, r, "/recordings/"+hall+"/",
http.StatusSeeOther)
return
default:
@@ -705,7 +705,7 @@ func handleGroupAction(w http.ResponseWriter, r *http.Request, group string) {
}
}
func checkGroupPermissions(w http.ResponseWriter, r *http.Request, hallname string) bool {
func checkHallPermissions(w http.ResponseWriter, r *http.Request, hallname string) bool {
user, pass, ok := r.BasicAuth()
if !ok {
return false
@@ -742,7 +742,7 @@ func checkGroupPermissions(w http.ResponseWriter, r *http.Request, hallname stri
return true
}
func serveGroupRecordings(w http.ResponseWriter, r *http.Request, f *os.File, group string) {
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)
if err != nil {
@@ -762,7 +762,7 @@ func serveGroupRecordings(w http.ResponseWriter, r *http.Request, f *os.File, gr
}
fmt.Fprintf(w, "<!DOCTYPE html>\n<html><head>\n")
fmt.Fprintf(w, "<title>Recordings for group %v</title>\n", group)
fmt.Fprintf(w, "<title>Recordings for hall %v</title>\n", hall)
fmt.Fprintf(w, "<link rel=\"stylesheet\" type=\"text/css\" href=\"/common.css\"/>")
fmt.Fprintf(w, "</head><body>\n")
@@ -781,7 +781,7 @@ func serveGroupRecordings(w http.ResponseWriter, r *http.Request, f *os.File, gr
"<input type=\"hidden\" name=\"filename\" value=\"%v\">"+
"<button type=\"submit\" name=\"q\" value=\"delete\">Delete</button>"+
"</form></td></tr>\n",
url.PathEscape(group), fi.Name())
url.PathEscape(hall), fi.Name())
}
fmt.Fprintf(w, "</table>\n")
fmt.Fprintf(w, "</body></html>\n")
+1 -1
View File
@@ -18,7 +18,7 @@ func TestParseHallName(t *testing.T) {
{"", ""},
{"/foo", ""},
{"foo", ""},
{"group/foo", ""},
{"hall/foo", ""},
{"/hall", ""},
{"/hall/..", ""},
{"/hall/foo/../bar", "bar"},