-
Notifications
You must be signed in to change notification settings - Fork 331
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix: close websocket with reason on invalid token #9744
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,38 +1,14 @@ | ||
import {WebSocketBehavior} from 'uWebSockets.js' | ||
import {TrebuchetCloseReason} from '../../client/types/constEnums' | ||
import safetyPatchRes from '../safetyPatchRes' | ||
import {isAuthenticated} from '../utils/authorization' | ||
import checkBlacklistJWT from '../utils/checkBlacklistJWT' | ||
import getQueryToken from '../utils/getQueryToken' | ||
import sendToSentry from '../utils/sendToSentry' | ||
import uwsGetIP from '../utils/uwsGetIP' | ||
|
||
const handleUpgrade: WebSocketBehavior<void>['upgrade'] = async (res, req, context) => { | ||
safetyPatchRes(res) | ||
const protocol = req.getHeader('sec-websocket-protocol') | ||
if (protocol !== 'trebuchet-ws') { | ||
sendToSentry(new Error(`WebSocket error: invalid protocol: ${protocol}`)) | ||
// WS Error 1002 is roughly HTTP 412 Precondition Failed because we can't support the req header | ||
res.writeStatus('412').end() | ||
return | ||
} | ||
const authToken = getQueryToken(req) | ||
if (!isAuthenticated(authToken)) { | ||
res.writeStatus('401').end() | ||
return | ||
} | ||
|
||
const handleUpgrade: WebSocketBehavior<void>['upgrade'] = (res, req, context) => { | ||
const key = req.getHeader('sec-websocket-key') | ||
const protocol = req.getHeader('sec-websocket-protocol') | ||
const extensions = req.getHeader('sec-websocket-extensions') | ||
const ip = uwsGetIP(res, req) | ||
const {sub: userId, iat} = authToken | ||
// ALL async calls must come after the message listener, or we'll skip out on messages (e.g. resub after server restart) | ||
const isBlacklistedJWT = await checkBlacklistJWT(userId, iat) | ||
if (isBlacklistedJWT) { | ||
res.writeStatus('401').end(TrebuchetCloseReason.EXPIRED_SESSION) | ||
return | ||
} | ||
res.upgrade({ip, authToken}, key, protocol, extensions, context) | ||
const authToken = getQueryToken(req) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. -2 we throw here now and the client tries reconnecting endlessly There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. whoa! could you provide some steps to reproduce? This function has a try/catch inside it so it shouldn't throw, it should just return a |
||
res.upgrade({ip, authToken, protocol}, key, protocol, extensions, context) | ||
} | ||
|
||
export default handleUpgrade |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
-1 I think we need to distinguish 2 cases here: The client speaks our language but says the wrong thing (right protocol, wrong auth) and we don't understand it at all (wrong protocol). I think in the latter case, we should not move forward with the upgrade which should also fail the client permanently because it could never connect. Only when the protocol matches, we should upgrade and do the other checks. In that case the client can talk websocket with the server, so there is no need to try other connection methods.