Compare commits
3 Commits
6f6ea33eaa
...
f067c13d67
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f067c13d67 | ||
|
|
28908db1c8 | ||
| a98e0ca349 |
@@ -1624,6 +1624,10 @@ authenticity.
|
|||||||
termination.
|
termination.
|
||||||
- **CORS**: The server allows all origins by default (`Access-Control-Allow-Origin: *`).
|
- **CORS**: The server allows all origins by default (`Access-Control-Allow-Origin: *`).
|
||||||
Restrict this in production via reverse proxy configuration if needed.
|
Restrict this in production via reverse proxy configuration if needed.
|
||||||
|
- **Content-Security-Policy**: The server sets a strict CSP header on all
|
||||||
|
responses, restricting resource loading to same-origin and disabling
|
||||||
|
dangerous features (object embeds, framing, base tag injection). The
|
||||||
|
embedded SPA works without `'unsafe-inline'` for scripts or styles.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -1118,28 +1118,6 @@ func (database *Database) PruneOldQueueEntries(
|
|||||||
return deleted, nil
|
return deleted, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// PruneOrphanedMessages deletes messages that are no
|
|
||||||
// longer referenced by any client_queues row and returns
|
|
||||||
// the number of rows removed.
|
|
||||||
func (database *Database) PruneOrphanedMessages(
|
|
||||||
ctx context.Context,
|
|
||||||
) (int64, error) {
|
|
||||||
res, err := database.conn.ExecContext(ctx,
|
|
||||||
`DELETE FROM messages WHERE id NOT IN
|
|
||||||
(SELECT DISTINCT message_id
|
|
||||||
FROM client_queues)`,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return 0, fmt.Errorf(
|
|
||||||
"prune orphaned messages: %w", err,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
deleted, _ := res.RowsAffected()
|
|
||||||
|
|
||||||
return deleted, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// RotateChannelMessages enforces MAX_HISTORY per channel
|
// RotateChannelMessages enforces MAX_HISTORY per channel
|
||||||
// by deleting the oldest messages beyond the limit for
|
// by deleting the oldest messages beyond the limit for
|
||||||
// each msg_to target. Returns the total number of rows
|
// each msg_to target. Returns the total number of rows
|
||||||
|
|||||||
@@ -245,18 +245,4 @@ func (hdlr *Handlers) pruneQueuesAndMessages(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
orphaned, err := hdlr.params.Database.
|
|
||||||
PruneOrphanedMessages(ctx)
|
|
||||||
if err != nil {
|
|
||||||
hdlr.log.Error(
|
|
||||||
"orphan message cleanup failed",
|
|
||||||
"error", err,
|
|
||||||
)
|
|
||||||
} else if orphaned > 0 {
|
|
||||||
hdlr.log.Info(
|
|
||||||
"pruned orphaned messages",
|
|
||||||
"deleted", orphaned,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -180,3 +180,36 @@ func (mware *Middleware) MetricsAuth() func(http.Handler) http.Handler {
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// cspPolicy is the Content-Security-Policy header value applied to all
|
||||||
|
// responses. The embedded SPA loads scripts and styles from same-origin
|
||||||
|
// files only (no inline scripts or inline style attributes), so a strict
|
||||||
|
// policy works without 'unsafe-inline'.
|
||||||
|
const cspPolicy = "default-src 'self'; " +
|
||||||
|
"script-src 'self'; " +
|
||||||
|
"style-src 'self'; " +
|
||||||
|
"connect-src 'self'; " +
|
||||||
|
"img-src 'self'; " +
|
||||||
|
"font-src 'self'; " +
|
||||||
|
"object-src 'none'; " +
|
||||||
|
"frame-ancestors 'none'; " +
|
||||||
|
"base-uri 'self'; " +
|
||||||
|
"form-action 'self'"
|
||||||
|
|
||||||
|
// CSP returns middleware that sets the Content-Security-Policy header on
|
||||||
|
// every response for defense-in-depth against XSS.
|
||||||
|
func (mware *Middleware) CSP() func(http.Handler) http.Handler {
|
||||||
|
return func(next http.Handler) http.Handler {
|
||||||
|
return http.HandlerFunc(
|
||||||
|
func(
|
||||||
|
writer http.ResponseWriter,
|
||||||
|
request *http.Request,
|
||||||
|
) {
|
||||||
|
writer.Header().Set(
|
||||||
|
"Content-Security-Policy",
|
||||||
|
cspPolicy,
|
||||||
|
)
|
||||||
|
next.ServeHTTP(writer, request)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ func (srv *Server) SetupRoutes() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
srv.router.Use(srv.mw.CORS())
|
srv.router.Use(srv.mw.CORS())
|
||||||
|
srv.router.Use(srv.mw.CSP())
|
||||||
srv.router.Use(middleware.Timeout(routeTimeout))
|
srv.router.Use(middleware.Timeout(routeTimeout))
|
||||||
|
|
||||||
if srv.sentryEnabled {
|
if srv.sentryEnabled {
|
||||||
|
|||||||
Reference in New Issue
Block a user