Initial DDC release
This commit is contained in:
commit
434f6441da
57 files changed
+4606
No files matched your search
Executable
+73
@@ -0,0 +1,73 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
sessionCookieName = "ddc_session"
|
||||
maxRequestBodyBytes = 64 << 10
|
||||
contentSecurityPolicy = "default-src 'self'; img-src 'self' data:; object-src 'none'; base-uri 'none'; frame-ancestors 'none'; form-action 'self'"
|
||||
)
|
||||
|
||||
func securityHeaders(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {
|
||||
header := writer.Header()
|
||||
header.Set("Content-Security-Policy", contentSecurityPolicy)
|
||||
header.Set("X-Content-Type-Options", "nosniff")
|
||||
header.Set("X-Frame-Options", "DENY")
|
||||
header.Set("Referrer-Policy", "no-referrer")
|
||||
header.Set("Cross-Origin-Opener-Policy", "same-origin")
|
||||
header.Set("Permissions-Policy", "camera=(), microphone=(), geolocation=()")
|
||||
if strings.HasPrefix(request.URL.Path, "/api/") {
|
||||
header.Set("Cache-Control", "no-store")
|
||||
}
|
||||
next.ServeHTTP(writer, request)
|
||||
})
|
||||
}
|
||||
|
||||
func protectStateChanges(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {
|
||||
if request.Method == http.MethodGet || request.Method == http.MethodHead {
|
||||
next.ServeHTTP(writer, request)
|
||||
return
|
||||
}
|
||||
if !isSameOrigin(request) {
|
||||
writeError(writer, http.StatusForbidden, "cross-origin request rejected")
|
||||
return
|
||||
}
|
||||
if request.Method == http.MethodPost && !strings.HasPrefix(request.Header.Get("Content-Type"), "application/json") {
|
||||
writeError(writer, http.StatusUnsupportedMediaType, "content type must be application/json")
|
||||
return
|
||||
}
|
||||
request.Body = http.MaxBytesReader(writer, request.Body, maxRequestBodyBytes)
|
||||
next.ServeHTTP(writer, request)
|
||||
})
|
||||
}
|
||||
|
||||
func isSameOrigin(request *http.Request) bool {
|
||||
origin := request.Header.Get("Origin")
|
||||
if origin == "" {
|
||||
fetchSite := request.Header.Get("Sec-Fetch-Site")
|
||||
return fetchSite == "" || fetchSite == "same-origin" || fetchSite == "none"
|
||||
}
|
||||
parsed, err := url.Parse(origin)
|
||||
return err == nil && strings.EqualFold(parsed.Host, request.Host)
|
||||
}
|
||||
|
||||
func (server *Server) requireSession(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {
|
||||
if !server.authenticated(request) {
|
||||
writeError(writer, http.StatusUnauthorized, "authentication required")
|
||||
return
|
||||
}
|
||||
next.ServeHTTP(writer, request)
|
||||
})
|
||||
}
|
||||
|
||||
func (server *Server) authenticated(request *http.Request) bool {
|
||||
cookie, err := request.Cookie(sessionCookieName)
|
||||
return err == nil && server.sessions.Valid(cookie.Value)
|
||||
}
|
||||
Reference in new issue
Block a user