mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
fix(coderd): validate webpush subscription endpoints (#24347)
Co-authored-by: Cian Johnston <cian@coder.com>
This commit is contained in:
co-authored by
Cian Johnston
parent
e317f3b239
commit
5812f84e1c
@@ -4,7 +4,12 @@ import (
|
||||
"database/sql"
|
||||
"errors"
|
||||
"net/http"
|
||||
"net/netip"
|
||||
"net/url"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/coder/coder/v2/coderd/database"
|
||||
"github.com/coder/coder/v2/coderd/database/dbtime"
|
||||
@@ -33,6 +38,13 @@ func (api *API) postUserWebpushSubscription(rw http.ResponseWriter, r *http.Requ
|
||||
if !httpapi.Read(ctx, rw, r, &req) {
|
||||
return
|
||||
}
|
||||
if err := validateWebpushEndpoint(req.Endpoint); err != nil {
|
||||
httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{
|
||||
Message: "Invalid webpush endpoint.",
|
||||
Detail: err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if err := api.WebpushDispatcher.Test(ctx, req); err != nil {
|
||||
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
|
||||
@@ -62,6 +74,42 @@ func (api *API) postUserWebpushSubscription(rw http.ResponseWriter, r *http.Requ
|
||||
rw.WriteHeader(http.StatusNoContent)
|
||||
}
|
||||
|
||||
func validateWebpushEndpoint(rawEndpoint string) error {
|
||||
endpoint, err := url.Parse(rawEndpoint)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("parse endpoint URL: %w", err)
|
||||
}
|
||||
if !endpoint.IsAbs() {
|
||||
return xerrors.New("endpoint must be an absolute URL")
|
||||
}
|
||||
if endpoint.Scheme != "https" {
|
||||
return xerrors.New("endpoint URL scheme must be https")
|
||||
}
|
||||
if endpoint.Host == "" {
|
||||
return xerrors.New("endpoint host is required")
|
||||
}
|
||||
if endpoint.User != nil {
|
||||
return xerrors.New("endpoint URL must not include userinfo")
|
||||
}
|
||||
|
||||
hostname := strings.ToLower(endpoint.Hostname())
|
||||
if hostname == "" {
|
||||
return xerrors.New("endpoint hostname is required")
|
||||
}
|
||||
if hostname == "localhost" || strings.HasSuffix(hostname, ".localhost") {
|
||||
return xerrors.New("endpoint hostname must not be localhost")
|
||||
}
|
||||
|
||||
if ip, err := netip.ParseAddr(hostname); err == nil &&
|
||||
(ip.IsPrivate() || ip.IsLoopback() || ip.IsLinkLocalUnicast() ||
|
||||
ip.IsLinkLocalMulticast() || ip.IsMulticast() ||
|
||||
ip.IsUnspecified()) {
|
||||
return xerrors.New("endpoint IP must not be private, loopback, link-local, multicast, or unspecified")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// @Summary Delete user webpush subscription
|
||||
// @ID delete-user-webpush-subscription
|
||||
// @Security CoderSessionToken
|
||||
|
||||
Reference in New Issue
Block a user