@dudousxd/nestjs-media-dashboard 0.7.2 → 0.9.0
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/dist/server/index.cjs +34 -9
- package/dist/server/index.cjs.map +1 -1
- package/dist/server/index.d.cts +11 -1
- package/dist/server/index.d.ts +11 -1
- package/dist/server/index.js +34 -9
- package/dist/server/index.js.map +1 -1
- package/dist/spa/assets/{index-CCjuiZ1u.js → index-BrkxqVg1.js} +1 -1
- package/dist/spa/assets/{preview-rp64mDIs.js → preview-CLr-sXUW.js} +1 -1
- package/dist/spa/assets/{styles-Bwprsevk.js → styles-CPr59Wd5.js} +30 -30
- package/dist/spa/index.html +2 -2
- package/dist/spa/preview.html +2 -2
- package/package.json +1 -1
package/dist/server/index.d.ts
CHANGED
|
@@ -13,6 +13,13 @@ interface ConsoleSessionUser {
|
|
|
13
13
|
type SessionHook = (request: unknown) => Promise<ConsoleSessionUser | null> | ConsoleSessionUser | null;
|
|
14
14
|
/** Host hook for Mode B — validates submitted credentials from the built-in login screen. */
|
|
15
15
|
type LoginHook = (username: string, password: string) => Promise<ConsoleSessionUser | null> | ConsoleSessionUser | null;
|
|
16
|
+
/**
|
|
17
|
+
* Re-checks a LIVE session when the cookie is slid forward. Runs at most once per `ttl/2` per
|
|
18
|
+
* session, so a DB round-trip here is cheap. Return `false` to revoke (the cookie is cleared and
|
|
19
|
+
* the request denied). Distinct from `session`: that hook reads the host's auth off a fresh
|
|
20
|
+
* request, which a console XHR does not carry — this one receives the already-minted session.
|
|
21
|
+
*/
|
|
22
|
+
type RevalidateHook = (session: ConsoleSessionUser) => Promise<boolean> | boolean;
|
|
16
23
|
/** Author-facing `auth` option on `MediaDashboardModule.forRoot`. Mirrors telescope's dashboardAuth. */
|
|
17
24
|
interface ConsoleAuthOptions {
|
|
18
25
|
/** REQUIRED HMAC-SHA256 signing key. Missing/empty => boot error (fail closed). */
|
|
@@ -23,6 +30,8 @@ interface ConsoleAuthOptions {
|
|
|
23
30
|
session?: SessionHook;
|
|
24
31
|
/** Mode B: validate credentials from the built-in login screen. */
|
|
25
32
|
login?: LoginHook;
|
|
33
|
+
/** Re-checks the session on sliding renewal. Not a mode — it cannot mint a session on its own. */
|
|
34
|
+
revalidate?: RevalidateHook;
|
|
26
35
|
}
|
|
27
36
|
|
|
28
37
|
interface MediaDashboardOptions {
|
|
@@ -46,7 +55,8 @@ interface MediaDashboardOptions {
|
|
|
46
55
|
* Gate the console (SPA + API) behind a built-in session-cookie login, telescope-style. Omit to
|
|
47
56
|
* leave the console open (front it with your own guard). When set, the SPA renders a login screen
|
|
48
57
|
* until a valid cookie exists; supply a `login(username, password)` and/or `session(request)`
|
|
49
|
-
* hook that returns a session user (or `null` to deny)
|
|
58
|
+
* hook that returns a session user (or `null` to deny), and optionally a `revalidate(session)`
|
|
59
|
+
* hook that re-checks the user when the cookie is slid forward — see {@link ConsoleAuthOptions}.
|
|
50
60
|
*/
|
|
51
61
|
auth?: ConsoleAuthOptions;
|
|
52
62
|
/**
|
package/dist/server/index.js
CHANGED
|
@@ -42,6 +42,9 @@ function resolveConsoleAuth(options) {
|
|
|
42
42
|
} : {},
|
|
43
43
|
...options.login ? {
|
|
44
44
|
login: options.login
|
|
45
|
+
} : {},
|
|
46
|
+
...options.revalidate ? {
|
|
47
|
+
revalidate: options.revalidate
|
|
45
48
|
} : {}
|
|
46
49
|
};
|
|
47
50
|
}
|
|
@@ -316,14 +319,16 @@ var MediaConsoleGuard = class {
|
|
|
316
319
|
this.auth = auth;
|
|
317
320
|
this.cookiePath = cookiePath;
|
|
318
321
|
}
|
|
319
|
-
canActivate(context) {
|
|
322
|
+
async canActivate(context) {
|
|
320
323
|
if (!this.auth) return true;
|
|
321
324
|
const http = context.switchToHttp();
|
|
322
325
|
const request = http.getRequest();
|
|
323
326
|
const session = this.verifyRequestSession(request);
|
|
324
327
|
if (!session) throw new UnauthorizedException();
|
|
325
328
|
attachSession(request, session);
|
|
326
|
-
this.maybeRenew(http.getResponse(), request, session)
|
|
329
|
+
if (!await this.maybeRenew(http.getResponse(), request, session)) {
|
|
330
|
+
throw new UnauthorizedException();
|
|
331
|
+
}
|
|
327
332
|
return true;
|
|
328
333
|
}
|
|
329
334
|
verifyRequestSession(request) {
|
|
@@ -335,26 +340,46 @@ var MediaConsoleGuard = class {
|
|
|
335
340
|
});
|
|
336
341
|
}
|
|
337
342
|
/**
|
|
338
|
-
* Sliding renewal: when a valid cookie is past half its TTL, re-issue a fresh one
|
|
339
|
-
* never get logged out mid-session
|
|
343
|
+
* Sliding renewal + revalidation: when a valid cookie is past half its TTL, re-issue a fresh one
|
|
344
|
+
* so active users never get logged out mid-session — but first let the host's `revalidate` hook
|
|
345
|
+
* re-check the user, so a deactivated or demoted operator loses access instead of riding a
|
|
346
|
+
* self-renewing cookie. Returns `false` when the session was revoked (cookie already cleared).
|
|
340
347
|
*/
|
|
341
|
-
maybeRenew(response, request, session) {
|
|
342
|
-
if (!this.auth) return;
|
|
348
|
+
async maybeRenew(response, request, session) {
|
|
349
|
+
if (!this.auth) return true;
|
|
343
350
|
const now = Date.now();
|
|
344
|
-
if (now - session.iat <= this.auth.ttlMs / 2) return;
|
|
345
|
-
|
|
351
|
+
if (now - session.iat <= this.auth.ttlMs / 2) return true;
|
|
352
|
+
const user = {
|
|
346
353
|
id: session.sub,
|
|
347
354
|
...session.name !== void 0 ? {
|
|
348
355
|
name: session.name
|
|
349
356
|
} : {},
|
|
350
357
|
roles: session.roles
|
|
351
|
-
}
|
|
358
|
+
};
|
|
359
|
+
if (this.auth.revalidate) {
|
|
360
|
+
let allowed;
|
|
361
|
+
try {
|
|
362
|
+
allowed = await this.auth.revalidate(user);
|
|
363
|
+
} catch {
|
|
364
|
+
allowed = false;
|
|
365
|
+
}
|
|
366
|
+
if (!allowed) {
|
|
367
|
+
clearSessionCookie({
|
|
368
|
+
cookiePath: this.cookiePath ?? "/",
|
|
369
|
+
request,
|
|
370
|
+
response
|
|
371
|
+
});
|
|
372
|
+
return false;
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
issueSessionCookie(user, {
|
|
352
376
|
auth: this.auth,
|
|
353
377
|
cookiePath: this.cookiePath ?? "/",
|
|
354
378
|
request,
|
|
355
379
|
response,
|
|
356
380
|
now
|
|
357
381
|
});
|
|
382
|
+
return true;
|
|
358
383
|
}
|
|
359
384
|
};
|
|
360
385
|
MediaConsoleGuard = _ts_decorate([
|