@nestjs-kit/better-auth 2.0.0 → 2.1.2
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/README.md +7 -7
- package/dist/admin.cjs +3 -4
- package/dist/admin.d.cts +1 -3
- package/dist/admin.d.cts.map +1 -1
- package/dist/admin.d.mts +1 -3
- package/dist/admin.d.mts.map +1 -1
- package/dist/admin.mjs +3 -4
- package/dist/api-key.cjs +4 -5
- package/dist/api-key.d.cts +1 -3
- package/dist/api-key.d.cts.map +1 -1
- package/dist/api-key.d.mts +1 -3
- package/dist/api-key.d.mts.map +1 -1
- package/dist/api-key.mjs +4 -5
- package/dist/{auth-contracts-Brh_Qko9.d.cts → auth-contracts-CADGyI0O.d.mts} +3 -53
- package/dist/auth-contracts-CADGyI0O.d.mts.map +1 -0
- package/dist/{auth-contracts-Cz7C4_Ch.d.mts → auth-contracts-zvt8ysoZ.d.cts} +3 -53
- package/dist/auth-contracts-zvt8ysoZ.d.cts.map +1 -0
- package/dist/{auth-decorators-Cu_nxWnF.cjs → auth-decorators-CJKE9wlT.cjs} +8 -10
- package/dist/{auth-decorators-Cu_nxWnF.cjs.map → auth-decorators-CJKE9wlT.cjs.map} +1 -1
- package/dist/{auth-decorators-B1mFnGJ6.mjs → auth-decorators-CkNkLNpU.mjs} +8 -10
- package/dist/{auth-decorators-B1mFnGJ6.mjs.map → auth-decorators-CkNkLNpU.mjs.map} +1 -1
- package/dist/{auth-errors-C3rbTV9p.mjs → auth-errors-JjxGDVSt.mjs} +3 -5
- package/dist/{auth-errors-C3rbTV9p.mjs.map → auth-errors-JjxGDVSt.mjs.map} +1 -1
- package/dist/{auth-errors-DmiKl0L_.cjs → auth-errors-RW7hOVI-.cjs} +3 -5
- package/dist/{auth-errors-DmiKl0L_.cjs.map → auth-errors-RW7hOVI-.cjs.map} +1 -1
- package/dist/{auth-guard-h9QB_l11.mjs → auth-guard-Da92QEK5.mjs} +4 -5
- package/dist/{auth-guard-h9QB_l11.mjs.map → auth-guard-Da92QEK5.mjs.map} +1 -1
- package/dist/{auth-guard-CLyhAEEj.cjs → auth-guard-wapEh_M_.cjs} +4 -5
- package/dist/{auth-guard-CLyhAEEj.cjs.map → auth-guard-wapEh_M_.cjs.map} +1 -1
- package/dist/{auth-module-BgcY2HpA.cjs → auth-module-ab60-WJZ.cjs} +28 -47
- package/dist/auth-module-ab60-WJZ.cjs.map +1 -0
- package/dist/{auth-module-CtHx3gRU.mjs → auth-module-uy3BBWwR.mjs} +28 -47
- package/dist/auth-module-uy3BBWwR.mjs.map +1 -0
- package/dist/{auth-scope-interceptor-BjxAL1-S.cjs → auth-scope-interceptor-Bui20-Ps.cjs} +5 -7
- package/dist/{auth-scope-interceptor-BjxAL1-S.cjs.map → auth-scope-interceptor-Bui20-Ps.cjs.map} +1 -1
- package/dist/{auth-scope-interceptor-DYPn3b8M.mjs → auth-scope-interceptor-CvCQ52dV.mjs} +5 -7
- package/dist/{auth-scope-interceptor-DYPn3b8M.mjs.map → auth-scope-interceptor-CvCQ52dV.mjs.map} +1 -1
- package/dist/{bridge-protocol-c66aEkr5.mjs → bridge-protocol-CmRsff2P.mjs} +2 -3
- package/dist/{bridge-protocol-BDw8opAG.cjs.map → bridge-protocol-CmRsff2P.mjs.map} +1 -1
- package/dist/{bridge-protocol-BDw8opAG.cjs → bridge-protocol-DNFhIKdo.cjs} +2 -3
- package/dist/{bridge-protocol-c66aEkr5.mjs.map → bridge-protocol-DNFhIKdo.cjs.map} +1 -1
- package/dist/{decorate-Dt0e9K6R.mjs → decorate-bO-rBn-G.mjs} +5 -9
- package/dist/{decorate-Dt0e9K6R.mjs.map → decorate-bO-rBn-G.mjs.map} +1 -1
- package/dist/{decorate-Cr4Q7bNE.cjs → decorate-fMNf0caZ.cjs} +5 -9
- package/dist/{decorate-Cr4Q7bNE.cjs.map → decorate-fMNf0caZ.cjs.map} +1 -1
- package/dist/express.cjs +3 -4
- package/dist/express.d.cts +1 -3
- package/dist/express.d.cts.map +1 -1
- package/dist/express.d.mts +1 -3
- package/dist/express.d.mts.map +1 -1
- package/dist/express.mjs +3 -4
- package/dist/fastify.cjs +2 -3
- package/dist/fastify.d.cts +1 -3
- package/dist/fastify.d.cts.map +1 -1
- package/dist/fastify.d.mts +1 -3
- package/dist/fastify.d.mts.map +1 -1
- package/dist/fastify.mjs +2 -3
- package/dist/graphql.cjs +7 -9
- package/dist/graphql.cjs.map +1 -1
- package/dist/graphql.d.cts +1 -3
- package/dist/graphql.d.cts.map +1 -1
- package/dist/graphql.d.mts +1 -3
- package/dist/graphql.d.mts.map +1 -1
- package/dist/graphql.mjs +7 -9
- package/dist/graphql.mjs.map +1 -1
- package/dist/index.cjs +7 -7
- package/dist/index.d.cts +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.mjs +7 -7
- package/dist/microservices.cjs +4 -6
- package/dist/microservices.cjs.map +1 -1
- package/dist/microservices.d.cts +1 -5
- package/dist/microservices.d.cts.map +1 -1
- package/dist/microservices.d.mts +1 -5
- package/dist/microservices.d.mts.map +1 -1
- package/dist/microservices.mjs +3 -5
- package/dist/microservices.mjs.map +1 -1
- package/dist/organization.cjs +3 -4
- package/dist/organization.d.cts +1 -3
- package/dist/organization.d.cts.map +1 -1
- package/dist/organization.d.mts +1 -3
- package/dist/organization.d.mts.map +1 -1
- package/dist/organization.mjs +3 -4
- package/dist/{platform-CZl7TY8j.mjs → platform-BKYVzAv1.mjs} +3 -5
- package/dist/{platform-CZl7TY8j.mjs.map → platform-BKYVzAv1.mjs.map} +1 -1
- package/dist/{platform-YICqqYv6.cjs → platform-C67dxSls.cjs} +3 -5
- package/dist/{platform-YICqqYv6.cjs.map → platform-C67dxSls.cjs.map} +1 -1
- package/dist/platform.cjs +1 -1
- package/dist/platform.d.cts +0 -2
- package/dist/platform.d.cts.map +1 -1
- package/dist/platform.d.mts +0 -2
- package/dist/platform.d.mts.map +1 -1
- package/dist/platform.mjs +1 -1
- package/dist/plugin.cjs +4 -8
- package/dist/plugin.cjs.map +1 -1
- package/dist/plugin.d.cts +0 -4
- package/dist/plugin.d.cts.map +1 -1
- package/dist/plugin.d.mts +0 -4
- package/dist/plugin.d.mts.map +1 -1
- package/dist/plugin.mjs +4 -8
- package/dist/plugin.mjs.map +1 -1
- package/dist/{principal-readings-Ied2staw.mjs → principal-readings-BuXTU0-2.mjs} +3 -4
- package/dist/{principal-readings-Ied2staw.mjs.map → principal-readings-BuXTU0-2.mjs.map} +1 -1
- package/dist/{principal-readings-Chmt6rQV.cjs → principal-readings-JLNT58k0.cjs} +3 -4
- package/dist/{principal-readings-Chmt6rQV.cjs.map → principal-readings-JLNT58k0.cjs.map} +1 -1
- package/dist/{rolldown-runtime-VH7oDXx4.cjs → rolldown-runtime-CmQyd0Gu.cjs} +1 -2
- package/dist/testing/conformance.cjs +24 -31
- package/dist/testing/conformance.cjs.map +1 -1
- package/dist/testing/conformance.d.cts +4 -14
- package/dist/testing/conformance.d.cts.map +1 -1
- package/dist/testing/conformance.d.mts +4 -14
- package/dist/testing/conformance.d.mts.map +1 -1
- package/dist/testing/conformance.mjs +23 -30
- package/dist/testing/conformance.mjs.map +1 -1
- package/dist/testing.cjs +6 -7
- package/dist/testing.d.cts +1 -3
- package/dist/testing.d.cts.map +1 -1
- package/dist/testing.d.mts +1 -3
- package/dist/testing.d.mts.map +1 -1
- package/dist/testing.mjs +6 -7
- package/dist/websockets.cjs +7 -10
- package/dist/websockets.cjs.map +1 -1
- package/dist/websockets.d.cts +1 -7
- package/dist/websockets.d.cts.map +1 -1
- package/dist/websockets.d.mts +1 -7
- package/dist/websockets.d.mts.map +1 -1
- package/dist/websockets.mjs +7 -10
- package/dist/websockets.mjs.map +1 -1
- package/package.json +25 -25
- package/dist/auth-contracts-Brh_Qko9.d.cts.map +0 -1
- package/dist/auth-contracts-Cz7C4_Ch.d.mts.map +0 -1
- package/dist/auth-module-BgcY2HpA.cjs.map +0 -1
- package/dist/auth-module-CtHx3gRU.mjs.map +0 -1
package/dist/testing.cjs
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_auth_errors = require("./auth-errors-
|
|
3
|
-
const
|
|
4
|
-
const
|
|
5
|
-
const require_bridge_protocol = require("./bridge-protocol-
|
|
6
|
-
const require_principal_readings = require("./principal-readings-
|
|
2
|
+
const require_auth_errors = require("./auth-errors-RW7hOVI-.cjs");
|
|
3
|
+
const require_auth_scope_interceptor = require("./auth-scope-interceptor-Bui20-Ps.cjs");
|
|
4
|
+
const require_decorate = require("./decorate-fMNf0caZ.cjs");
|
|
5
|
+
const require_bridge_protocol = require("./bridge-protocol-DNFhIKdo.cjs");
|
|
6
|
+
const require_principal_readings = require("./principal-readings-JLNT58k0.cjs");
|
|
7
7
|
let rxjs = require("rxjs");
|
|
8
|
-
|
|
8
|
+
// src/testing.ts
|
|
9
9
|
const TEST_APP = Symbol.for("@nestjs-kit/better-auth:test-app");
|
|
10
10
|
const TEST_APP_CLOSE = Symbol.for("@nestjs-kit/better-auth:test-app-close");
|
|
11
11
|
const TEST_OVERRIDES = Symbol.for("@nestjs-kit/better-auth:test-overrides");
|
|
@@ -209,7 +209,6 @@ function overrideAuthGuard(builder, impl) {
|
|
|
209
209
|
});
|
|
210
210
|
return builder;
|
|
211
211
|
}
|
|
212
|
-
//#endregion
|
|
213
212
|
exports.authHeadersFor = authHeadersFor;
|
|
214
213
|
exports.initTestApp = initTestApp;
|
|
215
214
|
exports.overrideAuthGuard = overrideAuthGuard;
|
package/dist/testing.d.cts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import { Ct as AuthPrincipal, ht as TransportCall, it as PrincipalSource, tt as PrincipalRequest, u as AuthorizationDecision, xt as AuthLike } from "./auth-contracts-
|
|
1
|
+
import { Ct as AuthPrincipal, ht as TransportCall, it as PrincipalSource, tt as PrincipalRequest, u as AuthorizationDecision, xt as AuthLike } from "./auth-contracts-zvt8ysoZ.cjs";
|
|
2
2
|
import { CanActivate, ExecutionContext, INestApplication } from "@nestjs/common";
|
|
3
3
|
import { TestingModuleBuilder } from "@nestjs/testing";
|
|
4
|
-
//#region src/testing.d.ts
|
|
5
4
|
type FixedPrincipal = AuthPrincipal | null | ((call: TransportCall) => AuthPrincipal | null);
|
|
6
5
|
type Decide = (policyId: string, params: unknown, principal: AuthPrincipal) => AuthorizationDecision | undefined | Promise<AuthorizationDecision | undefined>;
|
|
7
6
|
/**
|
|
@@ -59,6 +58,5 @@ export declare function stampPrincipal(context: ExecutionContext, principal: Aut
|
|
|
59
58
|
export declare function overrideAuthGuard(builder: TestingModuleBuilder, impl: CanActivate | {
|
|
60
59
|
principal: AuthPrincipal | null | ((ctx: ExecutionContext) => AuthPrincipal | null);
|
|
61
60
|
}): TestingModuleBuilder;
|
|
62
|
-
//#endregion
|
|
63
61
|
export {};
|
|
64
62
|
//# sourceMappingURL=testing.d.cts.map
|
package/dist/testing.d.cts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"testing.d.cts","names":[],"sources":["../src/testing.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"testing.d.cts","names":[],"sources":["../src/testing.ts"],"mappings":";;;KAoDK,iBACD,yBAEE,MAAM,kBAAkB;KACzB,UACH,kBACA,iBACA,WAAW,kBAET,oCAEA,QAAQ;;;;;;;;;;wBAoEU,YAAY,UAAU,kBAC1C,KAAK,GACL;EAAW,aAAa,aAAa;IACpC,QAAQ;;wBA2CW,eACpB,MAAM,UACN,iBACC,QAAQ;;;;;;wBAmBK,kBACd,SAAS,sBACT,WAAW,gBACX;EAAW;IACV;;;;;wBAiCa,kBACd,SAAS,sBACT,QAAQ,SACP;;wBAmBa,cACd,WAAW,kBAAkB,KAAK,qBAAqB,uBACvD;EACE;EACA;EACA;IAED;;;;;;;;wBA0Ba,eACd,SAAS,kBACT,WAAW,sBACX;EAAW;;;;;;;;;;;wBAoCG,kBACd,SAAS,sBACT,MACI;EAEE,WACI,yBAEE,KAAK,qBAAqB;IAErC"}
|
package/dist/testing.d.mts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import { Ct as AuthPrincipal, ht as TransportCall, it as PrincipalSource, tt as PrincipalRequest, u as AuthorizationDecision, xt as AuthLike } from "./auth-contracts-
|
|
1
|
+
import { Ct as AuthPrincipal, ht as TransportCall, it as PrincipalSource, tt as PrincipalRequest, u as AuthorizationDecision, xt as AuthLike } from "./auth-contracts-CADGyI0O.mjs";
|
|
2
2
|
import { CanActivate, ExecutionContext, INestApplication } from "@nestjs/common";
|
|
3
3
|
import { TestingModuleBuilder } from "@nestjs/testing";
|
|
4
|
-
//#region src/testing.d.ts
|
|
5
4
|
type FixedPrincipal = AuthPrincipal | null | ((call: TransportCall) => AuthPrincipal | null);
|
|
6
5
|
type Decide = (policyId: string, params: unknown, principal: AuthPrincipal) => AuthorizationDecision | undefined | Promise<AuthorizationDecision | undefined>;
|
|
7
6
|
/**
|
|
@@ -59,6 +58,5 @@ export declare function stampPrincipal(context: ExecutionContext, principal: Aut
|
|
|
59
58
|
export declare function overrideAuthGuard(builder: TestingModuleBuilder, impl: CanActivate | {
|
|
60
59
|
principal: AuthPrincipal | null | ((ctx: ExecutionContext) => AuthPrincipal | null);
|
|
61
60
|
}): TestingModuleBuilder;
|
|
62
|
-
//#endregion
|
|
63
61
|
export {};
|
|
64
62
|
//# sourceMappingURL=testing.d.mts.map
|
package/dist/testing.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"testing.d.mts","names":[],"sources":["../src/testing.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"testing.d.mts","names":[],"sources":["../src/testing.ts"],"mappings":";;;KAoDK,iBACD,yBAEE,MAAM,kBAAkB;KACzB,UACH,kBACA,iBACA,WAAW,kBAET,oCAEA,QAAQ;;;;;;;;;;wBAoEU,YAAY,UAAU,kBAC1C,KAAK,GACL;EAAW,aAAa,aAAa;IACpC,QAAQ;;wBA2CW,eACpB,MAAM,UACN,iBACC,QAAQ;;;;;;wBAmBK,kBACd,SAAS,sBACT,WAAW,gBACX;EAAW;IACV;;;;;wBAiCa,kBACd,SAAS,sBACT,QAAQ,SACP;;wBAmBa,cACd,WAAW,kBAAkB,KAAK,qBAAqB,uBACvD;EACE;EACA;EACA;IAED;;;;;;;;wBA0Ba,eACd,SAAS,kBACT,WAAW,sBACX;EAAW;;;;;;;;;;;wBAoCG,kBACd,SAAS,sBACT,MACI;EAEE,WACI,yBAEE,KAAK,qBAAqB;IAErC"}
|
package/dist/testing.mjs
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { n as BetterAuthConfigurationError } from "./auth-errors-
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { t as BRIDGE_HANDLE } from "./bridge-protocol-
|
|
5
|
-
import { n as stampResult, r as stampedReading, t as PrincipalReadings } from "./principal-readings-
|
|
1
|
+
import { n as BetterAuthConfigurationError } from "./auth-errors-JjxGDVSt.mjs";
|
|
2
|
+
import { a as absent, n as ScopeCore, o as authenticated, r as ChainPrincipalResolver } from "./auth-scope-interceptor-CvCQ52dV.mjs";
|
|
3
|
+
import { C as PRINCIPAL_RESOLVER, D as ROUTE_PLANNER, M as TRANSPORT_REGISTRY, O as SCOPE_CORE, T as REQUEST_SCOPE, f as GUARD_CORE, m as INSTANCE_REGISTRY, y as POLICY_INVOKER } from "./decorate-bO-rBn-G.mjs";
|
|
4
|
+
import { t as BRIDGE_HANDLE } from "./bridge-protocol-CmRsff2P.mjs";
|
|
5
|
+
import { n as stampResult, r as stampedReading, t as PrincipalReadings } from "./principal-readings-BuXTU0-2.mjs";
|
|
6
6
|
import { isObservable, lastValueFrom } from "rxjs";
|
|
7
|
-
|
|
7
|
+
// src/testing.ts
|
|
8
8
|
const TEST_APP = Symbol.for("@nestjs-kit/better-auth:test-app");
|
|
9
9
|
const TEST_APP_CLOSE = Symbol.for("@nestjs-kit/better-auth:test-app-close");
|
|
10
10
|
const TEST_OVERRIDES = Symbol.for("@nestjs-kit/better-auth:test-overrides");
|
|
@@ -208,7 +208,6 @@ function overrideAuthGuard(builder, impl) {
|
|
|
208
208
|
});
|
|
209
209
|
return builder;
|
|
210
210
|
}
|
|
211
|
-
//#endregion
|
|
212
211
|
export { authHeadersFor, initTestApp, overrideAuthGuard, overrideDecisions, overridePrincipal, stampPrincipal, testPrincipal };
|
|
213
212
|
|
|
214
213
|
//# sourceMappingURL=testing.mjs.map
|
package/dist/websockets.cjs
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_auth_errors = require("./auth-errors-
|
|
3
|
-
const
|
|
4
|
-
const
|
|
5
|
-
const
|
|
2
|
+
const require_auth_errors = require("./auth-errors-RW7hOVI-.cjs");
|
|
3
|
+
const require_bridge_protocol = require("./bridge-protocol-DNFhIKdo.cjs");
|
|
4
|
+
const require_platform = require("./platform-C67dxSls.cjs");
|
|
5
|
+
const require_decorate = require("./decorate-fMNf0caZ.cjs");
|
|
6
6
|
let _nestjs_common = require("@nestjs/common");
|
|
7
7
|
let _nestjs_core = require("@nestjs/core");
|
|
8
8
|
let _nestjs_websockets = require("@nestjs/websockets");
|
|
9
|
-
|
|
9
|
+
// src/ws-connection-auth.ts
|
|
10
10
|
function wsCloseCodeFor(failure) {
|
|
11
11
|
return failure.status === 401 ? 4401 : failure.status === 403 ? 4403 : 4429;
|
|
12
12
|
}
|
|
@@ -159,8 +159,7 @@ WsConnectionAuth = require_decorate.__decorate([
|
|
|
159
159
|
Object
|
|
160
160
|
])
|
|
161
161
|
], WsConnectionAuth);
|
|
162
|
-
|
|
163
|
-
//#region src/socket-io-transport.ts
|
|
162
|
+
// src/socket-io-transport.ts
|
|
164
163
|
/** Convert only mapped headers here: native Headers errors can quote the credential. */
|
|
165
164
|
function mappedCredentialHeaders(input) {
|
|
166
165
|
const headers = new Headers();
|
|
@@ -297,8 +296,7 @@ function socketIoTransport(options = {}) {
|
|
|
297
296
|
advise: (context) => quotaAdvice(context, ttl)
|
|
298
297
|
});
|
|
299
298
|
}
|
|
300
|
-
|
|
301
|
-
//#region src/ws-transport.ts
|
|
299
|
+
// src/ws-transport.ts
|
|
302
300
|
function recordUpgradeRequest(client, request) {
|
|
303
301
|
Object.defineProperty(client, require_bridge_protocol.UPGRADE_REQUEST, {
|
|
304
302
|
value: Object.freeze({
|
|
@@ -378,7 +376,6 @@ function wsTransport(options = {}) {
|
|
|
378
376
|
advise: (context) => quotaAdvice(context, ttl)
|
|
379
377
|
});
|
|
380
378
|
}
|
|
381
|
-
//#endregion
|
|
382
379
|
exports.UPGRADE_REQUEST = require_bridge_protocol.UPGRADE_REQUEST;
|
|
383
380
|
exports.WS_CONNECTION_AUTH = require_decorate.WS_CONNECTION_AUTH;
|
|
384
381
|
Object.defineProperty(exports, "WsConnectionAuth", {
|
package/dist/websockets.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"websockets.cjs","names":["isConfigurationError","isInfrastructureError","readErrorProperty","Logger","BetterAuthConfigurationError","isAuthFailure","AuthFailures","Inject","INSTANCE_REGISTRY","PRINCIPAL_RESOLVER","TRANSPORT_REGISTRY","AuthFailures","WsException","BetterAuthConfigurationError","MetadataScanner","EXTENSION_DEFINITION","WS_CONNECTION_AUTH","toWebHeaders","upgradeRequestUrl","UPGRADE_REQUEST","toWebHeaders","BetterAuthConfigurationError","upgradeRequestUrl"],"sources":["../src/ws-connection-auth.ts","../src/socket-io-transport.ts","../src/ws-transport.ts"],"sourcesContent":["import {\n type ContextType,\n type ExecutionContext,\n Inject,\n Logger,\n type Type,\n} from \"@nestjs/common\";\nimport type { PrincipalResolver, PrincipalResult } from \"./auth-contracts.js\";\nimport {\n AuthFailures,\n isAuthFailure,\n isConfigurationError,\n isInfrastructureError,\n BetterAuthConfigurationError,\n type AuthFailure,\n} from \"./auth-errors.js\";\nimport {\n INSTANCE_REGISTRY,\n PRINCIPAL_RESOLVER,\n TRANSPORT_REGISTRY,\n} from \"./auth-tokens.js\";\nimport { readErrorProperty } from \"./error-redactor.js\";\nimport type { InstanceLookup } from \"./instance-registry.js\";\nimport type { TransportRegistry } from \"./transport-registry.js\";\n\nexport { WS_CONNECTION_AUTH } from \"./auth-tokens.js\";\nexport function wsCloseCodeFor(failure: AuthFailure): 4401 | 4403 | 4429 {\n return failure.status === 401 ? 4401 : failure.status === 403 ? 4403 : 4429;\n}\n\nconst STACK_FRAME = /^\\s+at .+:\\d+:\\d+\\)?$/;\n\n/**\n * Describes an unexpected connection-authentication error for the server log. Package\n * errors carry fixed messages and already-redacted causes. Application and runtime error\n * messages can quote client credentials (native Headers errors do), so only their name\n * and stack frames are kept.\n */\nexport function connectionErrorLog(error: unknown): {\n message: string;\n stack?: string;\n} {\n const text = (value: unknown) =>\n typeof value === \"string\" ? value : undefined;\n let summary: string;\n if (isConfigurationError(error)) {\n summary = `${error.code}: ${error.detail}`;\n } else if (isInfrastructureError(error)) {\n const cause = readErrorProperty(error, \"cause\");\n summary = `${error.message} (${text(readErrorProperty(cause, \"name\")) ?? \"Error\"}: ${text(readErrorProperty(cause, \"message\")) ?? \"\"})`;\n } else {\n const name = text(readErrorProperty(error, \"name\"));\n summary = `${name !== undefined && /^[\\w$.]{1,64}$/.test(name) ? name : typeof error} (message withheld)`;\n }\n const frames = (text(readErrorProperty(error, \"stack\")) ?? \"\")\n .split(/\\r?\\n/)\n .filter((line) => STACK_FRAME.test(line));\n return {\n message: `WebSocket connection authentication failed: ${summary}`,\n stack: frames.length > 0 ? [summary, ...frames].join(\"\\n\") : undefined,\n };\n}\n\n/**\n * The `ws` execution context of a connection before any gateway handler runs. Nest exports no\n * public factory for execution contexts, so this implements the public `ExecutionContext`\n * interface with the values Nest's internal host reports for the arguments `[client, undefined]`.\n */\nexport class ConnectionExecutionContext implements ExecutionContext {\n readonly #args: unknown[];\n\n constructor(client: object) {\n this.#args = [client, undefined];\n }\n\n getType<TContext extends string = ContextType>(): TContext {\n return \"ws\" as TContext;\n }\n\n /** No handler runs yet, so there is no class; Nest's host reports `null` as well. */\n getClass<T>(): Type<T> {\n return null as unknown as Type<T>;\n }\n\n /** No handler runs yet; Nest's host reports `null` as well. */\n getHandler(): ReturnType<ExecutionContext[\"getHandler\"]> {\n return null as unknown as ReturnType<ExecutionContext[\"getHandler\"]>;\n }\n\n getArgs<T extends unknown[] = unknown[]>(): T {\n return this.#args as T;\n }\n\n getArgByIndex<T>(index: number): T {\n return this.#args[index] as T;\n }\n\n switchToHttp(): ReturnType<ExecutionContext[\"switchToHttp\"]> {\n return {\n getRequest: <T>() => this.getArgByIndex<T>(0),\n getResponse: <T>() => this.getArgByIndex<T>(1),\n getNext: <T>() => this.getArgByIndex<T>(2),\n };\n }\n\n switchToRpc(): ReturnType<ExecutionContext[\"switchToRpc\"]> {\n return {\n getData: <T>() => this.getArgByIndex<T>(0),\n getContext: <T>() => this.getArgByIndex<T>(1),\n };\n }\n\n switchToWs(): ReturnType<ExecutionContext[\"switchToWs\"]> {\n return {\n getClient: <T>() => this.getArgByIndex<T>(0),\n getData: <T>() => this.getArgByIndex<T>(1),\n getPattern: () => this.getArgByIndex<string>(this.#args.length - 1),\n };\n }\n}\n\n/** Connection authentication delegates to the same origin and principal kernel as messages. */\nexport class WsConnectionAuth {\n private readonly logger = new Logger(\"BetterAuth\");\n\n constructor(\n @Inject(INSTANCE_REGISTRY) private readonly instances: InstanceLookup,\n @Inject(PRINCIPAL_RESOLVER) private readonly resolver: PrincipalResolver,\n @Inject(TRANSPORT_REGISTRY) private readonly transports: TransportRegistry,\n ) {}\n\n async authenticate(\n client: unknown,\n options: { instance?: string } = {},\n ): Promise<PrincipalResult> {\n if (typeof client !== \"object\" || client === null) {\n throw BetterAuthConfigurationError.atRequest(\n \"INVALID_WS_CLIENT\",\n \"Connection authentication requires a WebSocket client.\",\n );\n }\n const context = new ConnectionExecutionContext(client);\n const transport = this.transports.select(context);\n const call = this.transports.describe(context, transport);\n const entry = this.instances.get(options.instance ?? \"default\");\n const browser = call.browser;\n if (browser && entry.options.originCheck?.mode !== \"off\") {\n const failure = await entry.handle.checkOrigin(browser, \"cookie\");\n if (failure) {\n return { outcome: \"rejected\", failure };\n }\n }\n const accepts = new Set(\n entry.sources\n .filter((source) => source.acceptance === \"default\")\n .flatMap((source) => [...source.kinds]),\n );\n try {\n return await this.resolver.resolve(call, {\n auth: entry.handle,\n accepts,\n sourceSet: JSON.stringify(\n entry.sources.flatMap((source, index) =>\n source.kinds.some((kind) => accepts.has(kind)) ? [index] : [],\n ),\n ),\n freshness:\n entry.options.session !== false &&\n entry.options.session?.freshness === \"authoritative\"\n ? \"authoritative\"\n : \"default\",\n });\n } catch (error) {\n if (isAuthFailure(error)) {\n return { outcome: \"rejected\", failure: error };\n }\n throw error;\n }\n }\n\n socketIoMiddleware(\n options: { required?: boolean; instance?: string } = {},\n ): (socket: unknown, next: (error?: Error) => void) => void {\n return (socket, next) => {\n void this.authenticate(socket, options).then(\n (result) => {\n const failure =\n result.outcome === \"rejected\"\n ? result.failure\n : result.outcome === \"absent\" && options.required\n ? AuthFailures.unauthenticated()\n : undefined;\n if (!failure) {\n next();\n return;\n }\n next(\n Object.assign(new Error(failure.message), {\n data: {\n status: \"error\",\n statusCode: failure.status,\n code: failure.code,\n ...(failure.reason ? { reason: failure.reason } : {}),\n message: failure.message,\n },\n }),\n );\n },\n (error: unknown) => {\n const log = connectionErrorLog(error);\n this.logger.error(log.message, log.stack);\n next(\n Object.assign(new Error(\"Internal server error\"), {\n data: {\n status: \"error\",\n statusCode: 500,\n message: \"Internal server error\",\n },\n }),\n );\n },\n );\n };\n }\n}\n","import type { IncomingHttpHeaders } from \"node:http\";\nimport type { ExecutionContext } from \"@nestjs/common\";\nimport { MetadataScanner } from \"@nestjs/core\";\nimport {\n SubscribeMessage,\n WebSocketGateway,\n WsException,\n} from \"@nestjs/websockets\";\nimport {\n type AuthTransport,\n type BootAdvice,\n type BootAdviceContext,\n type ExtensionDefinition,\n type TransportCall,\n type TransportValidationContext,\n} from \"./auth-contracts.js\";\nimport {\n AuthFailures,\n BetterAuthConfigurationError,\n type AuthFailure,\n} from \"./auth-errors.js\";\nimport { EXTENSION_DEFINITION } from \"./bridge-protocol.js\";\nimport { toWebHeaders, upgradeRequestUrl } from \"./platform.js\";\nimport { WsConnectionAuth, WS_CONNECTION_AUTH } from \"./ws-connection-auth.js\";\n\nexport interface WsTransportOptions<C> {\n /** Replaces principal credentials without changing the browser handshake used for origin checks. */\n credentials?: (client: C) => HeadersInit | undefined;\n /** Defaults to zero. Positive values delay revocation for non-authoritative messages. */\n principalTtlMs?: number;\n /** Every message handler requires explicit guard and scope coverage on every Nest major. */\n gatewayCoverage?: \"error\" | \"warn\" | \"off\";\n}\nexport interface SocketIoClientLike {\n readonly handshake: {\n readonly headers: IncomingHttpHeaders;\n readonly auth?: Record<string, unknown>;\n readonly address?: string;\n readonly url?: string;\n readonly secure?: boolean;\n };\n}\n/** Convert only mapped headers here: native Headers errors can quote the credential. */\nexport function mappedCredentialHeaders(\n input: HeadersInit | undefined,\n): Headers {\n const headers = new Headers();\n if (input === undefined) {\n return headers;\n }\n const malformed = () =>\n AuthFailures.rejected({ status: 401, reason: \"MALFORMED_CREDENTIALS\" });\n if (input === null || typeof input !== \"object\") {\n throw malformed();\n }\n // Read caller-provided getters/iterators outside the conversion catch so their\n // programming errors remain errors, as do errors thrown by the mapper itself.\n const iterable = (input as { [Symbol.iterator]?: unknown })[Symbol.iterator];\n if (iterable !== undefined && typeof iterable !== \"function\") {\n throw malformed();\n }\n const entries: Iterable<unknown> =\n typeof iterable === \"function\"\n ? (input as Iterable<unknown>)\n : Object.entries(input);\n for (const entry of entries) {\n if (!Array.isArray(entry) || entry.length !== 2) {\n throw malformed();\n }\n const [name, value] = entry;\n if (\n typeof name !== \"string\" ||\n typeof value !== \"string\" ||\n /[\\r\\n\\0]/.test(value)\n ) {\n throw malformed();\n }\n try {\n headers.append(name, value);\n } catch {\n throw malformed();\n }\n }\n return headers;\n}\nexport function isSocketIo(client: unknown): client is SocketIoClientLike {\n return typeof client === \"object\" && client !== null && \"handshake\" in client;\n}\nexport function wsException(failure: AuthFailure): WsException {\n return new WsException({\n status: \"error\",\n statusCode: failure.status,\n code: failure.code,\n ...(failure.reason ? { reason: failure.reason } : {}),\n message: failure.message,\n });\n}\nexport function validateGateways(\n context: TransportValidationContext,\n coverage: WsTransportOptions<unknown>[\"gatewayCoverage\"],\n): void {\n class Probe {\n message(): void {}\n }\n WebSocketGateway()(Probe);\n SubscribeMessage(\"probe\")(\n Probe.prototype,\n \"message\",\n Object.getOwnPropertyDescriptor(Probe.prototype, \"message\")!,\n );\n if (\n Reflect.getMetadata(\"websockets:is_gateway\", Probe) !== true ||\n Reflect.getMetadata(\n \"websockets:message_mapping\",\n Probe.prototype.message,\n ) !== true\n ) {\n throw new BetterAuthConfigurationError(\n \"NEST_METADATA_KEY_CHANGED\",\n \"Nest WebSocket gateway/message metadata failed its canary.\",\n );\n }\n const scanner = new MetadataScanner();\n for (const wrapper of context.discovery.getProviders()) {\n const target = wrapper.metatype;\n if (\n !target?.prototype ||\n wrapper.isAlias ||\n !Reflect.getMetadata(\"websockets:is_gateway\", target)\n ) {\n continue;\n }\n for (const method of scanner.getAllMethodNames(target.prototype)) {\n if (\n Reflect.getMetadata(\n \"websockets:message_mapping\",\n target.prototype[method],\n )\n ) {\n context.claim(target, method, \"explicit\", {\n everyHandler: true,\n code: \"GATEWAY_UNGUARDED\",\n coverage: coverage ?? \"error\",\n hint: `Add @UseBetterAuth() to ${target.name} (or @Public() to opt out). Global guards and interceptors do not reach gateways on NestJS 11, and this check does not depend on the version.`,\n });\n }\n }\n }\n}\nexport function quotaAdvice(\n context: BootAdviceContext,\n ttl: number,\n): readonly BootAdvice[] {\n return ttl === 0 &&\n context.sources.some((source) => source.effects?.consumesQuota)\n ? [\n {\n level: \"warn\",\n code: \"W_QUOTA_PER_MESSAGE\",\n message:\n \"Quota-consuming WebSocket principals verify on every message.\",\n hint: \"Consider connection-time authentication and principalTtlMs; a positive TTL delays revocation on non-authoritative handlers.\",\n },\n ]\n : [];\n}\nexport function transportDefinition(\n transport: AuthTransport,\n): ExtensionDefinition<AuthTransport> {\n return {\n [EXTENSION_DEFINITION]: true,\n use: { useFactory: () => transport },\n providers: [\n WsConnectionAuth,\n { provide: WS_CONNECTION_AUTH, useExisting: WsConnectionAuth },\n ],\n exports: [WsConnectionAuth, WS_CONNECTION_AUTH],\n };\n}\nexport function principalTtl(value = 0): number {\n if (!Number.isFinite(value) || value < 0) {\n throw new BetterAuthConfigurationError(\n \"INVALID_WS_TTL\",\n \"principalTtlMs must be a finite non-negative number.\",\n );\n }\n return value;\n}\nexport function socketIoTransport(\n options: WsTransportOptions<SocketIoClientLike> = {},\n): ExtensionDefinition<AuthTransport> {\n const ttl = principalTtl(options.principalTtlMs);\n return transportDefinition({\n id: \"socket.io\",\n handles: (context) =>\n context.getType() === \"ws\" &&\n isSocketIo(context.switchToWs().getClient()),\n describe(context: ExecutionContext): TransportCall {\n const client = context.switchToWs().getClient<SocketIoClientLike>();\n const original = () => toWebHeaders(client.handshake.headers);\n return {\n key: context.getArgs(),\n invocation: context.getArgs(),\n connection: client,\n principalTtlMs: ttl,\n headers: () => {\n const headers = original();\n let mapped: HeadersInit | undefined;\n if (options.credentials) {\n mapped = options.credentials(client);\n } else if (!headers.has(\"authorization\")) {\n const token = client.handshake.auth?.token;\n if (token !== undefined) {\n if (typeof token !== \"string\") {\n throw AuthFailures.rejected({\n status: 401,\n reason: \"MALFORMED_CREDENTIALS\",\n });\n }\n mapped = { authorization: `Bearer ${token}` };\n }\n }\n mappedCredentialHeaders(mapped).forEach((value, name) => {\n headers.set(name, value);\n });\n return headers;\n },\n get clientIp() {\n return client.handshake.address ?? null;\n },\n cookies: null,\n get request() {\n return { method: \"GET\", url: upgradeRequestUrl(client.handshake) };\n },\n param: (name) => context.switchToWs().getData()?.[name],\n get browser() {\n return {\n enforce: true,\n key: client,\n headers: original,\n url: upgradeRequestUrl(client.handshake),\n };\n },\n };\n },\n toException: wsException,\n validate: (context) => validateGateways(context, options.gatewayCoverage),\n advise: (context) => quotaAdvice(context, ttl),\n });\n}\n","import type { IncomingHttpHeaders } from \"node:http\";\nimport type { AuthTransport, ExtensionDefinition } from \"./auth-contracts.js\";\nimport { UPGRADE_REQUEST } from \"./bridge-protocol.js\";\nimport { BetterAuthConfigurationError } from \"./auth-errors.js\";\nimport { toWebHeaders, upgradeRequestUrl } from \"./platform.js\";\nimport {\n isSocketIo,\n mappedCredentialHeaders,\n principalTtl,\n quotaAdvice,\n transportDefinition,\n validateGateways,\n wsException,\n type WsTransportOptions,\n} from \"./socket-io-transport.js\";\n\nexport { UPGRADE_REQUEST } from \"./bridge-protocol.js\";\nexport interface WsClientLike {\n readonly [UPGRADE_REQUEST]?: {\n readonly headers: Headers;\n readonly url?: string;\n readonly remoteAddress?: string;\n readonly encrypted?: boolean;\n };\n}\nexport interface WsAdapterLike {\n bindClientConnect(\n server: unknown,\n callback: (...args: any[]) => void,\n ): unknown;\n}\nexport function recordUpgradeRequest(\n client: object,\n request: {\n headers: IncomingHttpHeaders;\n url?: string;\n socket?: { remoteAddress?: string; encrypted?: boolean };\n },\n): void {\n Object.defineProperty(client, UPGRADE_REQUEST, {\n value: Object.freeze({\n headers: toWebHeaders(request.headers),\n url: request.url,\n remoteAddress: request.socket?.remoteAddress,\n encrypted: request.socket?.encrypted,\n }),\n configurable: true,\n });\n}\nexport function withUpgradeRequest<\n T extends new (\n ...args: any[]\n ) => WsAdapterLike,\n>(Base: T): T {\n return class extends Base {\n override bindClientConnect(\n server: unknown,\n callback: (...args: any[]) => void,\n ): unknown {\n return super.bindClientConnect(server, (client, request, ...rest) => {\n recordUpgradeRequest(client, request);\n callback(client, request, ...rest);\n });\n }\n };\n}\nexport function wsTransport(\n options: WsTransportOptions<WsClientLike> = {},\n): ExtensionDefinition<AuthTransport> {\n const ttl = principalTtl(options.principalTtlMs);\n return transportDefinition({\n id: \"ws\",\n handles: (context) =>\n context.getType() === \"ws\" &&\n !isSocketIo(context.switchToWs().getClient()),\n describe(context) {\n const client = context.switchToWs().getClient<WsClientLike>();\n const upgrade = () => {\n const request = client[UPGRADE_REQUEST];\n if (!request) {\n throw BetterAuthConfigurationError.atRequest(\n \"WS_UPGRADE_REQUEST_MISSING\",\n \"WebSocket authentication requires its upgrade request.\",\n {\n hint: \"app.useWebSocketAdapter(new (withUpgradeRequest(WsAdapter))(app));\",\n },\n );\n }\n return request;\n };\n const url = () => {\n const request = upgrade();\n return upgradeRequestUrl({\n headers: request.headers,\n url: request.url,\n secure: request.encrypted,\n });\n };\n return {\n key: context.getArgs(),\n invocation: context.getArgs(),\n connection: client,\n principalTtlMs: ttl,\n headers: () => {\n const headers = new Headers(upgrade().headers);\n mappedCredentialHeaders(options.credentials?.(client)).forEach(\n (value, name) => {\n headers.set(name, value);\n },\n );\n return headers;\n },\n get clientIp() {\n return upgrade().remoteAddress ?? null;\n },\n cookies: null,\n get request() {\n return { method: \"GET\", url: url() };\n },\n param: (name) => context.switchToWs().getData()?.[name],\n get browser() {\n return {\n enforce: true,\n key: client,\n headers: () => new Headers(upgrade().headers),\n url: url(),\n };\n },\n };\n },\n toException: wsException,\n validate: (context) => validateGateways(context, options.gatewayCoverage),\n advise: (context) => quotaAdvice(context, ttl),\n });\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"websockets.cjs","names":["isConfigurationError","isInfrastructureError","readErrorProperty","Logger","BetterAuthConfigurationError","isAuthFailure","AuthFailures","Inject","INSTANCE_REGISTRY","PRINCIPAL_RESOLVER","TRANSPORT_REGISTRY","AuthFailures","WsException","BetterAuthConfigurationError","MetadataScanner","EXTENSION_DEFINITION","WS_CONNECTION_AUTH","toWebHeaders","upgradeRequestUrl","UPGRADE_REQUEST","toWebHeaders","BetterAuthConfigurationError","upgradeRequestUrl"],"sources":["../src/ws-connection-auth.ts","../src/socket-io-transport.ts","../src/ws-transport.ts"],"sourcesContent":["import {\n type ContextType,\n type ExecutionContext,\n Inject,\n Logger,\n type Type,\n} from \"@nestjs/common\";\nimport type { PrincipalResolver, PrincipalResult } from \"./auth-contracts.js\";\nimport {\n AuthFailures,\n isAuthFailure,\n isConfigurationError,\n isInfrastructureError,\n BetterAuthConfigurationError,\n type AuthFailure,\n} from \"./auth-errors.js\";\nimport {\n INSTANCE_REGISTRY,\n PRINCIPAL_RESOLVER,\n TRANSPORT_REGISTRY,\n} from \"./auth-tokens.js\";\nimport { readErrorProperty } from \"./error-redactor.js\";\nimport type { InstanceLookup } from \"./instance-registry.js\";\nimport type { TransportRegistry } from \"./transport-registry.js\";\n\nexport { WS_CONNECTION_AUTH } from \"./auth-tokens.js\";\nexport function wsCloseCodeFor(failure: AuthFailure): 4401 | 4403 | 4429 {\n return failure.status === 401 ? 4401 : failure.status === 403 ? 4403 : 4429;\n}\n\nconst STACK_FRAME = /^\\s+at .+:\\d+:\\d+\\)?$/;\n\n/**\n * Describes an unexpected connection-authentication error for the server log. Package\n * errors carry fixed messages and already-redacted causes. Application and runtime error\n * messages can quote client credentials (native Headers errors do), so only their name\n * and stack frames are kept.\n */\nexport function connectionErrorLog(error: unknown): {\n message: string;\n stack?: string;\n} {\n const text = (value: unknown) =>\n typeof value === \"string\" ? value : undefined;\n let summary: string;\n if (isConfigurationError(error)) {\n summary = `${error.code}: ${error.detail}`;\n } else if (isInfrastructureError(error)) {\n const cause = readErrorProperty(error, \"cause\");\n summary = `${error.message} (${text(readErrorProperty(cause, \"name\")) ?? \"Error\"}: ${text(readErrorProperty(cause, \"message\")) ?? \"\"})`;\n } else {\n const name = text(readErrorProperty(error, \"name\"));\n summary = `${name !== undefined && /^[\\w$.]{1,64}$/.test(name) ? name : typeof error} (message withheld)`;\n }\n const frames = (text(readErrorProperty(error, \"stack\")) ?? \"\")\n .split(/\\r?\\n/)\n .filter((line) => STACK_FRAME.test(line));\n return {\n message: `WebSocket connection authentication failed: ${summary}`,\n stack: frames.length > 0 ? [summary, ...frames].join(\"\\n\") : undefined,\n };\n}\n\n/**\n * The `ws` execution context of a connection before any gateway handler runs. Nest exports no\n * public factory for execution contexts, so this implements the public `ExecutionContext`\n * interface with the values Nest's internal host reports for the arguments `[client, undefined]`.\n */\nexport class ConnectionExecutionContext implements ExecutionContext {\n readonly #args: unknown[];\n\n constructor(client: object) {\n this.#args = [client, undefined];\n }\n\n getType<TContext extends string = ContextType>(): TContext {\n return \"ws\" as TContext;\n }\n\n /** No handler runs yet, so there is no class; Nest's host reports `null` as well. */\n getClass<T>(): Type<T> {\n return null as unknown as Type<T>;\n }\n\n /** No handler runs yet; Nest's host reports `null` as well. */\n getHandler(): ReturnType<ExecutionContext[\"getHandler\"]> {\n return null as unknown as ReturnType<ExecutionContext[\"getHandler\"]>;\n }\n\n getArgs<T extends unknown[] = unknown[]>(): T {\n return this.#args as T;\n }\n\n getArgByIndex<T>(index: number): T {\n return this.#args[index] as T;\n }\n\n switchToHttp(): ReturnType<ExecutionContext[\"switchToHttp\"]> {\n return {\n getRequest: <T>() => this.getArgByIndex<T>(0),\n getResponse: <T>() => this.getArgByIndex<T>(1),\n getNext: <T>() => this.getArgByIndex<T>(2),\n };\n }\n\n switchToRpc(): ReturnType<ExecutionContext[\"switchToRpc\"]> {\n return {\n getData: <T>() => this.getArgByIndex<T>(0),\n getContext: <T>() => this.getArgByIndex<T>(1),\n };\n }\n\n switchToWs(): ReturnType<ExecutionContext[\"switchToWs\"]> {\n return {\n getClient: <T>() => this.getArgByIndex<T>(0),\n getData: <T>() => this.getArgByIndex<T>(1),\n getPattern: () => this.getArgByIndex<string>(this.#args.length - 1),\n };\n }\n}\n\n/** Connection authentication delegates to the same origin and principal kernel as messages. */\nexport class WsConnectionAuth {\n private readonly logger = new Logger(\"BetterAuth\");\n\n constructor(\n @Inject(INSTANCE_REGISTRY) private readonly instances: InstanceLookup,\n @Inject(PRINCIPAL_RESOLVER) private readonly resolver: PrincipalResolver,\n @Inject(TRANSPORT_REGISTRY) private readonly transports: TransportRegistry,\n ) {}\n\n async authenticate(\n client: unknown,\n options: { instance?: string } = {},\n ): Promise<PrincipalResult> {\n if (typeof client !== \"object\" || client === null) {\n throw BetterAuthConfigurationError.atRequest(\n \"INVALID_WS_CLIENT\",\n \"Connection authentication requires a WebSocket client.\",\n );\n }\n const context = new ConnectionExecutionContext(client);\n const transport = this.transports.select(context);\n const call = this.transports.describe(context, transport);\n const entry = this.instances.get(options.instance ?? \"default\");\n const browser = call.browser;\n if (browser && entry.options.originCheck?.mode !== \"off\") {\n const failure = await entry.handle.checkOrigin(browser, \"cookie\");\n if (failure) {\n return { outcome: \"rejected\", failure };\n }\n }\n const accepts = new Set(\n entry.sources\n .filter((source) => source.acceptance === \"default\")\n .flatMap((source) => [...source.kinds]),\n );\n try {\n return await this.resolver.resolve(call, {\n auth: entry.handle,\n accepts,\n sourceSet: JSON.stringify(\n entry.sources.flatMap((source, index) =>\n source.kinds.some((kind) => accepts.has(kind)) ? [index] : [],\n ),\n ),\n freshness:\n entry.options.session !== false &&\n entry.options.session?.freshness === \"authoritative\"\n ? \"authoritative\"\n : \"default\",\n });\n } catch (error) {\n if (isAuthFailure(error)) {\n return { outcome: \"rejected\", failure: error };\n }\n throw error;\n }\n }\n\n socketIoMiddleware(\n options: { required?: boolean; instance?: string } = {},\n ): (socket: unknown, next: (error?: Error) => void) => void {\n return (socket, next) => {\n void this.authenticate(socket, options).then(\n (result) => {\n const failure =\n result.outcome === \"rejected\"\n ? result.failure\n : result.outcome === \"absent\" && options.required\n ? AuthFailures.unauthenticated()\n : undefined;\n if (!failure) {\n next();\n return;\n }\n next(\n Object.assign(new Error(failure.message), {\n data: {\n status: \"error\",\n statusCode: failure.status,\n code: failure.code,\n ...(failure.reason ? { reason: failure.reason } : {}),\n message: failure.message,\n },\n }),\n );\n },\n (error: unknown) => {\n const log = connectionErrorLog(error);\n this.logger.error(log.message, log.stack);\n next(\n Object.assign(new Error(\"Internal server error\"), {\n data: {\n status: \"error\",\n statusCode: 500,\n message: \"Internal server error\",\n },\n }),\n );\n },\n );\n };\n }\n}\n","import type { IncomingHttpHeaders } from \"node:http\";\nimport type { ExecutionContext } from \"@nestjs/common\";\nimport { MetadataScanner } from \"@nestjs/core\";\nimport {\n SubscribeMessage,\n WebSocketGateway,\n WsException,\n} from \"@nestjs/websockets\";\nimport {\n type AuthTransport,\n type BootAdvice,\n type BootAdviceContext,\n type ExtensionDefinition,\n type TransportCall,\n type TransportValidationContext,\n} from \"./auth-contracts.js\";\nimport {\n AuthFailures,\n BetterAuthConfigurationError,\n type AuthFailure,\n} from \"./auth-errors.js\";\nimport { EXTENSION_DEFINITION } from \"./bridge-protocol.js\";\nimport { toWebHeaders, upgradeRequestUrl } from \"./platform.js\";\nimport { WsConnectionAuth, WS_CONNECTION_AUTH } from \"./ws-connection-auth.js\";\n\nexport interface WsTransportOptions<C> {\n /** Replaces principal credentials without changing the browser handshake used for origin checks. */\n credentials?: (client: C) => HeadersInit | undefined;\n /** Defaults to zero. Positive values delay revocation for non-authoritative messages. */\n principalTtlMs?: number;\n /** Every message handler requires explicit guard and scope coverage on every Nest major. */\n gatewayCoverage?: \"error\" | \"warn\" | \"off\";\n}\nexport interface SocketIoClientLike {\n readonly handshake: {\n readonly headers: IncomingHttpHeaders;\n readonly auth?: Record<string, unknown>;\n readonly address?: string;\n readonly url?: string;\n readonly secure?: boolean;\n };\n}\n/** Convert only mapped headers here: native Headers errors can quote the credential. */\nexport function mappedCredentialHeaders(\n input: HeadersInit | undefined,\n): Headers {\n const headers = new Headers();\n if (input === undefined) {\n return headers;\n }\n const malformed = () =>\n AuthFailures.rejected({ status: 401, reason: \"MALFORMED_CREDENTIALS\" });\n if (input === null || typeof input !== \"object\") {\n throw malformed();\n }\n // Read caller-provided getters/iterators outside the conversion catch so their\n // programming errors remain errors, as do errors thrown by the mapper itself.\n const iterable = (input as { [Symbol.iterator]?: unknown })[Symbol.iterator];\n if (iterable !== undefined && typeof iterable !== \"function\") {\n throw malformed();\n }\n const entries: Iterable<unknown> =\n typeof iterable === \"function\"\n ? (input as Iterable<unknown>)\n : Object.entries(input);\n for (const entry of entries) {\n if (!Array.isArray(entry) || entry.length !== 2) {\n throw malformed();\n }\n const [name, value] = entry;\n if (\n typeof name !== \"string\" ||\n typeof value !== \"string\" ||\n /[\\r\\n\\0]/.test(value)\n ) {\n throw malformed();\n }\n try {\n headers.append(name, value);\n } catch {\n throw malformed();\n }\n }\n return headers;\n}\nexport function isSocketIo(client: unknown): client is SocketIoClientLike {\n return typeof client === \"object\" && client !== null && \"handshake\" in client;\n}\nexport function wsException(failure: AuthFailure): WsException {\n return new WsException({\n status: \"error\",\n statusCode: failure.status,\n code: failure.code,\n ...(failure.reason ? { reason: failure.reason } : {}),\n message: failure.message,\n });\n}\nexport function validateGateways(\n context: TransportValidationContext,\n coverage: WsTransportOptions<unknown>[\"gatewayCoverage\"],\n): void {\n class Probe {\n message(): void {}\n }\n WebSocketGateway()(Probe);\n SubscribeMessage(\"probe\")(\n Probe.prototype,\n \"message\",\n Object.getOwnPropertyDescriptor(Probe.prototype, \"message\")!,\n );\n if (\n Reflect.getMetadata(\"websockets:is_gateway\", Probe) !== true ||\n Reflect.getMetadata(\n \"websockets:message_mapping\",\n Probe.prototype.message,\n ) !== true\n ) {\n throw new BetterAuthConfigurationError(\n \"NEST_METADATA_KEY_CHANGED\",\n \"Nest WebSocket gateway/message metadata failed its canary.\",\n );\n }\n const scanner = new MetadataScanner();\n for (const wrapper of context.discovery.getProviders()) {\n const target = wrapper.metatype;\n if (\n !target?.prototype ||\n wrapper.isAlias ||\n !Reflect.getMetadata(\"websockets:is_gateway\", target)\n ) {\n continue;\n }\n for (const method of scanner.getAllMethodNames(target.prototype)) {\n if (\n Reflect.getMetadata(\n \"websockets:message_mapping\",\n target.prototype[method],\n )\n ) {\n context.claim(target, method, \"explicit\", {\n everyHandler: true,\n code: \"GATEWAY_UNGUARDED\",\n coverage: coverage ?? \"error\",\n hint: `Add @UseBetterAuth() to ${target.name} (or @Public() to opt out). Global guards and interceptors do not reach gateways on NestJS 11, and this check does not depend on the version.`,\n });\n }\n }\n }\n}\nexport function quotaAdvice(\n context: BootAdviceContext,\n ttl: number,\n): readonly BootAdvice[] {\n return ttl === 0 &&\n context.sources.some((source) => source.effects?.consumesQuota)\n ? [\n {\n level: \"warn\",\n code: \"W_QUOTA_PER_MESSAGE\",\n message:\n \"Quota-consuming WebSocket principals verify on every message.\",\n hint: \"Consider connection-time authentication and principalTtlMs; a positive TTL delays revocation on non-authoritative handlers.\",\n },\n ]\n : [];\n}\nexport function transportDefinition(\n transport: AuthTransport,\n): ExtensionDefinition<AuthTransport> {\n return {\n [EXTENSION_DEFINITION]: true,\n use: { useFactory: () => transport },\n providers: [\n WsConnectionAuth,\n { provide: WS_CONNECTION_AUTH, useExisting: WsConnectionAuth },\n ],\n exports: [WsConnectionAuth, WS_CONNECTION_AUTH],\n };\n}\nexport function principalTtl(value = 0): number {\n if (!Number.isFinite(value) || value < 0) {\n throw new BetterAuthConfigurationError(\n \"INVALID_WS_TTL\",\n \"principalTtlMs must be a finite non-negative number.\",\n );\n }\n return value;\n}\nexport function socketIoTransport(\n options: WsTransportOptions<SocketIoClientLike> = {},\n): ExtensionDefinition<AuthTransport> {\n const ttl = principalTtl(options.principalTtlMs);\n return transportDefinition({\n id: \"socket.io\",\n handles: (context) =>\n context.getType() === \"ws\" &&\n isSocketIo(context.switchToWs().getClient()),\n describe(context: ExecutionContext): TransportCall {\n const client = context.switchToWs().getClient<SocketIoClientLike>();\n const original = () => toWebHeaders(client.handshake.headers);\n return {\n key: context.getArgs(),\n invocation: context.getArgs(),\n connection: client,\n principalTtlMs: ttl,\n headers: () => {\n const headers = original();\n let mapped: HeadersInit | undefined;\n if (options.credentials) {\n mapped = options.credentials(client);\n } else if (!headers.has(\"authorization\")) {\n const token = client.handshake.auth?.token;\n if (token !== undefined) {\n if (typeof token !== \"string\") {\n throw AuthFailures.rejected({\n status: 401,\n reason: \"MALFORMED_CREDENTIALS\",\n });\n }\n mapped = { authorization: `Bearer ${token}` };\n }\n }\n mappedCredentialHeaders(mapped).forEach((value, name) => {\n headers.set(name, value);\n });\n return headers;\n },\n get clientIp() {\n return client.handshake.address ?? null;\n },\n cookies: null,\n get request() {\n return { method: \"GET\", url: upgradeRequestUrl(client.handshake) };\n },\n param: (name) => context.switchToWs().getData()?.[name],\n get browser() {\n return {\n enforce: true,\n key: client,\n headers: original,\n url: upgradeRequestUrl(client.handshake),\n };\n },\n };\n },\n toException: wsException,\n validate: (context) => validateGateways(context, options.gatewayCoverage),\n advise: (context) => quotaAdvice(context, ttl),\n });\n}\n","import type { IncomingHttpHeaders } from \"node:http\";\nimport type { AuthTransport, ExtensionDefinition } from \"./auth-contracts.js\";\nimport { UPGRADE_REQUEST } from \"./bridge-protocol.js\";\nimport { BetterAuthConfigurationError } from \"./auth-errors.js\";\nimport { toWebHeaders, upgradeRequestUrl } from \"./platform.js\";\nimport {\n isSocketIo,\n mappedCredentialHeaders,\n principalTtl,\n quotaAdvice,\n transportDefinition,\n validateGateways,\n wsException,\n type WsTransportOptions,\n} from \"./socket-io-transport.js\";\n\nexport { UPGRADE_REQUEST } from \"./bridge-protocol.js\";\nexport interface WsClientLike {\n readonly [UPGRADE_REQUEST]?: {\n readonly headers: Headers;\n readonly url?: string;\n readonly remoteAddress?: string;\n readonly encrypted?: boolean;\n };\n}\nexport interface WsAdapterLike {\n bindClientConnect(\n server: unknown,\n callback: (...args: any[]) => void,\n ): unknown;\n}\nexport function recordUpgradeRequest(\n client: object,\n request: {\n headers: IncomingHttpHeaders;\n url?: string;\n socket?: { remoteAddress?: string; encrypted?: boolean };\n },\n): void {\n Object.defineProperty(client, UPGRADE_REQUEST, {\n value: Object.freeze({\n headers: toWebHeaders(request.headers),\n url: request.url,\n remoteAddress: request.socket?.remoteAddress,\n encrypted: request.socket?.encrypted,\n }),\n configurable: true,\n });\n}\nexport function withUpgradeRequest<\n T extends new (...args: any[]) => WsAdapterLike,\n>(Base: T): T {\n return class extends Base {\n override bindClientConnect(\n server: unknown,\n callback: (...args: any[]) => void,\n ): unknown {\n return super.bindClientConnect(server, (client, request, ...rest) => {\n recordUpgradeRequest(client, request);\n callback(client, request, ...rest);\n });\n }\n };\n}\nexport function wsTransport(\n options: WsTransportOptions<WsClientLike> = {},\n): ExtensionDefinition<AuthTransport> {\n const ttl = principalTtl(options.principalTtlMs);\n return transportDefinition({\n id: \"ws\",\n handles: (context) =>\n context.getType() === \"ws\" &&\n !isSocketIo(context.switchToWs().getClient()),\n describe(context) {\n const client = context.switchToWs().getClient<WsClientLike>();\n const upgrade = () => {\n const request = client[UPGRADE_REQUEST];\n if (!request) {\n throw BetterAuthConfigurationError.atRequest(\n \"WS_UPGRADE_REQUEST_MISSING\",\n \"WebSocket authentication requires its upgrade request.\",\n {\n hint: \"app.useWebSocketAdapter(new (withUpgradeRequest(WsAdapter))(app));\",\n },\n );\n }\n return request;\n };\n const url = () => {\n const request = upgrade();\n return upgradeRequestUrl({\n headers: request.headers,\n url: request.url,\n secure: request.encrypted,\n });\n };\n return {\n key: context.getArgs(),\n invocation: context.getArgs(),\n connection: client,\n principalTtlMs: ttl,\n headers: () => {\n const headers = new Headers(upgrade().headers);\n mappedCredentialHeaders(options.credentials?.(client)).forEach(\n (value, name) => {\n headers.set(name, value);\n },\n );\n return headers;\n },\n get clientIp() {\n return upgrade().remoteAddress ?? null;\n },\n cookies: null,\n get request() {\n return { method: \"GET\", url: url() };\n },\n param: (name) => context.switchToWs().getData()?.[name],\n get browser() {\n return {\n enforce: true,\n key: client,\n headers: () => new Headers(upgrade().headers),\n url: url(),\n };\n },\n };\n },\n toException: wsException,\n validate: (context) => validateGateways(context, options.gatewayCoverage),\n advise: (context) => quotaAdvice(context, ttl),\n });\n}\n"],"mappings":"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"}
|
package/dist/websockets.d.cts
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import { Bn as WS_CONNECTION_AUTH, F as ExtensionDefinition, Mn as InstanceLookup, Pn as UPGRADE_REQUEST, c as AuthTransport, jn as TransportRegistry, nt as PrincipalResolver, qn as AuthFailure, rt as PrincipalResult } from "./auth-contracts-
|
|
1
|
+
import { Bn as WS_CONNECTION_AUTH, F as ExtensionDefinition, Mn as InstanceLookup, Pn as UPGRADE_REQUEST, c as AuthTransport, jn as TransportRegistry, nt as PrincipalResolver, qn as AuthFailure, rt as PrincipalResult } from "./auth-contracts-zvt8ysoZ.cjs";
|
|
2
2
|
import { IncomingHttpHeaders } from "node:http";
|
|
3
3
|
import { ExecutionContext, Type } from "@nestjs/common";
|
|
4
4
|
import "@nestjs/websockets";
|
|
5
|
-
//#region src/socket-io-transport.d.ts
|
|
6
5
|
interface WsTransportOptions<C> {
|
|
7
6
|
/** Replaces principal credentials without changing the browser handshake used for origin checks. */
|
|
8
7
|
credentials?: (client: C) => HeadersInit | undefined;
|
|
@@ -21,8 +20,6 @@ interface SocketIoClientLike {
|
|
|
21
20
|
};
|
|
22
21
|
}
|
|
23
22
|
export declare function socketIoTransport(options?: WsTransportOptions<SocketIoClientLike>): ExtensionDefinition<AuthTransport>;
|
|
24
|
-
//#endregion
|
|
25
|
-
//#region src/ws-transport.d.ts
|
|
26
23
|
interface WsClientLike {
|
|
27
24
|
readonly [UPGRADE_REQUEST]?: {
|
|
28
25
|
readonly headers: Headers;
|
|
@@ -44,8 +41,6 @@ export declare function recordUpgradeRequest(client: object, request: {
|
|
|
44
41
|
}): void;
|
|
45
42
|
export declare function withUpgradeRequest<T extends new (...args: any[]) => WsAdapterLike>(Base: T): T;
|
|
46
43
|
export declare function wsTransport(options?: WsTransportOptions<WsClientLike>): ExtensionDefinition<AuthTransport>;
|
|
47
|
-
//#endregion
|
|
48
|
-
//#region src/ws-connection-auth.d.ts
|
|
49
44
|
export declare function wsCloseCodeFor(failure: AuthFailure): 4401 | 4403 | 4429;
|
|
50
45
|
/** Connection authentication delegates to the same origin and principal kernel as messages. */
|
|
51
46
|
export declare class WsConnectionAuth {
|
|
@@ -62,6 +57,5 @@ export declare class WsConnectionAuth {
|
|
|
62
57
|
instance?: string;
|
|
63
58
|
}): (socket: unknown, next: (error?: Error) => void) => void;
|
|
64
59
|
}
|
|
65
|
-
//#endregion
|
|
66
60
|
export { type SocketIoClientLike, UPGRADE_REQUEST, WS_CONNECTION_AUTH, type WsAdapterLike, type WsClientLike, type WsTransportOptions };
|
|
67
61
|
//# sourceMappingURL=websockets.d.cts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"websockets.d.cts","names":[],"sources":["../src/socket-io-transport.ts","../src/ws-transport.ts","../src/ws-connection-auth.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"websockets.d.cts","names":[],"sources":["../src/socket-io-transport.ts","../src/ws-transport.ts","../src/ws-connection-auth.ts"],"mappings":";;;;UAyBiB,mBAAmB;;EAElC,eAAe,QAAQ,MAAM;;EAE7B;;EAEA;;UAEe;WACN;aACE,SAAS;aACT,OAAO;aACP;aACA;aACA;;;wBAqJG,kBACd,UAAS,mBAAmB,sBAC3B,oBAAoB;UC7KN;YACL;aACC,SAAS;aACT;aACA;aACA;;;UAGI;EACf,kBACE,iBACA,cAAc;;wBAGF,qBACd,gBACA;EACE,SAAS;EACT;EACA;IAAW;IAAwB;;;wBAavB,mBACd,kBAAkB,gBAAgB,eAClC,MAAM,IAAI;wBAaI,YACd,UAAS,mBAAmB,gBAC3B,oBAAoB;wBCxCP,eAAe,SAAS;;qBAgG3B;mBAImC;mBACC;mBACA;mBAL9B;EAG6B,YAAA,WAAW,gBACV,UAAU,mBACV,YAAY;EAGrD,aACJ,iBACA;IAAW;MACV,QAAQ;EA8CX,mBACE;IAAW;IAAoB;OAC7B,iBAAiB,OAAO,QAAQ"}
|
package/dist/websockets.d.mts
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import { Bn as WS_CONNECTION_AUTH, F as ExtensionDefinition, Mn as InstanceLookup, Pn as UPGRADE_REQUEST, c as AuthTransport, jn as TransportRegistry, nt as PrincipalResolver, qn as AuthFailure, rt as PrincipalResult } from "./auth-contracts-
|
|
1
|
+
import { Bn as WS_CONNECTION_AUTH, F as ExtensionDefinition, Mn as InstanceLookup, Pn as UPGRADE_REQUEST, c as AuthTransport, jn as TransportRegistry, nt as PrincipalResolver, qn as AuthFailure, rt as PrincipalResult } from "./auth-contracts-CADGyI0O.mjs";
|
|
2
2
|
import { ExecutionContext, Type } from "@nestjs/common";
|
|
3
3
|
import { IncomingHttpHeaders } from "node:http";
|
|
4
4
|
import { WsException } from "@nestjs/websockets";
|
|
5
|
-
//#region src/socket-io-transport.d.ts
|
|
6
5
|
interface WsTransportOptions<C> {
|
|
7
6
|
/** Replaces principal credentials without changing the browser handshake used for origin checks. */
|
|
8
7
|
credentials?: (client: C) => HeadersInit | undefined;
|
|
@@ -21,8 +20,6 @@ interface SocketIoClientLike {
|
|
|
21
20
|
};
|
|
22
21
|
}
|
|
23
22
|
export declare function socketIoTransport(options?: WsTransportOptions<SocketIoClientLike>): ExtensionDefinition<AuthTransport>;
|
|
24
|
-
//#endregion
|
|
25
|
-
//#region src/ws-transport.d.ts
|
|
26
23
|
interface WsClientLike {
|
|
27
24
|
readonly [UPGRADE_REQUEST]?: {
|
|
28
25
|
readonly headers: Headers;
|
|
@@ -44,8 +41,6 @@ export declare function recordUpgradeRequest(client: object, request: {
|
|
|
44
41
|
}): void;
|
|
45
42
|
export declare function withUpgradeRequest<T extends new (...args: any[]) => WsAdapterLike>(Base: T): T;
|
|
46
43
|
export declare function wsTransport(options?: WsTransportOptions<WsClientLike>): ExtensionDefinition<AuthTransport>;
|
|
47
|
-
//#endregion
|
|
48
|
-
//#region src/ws-connection-auth.d.ts
|
|
49
44
|
export declare function wsCloseCodeFor(failure: AuthFailure): 4401 | 4403 | 4429;
|
|
50
45
|
/** Connection authentication delegates to the same origin and principal kernel as messages. */
|
|
51
46
|
export declare class WsConnectionAuth {
|
|
@@ -62,6 +57,5 @@ export declare class WsConnectionAuth {
|
|
|
62
57
|
instance?: string;
|
|
63
58
|
}): (socket: unknown, next: (error?: Error) => void) => void;
|
|
64
59
|
}
|
|
65
|
-
//#endregion
|
|
66
60
|
export { type SocketIoClientLike, UPGRADE_REQUEST, WS_CONNECTION_AUTH, type WsAdapterLike, type WsClientLike, type WsTransportOptions };
|
|
67
61
|
//# sourceMappingURL=websockets.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"websockets.d.mts","names":[],"sources":["../src/socket-io-transport.ts","../src/ws-transport.ts","../src/ws-connection-auth.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"websockets.d.mts","names":[],"sources":["../src/socket-io-transport.ts","../src/ws-transport.ts","../src/ws-connection-auth.ts"],"mappings":";;;;UAyBiB,mBAAmB;;EAElC,eAAe,QAAQ,MAAM;;EAE7B;;EAEA;;UAEe;WACN;aACE,SAAS;aACT,OAAO;aACP;aACA;aACA;;;wBAqJG,kBACd,UAAS,mBAAmB,sBAC3B,oBAAoB;UC7KN;YACL;aACC,SAAS;aACT;aACA;aACA;;;UAGI;EACf,kBACE,iBACA,cAAc;;wBAGF,qBACd,gBACA;EACE,SAAS;EACT;EACA;IAAW;IAAwB;;;wBAavB,mBACd,kBAAkB,gBAAgB,eAClC,MAAM,IAAI;wBAaI,YACd,UAAS,mBAAmB,gBAC3B,oBAAoB;wBCxCP,eAAe,SAAS;;qBAgG3B;mBAImC;mBACC;mBACA;mBAL9B;EAG6B,YAAA,WAAW,gBACV,UAAU,mBACV,YAAY;EAGrD,aACJ,iBACA;IAAW;MACV,QAAQ;EA8CX,mBACE;IAAW;IAAoB;OAC7B,iBAAiB,OAAO,QAAQ"}
|
package/dist/websockets.mjs
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { c as isConfigurationError, l as isInfrastructureError, n as BetterAuthConfigurationError, p as readErrorProperty, s as isAuthFailure, t as AuthFailures } from "./auth-errors-
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
1
|
+
import { c as isConfigurationError, l as isInfrastructureError, n as BetterAuthConfigurationError, p as readErrorProperty, s as isAuthFailure, t as AuthFailures } from "./auth-errors-JjxGDVSt.mjs";
|
|
2
|
+
import { n as EXTENSION_DEFINITION, r as UPGRADE_REQUEST } from "./bridge-protocol-CmRsff2P.mjs";
|
|
3
|
+
import { o as toWebHeaders, s as upgradeRequestUrl } from "./platform-BKYVzAv1.mjs";
|
|
4
|
+
import { C as PRINCIPAL_RESOLVER, M as TRANSPORT_REGISTRY, P as WS_CONNECTION_AUTH, m as INSTANCE_REGISTRY, n as __decorateParam, r as __decorateMetadata, t as __decorate } from "./decorate-bO-rBn-G.mjs";
|
|
5
5
|
import { Inject, Logger } from "@nestjs/common";
|
|
6
6
|
import { MetadataScanner } from "@nestjs/core";
|
|
7
7
|
import { SubscribeMessage, WebSocketGateway, WsException } from "@nestjs/websockets";
|
|
8
|
-
|
|
8
|
+
// src/ws-connection-auth.ts
|
|
9
9
|
function wsCloseCodeFor(failure) {
|
|
10
10
|
return failure.status === 401 ? 4401 : failure.status === 403 ? 4403 : 4429;
|
|
11
11
|
}
|
|
@@ -158,8 +158,7 @@ WsConnectionAuth = __decorate([
|
|
|
158
158
|
Object
|
|
159
159
|
])
|
|
160
160
|
], WsConnectionAuth);
|
|
161
|
-
|
|
162
|
-
//#region src/socket-io-transport.ts
|
|
161
|
+
// src/socket-io-transport.ts
|
|
163
162
|
/** Convert only mapped headers here: native Headers errors can quote the credential. */
|
|
164
163
|
function mappedCredentialHeaders(input) {
|
|
165
164
|
const headers = new Headers();
|
|
@@ -296,8 +295,7 @@ function socketIoTransport(options = {}) {
|
|
|
296
295
|
advise: (context) => quotaAdvice(context, ttl)
|
|
297
296
|
});
|
|
298
297
|
}
|
|
299
|
-
|
|
300
|
-
//#region src/ws-transport.ts
|
|
298
|
+
// src/ws-transport.ts
|
|
301
299
|
function recordUpgradeRequest(client, request) {
|
|
302
300
|
Object.defineProperty(client, UPGRADE_REQUEST, {
|
|
303
301
|
value: Object.freeze({
|
|
@@ -377,7 +375,6 @@ function wsTransport(options = {}) {
|
|
|
377
375
|
advise: (context) => quotaAdvice(context, ttl)
|
|
378
376
|
});
|
|
379
377
|
}
|
|
380
|
-
//#endregion
|
|
381
378
|
export { UPGRADE_REQUEST, WS_CONNECTION_AUTH, WsConnectionAuth, recordUpgradeRequest, socketIoTransport, withUpgradeRequest, wsCloseCodeFor, wsTransport };
|
|
382
379
|
|
|
383
380
|
//# sourceMappingURL=websockets.mjs.map
|
package/dist/websockets.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"websockets.mjs","names":[],"sources":["../src/ws-connection-auth.ts","../src/socket-io-transport.ts","../src/ws-transport.ts"],"sourcesContent":["import {\n type ContextType,\n type ExecutionContext,\n Inject,\n Logger,\n type Type,\n} from \"@nestjs/common\";\nimport type { PrincipalResolver, PrincipalResult } from \"./auth-contracts.js\";\nimport {\n AuthFailures,\n isAuthFailure,\n isConfigurationError,\n isInfrastructureError,\n BetterAuthConfigurationError,\n type AuthFailure,\n} from \"./auth-errors.js\";\nimport {\n INSTANCE_REGISTRY,\n PRINCIPAL_RESOLVER,\n TRANSPORT_REGISTRY,\n} from \"./auth-tokens.js\";\nimport { readErrorProperty } from \"./error-redactor.js\";\nimport type { InstanceLookup } from \"./instance-registry.js\";\nimport type { TransportRegistry } from \"./transport-registry.js\";\n\nexport { WS_CONNECTION_AUTH } from \"./auth-tokens.js\";\nexport function wsCloseCodeFor(failure: AuthFailure): 4401 | 4403 | 4429 {\n return failure.status === 401 ? 4401 : failure.status === 403 ? 4403 : 4429;\n}\n\nconst STACK_FRAME = /^\\s+at .+:\\d+:\\d+\\)?$/;\n\n/**\n * Describes an unexpected connection-authentication error for the server log. Package\n * errors carry fixed messages and already-redacted causes. Application and runtime error\n * messages can quote client credentials (native Headers errors do), so only their name\n * and stack frames are kept.\n */\nexport function connectionErrorLog(error: unknown): {\n message: string;\n stack?: string;\n} {\n const text = (value: unknown) =>\n typeof value === \"string\" ? value : undefined;\n let summary: string;\n if (isConfigurationError(error)) {\n summary = `${error.code}: ${error.detail}`;\n } else if (isInfrastructureError(error)) {\n const cause = readErrorProperty(error, \"cause\");\n summary = `${error.message} (${text(readErrorProperty(cause, \"name\")) ?? \"Error\"}: ${text(readErrorProperty(cause, \"message\")) ?? \"\"})`;\n } else {\n const name = text(readErrorProperty(error, \"name\"));\n summary = `${name !== undefined && /^[\\w$.]{1,64}$/.test(name) ? name : typeof error} (message withheld)`;\n }\n const frames = (text(readErrorProperty(error, \"stack\")) ?? \"\")\n .split(/\\r?\\n/)\n .filter((line) => STACK_FRAME.test(line));\n return {\n message: `WebSocket connection authentication failed: ${summary}`,\n stack: frames.length > 0 ? [summary, ...frames].join(\"\\n\") : undefined,\n };\n}\n\n/**\n * The `ws` execution context of a connection before any gateway handler runs. Nest exports no\n * public factory for execution contexts, so this implements the public `ExecutionContext`\n * interface with the values Nest's internal host reports for the arguments `[client, undefined]`.\n */\nexport class ConnectionExecutionContext implements ExecutionContext {\n readonly #args: unknown[];\n\n constructor(client: object) {\n this.#args = [client, undefined];\n }\n\n getType<TContext extends string = ContextType>(): TContext {\n return \"ws\" as TContext;\n }\n\n /** No handler runs yet, so there is no class; Nest's host reports `null` as well. */\n getClass<T>(): Type<T> {\n return null as unknown as Type<T>;\n }\n\n /** No handler runs yet; Nest's host reports `null` as well. */\n getHandler(): ReturnType<ExecutionContext[\"getHandler\"]> {\n return null as unknown as ReturnType<ExecutionContext[\"getHandler\"]>;\n }\n\n getArgs<T extends unknown[] = unknown[]>(): T {\n return this.#args as T;\n }\n\n getArgByIndex<T>(index: number): T {\n return this.#args[index] as T;\n }\n\n switchToHttp(): ReturnType<ExecutionContext[\"switchToHttp\"]> {\n return {\n getRequest: <T>() => this.getArgByIndex<T>(0),\n getResponse: <T>() => this.getArgByIndex<T>(1),\n getNext: <T>() => this.getArgByIndex<T>(2),\n };\n }\n\n switchToRpc(): ReturnType<ExecutionContext[\"switchToRpc\"]> {\n return {\n getData: <T>() => this.getArgByIndex<T>(0),\n getContext: <T>() => this.getArgByIndex<T>(1),\n };\n }\n\n switchToWs(): ReturnType<ExecutionContext[\"switchToWs\"]> {\n return {\n getClient: <T>() => this.getArgByIndex<T>(0),\n getData: <T>() => this.getArgByIndex<T>(1),\n getPattern: () => this.getArgByIndex<string>(this.#args.length - 1),\n };\n }\n}\n\n/** Connection authentication delegates to the same origin and principal kernel as messages. */\nexport class WsConnectionAuth {\n private readonly logger = new Logger(\"BetterAuth\");\n\n constructor(\n @Inject(INSTANCE_REGISTRY) private readonly instances: InstanceLookup,\n @Inject(PRINCIPAL_RESOLVER) private readonly resolver: PrincipalResolver,\n @Inject(TRANSPORT_REGISTRY) private readonly transports: TransportRegistry,\n ) {}\n\n async authenticate(\n client: unknown,\n options: { instance?: string } = {},\n ): Promise<PrincipalResult> {\n if (typeof client !== \"object\" || client === null) {\n throw BetterAuthConfigurationError.atRequest(\n \"INVALID_WS_CLIENT\",\n \"Connection authentication requires a WebSocket client.\",\n );\n }\n const context = new ConnectionExecutionContext(client);\n const transport = this.transports.select(context);\n const call = this.transports.describe(context, transport);\n const entry = this.instances.get(options.instance ?? \"default\");\n const browser = call.browser;\n if (browser && entry.options.originCheck?.mode !== \"off\") {\n const failure = await entry.handle.checkOrigin(browser, \"cookie\");\n if (failure) {\n return { outcome: \"rejected\", failure };\n }\n }\n const accepts = new Set(\n entry.sources\n .filter((source) => source.acceptance === \"default\")\n .flatMap((source) => [...source.kinds]),\n );\n try {\n return await this.resolver.resolve(call, {\n auth: entry.handle,\n accepts,\n sourceSet: JSON.stringify(\n entry.sources.flatMap((source, index) =>\n source.kinds.some((kind) => accepts.has(kind)) ? [index] : [],\n ),\n ),\n freshness:\n entry.options.session !== false &&\n entry.options.session?.freshness === \"authoritative\"\n ? \"authoritative\"\n : \"default\",\n });\n } catch (error) {\n if (isAuthFailure(error)) {\n return { outcome: \"rejected\", failure: error };\n }\n throw error;\n }\n }\n\n socketIoMiddleware(\n options: { required?: boolean; instance?: string } = {},\n ): (socket: unknown, next: (error?: Error) => void) => void {\n return (socket, next) => {\n void this.authenticate(socket, options).then(\n (result) => {\n const failure =\n result.outcome === \"rejected\"\n ? result.failure\n : result.outcome === \"absent\" && options.required\n ? AuthFailures.unauthenticated()\n : undefined;\n if (!failure) {\n next();\n return;\n }\n next(\n Object.assign(new Error(failure.message), {\n data: {\n status: \"error\",\n statusCode: failure.status,\n code: failure.code,\n ...(failure.reason ? { reason: failure.reason } : {}),\n message: failure.message,\n },\n }),\n );\n },\n (error: unknown) => {\n const log = connectionErrorLog(error);\n this.logger.error(log.message, log.stack);\n next(\n Object.assign(new Error(\"Internal server error\"), {\n data: {\n status: \"error\",\n statusCode: 500,\n message: \"Internal server error\",\n },\n }),\n );\n },\n );\n };\n }\n}\n","import type { IncomingHttpHeaders } from \"node:http\";\nimport type { ExecutionContext } from \"@nestjs/common\";\nimport { MetadataScanner } from \"@nestjs/core\";\nimport {\n SubscribeMessage,\n WebSocketGateway,\n WsException,\n} from \"@nestjs/websockets\";\nimport {\n type AuthTransport,\n type BootAdvice,\n type BootAdviceContext,\n type ExtensionDefinition,\n type TransportCall,\n type TransportValidationContext,\n} from \"./auth-contracts.js\";\nimport {\n AuthFailures,\n BetterAuthConfigurationError,\n type AuthFailure,\n} from \"./auth-errors.js\";\nimport { EXTENSION_DEFINITION } from \"./bridge-protocol.js\";\nimport { toWebHeaders, upgradeRequestUrl } from \"./platform.js\";\nimport { WsConnectionAuth, WS_CONNECTION_AUTH } from \"./ws-connection-auth.js\";\n\nexport interface WsTransportOptions<C> {\n /** Replaces principal credentials without changing the browser handshake used for origin checks. */\n credentials?: (client: C) => HeadersInit | undefined;\n /** Defaults to zero. Positive values delay revocation for non-authoritative messages. */\n principalTtlMs?: number;\n /** Every message handler requires explicit guard and scope coverage on every Nest major. */\n gatewayCoverage?: \"error\" | \"warn\" | \"off\";\n}\nexport interface SocketIoClientLike {\n readonly handshake: {\n readonly headers: IncomingHttpHeaders;\n readonly auth?: Record<string, unknown>;\n readonly address?: string;\n readonly url?: string;\n readonly secure?: boolean;\n };\n}\n/** Convert only mapped headers here: native Headers errors can quote the credential. */\nexport function mappedCredentialHeaders(\n input: HeadersInit | undefined,\n): Headers {\n const headers = new Headers();\n if (input === undefined) {\n return headers;\n }\n const malformed = () =>\n AuthFailures.rejected({ status: 401, reason: \"MALFORMED_CREDENTIALS\" });\n if (input === null || typeof input !== \"object\") {\n throw malformed();\n }\n // Read caller-provided getters/iterators outside the conversion catch so their\n // programming errors remain errors, as do errors thrown by the mapper itself.\n const iterable = (input as { [Symbol.iterator]?: unknown })[Symbol.iterator];\n if (iterable !== undefined && typeof iterable !== \"function\") {\n throw malformed();\n }\n const entries: Iterable<unknown> =\n typeof iterable === \"function\"\n ? (input as Iterable<unknown>)\n : Object.entries(input);\n for (const entry of entries) {\n if (!Array.isArray(entry) || entry.length !== 2) {\n throw malformed();\n }\n const [name, value] = entry;\n if (\n typeof name !== \"string\" ||\n typeof value !== \"string\" ||\n /[\\r\\n\\0]/.test(value)\n ) {\n throw malformed();\n }\n try {\n headers.append(name, value);\n } catch {\n throw malformed();\n }\n }\n return headers;\n}\nexport function isSocketIo(client: unknown): client is SocketIoClientLike {\n return typeof client === \"object\" && client !== null && \"handshake\" in client;\n}\nexport function wsException(failure: AuthFailure): WsException {\n return new WsException({\n status: \"error\",\n statusCode: failure.status,\n code: failure.code,\n ...(failure.reason ? { reason: failure.reason } : {}),\n message: failure.message,\n });\n}\nexport function validateGateways(\n context: TransportValidationContext,\n coverage: WsTransportOptions<unknown>[\"gatewayCoverage\"],\n): void {\n class Probe {\n message(): void {}\n }\n WebSocketGateway()(Probe);\n SubscribeMessage(\"probe\")(\n Probe.prototype,\n \"message\",\n Object.getOwnPropertyDescriptor(Probe.prototype, \"message\")!,\n );\n if (\n Reflect.getMetadata(\"websockets:is_gateway\", Probe) !== true ||\n Reflect.getMetadata(\n \"websockets:message_mapping\",\n Probe.prototype.message,\n ) !== true\n ) {\n throw new BetterAuthConfigurationError(\n \"NEST_METADATA_KEY_CHANGED\",\n \"Nest WebSocket gateway/message metadata failed its canary.\",\n );\n }\n const scanner = new MetadataScanner();\n for (const wrapper of context.discovery.getProviders()) {\n const target = wrapper.metatype;\n if (\n !target?.prototype ||\n wrapper.isAlias ||\n !Reflect.getMetadata(\"websockets:is_gateway\", target)\n ) {\n continue;\n }\n for (const method of scanner.getAllMethodNames(target.prototype)) {\n if (\n Reflect.getMetadata(\n \"websockets:message_mapping\",\n target.prototype[method],\n )\n ) {\n context.claim(target, method, \"explicit\", {\n everyHandler: true,\n code: \"GATEWAY_UNGUARDED\",\n coverage: coverage ?? \"error\",\n hint: `Add @UseBetterAuth() to ${target.name} (or @Public() to opt out). Global guards and interceptors do not reach gateways on NestJS 11, and this check does not depend on the version.`,\n });\n }\n }\n }\n}\nexport function quotaAdvice(\n context: BootAdviceContext,\n ttl: number,\n): readonly BootAdvice[] {\n return ttl === 0 &&\n context.sources.some((source) => source.effects?.consumesQuota)\n ? [\n {\n level: \"warn\",\n code: \"W_QUOTA_PER_MESSAGE\",\n message:\n \"Quota-consuming WebSocket principals verify on every message.\",\n hint: \"Consider connection-time authentication and principalTtlMs; a positive TTL delays revocation on non-authoritative handlers.\",\n },\n ]\n : [];\n}\nexport function transportDefinition(\n transport: AuthTransport,\n): ExtensionDefinition<AuthTransport> {\n return {\n [EXTENSION_DEFINITION]: true,\n use: { useFactory: () => transport },\n providers: [\n WsConnectionAuth,\n { provide: WS_CONNECTION_AUTH, useExisting: WsConnectionAuth },\n ],\n exports: [WsConnectionAuth, WS_CONNECTION_AUTH],\n };\n}\nexport function principalTtl(value = 0): number {\n if (!Number.isFinite(value) || value < 0) {\n throw new BetterAuthConfigurationError(\n \"INVALID_WS_TTL\",\n \"principalTtlMs must be a finite non-negative number.\",\n );\n }\n return value;\n}\nexport function socketIoTransport(\n options: WsTransportOptions<SocketIoClientLike> = {},\n): ExtensionDefinition<AuthTransport> {\n const ttl = principalTtl(options.principalTtlMs);\n return transportDefinition({\n id: \"socket.io\",\n handles: (context) =>\n context.getType() === \"ws\" &&\n isSocketIo(context.switchToWs().getClient()),\n describe(context: ExecutionContext): TransportCall {\n const client = context.switchToWs().getClient<SocketIoClientLike>();\n const original = () => toWebHeaders(client.handshake.headers);\n return {\n key: context.getArgs(),\n invocation: context.getArgs(),\n connection: client,\n principalTtlMs: ttl,\n headers: () => {\n const headers = original();\n let mapped: HeadersInit | undefined;\n if (options.credentials) {\n mapped = options.credentials(client);\n } else if (!headers.has(\"authorization\")) {\n const token = client.handshake.auth?.token;\n if (token !== undefined) {\n if (typeof token !== \"string\") {\n throw AuthFailures.rejected({\n status: 401,\n reason: \"MALFORMED_CREDENTIALS\",\n });\n }\n mapped = { authorization: `Bearer ${token}` };\n }\n }\n mappedCredentialHeaders(mapped).forEach((value, name) => {\n headers.set(name, value);\n });\n return headers;\n },\n get clientIp() {\n return client.handshake.address ?? null;\n },\n cookies: null,\n get request() {\n return { method: \"GET\", url: upgradeRequestUrl(client.handshake) };\n },\n param: (name) => context.switchToWs().getData()?.[name],\n get browser() {\n return {\n enforce: true,\n key: client,\n headers: original,\n url: upgradeRequestUrl(client.handshake),\n };\n },\n };\n },\n toException: wsException,\n validate: (context) => validateGateways(context, options.gatewayCoverage),\n advise: (context) => quotaAdvice(context, ttl),\n });\n}\n","import type { IncomingHttpHeaders } from \"node:http\";\nimport type { AuthTransport, ExtensionDefinition } from \"./auth-contracts.js\";\nimport { UPGRADE_REQUEST } from \"./bridge-protocol.js\";\nimport { BetterAuthConfigurationError } from \"./auth-errors.js\";\nimport { toWebHeaders, upgradeRequestUrl } from \"./platform.js\";\nimport {\n isSocketIo,\n mappedCredentialHeaders,\n principalTtl,\n quotaAdvice,\n transportDefinition,\n validateGateways,\n wsException,\n type WsTransportOptions,\n} from \"./socket-io-transport.js\";\n\nexport { UPGRADE_REQUEST } from \"./bridge-protocol.js\";\nexport interface WsClientLike {\n readonly [UPGRADE_REQUEST]?: {\n readonly headers: Headers;\n readonly url?: string;\n readonly remoteAddress?: string;\n readonly encrypted?: boolean;\n };\n}\nexport interface WsAdapterLike {\n bindClientConnect(\n server: unknown,\n callback: (...args: any[]) => void,\n ): unknown;\n}\nexport function recordUpgradeRequest(\n client: object,\n request: {\n headers: IncomingHttpHeaders;\n url?: string;\n socket?: { remoteAddress?: string; encrypted?: boolean };\n },\n): void {\n Object.defineProperty(client, UPGRADE_REQUEST, {\n value: Object.freeze({\n headers: toWebHeaders(request.headers),\n url: request.url,\n remoteAddress: request.socket?.remoteAddress,\n encrypted: request.socket?.encrypted,\n }),\n configurable: true,\n });\n}\nexport function withUpgradeRequest<\n T extends new (\n ...args: any[]\n ) => WsAdapterLike,\n>(Base: T): T {\n return class extends Base {\n override bindClientConnect(\n server: unknown,\n callback: (...args: any[]) => void,\n ): unknown {\n return super.bindClientConnect(server, (client, request, ...rest) => {\n recordUpgradeRequest(client, request);\n callback(client, request, ...rest);\n });\n }\n };\n}\nexport function wsTransport(\n options: WsTransportOptions<WsClientLike> = {},\n): ExtensionDefinition<AuthTransport> {\n const ttl = principalTtl(options.principalTtlMs);\n return transportDefinition({\n id: \"ws\",\n handles: (context) =>\n context.getType() === \"ws\" &&\n !isSocketIo(context.switchToWs().getClient()),\n describe(context) {\n const client = context.switchToWs().getClient<WsClientLike>();\n const upgrade = () => {\n const request = client[UPGRADE_REQUEST];\n if (!request) {\n throw BetterAuthConfigurationError.atRequest(\n \"WS_UPGRADE_REQUEST_MISSING\",\n \"WebSocket authentication requires its upgrade request.\",\n {\n hint: \"app.useWebSocketAdapter(new (withUpgradeRequest(WsAdapter))(app));\",\n },\n );\n }\n return request;\n };\n const url = () => {\n const request = upgrade();\n return upgradeRequestUrl({\n headers: request.headers,\n url: request.url,\n secure: request.encrypted,\n });\n };\n return {\n key: context.getArgs(),\n invocation: context.getArgs(),\n connection: client,\n principalTtlMs: ttl,\n headers: () => {\n const headers = new Headers(upgrade().headers);\n mappedCredentialHeaders(options.credentials?.(client)).forEach(\n (value, name) => {\n headers.set(name, value);\n },\n );\n return headers;\n },\n get clientIp() {\n return upgrade().remoteAddress ?? null;\n },\n cookies: null,\n get request() {\n return { method: \"GET\", url: url() };\n },\n param: (name) => context.switchToWs().getData()?.[name],\n get browser() {\n return {\n enforce: true,\n key: client,\n headers: () => new Headers(upgrade().headers),\n url: url(),\n };\n },\n };\n },\n toException: wsException,\n validate: (context) => validateGateways(context, options.gatewayCoverage),\n advise: (context) => quotaAdvice(context, ttl),\n });\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"websockets.mjs","names":[],"sources":["../src/ws-connection-auth.ts","../src/socket-io-transport.ts","../src/ws-transport.ts"],"sourcesContent":["import {\n type ContextType,\n type ExecutionContext,\n Inject,\n Logger,\n type Type,\n} from \"@nestjs/common\";\nimport type { PrincipalResolver, PrincipalResult } from \"./auth-contracts.js\";\nimport {\n AuthFailures,\n isAuthFailure,\n isConfigurationError,\n isInfrastructureError,\n BetterAuthConfigurationError,\n type AuthFailure,\n} from \"./auth-errors.js\";\nimport {\n INSTANCE_REGISTRY,\n PRINCIPAL_RESOLVER,\n TRANSPORT_REGISTRY,\n} from \"./auth-tokens.js\";\nimport { readErrorProperty } from \"./error-redactor.js\";\nimport type { InstanceLookup } from \"./instance-registry.js\";\nimport type { TransportRegistry } from \"./transport-registry.js\";\n\nexport { WS_CONNECTION_AUTH } from \"./auth-tokens.js\";\nexport function wsCloseCodeFor(failure: AuthFailure): 4401 | 4403 | 4429 {\n return failure.status === 401 ? 4401 : failure.status === 403 ? 4403 : 4429;\n}\n\nconst STACK_FRAME = /^\\s+at .+:\\d+:\\d+\\)?$/;\n\n/**\n * Describes an unexpected connection-authentication error for the server log. Package\n * errors carry fixed messages and already-redacted causes. Application and runtime error\n * messages can quote client credentials (native Headers errors do), so only their name\n * and stack frames are kept.\n */\nexport function connectionErrorLog(error: unknown): {\n message: string;\n stack?: string;\n} {\n const text = (value: unknown) =>\n typeof value === \"string\" ? value : undefined;\n let summary: string;\n if (isConfigurationError(error)) {\n summary = `${error.code}: ${error.detail}`;\n } else if (isInfrastructureError(error)) {\n const cause = readErrorProperty(error, \"cause\");\n summary = `${error.message} (${text(readErrorProperty(cause, \"name\")) ?? \"Error\"}: ${text(readErrorProperty(cause, \"message\")) ?? \"\"})`;\n } else {\n const name = text(readErrorProperty(error, \"name\"));\n summary = `${name !== undefined && /^[\\w$.]{1,64}$/.test(name) ? name : typeof error} (message withheld)`;\n }\n const frames = (text(readErrorProperty(error, \"stack\")) ?? \"\")\n .split(/\\r?\\n/)\n .filter((line) => STACK_FRAME.test(line));\n return {\n message: `WebSocket connection authentication failed: ${summary}`,\n stack: frames.length > 0 ? [summary, ...frames].join(\"\\n\") : undefined,\n };\n}\n\n/**\n * The `ws` execution context of a connection before any gateway handler runs. Nest exports no\n * public factory for execution contexts, so this implements the public `ExecutionContext`\n * interface with the values Nest's internal host reports for the arguments `[client, undefined]`.\n */\nexport class ConnectionExecutionContext implements ExecutionContext {\n readonly #args: unknown[];\n\n constructor(client: object) {\n this.#args = [client, undefined];\n }\n\n getType<TContext extends string = ContextType>(): TContext {\n return \"ws\" as TContext;\n }\n\n /** No handler runs yet, so there is no class; Nest's host reports `null` as well. */\n getClass<T>(): Type<T> {\n return null as unknown as Type<T>;\n }\n\n /** No handler runs yet; Nest's host reports `null` as well. */\n getHandler(): ReturnType<ExecutionContext[\"getHandler\"]> {\n return null as unknown as ReturnType<ExecutionContext[\"getHandler\"]>;\n }\n\n getArgs<T extends unknown[] = unknown[]>(): T {\n return this.#args as T;\n }\n\n getArgByIndex<T>(index: number): T {\n return this.#args[index] as T;\n }\n\n switchToHttp(): ReturnType<ExecutionContext[\"switchToHttp\"]> {\n return {\n getRequest: <T>() => this.getArgByIndex<T>(0),\n getResponse: <T>() => this.getArgByIndex<T>(1),\n getNext: <T>() => this.getArgByIndex<T>(2),\n };\n }\n\n switchToRpc(): ReturnType<ExecutionContext[\"switchToRpc\"]> {\n return {\n getData: <T>() => this.getArgByIndex<T>(0),\n getContext: <T>() => this.getArgByIndex<T>(1),\n };\n }\n\n switchToWs(): ReturnType<ExecutionContext[\"switchToWs\"]> {\n return {\n getClient: <T>() => this.getArgByIndex<T>(0),\n getData: <T>() => this.getArgByIndex<T>(1),\n getPattern: () => this.getArgByIndex<string>(this.#args.length - 1),\n };\n }\n}\n\n/** Connection authentication delegates to the same origin and principal kernel as messages. */\nexport class WsConnectionAuth {\n private readonly logger = new Logger(\"BetterAuth\");\n\n constructor(\n @Inject(INSTANCE_REGISTRY) private readonly instances: InstanceLookup,\n @Inject(PRINCIPAL_RESOLVER) private readonly resolver: PrincipalResolver,\n @Inject(TRANSPORT_REGISTRY) private readonly transports: TransportRegistry,\n ) {}\n\n async authenticate(\n client: unknown,\n options: { instance?: string } = {},\n ): Promise<PrincipalResult> {\n if (typeof client !== \"object\" || client === null) {\n throw BetterAuthConfigurationError.atRequest(\n \"INVALID_WS_CLIENT\",\n \"Connection authentication requires a WebSocket client.\",\n );\n }\n const context = new ConnectionExecutionContext(client);\n const transport = this.transports.select(context);\n const call = this.transports.describe(context, transport);\n const entry = this.instances.get(options.instance ?? \"default\");\n const browser = call.browser;\n if (browser && entry.options.originCheck?.mode !== \"off\") {\n const failure = await entry.handle.checkOrigin(browser, \"cookie\");\n if (failure) {\n return { outcome: \"rejected\", failure };\n }\n }\n const accepts = new Set(\n entry.sources\n .filter((source) => source.acceptance === \"default\")\n .flatMap((source) => [...source.kinds]),\n );\n try {\n return await this.resolver.resolve(call, {\n auth: entry.handle,\n accepts,\n sourceSet: JSON.stringify(\n entry.sources.flatMap((source, index) =>\n source.kinds.some((kind) => accepts.has(kind)) ? [index] : [],\n ),\n ),\n freshness:\n entry.options.session !== false &&\n entry.options.session?.freshness === \"authoritative\"\n ? \"authoritative\"\n : \"default\",\n });\n } catch (error) {\n if (isAuthFailure(error)) {\n return { outcome: \"rejected\", failure: error };\n }\n throw error;\n }\n }\n\n socketIoMiddleware(\n options: { required?: boolean; instance?: string } = {},\n ): (socket: unknown, next: (error?: Error) => void) => void {\n return (socket, next) => {\n void this.authenticate(socket, options).then(\n (result) => {\n const failure =\n result.outcome === \"rejected\"\n ? result.failure\n : result.outcome === \"absent\" && options.required\n ? AuthFailures.unauthenticated()\n : undefined;\n if (!failure) {\n next();\n return;\n }\n next(\n Object.assign(new Error(failure.message), {\n data: {\n status: \"error\",\n statusCode: failure.status,\n code: failure.code,\n ...(failure.reason ? { reason: failure.reason } : {}),\n message: failure.message,\n },\n }),\n );\n },\n (error: unknown) => {\n const log = connectionErrorLog(error);\n this.logger.error(log.message, log.stack);\n next(\n Object.assign(new Error(\"Internal server error\"), {\n data: {\n status: \"error\",\n statusCode: 500,\n message: \"Internal server error\",\n },\n }),\n );\n },\n );\n };\n }\n}\n","import type { IncomingHttpHeaders } from \"node:http\";\nimport type { ExecutionContext } from \"@nestjs/common\";\nimport { MetadataScanner } from \"@nestjs/core\";\nimport {\n SubscribeMessage,\n WebSocketGateway,\n WsException,\n} from \"@nestjs/websockets\";\nimport {\n type AuthTransport,\n type BootAdvice,\n type BootAdviceContext,\n type ExtensionDefinition,\n type TransportCall,\n type TransportValidationContext,\n} from \"./auth-contracts.js\";\nimport {\n AuthFailures,\n BetterAuthConfigurationError,\n type AuthFailure,\n} from \"./auth-errors.js\";\nimport { EXTENSION_DEFINITION } from \"./bridge-protocol.js\";\nimport { toWebHeaders, upgradeRequestUrl } from \"./platform.js\";\nimport { WsConnectionAuth, WS_CONNECTION_AUTH } from \"./ws-connection-auth.js\";\n\nexport interface WsTransportOptions<C> {\n /** Replaces principal credentials without changing the browser handshake used for origin checks. */\n credentials?: (client: C) => HeadersInit | undefined;\n /** Defaults to zero. Positive values delay revocation for non-authoritative messages. */\n principalTtlMs?: number;\n /** Every message handler requires explicit guard and scope coverage on every Nest major. */\n gatewayCoverage?: \"error\" | \"warn\" | \"off\";\n}\nexport interface SocketIoClientLike {\n readonly handshake: {\n readonly headers: IncomingHttpHeaders;\n readonly auth?: Record<string, unknown>;\n readonly address?: string;\n readonly url?: string;\n readonly secure?: boolean;\n };\n}\n/** Convert only mapped headers here: native Headers errors can quote the credential. */\nexport function mappedCredentialHeaders(\n input: HeadersInit | undefined,\n): Headers {\n const headers = new Headers();\n if (input === undefined) {\n return headers;\n }\n const malformed = () =>\n AuthFailures.rejected({ status: 401, reason: \"MALFORMED_CREDENTIALS\" });\n if (input === null || typeof input !== \"object\") {\n throw malformed();\n }\n // Read caller-provided getters/iterators outside the conversion catch so their\n // programming errors remain errors, as do errors thrown by the mapper itself.\n const iterable = (input as { [Symbol.iterator]?: unknown })[Symbol.iterator];\n if (iterable !== undefined && typeof iterable !== \"function\") {\n throw malformed();\n }\n const entries: Iterable<unknown> =\n typeof iterable === \"function\"\n ? (input as Iterable<unknown>)\n : Object.entries(input);\n for (const entry of entries) {\n if (!Array.isArray(entry) || entry.length !== 2) {\n throw malformed();\n }\n const [name, value] = entry;\n if (\n typeof name !== \"string\" ||\n typeof value !== \"string\" ||\n /[\\r\\n\\0]/.test(value)\n ) {\n throw malformed();\n }\n try {\n headers.append(name, value);\n } catch {\n throw malformed();\n }\n }\n return headers;\n}\nexport function isSocketIo(client: unknown): client is SocketIoClientLike {\n return typeof client === \"object\" && client !== null && \"handshake\" in client;\n}\nexport function wsException(failure: AuthFailure): WsException {\n return new WsException({\n status: \"error\",\n statusCode: failure.status,\n code: failure.code,\n ...(failure.reason ? { reason: failure.reason } : {}),\n message: failure.message,\n });\n}\nexport function validateGateways(\n context: TransportValidationContext,\n coverage: WsTransportOptions<unknown>[\"gatewayCoverage\"],\n): void {\n class Probe {\n message(): void {}\n }\n WebSocketGateway()(Probe);\n SubscribeMessage(\"probe\")(\n Probe.prototype,\n \"message\",\n Object.getOwnPropertyDescriptor(Probe.prototype, \"message\")!,\n );\n if (\n Reflect.getMetadata(\"websockets:is_gateway\", Probe) !== true ||\n Reflect.getMetadata(\n \"websockets:message_mapping\",\n Probe.prototype.message,\n ) !== true\n ) {\n throw new BetterAuthConfigurationError(\n \"NEST_METADATA_KEY_CHANGED\",\n \"Nest WebSocket gateway/message metadata failed its canary.\",\n );\n }\n const scanner = new MetadataScanner();\n for (const wrapper of context.discovery.getProviders()) {\n const target = wrapper.metatype;\n if (\n !target?.prototype ||\n wrapper.isAlias ||\n !Reflect.getMetadata(\"websockets:is_gateway\", target)\n ) {\n continue;\n }\n for (const method of scanner.getAllMethodNames(target.prototype)) {\n if (\n Reflect.getMetadata(\n \"websockets:message_mapping\",\n target.prototype[method],\n )\n ) {\n context.claim(target, method, \"explicit\", {\n everyHandler: true,\n code: \"GATEWAY_UNGUARDED\",\n coverage: coverage ?? \"error\",\n hint: `Add @UseBetterAuth() to ${target.name} (or @Public() to opt out). Global guards and interceptors do not reach gateways on NestJS 11, and this check does not depend on the version.`,\n });\n }\n }\n }\n}\nexport function quotaAdvice(\n context: BootAdviceContext,\n ttl: number,\n): readonly BootAdvice[] {\n return ttl === 0 &&\n context.sources.some((source) => source.effects?.consumesQuota)\n ? [\n {\n level: \"warn\",\n code: \"W_QUOTA_PER_MESSAGE\",\n message:\n \"Quota-consuming WebSocket principals verify on every message.\",\n hint: \"Consider connection-time authentication and principalTtlMs; a positive TTL delays revocation on non-authoritative handlers.\",\n },\n ]\n : [];\n}\nexport function transportDefinition(\n transport: AuthTransport,\n): ExtensionDefinition<AuthTransport> {\n return {\n [EXTENSION_DEFINITION]: true,\n use: { useFactory: () => transport },\n providers: [\n WsConnectionAuth,\n { provide: WS_CONNECTION_AUTH, useExisting: WsConnectionAuth },\n ],\n exports: [WsConnectionAuth, WS_CONNECTION_AUTH],\n };\n}\nexport function principalTtl(value = 0): number {\n if (!Number.isFinite(value) || value < 0) {\n throw new BetterAuthConfigurationError(\n \"INVALID_WS_TTL\",\n \"principalTtlMs must be a finite non-negative number.\",\n );\n }\n return value;\n}\nexport function socketIoTransport(\n options: WsTransportOptions<SocketIoClientLike> = {},\n): ExtensionDefinition<AuthTransport> {\n const ttl = principalTtl(options.principalTtlMs);\n return transportDefinition({\n id: \"socket.io\",\n handles: (context) =>\n context.getType() === \"ws\" &&\n isSocketIo(context.switchToWs().getClient()),\n describe(context: ExecutionContext): TransportCall {\n const client = context.switchToWs().getClient<SocketIoClientLike>();\n const original = () => toWebHeaders(client.handshake.headers);\n return {\n key: context.getArgs(),\n invocation: context.getArgs(),\n connection: client,\n principalTtlMs: ttl,\n headers: () => {\n const headers = original();\n let mapped: HeadersInit | undefined;\n if (options.credentials) {\n mapped = options.credentials(client);\n } else if (!headers.has(\"authorization\")) {\n const token = client.handshake.auth?.token;\n if (token !== undefined) {\n if (typeof token !== \"string\") {\n throw AuthFailures.rejected({\n status: 401,\n reason: \"MALFORMED_CREDENTIALS\",\n });\n }\n mapped = { authorization: `Bearer ${token}` };\n }\n }\n mappedCredentialHeaders(mapped).forEach((value, name) => {\n headers.set(name, value);\n });\n return headers;\n },\n get clientIp() {\n return client.handshake.address ?? null;\n },\n cookies: null,\n get request() {\n return { method: \"GET\", url: upgradeRequestUrl(client.handshake) };\n },\n param: (name) => context.switchToWs().getData()?.[name],\n get browser() {\n return {\n enforce: true,\n key: client,\n headers: original,\n url: upgradeRequestUrl(client.handshake),\n };\n },\n };\n },\n toException: wsException,\n validate: (context) => validateGateways(context, options.gatewayCoverage),\n advise: (context) => quotaAdvice(context, ttl),\n });\n}\n","import type { IncomingHttpHeaders } from \"node:http\";\nimport type { AuthTransport, ExtensionDefinition } from \"./auth-contracts.js\";\nimport { UPGRADE_REQUEST } from \"./bridge-protocol.js\";\nimport { BetterAuthConfigurationError } from \"./auth-errors.js\";\nimport { toWebHeaders, upgradeRequestUrl } from \"./platform.js\";\nimport {\n isSocketIo,\n mappedCredentialHeaders,\n principalTtl,\n quotaAdvice,\n transportDefinition,\n validateGateways,\n wsException,\n type WsTransportOptions,\n} from \"./socket-io-transport.js\";\n\nexport { UPGRADE_REQUEST } from \"./bridge-protocol.js\";\nexport interface WsClientLike {\n readonly [UPGRADE_REQUEST]?: {\n readonly headers: Headers;\n readonly url?: string;\n readonly remoteAddress?: string;\n readonly encrypted?: boolean;\n };\n}\nexport interface WsAdapterLike {\n bindClientConnect(\n server: unknown,\n callback: (...args: any[]) => void,\n ): unknown;\n}\nexport function recordUpgradeRequest(\n client: object,\n request: {\n headers: IncomingHttpHeaders;\n url?: string;\n socket?: { remoteAddress?: string; encrypted?: boolean };\n },\n): void {\n Object.defineProperty(client, UPGRADE_REQUEST, {\n value: Object.freeze({\n headers: toWebHeaders(request.headers),\n url: request.url,\n remoteAddress: request.socket?.remoteAddress,\n encrypted: request.socket?.encrypted,\n }),\n configurable: true,\n });\n}\nexport function withUpgradeRequest<\n T extends new (...args: any[]) => WsAdapterLike,\n>(Base: T): T {\n return class extends Base {\n override bindClientConnect(\n server: unknown,\n callback: (...args: any[]) => void,\n ): unknown {\n return super.bindClientConnect(server, (client, request, ...rest) => {\n recordUpgradeRequest(client, request);\n callback(client, request, ...rest);\n });\n }\n };\n}\nexport function wsTransport(\n options: WsTransportOptions<WsClientLike> = {},\n): ExtensionDefinition<AuthTransport> {\n const ttl = principalTtl(options.principalTtlMs);\n return transportDefinition({\n id: \"ws\",\n handles: (context) =>\n context.getType() === \"ws\" &&\n !isSocketIo(context.switchToWs().getClient()),\n describe(context) {\n const client = context.switchToWs().getClient<WsClientLike>();\n const upgrade = () => {\n const request = client[UPGRADE_REQUEST];\n if (!request) {\n throw BetterAuthConfigurationError.atRequest(\n \"WS_UPGRADE_REQUEST_MISSING\",\n \"WebSocket authentication requires its upgrade request.\",\n {\n hint: \"app.useWebSocketAdapter(new (withUpgradeRequest(WsAdapter))(app));\",\n },\n );\n }\n return request;\n };\n const url = () => {\n const request = upgrade();\n return upgradeRequestUrl({\n headers: request.headers,\n url: request.url,\n secure: request.encrypted,\n });\n };\n return {\n key: context.getArgs(),\n invocation: context.getArgs(),\n connection: client,\n principalTtlMs: ttl,\n headers: () => {\n const headers = new Headers(upgrade().headers);\n mappedCredentialHeaders(options.credentials?.(client)).forEach(\n (value, name) => {\n headers.set(name, value);\n },\n );\n return headers;\n },\n get clientIp() {\n return upgrade().remoteAddress ?? null;\n },\n cookies: null,\n get request() {\n return { method: \"GET\", url: url() };\n },\n param: (name) => context.switchToWs().getData()?.[name],\n get browser() {\n return {\n enforce: true,\n key: client,\n headers: () => new Headers(upgrade().headers),\n url: url(),\n };\n },\n };\n },\n toException: wsException,\n validate: (context) => validateGateways(context, options.gatewayCoverage),\n advise: (context) => quotaAdvice(context, ttl),\n });\n}\n"],"mappings":"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"}
|