diff options
author | EuAndreh <eu@euandre.org> | 2024-03-16 06:03:40 -0300 |
---|---|---|
committer | EuAndreh <eu@euandre.org> | 2024-03-16 06:03:40 -0300 |
commit | c3387c891a4376a558f3c09c804f7aa45422ad41 (patch) | |
tree | 303eb83bf1064e51a0023a93331550d952d678b6 /src | |
parent | src/hero.mjs: Add "upgrade" and "socket" keys to `req` (diff) | |
download | papod-c3387c891a4376a558f3c09c804f7aa45422ad41.tar.gz papod-c3387c891a4376a558f3c09c804f7aa45422ad41.tar.xz |
src/hero.mjs: Add validateUpgrade(), computeHash() and their helper functions
Diffstat (limited to 'src')
-rw-r--r-- | src/hero.mjs | 99 |
1 files changed, 99 insertions, 0 deletions
diff --git a/src/hero.mjs b/src/hero.mjs index 859d86f..6df57ea 100644 --- a/src/hero.mjs +++ b/src/hero.mjs @@ -38,6 +38,105 @@ export const makeLogger = (writerFn = console.error) => ({ export const log = makeLogger(); +export const isValidMethod = method => + method === "GET"; + +export const isValidUpgrade = val => + val.toLowerCase() === "websocket"; + +export const isValidKey = key => + /^[0-9a-zA-Z+/]{22}==$/.test(key); + +export const isValidVersion = n => + n === 13; + +export const validateUpgrade = (method, headers) => { + const upgrade = headers["upgrade"]; + const key = headers["sec-websocket-key"]; + const versionStr = headers["sec-websocket-version"]; + const version = parseInt(versionStr); + + if (!isValidMethod(method)) { + return { + isValid: false, + response: { + status: 405, + }, + }; + } + + if (!upgrade) { + return { + isValid: false, + response: { + status: 400, + body: 'Missing "Upgrade" header\n', + }, + }; + } + + if (!isValidUpgrade(upgrade)) { + return { + isValid: false, + response: { + status: 400, + body: 'Invalid "Upgrade" value\n', + }, + }; + } + + if (!key) { + return { + isValid: false, + response: { + status: 400, + body: 'Missing "Sec-WebSocket-Key" header\n', + }, + }; + } + + if (!isValidKey(key)) { + return { + isValid: false, + response: { + status: 400, + body: 'Invalid "Sec-WebSocket-Key" value\n', + }, + }; + } + + if (!version) { + return { + isValid: false, + response: { + status: 400, + body: 'Missing "Sec-WebSocket-Version" header\n', + }, + }; + } + + if (!isValidVersion(version)) { + return { + isValid: false, + response: { + status: 400, + body: 'Invalid "Sec-WebSocket-Version" value\n', + }, + }; + } + + return { + isValid: true, + }; +}; + +const GUID_MAGIC_NUMBER = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; +export const computeHash = key => + crypto + .createHash("SHA1") + .update(key + GUID_MAGIC_NUMBER) + .digest("base64"); + export const interceptorsFn = ({ uuidFn = crypto.randomUUID, logger = log, |