insite-cookie 1.0.37 → 1.0.40
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bun.lockb +0 -0
- package/dist/client.js +2 -0
- package/dist/client.js.map +7 -0
- package/dist/server.js +2 -0
- package/dist/server.js.map +7 -0
- package/package.json +34 -34
- package/lib/Middleware.js +0 -60
- package/lib/index.js +0 -2
- package/lib/parse.js +0 -13
- package/lib/tokenMap.js +0 -1
- package/lib/ws/client/SetterClient.js +0 -52
- package/lib/ws/client/index.js +0 -1
- package/lib/ws/common.js +0 -3
- package/lib/ws/server/SetterServer.js +0 -80
- package/lib/ws/server/index.js +0 -1
package/bun.lockb
ADDED
|
Binary file
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
var u=(e,o,t)=>{if(!o.has(e))throw TypeError("Cannot "+t)};var h=(e,o,t)=>(u(e,o,"read from private field"),t?t.call(e):o.get(e)),i=(e,o,t)=>{if(o.has(e))throw TypeError("Cannot add the same private member more than once");o instanceof WeakSet?o.add(e):o.set(e,t)};var a={set:"~setcookie"};var r,l=class{constructor(o,t={}){i(this,r,o=>{let t=new XMLHttpRequest;t.onload=this.onload,t.onerror=this.onerror,t.open(this.method,`${this.url}?${o}`,!0),t.send(null)});let{method:d="GET",url:c="/cookie",onload:s,onerror:n}=t;this.method=d,this.url=c,s&&(this.onload=s),n&&(this.onerror=n),o.on(`message:${a.set}`,h(this,r))}onload(){this.readyState===4&&this.status!==200&&console.error("Set cookie:",this.statusText)}onerror(){console.error("Set cookie:",this.statusText)}};r=new WeakMap;export{l as CookieSetter};
|
|
2
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/common.js", "../src/client/Setter.js"],
|
|
4
|
+
"sourcesContent": ["export const headers = {\n\tset: \"~setcookie\"\n};\n", "import { headers } from \"../common\";\n\n\nexport class CookieSetter {\n\tconstructor(ws, options = {}) {\n\t\t\n\t\tconst {\n\t\t\tmethod = \"GET\",\n\t\t\turl = \"/cookie\",\n\t\t\tonload,\n\t\t\tonerror\n\t\t} = options;\n\t\t\n\t\tthis.method = method;\n\t\tthis.url = url;\n\t\t\n\t\tif (onload)\n\t\t\tthis.onload = onload;\n\t\t\n\t\tif (onerror)\n\t\t\tthis.onerror = onerror;\n\t\t\n\t\tws.on(`message:${headers.set}`, this.#handleSet);\n\t\t\n\t}\n\t\n\t#handleSet = token => {\n\t\tconst xhr = new XMLHttpRequest();\n\t\t\n\t\txhr.onload = this.onload;\n\t\txhr.onerror = this.onerror;\n\t\t\n\t\txhr.open(this.method, `${this.url}?${token}`, true);\n\t\t\n\t\txhr.send(null);\n\t\t\n\t};\n\t\n\tonload() {\n\t\t\n\t\tif (this.readyState === 4 && this.status !== 200)\n\t\t\tconsole.error(\"Set cookie:\", this.statusText);\n\t\t\n\t}\n\t\n\tonerror() {\n\t\t\n\t\tconsole.error(\"Set cookie:\", this.statusText);\n\t\t\n\t}\n\t\n}\n"],
|
|
5
|
+
"mappings": "yQAAO,IAAMA,EAAU,CACtB,IAAK,YACN,ECFA,IAAAC,EAGaC,EAAN,KAAmB,CACzB,YAAYC,EAAIC,EAAU,CAAC,EAAG,CAsB9BC,EAAA,KAAAJ,EAAaK,GAAS,CACrB,IAAMC,EAAM,IAAI,eAEhBA,EAAI,OAAS,KAAK,OAClBA,EAAI,QAAU,KAAK,QAEnBA,EAAI,KAAK,KAAK,OAAQ,GAAG,KAAK,GAAG,IAAID,CAAK,GAAI,EAAI,EAElDC,EAAI,KAAK,IAAI,CAEd,GA9BC,GAAM,CACL,OAAAC,EAAS,MACT,IAAAC,EAAM,UACN,OAAAC,EACA,QAAAC,CACD,EAAIP,EAEJ,KAAK,OAASI,EACd,KAAK,IAAMC,EAEPC,IACH,KAAK,OAASA,GAEXC,IACH,KAAK,QAAUA,GAEhBR,EAAG,GAAG,WAAWS,EAAQ,GAAG,GAAIC,EAAA,KAAKZ,EAAU,CAEhD,CAcA,QAAS,CAEJ,KAAK,aAAe,GAAK,KAAK,SAAW,KAC5C,QAAQ,MAAM,cAAe,KAAK,UAAU,CAE9C,CAEA,SAAU,CAET,QAAQ,MAAM,cAAe,KAAK,UAAU,CAE7C,CAED,EAzBCA,EAAA",
|
|
6
|
+
"names": ["headers", "_handleSet", "CookieSetter", "ws", "options", "__privateAdd", "token", "xhr", "method", "url", "onload", "onerror", "headers", "__privateGet"]
|
|
7
|
+
}
|
package/dist/server.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
var r=new Map;var l=class s{constructor(e={}){let{requestRegExp:o=/^\/cookie\/?\?/}=e;this.listeners={GET:[[o,this.handler]]}}handler=(e,o)=>{let t=e.url.split("?")[1];if(t&&r.has(t))o.writeHead(200,{"Content-Type":"text/plain; charset=utf-8","Set-Cookie":s.cookify(...r.getWithTimeout(t))}).end();else return!1};static make({name:e,value:o,maxAge:t,expiresAt:i,domain:p,path:u="/",secure:f=!0,httpOnly:k=!0,sameSite:h="Strict"}){let n=[`${e}=${o}`];return t!==void 0?n.push(`Max-Age=${t}`):i&&n.push(`Max-Age=${Math.round((i.getTime()-Date.now())/1e3)}`),p&&n.push(`Domain=${p}`),u&&n.push(`Path=${u}`),f&&n.push("Secure"),k&&n.push("HttpOnly"),h&&n.push(`SameSite=${h}`),n.join("; ")}static cookify(e,o){return Object.entries(e).map(([t,i])=>this.make({name:t,value:i,...o}))}};function a(s){return s?s.split(/;\s*/).reduce((e,o)=>{let[t,i]=o.split(/=/);try{e[t]=JSON.parse(i)}catch{e[t]=i}return e},{}):{}}import S from"node:crypto";var d={set:"~setcookie"};var x=2e3,c=Symbol("cookieSessionId"),m=class s{constructor(e,{users:o,domain:t,maxAge:i}){e.cookieSetter=this,this.domain=t??process.env.INSITE_HOST,this.maxAge=i??o?.sessions.collection.expireAfterSeconds,e.options.WebSocket.prototype.setCookie=s.set,e.options.WebSocket.prototype.unsetCookie=s.unset,o&&(this.users=o,e.on("client-connect",s.handleClientConnect),e.on("client-session",s.handleClientSession))}static set(e,o){let t=`${Math.round(performance.now()*Number.MAX_SAFE_INTEGER).toString(36)}$${S.randomBytes(Math.randomInt(4,8)).toString("hex")}`;r.setWithTimeout(t,[e,o],x),this.sendMessage(d.set,t)}static unset(e){this.setCookie(e.reduce((o,t)=>(o[t]="",o),{}),{maxAge:0})}static parse=a;static handleClientConnect(e,o){if(e[c]=null,o.headers.cookie){let{sessionId:t=null}=a(o.headers.cookie);e[c]=t,t&&e.setSession(t,!0)}}static handleClientSession(e){if(e[c]!==e.session?._id)if(e[c]=e.session?._id,e.isOpen&&e.session){let{domain:o,maxAge:t}=this.cookieSetter;e.setCookie({sessionId:e.session._id},{domain:o,maxAge:t})}else e.unsetCookie(["sessionId"])}};export{l as CookieMiddleware,m as CookieSetter,a as parseCookie};
|
|
2
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/server/tokenMap.js", "../src/server/Middleware.js", "../src/server/parse.js", "../src/server/Setter.js", "../src/common.js"],
|
|
4
|
+
"sourcesContent": ["export const tokenMap = new Map();\n", "import { tokenMap } from \"./tokenMap\";\n\n\nclass InSiteCookieMiddleware {\n\tconstructor(options = {}) {\n\t\tconst {\n\t\t\trequestRegExp = /^\\/cookie\\/?\\?/\n\t\t} = options;\n\t\t\n\t\tthis.listeners = { GET: [\n\t\t\t[ requestRegExp, this.handler ]\n\t\t] };\n\t\t\n\t}\n\t\n\thandler = (request, response) => {\n\t\tconst token = request.url.split(\"?\")[1];\n\t\t\n\t\tif (token && tokenMap.has(token))\n\t\t\tresponse.writeHead(200, {\n\t\t\t\t\"Content-Type\": \"text/plain; charset=utf-8\",\n\t\t\t\t\"Set-Cookie\": InSiteCookieMiddleware.cookify(...tokenMap.getWithTimeout(token))\n\t\t\t}).end();\n\t\telse\n\t\t\treturn false;\n\t\t\n\t};\n\t\n\t\n\tstatic make({ name, value, maxAge, expiresAt, domain, path = \"/\", secure = true, httpOnly = true, sameSite = \"Strict\" }) {\n\t\tconst cookie = [ `${name}=${value}` ];\n\t\t\n\t\tif (maxAge !== undefined)\n\t\t\tcookie.push(`Max-Age=${maxAge}`);\n\t\telse if (expiresAt)\n\t\t\tcookie.push(`Max-Age=${Math.round((expiresAt.getTime() - Date.now()) / 1000)}`);\n\t\t\n\t\tif (domain)\n\t\t\tcookie.push(`Domain=${domain}`);\n\t\t\n\t\tif (path)\n\t\t\tcookie.push(`Path=${path}`);\n\t\t\n\t\tif (secure)\n\t\t\tcookie.push(\"Secure\");\n\t\t\n\t\tif (httpOnly)\n\t\t\tcookie.push(\"HttpOnly\");\n\t\t\n\t\tif (sameSite)\n\t\t\tcookie.push(`SameSite=${sameSite}`);\n\t\t\n\t\treturn cookie.join(\"; \");\n\t}\n\t\n\tstatic cookify(object, options) {\n\t\treturn Object.entries(object).map(([ name, value ]) => this.make({ name, value, ...options }));\n\t}\n\t\n}\n\nexport { InSiteCookieMiddleware as CookieMiddleware };\n", "export function parseCookie(cookie) {\n\treturn cookie ? cookie.split(/;\\s*/).reduce((object, keyEqValue) => {\n\t\tconst [ key, value ] = keyEqValue.split(/=/);\n\t\t\n\t\ttry {\n\t\t\tobject[key] = JSON.parse(value);\n\t\t} catch {\n\t\t\tobject[key] = value;\n\t\t}\n\t\t\n\t\treturn object;\n\t}, {}) : {};\n}\n", "import crypto from \"node:crypto\";\nimport { headers } from \"../common\";\nimport { parseCookie } from \"./parse\";\nimport { tokenMap } from \"./tokenMap\";\n\n\nconst cookieTokenTimeout = 2000;\nconst cookieSessionIdSymbol = Symbol(\"cookieSessionId\");\n\n\nexport class CookieSetter {\n\tconstructor(wss, { users, domain, maxAge }) {\n\t\twss.cookieSetter = this;\n\t\t\n\t\tthis.domain = domain ?? process.env.INSITE_HOST;\n\t\tthis.maxAge = maxAge ?? users?.sessions.collection.expireAfterSeconds;\n\t\t\n\t\twss.options.WebSocket.prototype.setCookie = CookieSetter.set;\n\t\twss.options.WebSocket.prototype.unsetCookie = CookieSetter.unset;\n\t\t\n\t\tif (users) {\n\t\t\tthis.users = users;\n\t\t\t\n\t\t\twss.on(\"client-connect\", CookieSetter.handleClientConnect);\n\t\t\twss.on(\"client-session\", CookieSetter.handleClientSession);\n\t\t}\n\t\t\n\t}\n\t\n\t\n\tstatic set(cookie, options) {\n\t\t\n\t\tconst token = `${Math.round(performance.now() * Number.MAX_SAFE_INTEGER).toString(36)}$${crypto.randomBytes(Math.randomInt(4, 8)).toString(\"hex\")}`;\n\t\t\n\t\ttokenMap.setWithTimeout(token, [ cookie, options ], cookieTokenTimeout);\n\t\t\n\t\tthis.sendMessage(headers.set, token);\n\t\t\n\t}\n\t\n\tstatic unset(names) {\n\t\tthis.setCookie(names.reduce((cookie, name) => {\n\t\t\tcookie[name] = \"\";\n\t\t\t\n\t\t\treturn cookie;\n\t\t}, {}), { maxAge: 0 });\n\t\t\n\t}\n\t\n\tstatic parse = parseCookie;\n\t\n\t\n\tstatic handleClientConnect(ws, request) {\n\t\tws[cookieSessionIdSymbol] = null;\n\t\t\n\t\tif (request.headers.cookie) {\n\t\t\tconst { sessionId = null } = parseCookie(request.headers.cookie);\n\t\t\t\n\t\t\tws[cookieSessionIdSymbol] = sessionId;\n\t\t\t\n\t\t\tif (sessionId)\n\t\t\t\tws.setSession(sessionId, true);\n\t\t}\n\t\t\n\t}\n\t\n\tstatic handleClientSession(ws) {\n\t\tif (ws[cookieSessionIdSymbol] !== ws.session?._id) {\n\t\t\tws[cookieSessionIdSymbol] = ws.session?._id;\n\t\t\t\n\t\t\tif (ws.isOpen && ws.session) {\n\t\t\t\tconst { domain, maxAge } = this.cookieSetter;\n\t\t\t\tws.setCookie({ sessionId: ws.session._id }, { domain, maxAge });\n\t\t\t} else\n\t\t\t\tws.unsetCookie([ \"sessionId\" ]);\n\t\t}\n\t\t\n\t}\n\t\n}\n", "export const headers = {\n\tset: \"~setcookie\"\n};\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["tokenMap", "InSiteCookieMiddleware", "_InSiteCookieMiddleware", "options", "requestRegExp", "request", "response", "token", "tokenMap", "name", "value", "maxAge", "expiresAt", "domain", "path", "secure", "httpOnly", "sameSite", "cookie", "object", "parseCookie", "cookie", "object", "keyEqValue", "key", "value", "crypto", "headers", "cookieTokenTimeout", "cookieSessionIdSymbol", "CookieSetter", "_CookieSetter", "wss", "users", "domain", "maxAge", "cookie", "options", "token", "crypto", "tokenMap", "headers", "names", "name", "parseCookie", "ws", "request", "sessionId"]
|
|
7
|
+
}
|
package/package.json
CHANGED
|
@@ -1,36 +1,36 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
2
|
+
"name": "insite-cookie",
|
|
3
|
+
"version": "1.0.40",
|
|
4
|
+
"description": "Cookie support for inSite",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/server.js",
|
|
7
|
+
"module": "./dist/server.js",
|
|
8
|
+
"exports": {
|
|
9
|
+
"./server": "./dist/server.js",
|
|
10
|
+
"./client": "./dist/client.js"
|
|
11
|
+
},
|
|
12
|
+
"packageManager": "bun@1.1.8",
|
|
13
|
+
"scripts": {
|
|
14
|
+
"test": "echo \"Error: no test specified\" && exit 1",
|
|
15
|
+
"build": "bun .conveyer.js"
|
|
16
|
+
},
|
|
17
|
+
"repository": {
|
|
18
|
+
"type": "git",
|
|
19
|
+
"url": "git+https://github.com/nesvet/insite-cookie.git"
|
|
20
|
+
},
|
|
21
|
+
"keywords": [
|
|
22
|
+
"insite",
|
|
23
|
+
"cookie",
|
|
24
|
+
"client",
|
|
25
|
+
"server"
|
|
26
|
+
],
|
|
27
|
+
"author": "Eugene Nesvetaev <dev@nesvet.dev> (https://nesvet.dev/)",
|
|
28
|
+
"license": "MIT",
|
|
29
|
+
"dependencies": {
|
|
30
|
+
"insite-ws": "^1"
|
|
31
|
+
},
|
|
32
|
+
"devDependencies": {
|
|
33
|
+
"@nesvet/conveyer": "^2",
|
|
34
|
+
"@nesvet/eslint-config": "^1"
|
|
35
|
+
}
|
|
36
36
|
}
|
package/lib/Middleware.js
DELETED
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
import { tokenMap } from "./tokenMap";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
export class CookieMiddleware {
|
|
5
|
-
constructor(options = {}) {
|
|
6
|
-
const {
|
|
7
|
-
requestRegExp = /^\/cookie\/?\?/
|
|
8
|
-
} = options;
|
|
9
|
-
|
|
10
|
-
this.listeners = { GET: [
|
|
11
|
-
[ requestRegExp, this.handler ]
|
|
12
|
-
] };
|
|
13
|
-
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
handler = (request, response) => {
|
|
17
|
-
const token = request.url.split("?")[1];
|
|
18
|
-
|
|
19
|
-
if (token && tokenMap.has(token))
|
|
20
|
-
response.writeHead(200, {
|
|
21
|
-
"Content-Type": "text/plain; charset=utf-8",
|
|
22
|
-
"Set-Cookie": CookieMiddleware.cookify(...tokenMap.getWithTimeout(token))
|
|
23
|
-
}).end();
|
|
24
|
-
else
|
|
25
|
-
return false;
|
|
26
|
-
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
static make({ name, value, maxAge, expiresAt, domain, path = "/", secure = true, httpOnly = true, sameSite = "Strict" }) {
|
|
31
|
-
const cookie = [ `${name}=${value}` ];
|
|
32
|
-
|
|
33
|
-
if (maxAge !== undefined)
|
|
34
|
-
cookie.push(`Max-Age=${maxAge}`);
|
|
35
|
-
else if (expiresAt)
|
|
36
|
-
cookie.push(`Max-Age=${Math.round((expiresAt.getTime() - Date.now()) / 1000)}`);
|
|
37
|
-
|
|
38
|
-
if (domain)
|
|
39
|
-
cookie.push(`Domain=${domain}`);
|
|
40
|
-
|
|
41
|
-
if (path)
|
|
42
|
-
cookie.push(`Path=${path}`);
|
|
43
|
-
|
|
44
|
-
if (secure)
|
|
45
|
-
cookie.push("Secure");
|
|
46
|
-
|
|
47
|
-
if (httpOnly)
|
|
48
|
-
cookie.push("HttpOnly");
|
|
49
|
-
|
|
50
|
-
if (sameSite)
|
|
51
|
-
cookie.push(`SameSite=${sameSite}`);
|
|
52
|
-
|
|
53
|
-
return cookie.join("; ");
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
static cookify(object, options) {
|
|
57
|
-
return Object.entries(object).map(([ name, value ]) => this.make({ name, value, ...options }));
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
}
|
package/lib/index.js
DELETED
package/lib/parse.js
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
export function parseCookie(cookie) {
|
|
2
|
-
return cookie ? cookie.split(/;\s*/).reduce((object, keyEqValue) => {
|
|
3
|
-
const [ key, value ] = keyEqValue.split(/=/);
|
|
4
|
-
|
|
5
|
-
try {
|
|
6
|
-
object[key] = JSON.parse(value);
|
|
7
|
-
} catch {
|
|
8
|
-
object[key] = value;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
return object;
|
|
12
|
-
}, {}) : {};
|
|
13
|
-
}
|
package/lib/tokenMap.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export const tokenMap = new Map();
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
import { headers } from "../common";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
export class CookieSetterClient {
|
|
5
|
-
constructor(ws, options = {}) {
|
|
6
|
-
|
|
7
|
-
const {
|
|
8
|
-
method = "GET",
|
|
9
|
-
url = "/cookie",
|
|
10
|
-
onload,
|
|
11
|
-
onerror
|
|
12
|
-
} = options;
|
|
13
|
-
|
|
14
|
-
this.method = method;
|
|
15
|
-
this.url = url;
|
|
16
|
-
|
|
17
|
-
if (onload)
|
|
18
|
-
this.onload = onload;
|
|
19
|
-
|
|
20
|
-
if (onerror)
|
|
21
|
-
this.onerror = onerror;
|
|
22
|
-
|
|
23
|
-
ws.on(`message:${headers.set}`, this.#handleSet);
|
|
24
|
-
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
#handleSet = token => {
|
|
28
|
-
const xhr = new XMLHttpRequest();
|
|
29
|
-
|
|
30
|
-
xhr.onload = this.onload;
|
|
31
|
-
xhr.onerror = this.onerror;
|
|
32
|
-
|
|
33
|
-
xhr.open(this.method, `${this.url}?${token}`, true);
|
|
34
|
-
|
|
35
|
-
xhr.send(null);
|
|
36
|
-
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
onload() {
|
|
40
|
-
|
|
41
|
-
if (this.readyState === 4 && this.status !== 200)
|
|
42
|
-
console.error("Set cookie:", this.statusText);
|
|
43
|
-
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
onerror() {
|
|
47
|
-
|
|
48
|
-
console.error("Set cookie:", this.statusText);
|
|
49
|
-
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
}
|
package/lib/ws/client/index.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from "./SetterClient";
|
package/lib/ws/common.js
DELETED
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
import crypto from "node:crypto";
|
|
2
|
-
import { parseCookie } from "../../parse";
|
|
3
|
-
import { tokenMap } from "../../tokenMap";
|
|
4
|
-
import { headers } from "../common";
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
const cookieTokenTimeout = 2000;
|
|
8
|
-
const cookieSessionIdSymbol = Symbol("cookieSessionId");
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
export class CookieSetterServer {
|
|
12
|
-
constructor(wss, { users, domain, maxAge }) {
|
|
13
|
-
wss.cookieSetter = this;
|
|
14
|
-
|
|
15
|
-
this.domain = domain ?? process.env.HOST;
|
|
16
|
-
this.maxAge = maxAge ?? users?.sessions.collection.expireAfterSeconds;
|
|
17
|
-
|
|
18
|
-
wss.options.WebSocket.prototype.setCookie = CookieSetterServer.set;
|
|
19
|
-
wss.options.WebSocket.prototype.unsetCookie = CookieSetterServer.unset;
|
|
20
|
-
|
|
21
|
-
if (users) {
|
|
22
|
-
this.users = users;
|
|
23
|
-
|
|
24
|
-
wss.on("client-connect", CookieSetterServer.handleClientConnect);
|
|
25
|
-
wss.on("client-session", CookieSetterServer.handleClientSession);
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
static set(cookie, options) {
|
|
32
|
-
|
|
33
|
-
const token = `${Math.round(performance.now() * Number.MAX_SAFE_INTEGER).toString(36)}$${crypto.randomBytes(Math.randomInt(4, 8)).toString("hex")}`;
|
|
34
|
-
|
|
35
|
-
tokenMap.setWithTimeout(token, [ cookie, options ], cookieTokenTimeout);
|
|
36
|
-
|
|
37
|
-
this.sendMessage(headers.set, token);
|
|
38
|
-
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
static unset(names) {
|
|
42
|
-
this.setCookie(names.reduce((cookie, name) => {
|
|
43
|
-
cookie[name] = "";
|
|
44
|
-
|
|
45
|
-
return cookie;
|
|
46
|
-
}, {}), { maxAge: 0 });
|
|
47
|
-
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
static parse = parseCookie;
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
static handleClientConnect(ws, request) {
|
|
54
|
-
ws[cookieSessionIdSymbol] = null;
|
|
55
|
-
|
|
56
|
-
if (request.headers.cookie) {
|
|
57
|
-
const { sessionId = null } = parseCookie(request.headers.cookie);
|
|
58
|
-
|
|
59
|
-
ws[cookieSessionIdSymbol] = sessionId;
|
|
60
|
-
|
|
61
|
-
if (sessionId)
|
|
62
|
-
ws.setSession(sessionId, true);
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
static handleClientSession(ws) {
|
|
68
|
-
if (ws[cookieSessionIdSymbol] !== ws.session?._id) {
|
|
69
|
-
ws[cookieSessionIdSymbol] = ws.session?._id;
|
|
70
|
-
|
|
71
|
-
if (ws.isOpen && ws.session) {
|
|
72
|
-
const { domain, maxAge } = this.cookieSetter;
|
|
73
|
-
ws.setCookie({ sessionId: ws.session._id }, { domain, maxAge });
|
|
74
|
-
} else
|
|
75
|
-
ws.unsetCookie([ "sessionId" ]);
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
}
|
package/lib/ws/server/index.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from "./SetterServer";
|