@rhino-dev/rhino-nestjs 0.2.5 → 4.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +52 -1
- package/dist/cli/index.js +0 -0
- package/dist/controllers/auth.controller.d.ts +34 -5
- package/dist/controllers/auth.controller.js +132 -12
- package/dist/controllers/auth.controller.js.map +1 -1
- package/dist/controllers/invitation.controller.d.ts +41 -2
- package/dist/controllers/invitation.controller.js +97 -12
- package/dist/controllers/invitation.controller.js.map +1 -1
- package/dist/errors/rhino-exception.d.ts +12 -1
- package/dist/errors/rhino-exception.js +19 -1
- package/dist/errors/rhino-exception.js.map +1 -1
- package/dist/guards/group-membership.guard.d.ts +25 -0
- package/dist/guards/group-membership.guard.js +70 -0
- package/dist/guards/group-membership.guard.js.map +1 -0
- package/dist/guards/jwt-auth.guard.js +23 -4
- package/dist/guards/jwt-auth.guard.js.map +1 -1
- package/dist/index.d.ts +7 -1
- package/dist/index.js +17 -2
- package/dist/index.js.map +1 -1
- package/dist/interfaces/rhino-config.interface.d.ts +71 -0
- package/dist/middleware/domain-route-resolver.d.ts +54 -0
- package/dist/middleware/domain-route-resolver.js +145 -0
- package/dist/middleware/domain-route-resolver.js.map +1 -0
- package/dist/middleware/route-group.middleware.d.ts +48 -4
- package/dist/middleware/route-group.middleware.js +274 -13
- package/dist/middleware/route-group.middleware.js.map +1 -1
- package/dist/rhino.config.d.ts +26 -1
- package/dist/rhino.config.js +56 -1
- package/dist/rhino.config.js.map +1 -1
- package/dist/rhino.module.d.ts +7 -0
- package/dist/rhino.module.js +23 -1
- package/dist/rhino.module.js.map +1 -1
- package/dist/services/auth-hooks.service.d.ts +27 -0
- package/dist/services/auth-hooks.service.js +85 -0
- package/dist/services/auth-hooks.service.js.map +1 -0
- package/dist/services/auth.service.d.ts +19 -0
- package/dist/services/auth.service.js +80 -5
- package/dist/services/auth.service.js.map +1 -1
- package/dist/services/invitation.service.d.ts +6 -0
- package/dist/services/invitation.service.js +45 -3
- package/dist/services/invitation.service.js.map +1 -1
- package/dist/services/membership.service.d.ts +56 -0
- package/dist/services/membership.service.js +113 -0
- package/dist/services/membership.service.js.map +1 -0
- package/dist/services/organization.service.js +8 -1
- package/dist/services/organization.service.js.map +1 -1
- package/dist/services/route-registration.service.d.ts +1 -0
- package/dist/services/route-registration.service.js +2 -0
- package/dist/services/route-registration.service.js.map +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/dist/utils/domain-pattern.d.ts +36 -0
- package/dist/utils/domain-pattern.js +77 -0
- package/dist/utils/domain-pattern.js.map +1 -0
- package/dist/utils/permission-matcher.js +8 -0
- package/dist/utils/permission-matcher.js.map +1 -1
- package/dist/utils/route-group-validator.d.ts +14 -0
- package/dist/utils/route-group-validator.js +124 -0
- package/dist/utils/route-group-validator.js.map +1 -0
- package/package.json +6 -2
package/dist/rhino.module.js
CHANGED
|
@@ -29,8 +29,11 @@ const nested_service_1 = require("./services/nested.service");
|
|
|
29
29
|
const scope_service_1 = require("./services/scope.service");
|
|
30
30
|
const auth_service_1 = require("./services/auth.service");
|
|
31
31
|
const invitation_service_1 = require("./services/invitation.service");
|
|
32
|
+
const auth_hooks_service_1 = require("./services/auth-hooks.service");
|
|
33
|
+
const membership_service_1 = require("./services/membership.service");
|
|
32
34
|
const jwt_auth_guard_1 = require("./guards/jwt-auth.guard");
|
|
33
35
|
const resource_policy_guard_1 = require("./guards/resource-policy.guard");
|
|
36
|
+
const group_membership_guard_1 = require("./guards/group-membership.guard");
|
|
34
37
|
const global_controller_1 = require("./controllers/global.controller");
|
|
35
38
|
const auth_controller_1 = require("./controllers/auth.controller");
|
|
36
39
|
const invitation_controller_1 = require("./controllers/invitation.controller");
|
|
@@ -132,6 +135,7 @@ let RhinoModule = RhinoModule_1 = class RhinoModule {
|
|
|
132
135
|
static forRoot(config, options = {}) {
|
|
133
136
|
const normalized = (0, rhino_config_1.normalizeConfig)(config);
|
|
134
137
|
const middlewareFromConfig = RhinoModule_1.collectModelMiddleware(normalized);
|
|
138
|
+
const hookClasses = RhinoModule_1.collectHookClasses(normalized);
|
|
135
139
|
return RhinoModule_1.build({
|
|
136
140
|
configProviders: [
|
|
137
141
|
{ provide: tokens_1.RHINO_CONFIG, useValue: normalized },
|
|
@@ -143,6 +147,7 @@ let RhinoModule = RhinoModule_1 = class RhinoModule {
|
|
|
143
147
|
imports: [],
|
|
144
148
|
options,
|
|
145
149
|
middlewareClasses: middlewareFromConfig,
|
|
150
|
+
hookClasses,
|
|
146
151
|
});
|
|
147
152
|
}
|
|
148
153
|
/**
|
|
@@ -173,6 +178,8 @@ let RhinoModule = RhinoModule_1 = class RhinoModule {
|
|
|
173
178
|
const guardProviders = [];
|
|
174
179
|
if (opts.autoAuthGuard)
|
|
175
180
|
guardProviders.push({ provide: core_1.APP_GUARD, useClass: jwt_auth_guard_1.JwtAuthGuard });
|
|
181
|
+
if (opts.autoMembershipGuard)
|
|
182
|
+
guardProviders.push({ provide: core_1.APP_GUARD, useClass: group_membership_guard_1.GroupMembershipGuard });
|
|
176
183
|
if (opts.autoPolicyGuard)
|
|
177
184
|
guardProviders.push({ provide: core_1.APP_GUARD, useClass: resource_policy_guard_1.ResourcePolicyGuard });
|
|
178
185
|
return {
|
|
@@ -187,9 +194,10 @@ let RhinoModule = RhinoModule_1 = class RhinoModule {
|
|
|
187
194
|
...RhinoModule_1.coreProviders(),
|
|
188
195
|
jwt_auth_guard_1.JwtAuthGuard,
|
|
189
196
|
resource_policy_guard_1.ResourcePolicyGuard,
|
|
197
|
+
group_membership_guard_1.GroupMembershipGuard,
|
|
190
198
|
route_group_middleware_1.RouteGroupMiddleware,
|
|
191
199
|
resolve_organization_middleware_1.ResolveOrganizationMiddleware,
|
|
192
|
-
...dedupeTypes(args.middlewareClasses),
|
|
200
|
+
...dedupeTypes([...args.middlewareClasses, ...(args.hookClasses ?? [])]),
|
|
193
201
|
...guardProviders,
|
|
194
202
|
],
|
|
195
203
|
exports: RhinoModule_1.coreExports(),
|
|
@@ -221,8 +229,19 @@ let RhinoModule = RhinoModule_1 = class RhinoModule {
|
|
|
221
229
|
scope_service_1.ScopeService,
|
|
222
230
|
auth_service_1.AuthService,
|
|
223
231
|
invitation_service_1.InvitationService,
|
|
232
|
+
auth_hooks_service_1.AuthHooksService,
|
|
233
|
+
membership_service_1.MembershipService,
|
|
224
234
|
];
|
|
225
235
|
}
|
|
236
|
+
static collectHookClasses(config) {
|
|
237
|
+
const set = new Set();
|
|
238
|
+
for (const group of Object.values(config.routeGroups ?? {})) {
|
|
239
|
+
const hooks = group.hooks;
|
|
240
|
+
if (hooks && typeof hooks === 'function')
|
|
241
|
+
set.add(hooks);
|
|
242
|
+
}
|
|
243
|
+
return Array.from(set);
|
|
244
|
+
}
|
|
226
245
|
static coreExports() {
|
|
227
246
|
return [
|
|
228
247
|
// Injection tokens (BP-010 — surfaced for consumer middleware/services)
|
|
@@ -241,8 +260,11 @@ let RhinoModule = RhinoModule_1 = class RhinoModule {
|
|
|
241
260
|
scope_service_1.ScopeService,
|
|
242
261
|
auth_service_1.AuthService,
|
|
243
262
|
invitation_service_1.InvitationService,
|
|
263
|
+
auth_hooks_service_1.AuthHooksService,
|
|
264
|
+
membership_service_1.MembershipService,
|
|
244
265
|
jwt_auth_guard_1.JwtAuthGuard,
|
|
245
266
|
resource_policy_guard_1.ResourcePolicyGuard,
|
|
267
|
+
group_membership_guard_1.GroupMembershipGuard,
|
|
246
268
|
];
|
|
247
269
|
}
|
|
248
270
|
};
|
package/dist/rhino.module.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rhino.module.js","sourceRoot":"","sources":["../src/rhino.module.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,2CAUwB;AACxB,uCAAyC;AACzC,iDAAqE;AACrE,+CAI4B;AAK5B,4DAAwD;AACxD,kEAA8D;AAC9D,4EAAuE;AACvE,sEAAkE;AAClE,sEAAkE;AAClE,0EAAsE;AACtE,4DAAwD;AACxD,8DAA0D;AAC1D,4DAAwD;AACxD,0DAAsD;AACtD,sEAAkE;AAClE,4DAAuD;AACvD,0EAAqE;AACrE,uEAAmE;AACnE,mEAA+D;AAC/D,+EAA2E;AAC3E,uEAAmE;AACnE,gFAA2E;AAC3E,kGAA6F;AAE7F,MAAM,gBAAgB,GAAkC;IACtD,KAAK,EAAE,sBAAa,CAAC,GAAG;IACxB,IAAI,EAAE,sBAAa,CAAC,GAAG;IACvB,KAAK,EAAE,sBAAa,CAAC,IAAI;IACzB,MAAM,EAAE,sBAAa,CAAC,GAAG;IACzB,OAAO,EAAE,sBAAa,CAAC,MAAM;IAC7B,OAAO,EAAE,sBAAa,CAAC,GAAG;IAC1B,OAAO,EAAE,sBAAa,CAAC,IAAI;IAC3B,WAAW,EAAE,sBAAa,CAAC,MAAM;CAClC,CAAC;AAEF,SAAS,UAAU,CAAC,IAAY,EAAE,MAAc;IAC9C,QAAQ,MAAM,EAAE,CAAC;QACf,KAAK,OAAO,CAAC;QACb,KAAK,OAAO;YACV,OAAO,IAAI,CAAC;QACd,KAAK,SAAS;YACZ,OAAO,GAAG,IAAI,UAAU,CAAC;QAC3B,KAAK,MAAM,CAAC;QACZ,KAAK,QAAQ,CAAC;QACd,KAAK,SAAS;YACZ,OAAO,GAAG,IAAI,MAAM,CAAC;QACvB,KAAK,SAAS;YACZ,OAAO,GAAG,IAAI,cAAc,CAAC;QAC/B,KAAK,aAAa;YAChB,OAAO,GAAG,IAAI,mBAAmB,CAAC;QACpC;YACE,OAAO,IAAI,CAAC;IAChB,CAAC;AACH,CAAC;
|
|
1
|
+
{"version":3,"file":"rhino.module.js","sourceRoot":"","sources":["../src/rhino.module.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { ModuleRef } from '@nestjs/core';
|
|
2
|
+
import { RhinoConfigService } from '../rhino.config';
|
|
3
|
+
import type { AuthHookContext, AuthLifecycleHooks } from '../interfaces/rhino-config.interface';
|
|
4
|
+
export type AuthHookEvent = 'afterLogin' | 'afterLogout' | 'afterRegister' | 'afterPasswordRecover' | 'afterPasswordReset';
|
|
5
|
+
/**
|
|
6
|
+
* Resolves a group's optional lifecycle-hooks class/object and runs a single
|
|
7
|
+
* event (design §7). A hook may reject by throwing — the caller (auth
|
|
8
|
+
* controller) decides whether to revoke a token. When a group has no `hooks`
|
|
9
|
+
* config, every event is a silent no-op.
|
|
10
|
+
*
|
|
11
|
+
* `ModuleRef` is optional so the service works in lightweight unit tests that
|
|
12
|
+
* construct it without a Nest container; in that case a `Type` hooks value is
|
|
13
|
+
* instantiated directly via `new`.
|
|
14
|
+
*/
|
|
15
|
+
export declare class AuthHooksService {
|
|
16
|
+
private readonly config;
|
|
17
|
+
private readonly moduleRef?;
|
|
18
|
+
constructor(config: RhinoConfigService, moduleRef?: ModuleRef);
|
|
19
|
+
/** Resolve the hooks instance for a group, or `null` when none is configured. */
|
|
20
|
+
resolve(routeGroup: string | null | undefined): AuthLifecycleHooks | null;
|
|
21
|
+
/**
|
|
22
|
+
* Run a single lifecycle event for the resolved group. Returns silently when
|
|
23
|
+
* the group has no hooks or the specific method is absent. A rejection
|
|
24
|
+
* propagates to the caller verbatim.
|
|
25
|
+
*/
|
|
26
|
+
run(event: AuthHookEvent, routeGroup: string | null | undefined, ctx: AuthHookContext): Promise<void>;
|
|
27
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
12
|
+
return function (target, key) { decorator(target, key, paramIndex); }
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.AuthHooksService = void 0;
|
|
16
|
+
const common_1 = require("@nestjs/common");
|
|
17
|
+
const core_1 = require("@nestjs/core");
|
|
18
|
+
const rhino_config_1 = require("../rhino.config");
|
|
19
|
+
/**
|
|
20
|
+
* Resolves a group's optional lifecycle-hooks class/object and runs a single
|
|
21
|
+
* event (design §7). A hook may reject by throwing — the caller (auth
|
|
22
|
+
* controller) decides whether to revoke a token. When a group has no `hooks`
|
|
23
|
+
* config, every event is a silent no-op.
|
|
24
|
+
*
|
|
25
|
+
* `ModuleRef` is optional so the service works in lightweight unit tests that
|
|
26
|
+
* construct it without a Nest container; in that case a `Type` hooks value is
|
|
27
|
+
* instantiated directly via `new`.
|
|
28
|
+
*/
|
|
29
|
+
let AuthHooksService = class AuthHooksService {
|
|
30
|
+
config;
|
|
31
|
+
moduleRef;
|
|
32
|
+
constructor(config, moduleRef) {
|
|
33
|
+
this.config = config;
|
|
34
|
+
this.moduleRef = moduleRef;
|
|
35
|
+
}
|
|
36
|
+
/** Resolve the hooks instance for a group, or `null` when none is configured. */
|
|
37
|
+
resolve(routeGroup) {
|
|
38
|
+
const hooks = this.config.routeGroupHooks(routeGroup);
|
|
39
|
+
if (!hooks)
|
|
40
|
+
return null;
|
|
41
|
+
// Plain object implementing the contract.
|
|
42
|
+
if (typeof hooks !== 'function')
|
|
43
|
+
return hooks;
|
|
44
|
+
// A class/Type: prefer the DI container, fall back to direct construction.
|
|
45
|
+
const Cls = hooks;
|
|
46
|
+
if (this.moduleRef) {
|
|
47
|
+
try {
|
|
48
|
+
const instance = this.moduleRef.get(Cls, { strict: false });
|
|
49
|
+
if (instance)
|
|
50
|
+
return instance;
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
/* not registered as a provider — construct directly below */
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
try {
|
|
57
|
+
return new Cls();
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Run a single lifecycle event for the resolved group. Returns silently when
|
|
65
|
+
* the group has no hooks or the specific method is absent. A rejection
|
|
66
|
+
* propagates to the caller verbatim.
|
|
67
|
+
*/
|
|
68
|
+
async run(event, routeGroup, ctx) {
|
|
69
|
+
const instance = this.resolve(routeGroup);
|
|
70
|
+
if (!instance)
|
|
71
|
+
return;
|
|
72
|
+
const fn = instance[event];
|
|
73
|
+
if (typeof fn !== 'function')
|
|
74
|
+
return;
|
|
75
|
+
await fn.call(instance, ctx);
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
exports.AuthHooksService = AuthHooksService;
|
|
79
|
+
exports.AuthHooksService = AuthHooksService = __decorate([
|
|
80
|
+
(0, common_1.Injectable)(),
|
|
81
|
+
__param(1, (0, common_1.Optional)()),
|
|
82
|
+
__metadata("design:paramtypes", [rhino_config_1.RhinoConfigService,
|
|
83
|
+
core_1.ModuleRef])
|
|
84
|
+
], AuthHooksService);
|
|
85
|
+
//# sourceMappingURL=auth-hooks.service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth-hooks.service.js","sourceRoot":"","sources":["../../src/services/auth-hooks.service.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,2CAAsD;AACtD,uCAAyC;AACzC,kDAAqD;AAarD;;;;;;;;;GASG;AAEI,IAAM,gBAAgB,GAAtB,MAAM,gBAAgB;IAER;IACY;IAF/B,YACmB,MAA0B,EACd,SAAqB;QADjC,WAAM,GAAN,MAAM,CAAoB;QACd,cAAS,GAAT,SAAS,CAAY;IACjD,CAAC;IAEJ,iFAAiF;IACjF,OAAO,CAAC,UAAqC;QAC3C,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,eAAe,CAAC,UAAU,CAAC,CAAC;QACtD,IAAI,CAAC,KAAK;YAAE,OAAO,IAAI,CAAC;QACxB,0CAA0C;QAC1C,IAAI,OAAO,KAAK,KAAK,UAAU;YAAE,OAAO,KAA2B,CAAC;QACpE,2EAA2E;QAC3E,MAAM,GAAG,GAAG,KAAmD,CAAC;QAChE,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YACnB,IAAI,CAAC;gBACH,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;gBAC5D,IAAI,QAAQ;oBAAE,OAAO,QAAQ,CAAC;YAChC,CAAC;YAAC,MAAM,CAAC;gBACP,6DAA6D;YAC/D,CAAC;QACH,CAAC;QACD,IAAI,CAAC;YACH,OAAO,IAAI,GAAG,EAAE,CAAC;QACnB,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,GAAG,CACP,KAAoB,EACpB,UAAqC,EACrC,GAAoB;QAEpB,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;QAC1C,IAAI,CAAC,QAAQ;YAAE,OAAO;QACtB,MAAM,EAAE,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;QAC3B,IAAI,OAAO,EAAE,KAAK,UAAU;YAAE,OAAO;QACrC,MAAM,EAAE,CAAC,IAAI,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;IAC/B,CAAC;CACF,CAAA;AA7CY,4CAAgB;2BAAhB,gBAAgB;IAD5B,IAAA,mBAAU,GAAE;IAIR,WAAA,IAAA,iBAAQ,GAAE,CAAA;qCADc,iCAAkB;QACF,gBAAS;GAHzC,gBAAgB,CA6C5B"}
|
|
@@ -26,8 +26,27 @@ export declare class AuthService {
|
|
|
26
26
|
verifyToken(token: string): TokenPayload;
|
|
27
27
|
login(email: string, password: string): Promise<LoginResult>;
|
|
28
28
|
logout(_user: any): Promise<void>;
|
|
29
|
+
/**
|
|
30
|
+
* Revoke a just-issued token. JWTs are stateless, so "revoking" means
|
|
31
|
+
* recording the token in a denylist (when the consumer provides a
|
|
32
|
+
* `RevokedToken` model) so the JwtAuthGuard can reject it on the next
|
|
33
|
+
* request. Used when a lifecycle hook rejects a login/register: the token is
|
|
34
|
+
* never returned AND — IF a denylist model exists — can no longer be used
|
|
35
|
+
* even if it leaked.
|
|
36
|
+
*
|
|
37
|
+
* Bounded guarantee: the caller (AuthController) ALWAYS drops the token from
|
|
38
|
+
* the response on rejection, so an attacker never receives it. Persisting it
|
|
39
|
+
* to a denylist is the *additional* protection against a leaked token. When
|
|
40
|
+
* no `RevokedToken` model is configured we log a clear WARNING so operators
|
|
41
|
+
* know revoke is advisory-only — pair it with short-TTL JWTs (see README /
|
|
42
|
+
* CLAUDE.md "Group-auth hooks & token revocation").
|
|
43
|
+
*/
|
|
44
|
+
revokeToken(token: string): Promise<void>;
|
|
45
|
+
/** Whether a token has been revoked via {@link revokeToken}. */
|
|
46
|
+
isTokenRevoked(token: string): Promise<boolean>;
|
|
29
47
|
requestPasswordRecovery(email: string): Promise<{
|
|
30
48
|
token: string;
|
|
49
|
+
user: any;
|
|
31
50
|
} | null>;
|
|
32
51
|
resetPassword(email: string, token: string, newPassword: string): Promise<void>;
|
|
33
52
|
}
|
|
@@ -90,10 +90,27 @@ let AuthService = AuthService_1 = class AuthService {
|
|
|
90
90
|
}
|
|
91
91
|
async login(email, password) {
|
|
92
92
|
const auth = this.config.authConfig();
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
93
|
+
// Only eager-load the org membership graph when multi-tenancy is configured.
|
|
94
|
+
// Single-tenant / org-less apps have no `userRoles` relation on their User
|
|
95
|
+
// model, so an unconditional include would throw inside Prisma and the
|
|
96
|
+
// `.catch(() => null)` below would surface as "Invalid credentials" — i.e.
|
|
97
|
+
// an org-less app could never log a valid user in. Gating the include on
|
|
98
|
+
// `multiTenantEnabled()` keeps multi-tenant behavior byte-for-byte while
|
|
99
|
+
// letting org-less apps authenticate. (We still degrade gracefully if the
|
|
100
|
+
// include fails for any other reason: retry the plain lookup.)
|
|
101
|
+
const wantsOrg = this.config.multiTenantEnabled();
|
|
102
|
+
let user = null;
|
|
103
|
+
if (wantsOrg) {
|
|
104
|
+
user = await this.userDelegate().findFirst({
|
|
105
|
+
where: { [auth.emailField]: email },
|
|
106
|
+
include: { userRoles: { include: { organization: true, role: true } } },
|
|
107
|
+
}).catch(() => null);
|
|
108
|
+
}
|
|
109
|
+
if (!user) {
|
|
110
|
+
user = await this.userDelegate().findFirst({
|
|
111
|
+
where: { [auth.emailField]: email },
|
|
112
|
+
}).catch(() => null);
|
|
113
|
+
}
|
|
97
114
|
if (!user)
|
|
98
115
|
throw rhino_exception_1.RhinoException.unauthorized('Invalid credentials');
|
|
99
116
|
const hashed = user[auth.passwordField];
|
|
@@ -107,6 +124,64 @@ let AuthService = AuthService_1 = class AuthService {
|
|
|
107
124
|
async logout(_user) {
|
|
108
125
|
// JWT stateless; consumer can add blacklist logic via hooks.
|
|
109
126
|
}
|
|
127
|
+
/**
|
|
128
|
+
* Revoke a just-issued token. JWTs are stateless, so "revoking" means
|
|
129
|
+
* recording the token in a denylist (when the consumer provides a
|
|
130
|
+
* `RevokedToken` model) so the JwtAuthGuard can reject it on the next
|
|
131
|
+
* request. Used when a lifecycle hook rejects a login/register: the token is
|
|
132
|
+
* never returned AND — IF a denylist model exists — can no longer be used
|
|
133
|
+
* even if it leaked.
|
|
134
|
+
*
|
|
135
|
+
* Bounded guarantee: the caller (AuthController) ALWAYS drops the token from
|
|
136
|
+
* the response on rejection, so an attacker never receives it. Persisting it
|
|
137
|
+
* to a denylist is the *additional* protection against a leaked token. When
|
|
138
|
+
* no `RevokedToken` model is configured we log a clear WARNING so operators
|
|
139
|
+
* know revoke is advisory-only — pair it with short-TTL JWTs (see README /
|
|
140
|
+
* CLAUDE.md "Group-auth hooks & token revocation").
|
|
141
|
+
*/
|
|
142
|
+
async revokeToken(token) {
|
|
143
|
+
if (!token)
|
|
144
|
+
return;
|
|
145
|
+
let delegate;
|
|
146
|
+
try {
|
|
147
|
+
delegate = this.prisma.model('revokedToken');
|
|
148
|
+
}
|
|
149
|
+
catch {
|
|
150
|
+
this.logger.warn('AuthService.revokeToken: no `RevokedToken` model is configured, so token ' +
|
|
151
|
+
'revocation is advisory only — the token is dropped from the response but ' +
|
|
152
|
+
'cannot be denylisted if it has already leaked. Add a `RevokedToken` model ' +
|
|
153
|
+
'(token, createdAt) to your Prisma schema and use short-TTL JWTs.');
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
try {
|
|
157
|
+
await delegate.create({ data: { token, createdAt: new Date() } });
|
|
158
|
+
}
|
|
159
|
+
catch (err) {
|
|
160
|
+
// The model exists but the write failed — surface it so a misconfigured
|
|
161
|
+
// denylist is not silently a no-op.
|
|
162
|
+
this.logger.warn(`AuthService.revokeToken: failed to persist revoked token (${err.message}).`);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
/** Whether a token has been revoked via {@link revokeToken}. */
|
|
166
|
+
async isTokenRevoked(token) {
|
|
167
|
+
if (!token)
|
|
168
|
+
return false;
|
|
169
|
+
let delegate;
|
|
170
|
+
try {
|
|
171
|
+
delegate = this.prisma.model('revokedToken');
|
|
172
|
+
}
|
|
173
|
+
catch {
|
|
174
|
+
// No denylist model — nothing can be revoked, so nothing is revoked.
|
|
175
|
+
return false;
|
|
176
|
+
}
|
|
177
|
+
try {
|
|
178
|
+
const row = await delegate.findFirst({ where: { token } });
|
|
179
|
+
return Boolean(row);
|
|
180
|
+
}
|
|
181
|
+
catch {
|
|
182
|
+
return false;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
110
185
|
async requestPasswordRecovery(email) {
|
|
111
186
|
const user = await this.userDelegate().findFirst({ where: { email } }).catch(() => null);
|
|
112
187
|
if (!user)
|
|
@@ -123,7 +198,7 @@ let AuthService = AuthService_1 = class AuthService {
|
|
|
123
198
|
this.logger.warn(`AuthService: could not persist password reset token (${err.message}). ` +
|
|
124
199
|
'Add a `PasswordResetToken` model to your Prisma schema to enable this feature.');
|
|
125
200
|
}
|
|
126
|
-
return { token };
|
|
201
|
+
return { token, user };
|
|
127
202
|
}
|
|
128
203
|
async resetPassword(email, token, newPassword) {
|
|
129
204
|
let reset = null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.service.js","sourceRoot":"","sources":["../../src/services/auth.service.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,2CAIwB;AACxB,+DAA2D;AAC3D,iDAAmC;AACnC,kDAAoC;AACpC,mCAAqC;AACrC,6DAAyD;AACzD,kDAAqD;AAcrD;;;GAGG;AAEI,IAAM,WAAW,mBAAjB,MAAM,WAAW;IAIH;IACA;IAJF,MAAM,GAAG,IAAI,eAAM,CAAC,aAAW,CAAC,IAAI,CAAC,CAAC;IAEvD,YACmB,MAAqB,EACrB,MAA0B;QAD1B,WAAM,GAAN,MAAM,CAAe;QACrB,WAAM,GAAN,MAAM,CAAoB;IAC1C,CAAC;IAEI,YAAY;QAClB,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC,SAAS,CAAC;QACrD,OAAO,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;IACtC,CAAC;IAED,KAAK,CAAC,YAAY,CAAC,KAAa;QAC9B,OAAO,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IAChC,CAAC;IAED,KAAK,CAAC,aAAa,CAAC,KAAa,EAAE,MAAc;QAC/C,IAAI,CAAC,MAAM;YAAE,OAAO,KAAK,CAAC;QAC1B,OAAO,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;IACvC,CAAC;IAED,SAAS,CAAC,OAAqB;QAC7B,MAAM,EAAE,SAAS,EAAE,YAAY,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC;QAC7D,OAAO,GAAG,CAAC,IAAI,CAAC,OAAO,EAAE,SAAS,EAAE,EAAE,SAAS,EAAE,YAAY,EAAS,CAAC,CAAC;IAC1E,CAAC;IAED,WAAW,CAAC,KAAa;QACvB,MAAM,EAAE,SAAS,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC;QAC/C,IAAI,CAAC;YACH,OAAO,GAAG,CAAC,MAAM,CAAC,KAAK,EAAE,SAAS,CAAiB,CAAC;QACtD,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,gCAAc,CAAC,YAAY,CAAC,0BAA0B,CAAC,CAAC;QAChE,CAAC;IACH,CAAC;IAED,KAAK,CAAC,KAAK,CAAC,KAAa,EAAE,QAAgB;QACzC,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC;QACtC,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,YAAY,EAAE,CAAC,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"auth.service.js","sourceRoot":"","sources":["../../src/services/auth.service.ts"],"names":[],"mappings":"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"}
|
|
@@ -5,6 +5,8 @@ export interface CreateInvitationInput {
|
|
|
5
5
|
roleId: number;
|
|
6
6
|
organization: any;
|
|
7
7
|
invitedBy: any;
|
|
8
|
+
/** The group the invitee will join (design §8). NULL = wildcard membership. */
|
|
9
|
+
routeGroup?: string | null;
|
|
8
10
|
}
|
|
9
11
|
/**
|
|
10
12
|
* Invitation lifecycle: create/resend/cancel/accept with token-based acceptance.
|
|
@@ -16,6 +18,8 @@ export declare class InvitationService {
|
|
|
16
18
|
constructor(prisma: PrismaService, config: RhinoConfigService);
|
|
17
19
|
private delegate;
|
|
18
20
|
private generateToken;
|
|
21
|
+
/** Whether the inviter holds a membership row for `routeGroup` (wildcard ok). */
|
|
22
|
+
private inviterIsMember;
|
|
19
23
|
private expiresAt;
|
|
20
24
|
list(organizationId: number, status?: string): Promise<any>;
|
|
21
25
|
create(input: CreateInvitationInput): Promise<any>;
|
|
@@ -26,10 +30,12 @@ export declare class InvitationService {
|
|
|
26
30
|
organization: any;
|
|
27
31
|
role: any;
|
|
28
32
|
email: any;
|
|
33
|
+
routeGroup: any;
|
|
29
34
|
accepted?: undefined;
|
|
30
35
|
} | {
|
|
31
36
|
accepted: boolean;
|
|
32
37
|
organization: any;
|
|
38
|
+
routeGroup: any;
|
|
33
39
|
requiresRegistration?: undefined;
|
|
34
40
|
role?: undefined;
|
|
35
41
|
email?: undefined;
|
|
@@ -14,6 +14,7 @@ const common_1 = require("@nestjs/common");
|
|
|
14
14
|
const crypto_1 = require("crypto");
|
|
15
15
|
const prisma_service_1 = require("../prisma/prisma.service");
|
|
16
16
|
const rhino_config_1 = require("../rhino.config");
|
|
17
|
+
const rhino_exception_1 = require("../errors/rhino-exception");
|
|
17
18
|
/**
|
|
18
19
|
* Invitation lifecycle: create/resend/cancel/accept with token-based acceptance.
|
|
19
20
|
* Mirrors Laravel's InvitationController + OrganizationInvitation model.
|
|
@@ -31,6 +32,21 @@ let InvitationService = class InvitationService {
|
|
|
31
32
|
generateToken() {
|
|
32
33
|
return (0, crypto_1.randomBytes)(32).toString('hex'); // 64 hex chars
|
|
33
34
|
}
|
|
35
|
+
/** Whether the inviter holds a membership row for `routeGroup` (wildcard ok). */
|
|
36
|
+
inviterIsMember(inviter, routeGroup, org) {
|
|
37
|
+
const rows = inviter?.userRoles ?? inviter?.user_roles ?? [];
|
|
38
|
+
const orgId = org?.id ?? null;
|
|
39
|
+
for (const ur of rows) {
|
|
40
|
+
const rg = ur.routeGroup ?? ur.route_group ?? null;
|
|
41
|
+
if (rg !== null && String(rg) !== routeGroup)
|
|
42
|
+
continue;
|
|
43
|
+
const rowOrg = ur.organizationId ?? ur.organization_id ?? null;
|
|
44
|
+
if (orgId != null && rowOrg != null && rowOrg !== orgId)
|
|
45
|
+
continue;
|
|
46
|
+
return true;
|
|
47
|
+
}
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
34
50
|
expiresAt() {
|
|
35
51
|
const days = this.config.invitationsConfig().expiresDays;
|
|
36
52
|
const d = new Date();
|
|
@@ -51,12 +67,35 @@ let InvitationService = class InvitationService {
|
|
|
51
67
|
throw new common_1.BadRequestException('Role not allowed for invitations');
|
|
52
68
|
}
|
|
53
69
|
}
|
|
70
|
+
const routeGroup = input.routeGroup ?? null;
|
|
71
|
+
// The `public` group has no auth, so it cannot be invited into (design §8).
|
|
72
|
+
if (routeGroup === 'public') {
|
|
73
|
+
throw new common_1.BadRequestException('Cannot invite into the public group');
|
|
74
|
+
}
|
|
75
|
+
// When enforcement is on, the inviter must themselves be a member of the
|
|
76
|
+
// group they are inviting into (design §8). NULL (wildcard) skips this — a
|
|
77
|
+
// wildcard inviter can invite into any group.
|
|
78
|
+
if (this.config.enforceGroupMembership() && routeGroup != null) {
|
|
79
|
+
if (!this.inviterIsMember(input.invitedBy, routeGroup, input.organization)) {
|
|
80
|
+
// Coarse membership denial → 403 for parity with Laravel/Rails
|
|
81
|
+
// (Decision 9.C), matching the controller's gate.
|
|
82
|
+
throw rhino_exception_1.RhinoException.membershipDenied('You are not a member of that group');
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
// Tenant groups carry an org; non-tenant groups store a NULL org. Default
|
|
86
|
+
// to using the org (legacy behavior) — only drop it when enforcement is on
|
|
87
|
+
// AND the group is positively non-tenant, keeping flag-off paths unchanged.
|
|
88
|
+
const dropOrg = this.config.enforceGroupMembership() &&
|
|
89
|
+
routeGroup != null &&
|
|
90
|
+
!this.config.isTenantGroup(routeGroup);
|
|
91
|
+
const organizationId = dropOrg ? null : input.organization?.id ?? null;
|
|
54
92
|
const token = this.generateToken();
|
|
55
93
|
const invitation = await this.delegate().create({
|
|
56
94
|
data: {
|
|
57
|
-
organizationId
|
|
95
|
+
organizationId,
|
|
58
96
|
email: input.email,
|
|
59
97
|
roleId: input.roleId,
|
|
98
|
+
routeGroup,
|
|
60
99
|
token,
|
|
61
100
|
status: 'pending',
|
|
62
101
|
invitedById: input.invitedBy.id,
|
|
@@ -110,6 +149,7 @@ let InvitationService = class InvitationService {
|
|
|
110
149
|
await this.delegate().update({ where: { id: inv.id }, data: { status: 'expired' } });
|
|
111
150
|
throw new common_1.BadRequestException('Invitation expired');
|
|
112
151
|
}
|
|
152
|
+
const routeGroup = inv.routeGroup ?? inv.route_group ?? null;
|
|
113
153
|
if (!userId) {
|
|
114
154
|
// User is unauthenticated — return org/role so client can register
|
|
115
155
|
return {
|
|
@@ -117,13 +157,15 @@ let InvitationService = class InvitationService {
|
|
|
117
157
|
organization: inv.organization,
|
|
118
158
|
role: inv.role,
|
|
119
159
|
email: inv.email,
|
|
160
|
+
routeGroup,
|
|
120
161
|
};
|
|
121
162
|
}
|
|
122
163
|
await this.prisma.model('userRole').create({
|
|
123
164
|
data: {
|
|
124
165
|
userId,
|
|
125
|
-
organizationId: inv.organizationId,
|
|
166
|
+
organizationId: inv.organizationId ?? null,
|
|
126
167
|
roleId: inv.roleId,
|
|
168
|
+
routeGroup,
|
|
127
169
|
permissions: [],
|
|
128
170
|
},
|
|
129
171
|
});
|
|
@@ -131,7 +173,7 @@ let InvitationService = class InvitationService {
|
|
|
131
173
|
where: { id: inv.id },
|
|
132
174
|
data: { status: 'accepted', acceptedAt: new Date() },
|
|
133
175
|
});
|
|
134
|
-
return { accepted: true, organization: inv.organization };
|
|
176
|
+
return { accepted: true, organization: inv.organization, routeGroup };
|
|
135
177
|
}
|
|
136
178
|
};
|
|
137
179
|
exports.InvitationService = InvitationService;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"invitation.service.js","sourceRoot":"","sources":["../../src/services/invitation.service.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,2CAIwB;AACxB,mCAAqC;AACrC,6DAAyD;AACzD,kDAAqD;
|
|
1
|
+
{"version":3,"file":"invitation.service.js","sourceRoot":"","sources":["../../src/services/invitation.service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { RhinoConfigService } from '../rhino.config';
|
|
2
|
+
/**
|
|
3
|
+
* A single `user_roles` membership row, normalized across snake_case /
|
|
4
|
+
* camelCase shapes (Prisma vs raw SQL). `routeGroup === null` is a WILDCARD
|
|
5
|
+
* (Decision 9.B) — the row is a member of every group.
|
|
6
|
+
*/
|
|
7
|
+
export interface MembershipRow {
|
|
8
|
+
routeGroup: string | null;
|
|
9
|
+
organizationId: number | string | null;
|
|
10
|
+
permissions: unknown;
|
|
11
|
+
role?: any;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Membership enforcement & permission resolution (design §6).
|
|
15
|
+
*
|
|
16
|
+
* Gated entirely by `auth.enforceGroupMembership`:
|
|
17
|
+
* - OFF (default): {@link enabled} is `false`; callers skip every check and
|
|
18
|
+
* fall back to the legacy org-presence heuristic. Behavior is unchanged.
|
|
19
|
+
* - ON: a user must hold a `user_roles` row whose `route_group` matches the
|
|
20
|
+
* request's group (a NULL row is a wildcard) and — for tenant groups — whose
|
|
21
|
+
* organization matches the resolved org. Permissions then resolve from that
|
|
22
|
+
* matched row only.
|
|
23
|
+
*
|
|
24
|
+
* Membership is a COARSE gate (may you enter the group); the ResourcePolicy
|
|
25
|
+
* remains the FINE check. They run in sequence and are never merged.
|
|
26
|
+
*/
|
|
27
|
+
export declare class MembershipService {
|
|
28
|
+
private readonly config;
|
|
29
|
+
constructor(config: RhinoConfigService);
|
|
30
|
+
/** Whether membership enforcement is active at all. */
|
|
31
|
+
enabled(): boolean;
|
|
32
|
+
private userRoles;
|
|
33
|
+
/**
|
|
34
|
+
* Find the membership rows that admit `user` into `routeGroup` for the given
|
|
35
|
+
* organization. A row matches when:
|
|
36
|
+
* - its `route_group` is NULL (wildcard) OR equals `routeGroup`, AND
|
|
37
|
+
* - for tenant groups, its organization equals the resolved org's id
|
|
38
|
+
* (NULL-org wildcard rows still match); for non-tenant groups the org is
|
|
39
|
+
* ignored entirely.
|
|
40
|
+
*/
|
|
41
|
+
matchingRows(user: any, routeGroup: string | null | undefined, organization: {
|
|
42
|
+
id: number | string;
|
|
43
|
+
} | null | undefined, isTenant: boolean): MembershipRow[];
|
|
44
|
+
/**
|
|
45
|
+
* Whether `user` is a member of `routeGroup` (for the resolved org, when the
|
|
46
|
+
* group is a tenant group). Only meaningful when {@link enabled}.
|
|
47
|
+
*/
|
|
48
|
+
isMember(user: any, routeGroup: string | null | undefined, organization: {
|
|
49
|
+
id: number | string;
|
|
50
|
+
} | null | undefined, isTenant: boolean): boolean;
|
|
51
|
+
/**
|
|
52
|
+
* Permissions granted to the user from the matched membership rows only
|
|
53
|
+
* (design §6: "permissions then resolve from that matching membership row").
|
|
54
|
+
*/
|
|
55
|
+
permissionsFromRows(rows: MembershipRow[]): string[];
|
|
56
|
+
}
|