@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
|
@@ -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 ===
|
|
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,
|
|
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
|
-
|
|
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,
|
|
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
|
-
|
|
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
|
-
|
|
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,
|
|
242
|
+
appendCookie(response, name, "", attributes(0, path));
|
|
215
243
|
}
|