@dudousxd/nestjs-durable-dashboard 0.36.0 → 0.37.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 +257 -103
- package/dist/server/index.cjs.map +1 -1
- package/dist/server/index.d.cts +101 -40
- package/dist/server/index.d.ts +101 -40
- package/dist/server/index.js +212 -58
- package/dist/server/index.js.map +1 -1
- package/package.json +1 -1
package/dist/server/index.js
CHANGED
|
@@ -543,28 +543,51 @@ function resolveDashboardAuth(options) {
|
|
|
543
543
|
if (typeof options.secret !== "string" || options.secret === "") {
|
|
544
544
|
throw new Error("DurableDashboardModule: dashboardAuth.secret is required and must be a non-empty string (HMAC-SHA256 signing key, 32+ bytes recommended). Failing closed.");
|
|
545
545
|
}
|
|
546
|
-
|
|
547
|
-
|
|
546
|
+
const modes = [];
|
|
547
|
+
if (options.session !== void 0) {
|
|
548
|
+
if (typeof options.session !== "function") {
|
|
549
|
+
throw new Error("DurableDashboardModule: dashboardAuth.session must be a function.");
|
|
550
|
+
}
|
|
551
|
+
modes.push("session");
|
|
552
|
+
}
|
|
553
|
+
if (options.login !== void 0) {
|
|
554
|
+
if (typeof options.login !== "function") {
|
|
555
|
+
throw new Error("DurableDashboardModule: dashboardAuth.login must be a function.");
|
|
556
|
+
}
|
|
557
|
+
modes.push("login");
|
|
558
|
+
}
|
|
559
|
+
if (options.revalidate !== void 0 && typeof options.revalidate !== "function") {
|
|
560
|
+
throw new Error("DurableDashboardModule: dashboardAuth.revalidate must be a function.");
|
|
561
|
+
}
|
|
562
|
+
if (modes.length === 0) {
|
|
563
|
+
throw new Error("DurableDashboardModule: dashboardAuth needs at least one of `session` or `login` (otherwise the cookie can never be minted). Failing closed.");
|
|
548
564
|
}
|
|
549
565
|
return {
|
|
550
566
|
secret: options.secret,
|
|
551
567
|
ttlMs: durationToMs(options.ttl ?? DEFAULT_TTL),
|
|
552
|
-
|
|
568
|
+
modes,
|
|
569
|
+
...options.session !== void 0 ? {
|
|
570
|
+
session: options.session
|
|
571
|
+
} : {},
|
|
572
|
+
...options.login !== void 0 ? {
|
|
573
|
+
login: options.login
|
|
574
|
+
} : {},
|
|
575
|
+
...options.revalidate !== void 0 ? {
|
|
576
|
+
revalidate: options.revalidate
|
|
577
|
+
} : {}
|
|
553
578
|
};
|
|
554
579
|
}
|
|
555
580
|
__name(resolveDashboardAuth, "resolveDashboardAuth");
|
|
556
581
|
|
|
557
582
|
// src/server/auth/login-page.ts
|
|
558
|
-
function
|
|
559
|
-
const loginAction = `${basePath}/login`;
|
|
560
|
-
const defaultReturnTo = basePath;
|
|
583
|
+
function page(content, title = "Durable") {
|
|
561
584
|
return `<!doctype html>
|
|
562
585
|
<html lang="en">
|
|
563
586
|
<head>
|
|
564
587
|
<meta charset="utf-8" />
|
|
565
588
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
566
589
|
<meta name="robots" content="noindex, nofollow" />
|
|
567
|
-
<title
|
|
590
|
+
<title>${title}</title>
|
|
568
591
|
<style>
|
|
569
592
|
:root { color-scheme: dark; }
|
|
570
593
|
* { box-sizing: border-box; }
|
|
@@ -595,6 +618,13 @@ function renderLoginPage(basePath) {
|
|
|
595
618
|
font-weight: 600;
|
|
596
619
|
color: #34d399;
|
|
597
620
|
}
|
|
621
|
+
h1 {
|
|
622
|
+
margin: 0 0 12px;
|
|
623
|
+
font-size: 16px;
|
|
624
|
+
font-weight: 600;
|
|
625
|
+
color: #f4f4f5;
|
|
626
|
+
}
|
|
627
|
+
p { margin: 0 0 16px; color: #a1a1aa; }
|
|
598
628
|
form { display: flex; flex-direction: column; gap: 16px; }
|
|
599
629
|
label { display: flex; flex-direction: column; gap: 6px; }
|
|
600
630
|
.field-label {
|
|
@@ -619,7 +649,7 @@ function renderLoginPage(basePath) {
|
|
|
619
649
|
font-size: 12px;
|
|
620
650
|
color: #fb7185;
|
|
621
651
|
}
|
|
622
|
-
button {
|
|
652
|
+
button, .button {
|
|
623
653
|
margin-top: 8px;
|
|
624
654
|
border-radius: 4px;
|
|
625
655
|
border: 1px solid rgb(52 211 153 / 0.4);
|
|
@@ -632,14 +662,27 @@ function renderLoginPage(basePath) {
|
|
|
632
662
|
text-transform: uppercase;
|
|
633
663
|
letter-spacing: 0.05em;
|
|
634
664
|
cursor: pointer;
|
|
665
|
+
display: inline-block;
|
|
666
|
+
text-align: center;
|
|
667
|
+
text-decoration: none;
|
|
668
|
+
box-sizing: border-box;
|
|
635
669
|
}
|
|
636
|
-
button:hover:not(:disabled) { background: rgb(52 211 153 / 0.2); }
|
|
670
|
+
button:hover:not(:disabled), .button:hover { background: rgb(52 211 153 / 0.2); }
|
|
637
671
|
button:disabled { opacity: 0.6; cursor: default; }
|
|
638
672
|
</style>
|
|
639
673
|
</head>
|
|
640
674
|
<body>
|
|
641
675
|
<div class="card">
|
|
642
|
-
|
|
676
|
+
${content}
|
|
677
|
+
</div>
|
|
678
|
+
</body>
|
|
679
|
+
</html>`;
|
|
680
|
+
}
|
|
681
|
+
__name(page, "page");
|
|
682
|
+
function renderLoginPage(basePath) {
|
|
683
|
+
const loginAction = `${basePath}/login`;
|
|
684
|
+
const defaultReturnTo = basePath;
|
|
685
|
+
return page(`<p class="brand">Durable</p>
|
|
643
686
|
<form id="login-form" autocomplete="on">
|
|
644
687
|
<label>
|
|
645
688
|
<span class="field-label">Username</span>
|
|
@@ -652,7 +695,6 @@ function renderLoginPage(basePath) {
|
|
|
652
695
|
<p id="error" role="alert">Invalid username or password.</p>
|
|
653
696
|
<button id="submit" type="submit">Sign in</button>
|
|
654
697
|
</form>
|
|
655
|
-
</div>
|
|
656
698
|
<script>
|
|
657
699
|
(function () {
|
|
658
700
|
var LOGIN_ACTION = ${JSON.stringify(loginAction)};
|
|
@@ -699,11 +741,15 @@ function renderLoginPage(basePath) {
|
|
|
699
741
|
});
|
|
700
742
|
});
|
|
701
743
|
})();
|
|
702
|
-
</script
|
|
703
|
-
</body>
|
|
704
|
-
</html>`;
|
|
744
|
+
</script>`, "Sign in \u2014 Durable");
|
|
705
745
|
}
|
|
706
746
|
__name(renderLoginPage, "renderLoginPage");
|
|
747
|
+
function renderSessionRequiredPage(basePath) {
|
|
748
|
+
return page(`<h1>Open this console from your application</h1>
|
|
749
|
+
<p>Your session is minted by the host app. Use its console launcher to sign in, then reload.</p>
|
|
750
|
+
<a class="button" href="${basePath}">Retry</a>`);
|
|
751
|
+
}
|
|
752
|
+
__name(renderSessionRequiredPage, "renderSessionRequiredPage");
|
|
707
753
|
|
|
708
754
|
// src/server/auth/request.ts
|
|
709
755
|
function isRecord(value) {
|
|
@@ -804,6 +850,15 @@ function redirectRaw(response, location, status = 302) {
|
|
|
804
850
|
raw.end();
|
|
805
851
|
}
|
|
806
852
|
__name(redirectRaw, "redirectRaw");
|
|
853
|
+
function writeHtmlRaw(response, html, status = 200) {
|
|
854
|
+
const raw = resolveRedirectResponse(response);
|
|
855
|
+
if (!raw) return;
|
|
856
|
+
raw.statusCode = status;
|
|
857
|
+
raw.setHeader("content-type", "text/html; charset=utf-8");
|
|
858
|
+
raw.setHeader("cache-control", "no-store, must-revalidate");
|
|
859
|
+
raw.end(html);
|
|
860
|
+
}
|
|
861
|
+
__name(writeHtmlRaw, "writeHtmlRaw");
|
|
807
862
|
|
|
808
863
|
// src/server/auth/cookie-header.ts
|
|
809
864
|
function parseCookieHeader(header) {
|
|
@@ -959,21 +1014,37 @@ function readSessionFromRequest(auth, request) {
|
|
|
959
1014
|
});
|
|
960
1015
|
}
|
|
961
1016
|
__name(readSessionFromRequest, "readSessionFromRequest");
|
|
962
|
-
function maybeRenewSession(auth, session, request, response) {
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
issueSessionCookie({
|
|
1017
|
+
async function maybeRenewSession(auth, session, request, response, now = Date.now()) {
|
|
1018
|
+
if (now - session.iat <= auth.ttlMs / 2) return true;
|
|
1019
|
+
const user = {
|
|
966
1020
|
id: session.sub,
|
|
967
1021
|
...session.name !== void 0 ? {
|
|
968
1022
|
name: session.name
|
|
969
1023
|
} : {},
|
|
970
1024
|
roles: session.roles
|
|
971
|
-
}
|
|
1025
|
+
};
|
|
1026
|
+
if (auth.revalidate) {
|
|
1027
|
+
let allowed;
|
|
1028
|
+
try {
|
|
1029
|
+
allowed = await auth.revalidate(user);
|
|
1030
|
+
} catch {
|
|
1031
|
+
allowed = false;
|
|
1032
|
+
}
|
|
1033
|
+
if (!allowed) {
|
|
1034
|
+
clearSessionCookie({
|
|
1035
|
+
request,
|
|
1036
|
+
response
|
|
1037
|
+
});
|
|
1038
|
+
return false;
|
|
1039
|
+
}
|
|
1040
|
+
}
|
|
1041
|
+
issueSessionCookie(user, {
|
|
972
1042
|
auth,
|
|
973
1043
|
request,
|
|
974
1044
|
response,
|
|
975
1045
|
now
|
|
976
1046
|
});
|
|
1047
|
+
return true;
|
|
977
1048
|
}
|
|
978
1049
|
__name(maybeRenewSession, "maybeRenewSession");
|
|
979
1050
|
|
|
@@ -1016,7 +1087,8 @@ DashboardLoginRedirectFilter = _ts_decorate3([
|
|
|
1016
1087
|
Catch(DashboardLoginRedirectException)
|
|
1017
1088
|
], DashboardLoginRedirectFilter);
|
|
1018
1089
|
|
|
1019
|
-
// src/server/
|
|
1090
|
+
// src/server/auth/session-required.exception.ts
|
|
1091
|
+
import { Catch as Catch2, HttpException as HttpException2, HttpStatus as HttpStatus2 } from "@nestjs/common";
|
|
1020
1092
|
function _ts_decorate4(decorators, target, key, desc) {
|
|
1021
1093
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
1022
1094
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
@@ -1024,6 +1096,38 @@ function _ts_decorate4(decorators, target, key, desc) {
|
|
|
1024
1096
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
1025
1097
|
}
|
|
1026
1098
|
__name(_ts_decorate4, "_ts_decorate");
|
|
1099
|
+
var DashboardSessionRequiredException = class extends HttpException2 {
|
|
1100
|
+
static {
|
|
1101
|
+
__name(this, "DashboardSessionRequiredException");
|
|
1102
|
+
}
|
|
1103
|
+
basePath;
|
|
1104
|
+
constructor(basePath) {
|
|
1105
|
+
super({
|
|
1106
|
+
basePath
|
|
1107
|
+
}, HttpStatus2.UNAUTHORIZED), this.basePath = basePath;
|
|
1108
|
+
}
|
|
1109
|
+
};
|
|
1110
|
+
var DashboardSessionRequiredFilter = class {
|
|
1111
|
+
static {
|
|
1112
|
+
__name(this, "DashboardSessionRequiredFilter");
|
|
1113
|
+
}
|
|
1114
|
+
catch(exception, host) {
|
|
1115
|
+
const response = host.switchToHttp().getResponse();
|
|
1116
|
+
writeHtmlRaw(response, renderSessionRequiredPage(exception.basePath), HttpStatus2.UNAUTHORIZED);
|
|
1117
|
+
}
|
|
1118
|
+
};
|
|
1119
|
+
DashboardSessionRequiredFilter = _ts_decorate4([
|
|
1120
|
+
Catch2(DashboardSessionRequiredException)
|
|
1121
|
+
], DashboardSessionRequiredFilter);
|
|
1122
|
+
|
|
1123
|
+
// src/server/durable-ui.controller.ts
|
|
1124
|
+
function _ts_decorate5(decorators, target, key, desc) {
|
|
1125
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
1126
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
1127
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
1128
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
1129
|
+
}
|
|
1130
|
+
__name(_ts_decorate5, "_ts_decorate");
|
|
1027
1131
|
function _ts_metadata3(k, v) {
|
|
1028
1132
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
1029
1133
|
}
|
|
@@ -1086,7 +1190,7 @@ var DurableUiController = class {
|
|
|
1086
1190
|
});
|
|
1087
1191
|
}
|
|
1088
1192
|
};
|
|
1089
|
-
|
|
1193
|
+
_ts_decorate5([
|
|
1090
1194
|
Get2(),
|
|
1091
1195
|
Header2("Content-Type", "text/html; charset=utf-8"),
|
|
1092
1196
|
Header2("Cache-Control", "no-store, must-revalidate"),
|
|
@@ -1094,7 +1198,7 @@ _ts_decorate4([
|
|
|
1094
1198
|
_ts_metadata3("design:paramtypes", []),
|
|
1095
1199
|
_ts_metadata3("design:returntype", String)
|
|
1096
1200
|
], DurableUiController.prototype, "index", null);
|
|
1097
|
-
|
|
1201
|
+
_ts_decorate5([
|
|
1098
1202
|
Get2("assets/:file"),
|
|
1099
1203
|
Header2("Cache-Control", "public, max-age=31536000, immutable"),
|
|
1100
1204
|
_ts_param3(0, Param2("file")),
|
|
@@ -1104,8 +1208,8 @@ _ts_decorate4([
|
|
|
1104
1208
|
]),
|
|
1105
1209
|
_ts_metadata3("design:returntype", typeof StreamableFile === "undefined" ? Object : StreamableFile)
|
|
1106
1210
|
], DurableUiController.prototype, "asset", null);
|
|
1107
|
-
DurableUiController =
|
|
1108
|
-
UseFilters(DashboardLoginRedirectFilter),
|
|
1211
|
+
DurableUiController = _ts_decorate5([
|
|
1212
|
+
UseFilters(DashboardLoginRedirectFilter, DashboardSessionRequiredFilter),
|
|
1109
1213
|
Controller2(),
|
|
1110
1214
|
_ts_param3(0, Inject2(DASHBOARD_BASE_PATH)),
|
|
1111
1215
|
_ts_param3(1, Inject2(DASHBOARD_API_PATH)),
|
|
@@ -1117,13 +1221,13 @@ DurableUiController = _ts_decorate4([
|
|
|
1117
1221
|
], DurableUiController);
|
|
1118
1222
|
|
|
1119
1223
|
// src/server/durable-auth.controller.ts
|
|
1120
|
-
function
|
|
1224
|
+
function _ts_decorate6(decorators, target, key, desc) {
|
|
1121
1225
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
1122
1226
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
1123
1227
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
1124
1228
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
1125
1229
|
}
|
|
1126
|
-
__name(
|
|
1230
|
+
__name(_ts_decorate6, "_ts_decorate");
|
|
1127
1231
|
function _ts_metadata4(k, v) {
|
|
1128
1232
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
1129
1233
|
}
|
|
@@ -1145,8 +1249,8 @@ var DurableAuthController = class _DurableAuthController {
|
|
|
1145
1249
|
auth;
|
|
1146
1250
|
basePath;
|
|
1147
1251
|
logger = new Logger(_DurableAuthController.name);
|
|
1148
|
-
/** Warn once so a throwing
|
|
1149
|
-
|
|
1252
|
+
/** Warn once per hook kind so a throwing hook doesn't spam logs on every failed attempt. */
|
|
1253
|
+
warnedHooks = /* @__PURE__ */ new Set();
|
|
1150
1254
|
constructor(auth, basePath) {
|
|
1151
1255
|
this.auth = auth;
|
|
1152
1256
|
this.basePath = basePath;
|
|
@@ -1155,7 +1259,8 @@ var DurableAuthController = class _DurableAuthController {
|
|
|
1155
1259
|
// `login-page.ts`), so this response never varies per request and needs no templating beyond
|
|
1156
1260
|
// the developer-controlled `basePath`.
|
|
1157
1261
|
loginPage() {
|
|
1158
|
-
|
|
1262
|
+
const auth = this.requireAuth();
|
|
1263
|
+
if (!auth.login) throw new NotFoundException3();
|
|
1159
1264
|
return renderLoginPage(this.basePath);
|
|
1160
1265
|
}
|
|
1161
1266
|
// Called by the login page's own fetch (JSON, not a classic form POST — see `login-page.ts` for
|
|
@@ -1164,10 +1269,12 @@ var DurableAuthController = class _DurableAuthController {
|
|
|
1164
1269
|
// (unknown user, wrong password, throwing hook) — no user-enumeration.
|
|
1165
1270
|
async login(body, request, response) {
|
|
1166
1271
|
const auth = this.requireAuth();
|
|
1272
|
+
if (!auth.login) throw new NotFoundException3();
|
|
1167
1273
|
if (!isString(body?.username) || !isString(body?.password)) {
|
|
1168
1274
|
throw new BadRequestException("Body must include string `username` and `password`.");
|
|
1169
1275
|
}
|
|
1170
|
-
const
|
|
1276
|
+
const { username, password } = body;
|
|
1277
|
+
const user = await this.runHook("login", () => auth.login?.(username, password) ?? null);
|
|
1171
1278
|
if (!user) throw new UnauthorizedException({
|
|
1172
1279
|
message: "Invalid username or password."
|
|
1173
1280
|
});
|
|
@@ -1180,6 +1287,20 @@ var DurableAuthController = class _DurableAuthController {
|
|
|
1180
1287
|
redirectTo: sanitizeReturnTo(body.returnTo, this.basePath)
|
|
1181
1288
|
};
|
|
1182
1289
|
}
|
|
1290
|
+
// Mode A: the host frontend (carrying its own auth) POSTs here; the host hook validates the raw
|
|
1291
|
+
// request and returns the session user, or `null` to deny. This is the SSO path — the host's own
|
|
1292
|
+
// guard decides, and no credential ever reaches this library.
|
|
1293
|
+
async session(request, response) {
|
|
1294
|
+
const auth = this.requireAuth();
|
|
1295
|
+
if (!auth.session) throw new NotFoundException3();
|
|
1296
|
+
const user = await this.runHook("session", () => auth.session?.(request) ?? null);
|
|
1297
|
+
if (!user) throw new UnauthorizedException();
|
|
1298
|
+
issueSessionCookie(user, {
|
|
1299
|
+
auth,
|
|
1300
|
+
request,
|
|
1301
|
+
response
|
|
1302
|
+
});
|
|
1303
|
+
}
|
|
1183
1304
|
// Plain `GET` (not `POST`): logging out only ever destroys the CALLER's own session, so it's
|
|
1184
1305
|
// safe/idempotent from the caller's perspective — a simple `<a href>` (no JS, no CSRF token)
|
|
1185
1306
|
// works. Non-passthrough `@Res()`: this handler owns the response outright (clears the cookie,
|
|
@@ -1189,30 +1310,30 @@ var DurableAuthController = class _DurableAuthController {
|
|
|
1189
1310
|
request,
|
|
1190
1311
|
response
|
|
1191
1312
|
});
|
|
1192
|
-
redirectRaw(response, `${this.basePath}/login`);
|
|
1313
|
+
redirectRaw(response, this.auth?.login ? `${this.basePath}/login` : this.basePath);
|
|
1193
1314
|
}
|
|
1194
1315
|
requireAuth() {
|
|
1195
1316
|
if (!this.auth) throw new NotFoundException3();
|
|
1196
1317
|
return this.auth;
|
|
1197
1318
|
}
|
|
1198
1319
|
/**
|
|
1199
|
-
* Run
|
|
1200
|
-
* warn-logged once, so a buggy hook never 500s the endpoint into a
|
|
1201
|
-
* the logs on repeated bad attempts.
|
|
1320
|
+
* Run a host hook (`login` or `session`) defensively: a throw is treated as a denial (uniform
|
|
1321
|
+
* failure) and warn-logged once PER KIND, so a buggy hook never 500s the endpoint into a
|
|
1322
|
+
* stack-trace leak nor floods the logs on repeated bad attempts.
|
|
1202
1323
|
*/
|
|
1203
|
-
async
|
|
1324
|
+
async runHook(kind, run) {
|
|
1204
1325
|
try {
|
|
1205
|
-
return await
|
|
1326
|
+
return await run() ?? null;
|
|
1206
1327
|
} catch (error) {
|
|
1207
|
-
if (!this.
|
|
1208
|
-
this.
|
|
1209
|
-
this.logger.warn(`dashboardAuth
|
|
1328
|
+
if (!this.warnedHooks.has(kind)) {
|
|
1329
|
+
this.warnedHooks.add(kind);
|
|
1330
|
+
this.logger.warn(`dashboardAuth ${kind} hook threw; treating as denial. ${error instanceof Error ? error.message : String(error)}`);
|
|
1210
1331
|
}
|
|
1211
1332
|
return null;
|
|
1212
1333
|
}
|
|
1213
1334
|
}
|
|
1214
1335
|
};
|
|
1215
|
-
|
|
1336
|
+
_ts_decorate6([
|
|
1216
1337
|
Get3("login"),
|
|
1217
1338
|
Header3("Content-Type", "text/html; charset=utf-8"),
|
|
1218
1339
|
Header3("Cache-Control", "no-store, must-revalidate"),
|
|
@@ -1220,7 +1341,7 @@ _ts_decorate5([
|
|
|
1220
1341
|
_ts_metadata4("design:paramtypes", []),
|
|
1221
1342
|
_ts_metadata4("design:returntype", String)
|
|
1222
1343
|
], DurableAuthController.prototype, "loginPage", null);
|
|
1223
|
-
|
|
1344
|
+
_ts_decorate6([
|
|
1224
1345
|
Post2("login"),
|
|
1225
1346
|
HttpCode(200),
|
|
1226
1347
|
_ts_param4(0, Body2()),
|
|
@@ -1236,7 +1357,21 @@ _ts_decorate5([
|
|
|
1236
1357
|
]),
|
|
1237
1358
|
_ts_metadata4("design:returntype", Promise)
|
|
1238
1359
|
], DurableAuthController.prototype, "login", null);
|
|
1239
|
-
|
|
1360
|
+
_ts_decorate6([
|
|
1361
|
+
Post2("session"),
|
|
1362
|
+
HttpCode(204),
|
|
1363
|
+
_ts_param4(0, Req()),
|
|
1364
|
+
_ts_param4(1, Res({
|
|
1365
|
+
passthrough: true
|
|
1366
|
+
})),
|
|
1367
|
+
_ts_metadata4("design:type", Function),
|
|
1368
|
+
_ts_metadata4("design:paramtypes", [
|
|
1369
|
+
Object,
|
|
1370
|
+
Object
|
|
1371
|
+
]),
|
|
1372
|
+
_ts_metadata4("design:returntype", Promise)
|
|
1373
|
+
], DurableAuthController.prototype, "session", null);
|
|
1374
|
+
_ts_decorate6([
|
|
1240
1375
|
Get3("logout"),
|
|
1241
1376
|
_ts_param4(0, Req()),
|
|
1242
1377
|
_ts_param4(1, Res()),
|
|
@@ -1247,7 +1382,7 @@ _ts_decorate5([
|
|
|
1247
1382
|
]),
|
|
1248
1383
|
_ts_metadata4("design:returntype", void 0)
|
|
1249
1384
|
], DurableAuthController.prototype, "logout", null);
|
|
1250
|
-
DurableAuthController =
|
|
1385
|
+
DurableAuthController = _ts_decorate6([
|
|
1251
1386
|
Controller3(),
|
|
1252
1387
|
_ts_param4(0, Optional2()),
|
|
1253
1388
|
_ts_param4(0, Inject3(DASHBOARD_AUTH)),
|
|
@@ -1266,13 +1401,13 @@ import { RouterModule } from "@nestjs/core";
|
|
|
1266
1401
|
|
|
1267
1402
|
// src/server/durable-session.guard.ts
|
|
1268
1403
|
import { Inject as Inject4, Injectable as Injectable2, UnauthorizedException as UnauthorizedException2 } from "@nestjs/common";
|
|
1269
|
-
function
|
|
1404
|
+
function _ts_decorate7(decorators, target, key, desc) {
|
|
1270
1405
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
1271
1406
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
1272
1407
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
1273
1408
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
1274
1409
|
}
|
|
1275
|
-
__name(
|
|
1410
|
+
__name(_ts_decorate7, "_ts_decorate");
|
|
1276
1411
|
function _ts_metadata5(k, v) {
|
|
1277
1412
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
1278
1413
|
}
|
|
@@ -1293,20 +1428,37 @@ var DurableUiSessionGuard = class {
|
|
|
1293
1428
|
this.auth = auth;
|
|
1294
1429
|
this.basePath = basePath;
|
|
1295
1430
|
}
|
|
1296
|
-
canActivate(context) {
|
|
1431
|
+
async canActivate(context) {
|
|
1297
1432
|
if (!this.auth) return true;
|
|
1433
|
+
const auth = this.auth;
|
|
1298
1434
|
const http = context.switchToHttp();
|
|
1299
1435
|
const request = http.getRequest();
|
|
1300
|
-
const session = readSessionFromRequest(
|
|
1436
|
+
const session = readSessionFromRequest(auth, request);
|
|
1301
1437
|
if (!session) {
|
|
1302
|
-
|
|
1303
|
-
|
|
1438
|
+
this.denyUnauthenticated(auth, request);
|
|
1439
|
+
}
|
|
1440
|
+
if (!await maybeRenewSession(auth, session, request, http.getResponse())) {
|
|
1441
|
+
this.denyUnauthenticated(auth, request);
|
|
1304
1442
|
}
|
|
1305
|
-
maybeRenewSession(this.auth, session, request, http.getResponse());
|
|
1306
1443
|
return true;
|
|
1307
1444
|
}
|
|
1445
|
+
/**
|
|
1446
|
+
* A revoked session (the host's `revalidate` hook says no) is denied exactly like an absent
|
|
1447
|
+
* one — by design, there is nothing left to distinguish "never had a session" from "had one,
|
|
1448
|
+
* then lost it" once the cookie is cleared, so both get the same Mode-aware treatment.
|
|
1449
|
+
*
|
|
1450
|
+
* Takes `auth` explicitly rather than reading `this.auth`: `canActivate`'s `!this.auth` early
|
|
1451
|
+
* return narrows the field within that method only — TS doesn't carry it across a method call
|
|
1452
|
+
* — so callers pass the already-narrowed value instead of this method re-deriving (or
|
|
1453
|
+
* asserting away) the nullability.
|
|
1454
|
+
*/
|
|
1455
|
+
denyUnauthenticated(auth, request) {
|
|
1456
|
+
if (!auth.login) throw new DashboardSessionRequiredException(this.basePath);
|
|
1457
|
+
const returnTo = encodeURIComponent(originalRequestUrl(request));
|
|
1458
|
+
throw new DashboardLoginRedirectException(`${this.basePath}/login?returnTo=${returnTo}`);
|
|
1459
|
+
}
|
|
1308
1460
|
};
|
|
1309
|
-
DurableUiSessionGuard =
|
|
1461
|
+
DurableUiSessionGuard = _ts_decorate7([
|
|
1310
1462
|
Injectable2(),
|
|
1311
1463
|
_ts_param5(0, Inject4(DASHBOARD_AUTH)),
|
|
1312
1464
|
_ts_param5(1, Inject4(DASHBOARD_BASE_PATH)),
|
|
@@ -1324,17 +1476,19 @@ var DurableApiSessionGuard = class {
|
|
|
1324
1476
|
constructor(auth) {
|
|
1325
1477
|
this.auth = auth;
|
|
1326
1478
|
}
|
|
1327
|
-
canActivate(context) {
|
|
1479
|
+
async canActivate(context) {
|
|
1328
1480
|
if (!this.auth) return true;
|
|
1329
1481
|
const http = context.switchToHttp();
|
|
1330
1482
|
const request = http.getRequest();
|
|
1331
1483
|
const session = readSessionFromRequest(this.auth, request);
|
|
1332
1484
|
if (!session) throw new UnauthorizedException2();
|
|
1333
|
-
maybeRenewSession(this.auth, session, request, http.getResponse())
|
|
1485
|
+
if (!await maybeRenewSession(this.auth, session, request, http.getResponse())) {
|
|
1486
|
+
throw new UnauthorizedException2();
|
|
1487
|
+
}
|
|
1334
1488
|
return true;
|
|
1335
1489
|
}
|
|
1336
1490
|
};
|
|
1337
|
-
DurableApiSessionGuard =
|
|
1491
|
+
DurableApiSessionGuard = _ts_decorate7([
|
|
1338
1492
|
Injectable2(),
|
|
1339
1493
|
_ts_param5(0, Inject4(DASHBOARD_AUTH)),
|
|
1340
1494
|
_ts_metadata5("design:type", Function),
|
|
@@ -1344,13 +1498,13 @@ DurableApiSessionGuard = _ts_decorate6([
|
|
|
1344
1498
|
], DurableApiSessionGuard);
|
|
1345
1499
|
|
|
1346
1500
|
// src/server/durable-dashboard.module.ts
|
|
1347
|
-
function
|
|
1501
|
+
function _ts_decorate8(decorators, target, key, desc) {
|
|
1348
1502
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
1349
1503
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
1350
1504
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
1351
1505
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
1352
1506
|
}
|
|
1353
|
-
__name(
|
|
1507
|
+
__name(_ts_decorate8, "_ts_decorate");
|
|
1354
1508
|
var GUARDS_METADATA = "__guards__";
|
|
1355
1509
|
function normalize(path) {
|
|
1356
1510
|
return `/${path.replace(/^\/+|\/+$/g, "")}`;
|
|
@@ -1392,7 +1546,7 @@ var DurableApiModule = class _DurableApiModule {
|
|
|
1392
1546
|
};
|
|
1393
1547
|
}
|
|
1394
1548
|
};
|
|
1395
|
-
DurableApiModule =
|
|
1549
|
+
DurableApiModule = _ts_decorate8([
|
|
1396
1550
|
Module({})
|
|
1397
1551
|
], DurableApiModule);
|
|
1398
1552
|
var DurableDashboardModule = class _DurableDashboardModule {
|
|
@@ -1478,7 +1632,7 @@ var DurableDashboardModule = class _DurableDashboardModule {
|
|
|
1478
1632
|
};
|
|
1479
1633
|
}
|
|
1480
1634
|
};
|
|
1481
|
-
DurableDashboardModule =
|
|
1635
|
+
DurableDashboardModule = _ts_decorate8([
|
|
1482
1636
|
Module({})
|
|
1483
1637
|
], DurableDashboardModule);
|
|
1484
1638
|
export {
|