@antelopejs/dms-frontend 0.5.2 → 0.5.3

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@antelopejs/dms-frontend",
3
- "version": "0.5.2",
3
+ "version": "0.5.3",
4
4
  "description": "Frontend-agnostic loader for AntelopeJS DMS, shipping the Vue 3 renderer (Vite, Inertia, SSR)",
5
5
  "keywords": [
6
6
  "antelope",
@@ -14,6 +14,32 @@ const MAX_AGE = 60 * 60 * 24 * 30;
14
14
  const UUID =
15
15
  /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
16
16
 
17
+ /**
18
+ * A suffix that keeps this instance's cookies apart from another's on the same
19
+ * host. Browsers scope cookies by hostname, not port: without it, two DMS
20
+ * frontends on localhost:3000 and localhost:3001 would overwrite each other's
21
+ * session, each failing to decrypt the other's and signing the user out. The
22
+ * suffix follows the backend, so a restart keeps the cookies it wrote.
23
+ */
24
+ function cookieScope() {
25
+ const backendUrl = (process.env.DMS_API_BASE_URL ?? "").trim();
26
+ let canonical = backendUrl;
27
+ try {
28
+ const url = new URL(backendUrl);
29
+ if (url.hostname === "localhost" || url.hostname === "[::1]")
30
+ url.hostname = "127.0.0.1";
31
+ canonical = url.toString().replace(/\/$/, "");
32
+ } catch {
33
+ // Not a URL: the raw string still tells two backends apart.
34
+ }
35
+ return createHash("sha256").update(canonical).digest("hex").slice(0, 12);
36
+ }
37
+
38
+ /** The name `name` takes in this instance's cookie jar. */
39
+ export function scopedCookieName(name) {
40
+ return `${name}_${cookieScope()}`;
41
+ }
42
+
17
43
  function key() {
18
44
  const secret = process.env.DMS_SESSION_SECRET;
19
45
  if (!secret || secret.length < 32)
@@ -54,10 +80,11 @@ function decode(value) {
54
80
  }
55
81
 
56
82
  function cookieValue(request, name) {
83
+ const scoped = scopedCookieName(name);
57
84
  const cookies = request.headers.cookie?.split(";") ?? [];
58
85
  return cookies
59
86
  .map((part) => part.trim().split("="))
60
- .find(([key]) => key === name)?.[1];
87
+ .find(([key]) => key === scoped)?.[1];
61
88
  }
62
89
 
63
90
  /**
@@ -83,7 +110,8 @@ function lifetime(persistent) {
83
110
  return persistent ? MAX_AGE : undefined;
84
111
  }
85
112
 
86
- function appendCookie(response, cookie) {
113
+ function appendCookie(response, name, value, cookieAttributes) {
114
+ const cookie = `${scopedCookieName(name)}=${value}; ${cookieAttributes}`;
87
115
  const current = response.getHeader("set-cookie");
88
116
  response.setHeader(
89
117
  "set-cookie",
@@ -122,12 +150,14 @@ export function setRequestSession(request, session) {
122
150
  export function writeSession(response, session) {
123
151
  appendCookie(
124
152
  response,
125
- `${SESSION_COOKIE}=${encode(session)}; ${attributes(lifetime(isPersistent(session)))}`,
153
+ SESSION_COOKIE,
154
+ encode(session),
155
+ attributes(lifetime(isPersistent(session))),
126
156
  );
127
157
  }
128
158
 
129
159
  export function clearSession(response) {
130
- appendCookie(response, `${SESSION_COOKIE}=; ${attributes(0)}`);
160
+ appendCookie(response, SESSION_COOKIE, "", attributes(0));
131
161
  }
132
162
 
133
163
  export function readAccounts(request) {
@@ -139,7 +169,9 @@ function writeAccountIndex(response, accounts) {
139
169
  const persistent = Object.values(accounts).some(isPersistent);
140
170
  appendCookie(
141
171
  response,
142
- `${ACCOUNT_INDEX_COOKIE}=${encode(accounts)}; ${attributes(lifetime(persistent))}`,
172
+ ACCOUNT_INDEX_COOKIE,
173
+ encode(accounts),
174
+ attributes(lifetime(persistent)),
143
175
  );
144
176
  }
145
177
 
@@ -156,7 +188,9 @@ export function storeAccount(request, response, session, accountId) {
156
188
  writeAccountIndex(response, accounts);
157
189
  appendCookie(
158
190
  response,
159
- `${accountCookieName(id)}=${encode({ refreshToken: session.refreshToken, ...accountDescriptor })}; ${attributes(lifetime(accountDescriptor.persistent))}`,
191
+ accountCookieName(id),
192
+ encode({ refreshToken: session.refreshToken, ...accountDescriptor }),
193
+ attributes(lifetime(accountDescriptor.persistent)),
160
194
  );
161
195
  return accountDescriptor;
162
196
  }
@@ -186,10 +220,7 @@ export function removeAccount(request, response, accountId) {
186
220
  delete accounts[accountId];
187
221
  writeAccountIndex(response, accounts);
188
222
  if (UUID.test(accountId ?? ""))
189
- appendCookie(
190
- response,
191
- `${accountCookieName(accountId)}=; ${attributes(0)}`,
192
- );
223
+ appendCookie(response, accountCookieName(accountId), "", attributes(0));
193
224
  }
194
225
 
195
226
  export function readSealedCookie(request, name) {
@@ -204,12 +235,9 @@ export function writeSealedCookie(
204
235
  maxAge,
205
236
  path = "/auth/oauth",
206
237
  ) {
207
- appendCookie(
208
- response,
209
- `${name}=${encode(value)}; ${attributes(maxAge, path)}`,
210
- );
238
+ appendCookie(response, name, encode(value), attributes(maxAge, path));
211
239
  }
212
240
 
213
241
  export function clearSealedCookie(response, name, path = "/auth/oauth") {
214
- appendCookie(response, `${name}=; ${attributes(0, path)}`);
242
+ appendCookie(response, name, "", attributes(0, path));
215
243
  }