@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
|
@@ -0,0 +1,113 @@
|
|
|
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
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.MembershipService = void 0;
|
|
13
|
+
const common_1 = require("@nestjs/common");
|
|
14
|
+
const rhino_config_1 = require("../rhino.config");
|
|
15
|
+
const permission_matcher_1 = require("../utils/permission-matcher");
|
|
16
|
+
function readRouteGroup(ur) {
|
|
17
|
+
const v = ur.routeGroup ?? ur.route_group;
|
|
18
|
+
return v == null ? null : String(v);
|
|
19
|
+
}
|
|
20
|
+
function readOrgId(ur) {
|
|
21
|
+
const v = ur.organizationId ?? ur.organization_id;
|
|
22
|
+
return v == null ? null : v;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Membership enforcement & permission resolution (design §6).
|
|
26
|
+
*
|
|
27
|
+
* Gated entirely by `auth.enforceGroupMembership`:
|
|
28
|
+
* - OFF (default): {@link enabled} is `false`; callers skip every check and
|
|
29
|
+
* fall back to the legacy org-presence heuristic. Behavior is unchanged.
|
|
30
|
+
* - ON: a user must hold a `user_roles` row whose `route_group` matches the
|
|
31
|
+
* request's group (a NULL row is a wildcard) and — for tenant groups — whose
|
|
32
|
+
* organization matches the resolved org. Permissions then resolve from that
|
|
33
|
+
* matched row only.
|
|
34
|
+
*
|
|
35
|
+
* Membership is a COARSE gate (may you enter the group); the ResourcePolicy
|
|
36
|
+
* remains the FINE check. They run in sequence and are never merged.
|
|
37
|
+
*/
|
|
38
|
+
let MembershipService = class MembershipService {
|
|
39
|
+
config;
|
|
40
|
+
constructor(config) {
|
|
41
|
+
this.config = config;
|
|
42
|
+
}
|
|
43
|
+
/** Whether membership enforcement is active at all. */
|
|
44
|
+
enabled() {
|
|
45
|
+
return this.config.enforceGroupMembership();
|
|
46
|
+
}
|
|
47
|
+
userRoles(user) {
|
|
48
|
+
if (!user)
|
|
49
|
+
return [];
|
|
50
|
+
return user.userRoles ?? user.user_roles ?? [];
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Find the membership rows that admit `user` into `routeGroup` for the given
|
|
54
|
+
* organization. A row matches when:
|
|
55
|
+
* - its `route_group` is NULL (wildcard) OR equals `routeGroup`, AND
|
|
56
|
+
* - for tenant groups, its organization equals the resolved org's id
|
|
57
|
+
* (NULL-org wildcard rows still match); for non-tenant groups the org is
|
|
58
|
+
* ignored entirely.
|
|
59
|
+
*/
|
|
60
|
+
matchingRows(user, routeGroup, organization, isTenant) {
|
|
61
|
+
const group = routeGroup == null ? null : String(routeGroup);
|
|
62
|
+
const orgId = organization?.id ?? null;
|
|
63
|
+
const rows = [];
|
|
64
|
+
for (const ur of this.userRoles(user)) {
|
|
65
|
+
const rowGroup = readRouteGroup(ur);
|
|
66
|
+
// route_group gate: NULL row is a wildcard, else must equal the group.
|
|
67
|
+
if (rowGroup !== null && group !== null && rowGroup !== group)
|
|
68
|
+
continue;
|
|
69
|
+
// (a concrete group request with a non-matching concrete row is rejected
|
|
70
|
+
// above; a NULL request — legacy/global — matches any row.)
|
|
71
|
+
const rowOrg = readOrgId(ur);
|
|
72
|
+
if (isTenant && orgId != null) {
|
|
73
|
+
// Tenant group with a resolved org: the row must target that org, or be
|
|
74
|
+
// an org-wildcard (NULL org) row.
|
|
75
|
+
if (rowOrg !== null && rowOrg !== orgId)
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
// Non-tenant group: org is ignored.
|
|
79
|
+
rows.push({
|
|
80
|
+
routeGroup: rowGroup,
|
|
81
|
+
organizationId: rowOrg,
|
|
82
|
+
permissions: ur.permissions,
|
|
83
|
+
role: ur.role,
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
return rows;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Whether `user` is a member of `routeGroup` (for the resolved org, when the
|
|
90
|
+
* group is a tenant group). Only meaningful when {@link enabled}.
|
|
91
|
+
*/
|
|
92
|
+
isMember(user, routeGroup, organization, isTenant) {
|
|
93
|
+
return this.matchingRows(user, routeGroup, organization, isTenant).length > 0;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Permissions granted to the user from the matched membership rows only
|
|
97
|
+
* (design §6: "permissions then resolve from that matching membership row").
|
|
98
|
+
*/
|
|
99
|
+
permissionsFromRows(rows) {
|
|
100
|
+
const out = [];
|
|
101
|
+
for (const r of rows) {
|
|
102
|
+
for (const p of (0, permission_matcher_1.coercePermissions)(r.permissions))
|
|
103
|
+
out.push(p);
|
|
104
|
+
}
|
|
105
|
+
return out;
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
exports.MembershipService = MembershipService;
|
|
109
|
+
exports.MembershipService = MembershipService = __decorate([
|
|
110
|
+
(0, common_1.Injectable)(),
|
|
111
|
+
__metadata("design:paramtypes", [rhino_config_1.RhinoConfigService])
|
|
112
|
+
], MembershipService);
|
|
113
|
+
//# sourceMappingURL=membership.service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"membership.service.js","sourceRoot":"","sources":["../../src/services/membership.service.ts"],"names":[],"mappings":"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"}
|
|
@@ -36,7 +36,14 @@ let OrganizationService = class OrganizationService {
|
|
|
36
36
|
const org = await delegate.findFirst({ where: { [column]: value } });
|
|
37
37
|
if (!org)
|
|
38
38
|
throw new common_1.NotFoundException('Organization not found');
|
|
39
|
-
|
|
39
|
+
// FIX 11.2: when group-membership enforcement is ON, an authenticated
|
|
40
|
+
// non-member must receive 403 from GroupMembershipGuard, which takes
|
|
41
|
+
// precedence over this org-resolution 404. So we DON'T 404 here for a
|
|
42
|
+
// non-member — we resolve & attach the org and let the downstream guard
|
|
43
|
+
// decide (allow vs 403). A genuinely non-existent org still 404s above.
|
|
44
|
+
// When enforcement is OFF (default), behavior is byte-for-byte unchanged:
|
|
45
|
+
// a non-member still gets the info-hiding 404 here.
|
|
46
|
+
if (user && !this.config.enforceGroupMembership()) {
|
|
40
47
|
await this.ensureMembership(user, org);
|
|
41
48
|
}
|
|
42
49
|
return org;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"organization.service.js","sourceRoot":"","sources":["../../src/services/organization.service.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,2CAA+D;AAC/D,6DAAyD;AACzD,kDAAqD;AAErD;;;GAGG;AAEI,IAAM,mBAAmB,GAAzB,MAAM,mBAAmB;IAEX;IACA;IAFnB,YACmB,MAAqB,EACrB,MAA0B;QAD1B,WAAM,GAAN,MAAM,CAAe;QACrB,WAAM,GAAN,MAAM,CAAoB;IAC1C,CAAC;IAEJ,KAAK,CAAC,OAAO,CAAC,UAA2B,EAAE,IAAU;QACnD,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,4BAA4B,EAAE,CAAC;QAC1D,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE,iBAAiB,IAAI,cAAc,CAAC;QACrF,MAAM,KAAK,GACT,MAAM,KAAK,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;YACjD,CAAC,CAAC,MAAM,KAAK,IAAI;gBACf,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC;gBACpB,CAAC,CAAC,UAAU;YACd,CAAC,CAAC,UAAU,CAAC;QAEjB,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;QAC9C,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,EAAE,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC;QACrE,IAAI,CAAC,GAAG;YAAE,MAAM,IAAI,0BAAiB,CAAC,wBAAwB,CAAC,CAAC;QAEhE,IAAI,IAAI,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"organization.service.js","sourceRoot":"","sources":["../../src/services/organization.service.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,2CAA+D;AAC/D,6DAAyD;AACzD,kDAAqD;AAErD;;;GAGG;AAEI,IAAM,mBAAmB,GAAzB,MAAM,mBAAmB;IAEX;IACA;IAFnB,YACmB,MAAqB,EACrB,MAA0B;QAD1B,WAAM,GAAN,MAAM,CAAe;QACrB,WAAM,GAAN,MAAM,CAAoB;IAC1C,CAAC;IAEJ,KAAK,CAAC,OAAO,CAAC,UAA2B,EAAE,IAAU;QACnD,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,4BAA4B,EAAE,CAAC;QAC1D,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE,iBAAiB,IAAI,cAAc,CAAC;QACrF,MAAM,KAAK,GACT,MAAM,KAAK,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;YACjD,CAAC,CAAC,MAAM,KAAK,IAAI;gBACf,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC;gBACpB,CAAC,CAAC,UAAU;YACd,CAAC,CAAC,UAAU,CAAC;QAEjB,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;QAC9C,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,EAAE,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC;QACrE,IAAI,CAAC,GAAG;YAAE,MAAM,IAAI,0BAAiB,CAAC,wBAAwB,CAAC,CAAC;QAEhE,sEAAsE;QACtE,qEAAqE;QACrE,sEAAsE;QACtE,wEAAwE;QACxE,wEAAwE;QACxE,0EAA0E;QAC1E,oDAAoD;QACpD,IAAI,IAAI,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,sBAAsB,EAAE,EAAE,CAAC;YAClD,MAAM,IAAI,CAAC,gBAAgB,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;QACzC,CAAC;QAED,OAAO,GAAG,CAAC;IACb,CAAC;IAED,KAAK,CAAC,gBAAgB,CAAC,IAAS,EAAE,GAAQ;QACxC,MAAM,YAAY,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE,qBAAqB,IAAI,UAAU,CAAC;QACxF,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;QACjD,MAAM,UAAU,GAAG,MAAM,QAAQ,CAAC,SAAS,CAAC;YAC1C,KAAK,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,EAAE,cAAc,EAAE,GAAG,CAAC,EAAE,EAAE;SACnD,CAAC,CAAC;QACH,IAAI,CAAC,UAAU;YAAE,MAAM,IAAI,0BAAiB,CAAC,wBAAwB,CAAC,CAAC;IACzE,CAAC;CACF,CAAA;AA1CY,kDAAmB;8BAAnB,mBAAmB;IAD/B,IAAA,mBAAU,GAAE;qCAGgB,8BAAa;QACb,iCAAkB;GAHlC,mBAAmB,CA0C/B"}
|
|
@@ -43,6 +43,7 @@ function describeRoutes(config) {
|
|
|
43
43
|
group: name,
|
|
44
44
|
slug,
|
|
45
45
|
prefix: group.prefix ?? '',
|
|
46
|
+
domain: group.domain ?? null,
|
|
46
47
|
model: reg.model,
|
|
47
48
|
softDeletes: !!reg.softDeletes,
|
|
48
49
|
hasAuditTrail: !!reg.hasAuditTrail,
|
|
@@ -56,6 +57,7 @@ function describeRoutes(config) {
|
|
|
56
57
|
group: '(default)',
|
|
57
58
|
slug,
|
|
58
59
|
prefix: '',
|
|
60
|
+
domain: null,
|
|
59
61
|
model: reg.model,
|
|
60
62
|
softDeletes: !!reg.softDeletes,
|
|
61
63
|
hasAuditTrail: !!reg.hasAuditTrail,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"route-registration.service.js","sourceRoot":"","sources":["../../src/services/route-registration.service.ts"],"names":[],"mappings":";;AA0BA,8CAOC;AAKD,
|
|
1
|
+
{"version":3,"file":"route-registration.service.js","sourceRoot":"","sources":["../../src/services/route-registration.service.ts"],"names":[],"mappings":";;AA0BA,8CAOC;AAKD,wCAgDC;AA5ED;;;;;;;;;;;;;;;GAeG;AACH,SAAgB,iBAAiB,CAC/B,GAAqB,EACrB,UAAiC,EAAE;IAEnC,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,KAAK,CAAC;IACvC,GAAG,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC;IAC5B,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,OAAO,CAAC,UAAU,IAAI,IAAI,EAAE,CAAC;AAC5D,CAAC;AAED;;GAEG;AACH,SAAgB,cAAc,CAAC,MAA0B;IAUvD,MAAM,MAAM,GAAU,EAAE,CAAC;IACzB,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC;IAC/B,MAAM,MAAM,GAAG,MAAM,CAAC,WAAW,EAAE,CAAC;IACpC,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACvC,MAAM,QAAQ,GAAG,UAAU,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IACzE,KAAK,MAAM,IAAI,IAAI,UAAU,EAAE,CAAC;QAC9B,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC;QAC3B,MAAM,QAAQ,GAAG,KAAK,CAAC,MAAM,KAAK,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC;QAC3E,KAAK,MAAM,IAAI,IAAI,QAAQ,EAAE,CAAC;YAC5B,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC;YACzB,IAAI,CAAC,GAAG;gBAAE,SAAS;YACnB,MAAM,CAAC,IAAI,CAAC;gBACV,KAAK,EAAE,IAAI;gBACX,IAAI;gBACJ,MAAM,EAAE,KAAK,CAAC,MAAM,IAAI,EAAE;gBAC1B,MAAM,EAAE,KAAK,CAAC,MAAM,IAAI,IAAI;gBAC5B,KAAK,EAAE,GAAG,CAAC,KAAK;gBAChB,WAAW,EAAE,CAAC,CAAC,GAAG,CAAC,WAAW;gBAC9B,aAAa,EAAE,CAAC,CAAC,GAAG,CAAC,aAAa;gBAClC,aAAa,EAAE,GAAG,CAAC,aAAa,IAAI,EAAE;aACvC,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IACD,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACxB,KAAK,MAAM,CAAC,IAAI,EAAE,GAAG,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;YACjD,MAAM,CAAC,IAAI,CAAC;gBACV,KAAK,EAAE,WAAW;gBAClB,IAAI;gBACJ,MAAM,EAAE,EAAE;gBACV,MAAM,EAAE,IAAI;gBACZ,KAAK,EAAE,GAAG,CAAC,KAAK;gBAChB,WAAW,EAAE,CAAC,CAAC,GAAG,CAAC,WAAW;gBAC9B,aAAa,EAAE,CAAC,CAAC,GAAG,CAAC,aAAa;gBAClC,aAAa,EAAE,GAAG,CAAC,aAAa,IAAI,EAAE;aACvC,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC"}
|