Implement CORS for the administrative interface.

This commit is contained in:
Juliusz Chroboczek
2025-06-13 15:00:16 +02:00
parent 7204889085
commit a6410b5a68
4 changed files with 54 additions and 20 deletions
+3
View File
@@ -112,6 +112,9 @@ The fields are as follows:
- `allowOrigin` is an array that contains the list of HTTP origins that
are allowed to access the server.
- `allowAdminOrigin` is like `allowOrigin`, but applies to the
administrative interface.
- `proxyURL`: if running behind a reverse proxy, this specifies the root
URL that will be visible outside the proxy.
+47 -9
View File
@@ -104,6 +104,19 @@ func getJSON(w http.ResponseWriter, r *http.Request, v any) bool {
return false
}
func apiCORS(w http.ResponseWriter, r *http.Request, methods string) bool {
CheckOrigin(w, r, true)
if r.Method == "OPTIONS" {
w.Header().Set("Access-Control-Allow-Methods",
"OPTIONS, "+methods)
w.Header().Set("Access-Control-Allow-Headers",
"Authorization, Content-Type",
)
return true
}
return false
}
func apiHandler(w http.ResponseWriter, r *http.Request) {
if !strings.HasPrefix(r.URL.Path, "/galene-api/") {
http.NotFound(w, r)
@@ -112,11 +125,14 @@ func apiHandler(w http.ResponseWriter, r *http.Request) {
first, kind, rest := splitPath(r.URL.Path[len("/galene-api"):])
if first == "/v0" && kind == ".stats" && rest == "" {
if apiCORS(w, r, "HEAD, GET") {
return
}
if !checkAdmin(w, r) {
return
}
if r.Method != "HEAD" && r.Method != "GET" {
methodNotAllowed(w, "HEAD", "GET")
methodNotAllowed(w, "HEAD, GET")
return
}
w.Header().Set("cache-control", "no-cache")
@@ -139,11 +155,14 @@ func apiGroupHandler(w http.ResponseWriter, r *http.Request, pth string) {
}
g := first[1:]
if g == "" && kind == "" {
if apiCORS(w, r, "HEAD, GET") {
return
}
if !checkAdmin(w, r) {
return
}
if r.Method != "HEAD" && r.Method != "GET" {
methodNotAllowed(w, "HEAD", "GET")
methodNotAllowed(w, "HEAD, GET")
return
}
groups, err := group.GetDescriptionNames()
@@ -178,6 +197,9 @@ func apiGroupHandler(w http.ResponseWriter, r *http.Request, pth string) {
return
}
if apiCORS(w, r, "HEAD, GET, PUT, DELETE") {
return
}
if !checkAdmin(w, r) {
return
}
@@ -248,7 +270,7 @@ func apiGroupHandler(w http.ResponseWriter, r *http.Request, pth string) {
w.WriteHeader(http.StatusNoContent)
return
}
methodNotAllowed(w, "HEAD", "GET", "PUT", "DELETE")
methodNotAllowed(w, "HEAD, GET, PUT, DELETE")
return
}
@@ -258,11 +280,14 @@ func usersHandler(w http.ResponseWriter, r *http.Request, g, pth string) {
return
}
if pth == "/" {
if apiCORS(w, r, "HEAD, GET") {
return
}
if !checkAdmin(w, r) {
return
}
if r.Method != "HEAD" && r.Method != "GET" {
methodNotAllowed(w, "HEAD", "GET")
methodNotAllowed(w, "HEAD, GET")
return
}
users, etag, err := group.GetUsers(g)
@@ -310,6 +335,9 @@ func specialUserHandler(w http.ResponseWriter, r *http.Request, g, pth string, w
}
func userHandler(w http.ResponseWriter, r *http.Request, g, user string, wildcard bool) {
if apiCORS(w, r, "HEAD, GET, PUT, DELETE") {
return
}
if !checkAdmin(w, r) {
return
}
@@ -378,11 +406,14 @@ func userHandler(w http.ResponseWriter, r *http.Request, g, user string, wildcar
w.WriteHeader(http.StatusNoContent)
return
}
methodNotAllowed(w, "HEAD", "GET", "PUT", "DELETE")
methodNotAllowed(w, "HEAD, GET, PUT, DELETE")
return
}
func passwordHandler(w http.ResponseWriter, r *http.Request, g, user string, wildcard bool) {
if apiCORS(w, r, "PUT, POST, DELETE") {
return
}
if !checkPasswordAdmin(w, r, g, user, wildcard) {
return
}
@@ -433,7 +464,7 @@ func passwordHandler(w http.ResponseWriter, r *http.Request, g, user string, wil
return
}
methodNotAllowed(w, "PUT", "POST", "DELETE")
methodNotAllowed(w, "PUT, POST, DELETE")
return
}
@@ -442,6 +473,9 @@ type jwkset = struct {
}
func keysHandler(w http.ResponseWriter, r *http.Request, g string) {
if apiCORS(w, r, "HEAD, GET") {
return
}
if !checkAdmin(w, r) {
return
}
@@ -481,7 +515,7 @@ func keysHandler(w http.ResponseWriter, r *http.Request, g string) {
return
}
methodNotAllowed(w, "PUT", "DELETE")
methodNotAllowed(w, "PUT, DELETE")
return
}
@@ -490,9 +524,13 @@ func tokensHandler(w http.ResponseWriter, r *http.Request, g, pth string) {
http.NotFound(w, r)
return
}
if apiCORS(w, r, "HEAD, GET, POST, PUT, DELETE") {
return
}
if !checkAdmin(w, r) {
return
}
// check that the group exists
_, err := group.GetDescription(g)
if err != nil {
@@ -541,7 +579,7 @@ func tokensHandler(w http.ResponseWriter, r *http.Request, g, pth string) {
w.WriteHeader(http.StatusCreated)
return
}
methodNotAllowed(w, "HEAD", "GET", "POST")
methodNotAllowed(w, "HEAD, GET, POST")
return
}
@@ -637,6 +675,6 @@ func tokensHandler(w http.ResponseWriter, r *http.Request, g, pth string) {
w.WriteHeader(http.StatusNoContent)
return
}
methodNotAllowed(w, "HEAD", "GET", "PUT", "DELETE")
methodNotAllowed(w, "HEAD, GET, PUT, DELETE")
return
}
+2 -9
View File
@@ -146,15 +146,8 @@ func httpError(w http.ResponseWriter, err error) {
http.StatusInternalServerError)
}
func methodNotAllowed(w http.ResponseWriter, methods ...string) {
ms := ""
for _, m := range methods {
if ms != "" {
ms = ms + ", "
}
ms = ms + m
}
w.Header().Set("Allow", ms)
func methodNotAllowed(w http.ResponseWriter, methods string) {
w.Header().Set("Allow", "OPTIONS, " + methods)
http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
}
+2 -2
View File
@@ -178,7 +178,7 @@ func whipEndpointHandler(w http.ResponseWriter, r *http.Request) {
}
if r.Method != "POST" {
methodNotAllowed(w, "OPTIONS", "POST")
methodNotAllowed(w, "POST")
return
}
@@ -323,7 +323,7 @@ func whipResourceHandler(w http.ResponseWriter, r *http.Request) {
}
if r.Method != "PATCH" {
methodNotAllowed(w, "OPTIONS", "DELETE", "PATCH")
methodNotAllowed(w, "DELETE, PATCH")
return
}