mirror of
https://github.com/superseriousbusiness/gotosocial
synced 2025-06-05 21:59:39 +02:00
[bugfix] websocket header token not always returned (#4009)
* always include headerToken response if provided, because Chrome *sigh* * wording * Update internal/api/client/streaming/stream.go Co-authored-by: Ilia Pozdnyakov <iliazeus@proton.me> --------- Co-authored-by: Ilia Pozdnyakov <iliazeus@proton.me>
This commit is contained in:
@@ -18,6 +18,7 @@
|
|||||||
package streaming
|
package streaming
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"cmp"
|
||||||
"context"
|
"context"
|
||||||
"net/http"
|
"net/http"
|
||||||
"slices"
|
"slices"
|
||||||
@@ -153,25 +154,22 @@ var pingMsg = []byte("ping!")
|
|||||||
// description: bad request
|
// description: bad request
|
||||||
func (m *Module) StreamGETHandler(c *gin.Context) {
|
func (m *Module) StreamGETHandler(c *gin.Context) {
|
||||||
var (
|
var (
|
||||||
token string
|
|
||||||
tokenInHeader bool
|
|
||||||
account *gtsmodel.Account
|
account *gtsmodel.Account
|
||||||
errWithCode gtserror.WithCode
|
errWithCode gtserror.WithCode
|
||||||
)
|
)
|
||||||
|
|
||||||
if t := c.Query(AccessTokenQueryKey); t != "" {
|
// Check both query parameter AND header "Sec-Websocket-Protocol"
|
||||||
// Token was provided as
|
// value for a token. The latter is hacky and not technically
|
||||||
// query param, no problem.
|
// correct, but some client do it since Mastodon allows it, so
|
||||||
token = t
|
// we must allow it for compatibility.
|
||||||
} else if t := c.GetHeader(AccessTokenHeader); t != "" {
|
|
||||||
// Token was provided in "Sec-Websocket-Protocol" header.
|
|
||||||
//
|
//
|
||||||
// This is hacky and not technically correct but some
|
// Chrome also *always* expects the "Sec-Websocket-Protocol"
|
||||||
// clients do it since Mastodon allows it, so we must
|
// response value to match input, so it must always be checked.
|
||||||
// also allow it to avoid breaking expectations.
|
queryToken := c.Query(AccessTokenQueryKey)
|
||||||
token = t
|
headerToken := c.GetHeader(AccessTokenHeader)
|
||||||
tokenInHeader = true
|
|
||||||
}
|
// Prefer query token else use header token.
|
||||||
|
token := cmp.Or(queryToken, headerToken)
|
||||||
|
|
||||||
if token != "" {
|
if token != "" {
|
||||||
|
|
||||||
@@ -229,8 +227,7 @@ func (m *Module) StreamGETHandler(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
l := log.
|
l := log.WithContext(c.Request.Context()).
|
||||||
WithContext(c.Request.Context()).
|
|
||||||
WithField("streamID", id.NewULID()).
|
WithField("streamID", id.NewULID()).
|
||||||
WithField("username", account.Username)
|
WithField("username", account.Username)
|
||||||
|
|
||||||
@@ -241,12 +238,14 @@ func (m *Module) StreamGETHandler(c *gin.Context) {
|
|||||||
// If the upgrade fails, then Upgrade replies to the client
|
// If the upgrade fails, then Upgrade replies to the client
|
||||||
// with an HTTP error response.
|
// with an HTTP error response.
|
||||||
var responseHeader http.Header
|
var responseHeader http.Header
|
||||||
if tokenInHeader {
|
if headerToken != "" {
|
||||||
// Return the token in the response,
|
|
||||||
// else Chrome fails to connect.
|
// Chrome always requires the input header
|
||||||
|
// token to be provided in response, even
|
||||||
|
// if it also provided via query... *shrugs*
|
||||||
//
|
//
|
||||||
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Protocol_upgrade_mechanism#sec-websocket-protocol
|
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Protocol_upgrade_mechanism#sec-websocket-protocol
|
||||||
responseHeader = http.Header{AccessTokenHeader: {token}}
|
responseHeader = http.Header{AccessTokenHeader: {headerToken}}
|
||||||
}
|
}
|
||||||
|
|
||||||
wsConn, err := m.wsUpgrade.Upgrade(c.Writer, c.Request, responseHeader)
|
wsConn, err := m.wsUpgrade.Upgrade(c.Writer, c.Request, responseHeader)
|
||||||
|
Reference in New Issue
Block a user