@spinajs/rbac-http-token 2.0.507

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.
Files changed (198) hide show
  1. package/README.md +152 -0
  2. package/lib/cjs/actions.d.ts +119 -0
  3. package/lib/cjs/actions.d.ts.map +1 -0
  4. package/lib/cjs/actions.js +257 -0
  5. package/lib/cjs/actions.js.map +1 -0
  6. package/lib/cjs/cli/CreateToken.d.ts +13 -0
  7. package/lib/cjs/cli/CreateToken.d.ts.map +1 -0
  8. package/lib/cjs/cli/CreateToken.js +56 -0
  9. package/lib/cjs/cli/CreateToken.js.map +1 -0
  10. package/lib/cjs/cli/DeleteExpiredTokens.d.ts +11 -0
  11. package/lib/cjs/cli/DeleteExpiredTokens.d.ts.map +1 -0
  12. package/lib/cjs/cli/DeleteExpiredTokens.js +39 -0
  13. package/lib/cjs/cli/DeleteExpiredTokens.js.map +1 -0
  14. package/lib/cjs/cli/DeleteToken.d.ts +7 -0
  15. package/lib/cjs/cli/DeleteToken.d.ts.map +1 -0
  16. package/lib/cjs/cli/DeleteToken.js +36 -0
  17. package/lib/cjs/cli/DeleteToken.js.map +1 -0
  18. package/lib/cjs/cli/GrantTokenRole.d.ts +7 -0
  19. package/lib/cjs/cli/GrantTokenRole.d.ts.map +1 -0
  20. package/lib/cjs/cli/GrantTokenRole.js +37 -0
  21. package/lib/cjs/cli/GrantTokenRole.js.map +1 -0
  22. package/lib/cjs/cli/RevokeTokenRole.d.ts +12 -0
  23. package/lib/cjs/cli/RevokeTokenRole.d.ts.map +1 -0
  24. package/lib/cjs/cli/RevokeTokenRole.js +42 -0
  25. package/lib/cjs/cli/RevokeTokenRole.js.map +1 -0
  26. package/lib/cjs/config/rbac-http-token.d.ts +71 -0
  27. package/lib/cjs/config/rbac-http-token.d.ts.map +1 -0
  28. package/lib/cjs/config/rbac-http-token.js +98 -0
  29. package/lib/cjs/config/rbac-http-token.js.map +1 -0
  30. package/lib/cjs/controllers/AccessTokenController.d.ts +139 -0
  31. package/lib/cjs/controllers/AccessTokenController.d.ts.map +1 -0
  32. package/lib/cjs/controllers/AccessTokenController.js +264 -0
  33. package/lib/cjs/controllers/AccessTokenController.js.map +1 -0
  34. package/lib/cjs/dto/create-token-dto.d.ts +34 -0
  35. package/lib/cjs/dto/create-token-dto.d.ts.map +1 -0
  36. package/lib/cjs/dto/create-token-dto.js +35 -0
  37. package/lib/cjs/dto/create-token-dto.js.map +1 -0
  38. package/lib/cjs/events/AccessTokenCreated.d.ts +4 -0
  39. package/lib/cjs/events/AccessTokenCreated.d.ts.map +1 -0
  40. package/lib/cjs/events/AccessTokenCreated.js +18 -0
  41. package/lib/cjs/events/AccessTokenCreated.js.map +1 -0
  42. package/lib/cjs/events/AccessTokenDeleted.d.ts +4 -0
  43. package/lib/cjs/events/AccessTokenDeleted.d.ts.map +1 -0
  44. package/lib/cjs/events/AccessTokenDeleted.js +18 -0
  45. package/lib/cjs/events/AccessTokenDeleted.js.map +1 -0
  46. package/lib/cjs/events/AccessTokenEvent.d.ts +10 -0
  47. package/lib/cjs/events/AccessTokenEvent.d.ts.map +1 -0
  48. package/lib/cjs/events/AccessTokenEvent.js +26 -0
  49. package/lib/cjs/events/AccessTokenEvent.js.map +1 -0
  50. package/lib/cjs/events/AccessTokenRoleGranted.d.ts +7 -0
  51. package/lib/cjs/events/AccessTokenRoleGranted.d.ts.map +1 -0
  52. package/lib/cjs/events/AccessTokenRoleGranted.js +27 -0
  53. package/lib/cjs/events/AccessTokenRoleGranted.js.map +1 -0
  54. package/lib/cjs/events/AccessTokenRoleRevoked.d.ts +7 -0
  55. package/lib/cjs/events/AccessTokenRoleRevoked.d.ts.map +1 -0
  56. package/lib/cjs/events/AccessTokenRoleRevoked.js +27 -0
  57. package/lib/cjs/events/AccessTokenRoleRevoked.js.map +1 -0
  58. package/lib/cjs/events/index.d.ts +6 -0
  59. package/lib/cjs/events/index.d.ts.map +1 -0
  60. package/lib/cjs/events/index.js +22 -0
  61. package/lib/cjs/events/index.js.map +1 -0
  62. package/lib/cjs/generator.d.ts +12 -0
  63. package/lib/cjs/generator.d.ts.map +1 -0
  64. package/lib/cjs/generator.js +42 -0
  65. package/lib/cjs/generator.js.map +1 -0
  66. package/lib/cjs/index.d.ts +20 -0
  67. package/lib/cjs/index.d.ts.map +1 -0
  68. package/lib/cjs/index.js +39 -0
  69. package/lib/cjs/index.js.map +1 -0
  70. package/lib/cjs/interfaces.d.ts +57 -0
  71. package/lib/cjs/interfaces.d.ts.map +1 -0
  72. package/lib/cjs/interfaces.js +11 -0
  73. package/lib/cjs/interfaces.js.map +1 -0
  74. package/lib/cjs/middlewares.d.ts +76 -0
  75. package/lib/cjs/middlewares.d.ts.map +1 -0
  76. package/lib/cjs/middlewares.js +181 -0
  77. package/lib/cjs/middlewares.js.map +1 -0
  78. package/lib/cjs/migrations/RbacHttpTokenInitial_2026_08_11_01_00_00.d.ts +6 -0
  79. package/lib/cjs/migrations/RbacHttpTokenInitial_2026_08_11_01_00_00.d.ts.map +1 -0
  80. package/lib/cjs/migrations/RbacHttpTokenInitial_2026_08_11_01_00_00.js +38 -0
  81. package/lib/cjs/migrations/RbacHttpTokenInitial_2026_08_11_01_00_00.js.map +1 -0
  82. package/lib/cjs/models/AccessToken.d.ts +55 -0
  83. package/lib/cjs/models/AccessToken.d.ts.map +1 -0
  84. package/lib/cjs/models/AccessToken.js +73 -0
  85. package/lib/cjs/models/AccessToken.js.map +1 -0
  86. package/lib/cjs/package.json +1 -0
  87. package/lib/cjs/policies/NoImpersonationPolicy.d.ts +28 -0
  88. package/lib/cjs/policies/NoImpersonationPolicy.d.ts.map +1 -0
  89. package/lib/cjs/policies/NoImpersonationPolicy.js +45 -0
  90. package/lib/cjs/policies/NoImpersonationPolicy.js.map +1 -0
  91. package/lib/cjs/policies/NoTokenAuthPolicy.d.ts +12 -0
  92. package/lib/cjs/policies/NoTokenAuthPolicy.d.ts.map +1 -0
  93. package/lib/cjs/policies/NoTokenAuthPolicy.js +24 -0
  94. package/lib/cjs/policies/NoTokenAuthPolicy.js.map +1 -0
  95. package/lib/cjs/policies/TokenPolicy.d.ts +49 -0
  96. package/lib/cjs/policies/TokenPolicy.d.ts.map +1 -0
  97. package/lib/cjs/policies/TokenPolicy.js +79 -0
  98. package/lib/cjs/policies/TokenPolicy.js.map +1 -0
  99. package/lib/mjs/actions.d.ts +119 -0
  100. package/lib/mjs/actions.d.ts.map +1 -0
  101. package/lib/mjs/actions.js +242 -0
  102. package/lib/mjs/actions.js.map +1 -0
  103. package/lib/mjs/cli/CreateToken.d.ts +13 -0
  104. package/lib/mjs/cli/CreateToken.d.ts.map +1 -0
  105. package/lib/mjs/cli/CreateToken.js +53 -0
  106. package/lib/mjs/cli/CreateToken.js.map +1 -0
  107. package/lib/mjs/cli/DeleteExpiredTokens.d.ts +11 -0
  108. package/lib/mjs/cli/DeleteExpiredTokens.d.ts.map +1 -0
  109. package/lib/mjs/cli/DeleteExpiredTokens.js +36 -0
  110. package/lib/mjs/cli/DeleteExpiredTokens.js.map +1 -0
  111. package/lib/mjs/cli/DeleteToken.d.ts +7 -0
  112. package/lib/mjs/cli/DeleteToken.d.ts.map +1 -0
  113. package/lib/mjs/cli/DeleteToken.js +33 -0
  114. package/lib/mjs/cli/DeleteToken.js.map +1 -0
  115. package/lib/mjs/cli/GrantTokenRole.d.ts +7 -0
  116. package/lib/mjs/cli/GrantTokenRole.d.ts.map +1 -0
  117. package/lib/mjs/cli/GrantTokenRole.js +34 -0
  118. package/lib/mjs/cli/GrantTokenRole.js.map +1 -0
  119. package/lib/mjs/cli/RevokeTokenRole.d.ts +12 -0
  120. package/lib/mjs/cli/RevokeTokenRole.d.ts.map +1 -0
  121. package/lib/mjs/cli/RevokeTokenRole.js +39 -0
  122. package/lib/mjs/cli/RevokeTokenRole.js.map +1 -0
  123. package/lib/mjs/config/rbac-http-token.d.ts +71 -0
  124. package/lib/mjs/config/rbac-http-token.d.ts.map +1 -0
  125. package/lib/mjs/config/rbac-http-token.js +96 -0
  126. package/lib/mjs/config/rbac-http-token.js.map +1 -0
  127. package/lib/mjs/controllers/AccessTokenController.d.ts +139 -0
  128. package/lib/mjs/controllers/AccessTokenController.d.ts.map +1 -0
  129. package/lib/mjs/controllers/AccessTokenController.js +261 -0
  130. package/lib/mjs/controllers/AccessTokenController.js.map +1 -0
  131. package/lib/mjs/dto/create-token-dto.d.ts +34 -0
  132. package/lib/mjs/dto/create-token-dto.d.ts.map +1 -0
  133. package/lib/mjs/dto/create-token-dto.js +32 -0
  134. package/lib/mjs/dto/create-token-dto.js.map +1 -0
  135. package/lib/mjs/events/AccessTokenCreated.d.ts +4 -0
  136. package/lib/mjs/events/AccessTokenCreated.d.ts.map +1 -0
  137. package/lib/mjs/events/AccessTokenCreated.js +15 -0
  138. package/lib/mjs/events/AccessTokenCreated.js.map +1 -0
  139. package/lib/mjs/events/AccessTokenDeleted.d.ts +4 -0
  140. package/lib/mjs/events/AccessTokenDeleted.d.ts.map +1 -0
  141. package/lib/mjs/events/AccessTokenDeleted.js +15 -0
  142. package/lib/mjs/events/AccessTokenDeleted.js.map +1 -0
  143. package/lib/mjs/events/AccessTokenEvent.d.ts +10 -0
  144. package/lib/mjs/events/AccessTokenEvent.d.ts.map +1 -0
  145. package/lib/mjs/events/AccessTokenEvent.js +23 -0
  146. package/lib/mjs/events/AccessTokenEvent.js.map +1 -0
  147. package/lib/mjs/events/AccessTokenRoleGranted.d.ts +7 -0
  148. package/lib/mjs/events/AccessTokenRoleGranted.d.ts.map +1 -0
  149. package/lib/mjs/events/AccessTokenRoleGranted.js +24 -0
  150. package/lib/mjs/events/AccessTokenRoleGranted.js.map +1 -0
  151. package/lib/mjs/events/AccessTokenRoleRevoked.d.ts +7 -0
  152. package/lib/mjs/events/AccessTokenRoleRevoked.d.ts.map +1 -0
  153. package/lib/mjs/events/AccessTokenRoleRevoked.js +24 -0
  154. package/lib/mjs/events/AccessTokenRoleRevoked.js.map +1 -0
  155. package/lib/mjs/events/index.d.ts +6 -0
  156. package/lib/mjs/events/index.d.ts.map +1 -0
  157. package/lib/mjs/events/index.js +6 -0
  158. package/lib/mjs/events/index.js.map +1 -0
  159. package/lib/mjs/generator.d.ts +12 -0
  160. package/lib/mjs/generator.d.ts.map +1 -0
  161. package/lib/mjs/generator.js +39 -0
  162. package/lib/mjs/generator.js.map +1 -0
  163. package/lib/mjs/index.d.ts +20 -0
  164. package/lib/mjs/index.d.ts.map +1 -0
  165. package/lib/mjs/index.js +23 -0
  166. package/lib/mjs/index.js.map +1 -0
  167. package/lib/mjs/interfaces.d.ts +57 -0
  168. package/lib/mjs/interfaces.d.ts.map +1 -0
  169. package/lib/mjs/interfaces.js +7 -0
  170. package/lib/mjs/interfaces.js.map +1 -0
  171. package/lib/mjs/middlewares.d.ts +76 -0
  172. package/lib/mjs/middlewares.d.ts.map +1 -0
  173. package/lib/mjs/middlewares.js +178 -0
  174. package/lib/mjs/middlewares.js.map +1 -0
  175. package/lib/mjs/migrations/RbacHttpTokenInitial_2026_08_11_01_00_00.d.ts +6 -0
  176. package/lib/mjs/migrations/RbacHttpTokenInitial_2026_08_11_01_00_00.d.ts.map +1 -0
  177. package/lib/mjs/migrations/RbacHttpTokenInitial_2026_08_11_01_00_00.js +35 -0
  178. package/lib/mjs/migrations/RbacHttpTokenInitial_2026_08_11_01_00_00.js.map +1 -0
  179. package/lib/mjs/models/AccessToken.d.ts +55 -0
  180. package/lib/mjs/models/AccessToken.d.ts.map +1 -0
  181. package/lib/mjs/models/AccessToken.js +70 -0
  182. package/lib/mjs/models/AccessToken.js.map +1 -0
  183. package/lib/mjs/package.json +1 -0
  184. package/lib/mjs/policies/NoImpersonationPolicy.d.ts +28 -0
  185. package/lib/mjs/policies/NoImpersonationPolicy.d.ts.map +1 -0
  186. package/lib/mjs/policies/NoImpersonationPolicy.js +41 -0
  187. package/lib/mjs/policies/NoImpersonationPolicy.js.map +1 -0
  188. package/lib/mjs/policies/NoTokenAuthPolicy.d.ts +12 -0
  189. package/lib/mjs/policies/NoTokenAuthPolicy.d.ts.map +1 -0
  190. package/lib/mjs/policies/NoTokenAuthPolicy.js +20 -0
  191. package/lib/mjs/policies/NoTokenAuthPolicy.js.map +1 -0
  192. package/lib/mjs/policies/TokenPolicy.d.ts +49 -0
  193. package/lib/mjs/policies/TokenPolicy.d.ts.map +1 -0
  194. package/lib/mjs/policies/TokenPolicy.js +75 -0
  195. package/lib/mjs/policies/TokenPolicy.js.map +1 -0
  196. package/lib/tsconfig.cjs.tsbuildinfo +1 -0
  197. package/lib/tsconfig.mjs.tsbuildinfo +1 -0
  198. package/package.json +78 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AccessTokenDeleted.js","sourceRoot":"","sources":["../../../src/events/AccessTokenDeleted.ts"],"names":[],"mappings":";;;;;;AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AACvC,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAGlD,IAAM,kBAAkB,GAAxB,MAAM,kBAAmB,SAAQ,gBAAgB;CAAG,CAAA;AAA9C,kBAAkB;IAD9B,KAAK,EAAE;GACK,kBAAkB,CAA4B"}
@@ -0,0 +1,10 @@
1
+ import { QueueEvent } from '@spinajs/queue';
2
+ import { AccessToken } from '../models/AccessToken.js';
3
+ export declare class AccessTokenEvent extends QueueEvent {
4
+ /**
5
+ * Public token identifier. Never the token material.
6
+ */
7
+ TokenUuid: string;
8
+ constructor(token: AccessToken);
9
+ }
10
+ //# sourceMappingURL=AccessTokenEvent.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AccessTokenEvent.d.ts","sourceRoot":"","sources":["../../../src/events/AccessTokenEvent.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAS,MAAM,gBAAgB,CAAC;AACnD,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAEvD,qBACa,gBAAiB,SAAQ,UAAU;IAC9C;;OAEG;IACI,SAAS,EAAE,MAAM,CAAC;IAEzB,YAAY,KAAK,EAAE,WAAW,EAG7B;CACF"}
@@ -0,0 +1,23 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ 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;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ var __metadata = (this && this.__metadata) || function (k, v) {
8
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
+ };
10
+ import { QueueEvent, Event } from '@spinajs/queue';
11
+ import { AccessToken } from '../models/AccessToken.js';
12
+ let AccessTokenEvent = class AccessTokenEvent extends QueueEvent {
13
+ constructor(token) {
14
+ super();
15
+ this.TokenUuid = token.Uuid;
16
+ }
17
+ };
18
+ AccessTokenEvent = __decorate([
19
+ Event(),
20
+ __metadata("design:paramtypes", [AccessToken])
21
+ ], AccessTokenEvent);
22
+ export { AccessTokenEvent };
23
+ //# sourceMappingURL=AccessTokenEvent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AccessTokenEvent.js","sourceRoot":"","sources":["../../../src/events/AccessTokenEvent.ts"],"names":[],"mappings":";;;;;;;;;AAAA,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AACnD,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAGhD,IAAM,gBAAgB,GAAtB,MAAM,gBAAiB,SAAQ,UAAU;IAM9C,YAAY,KAAkB;QAC5B,KAAK,EAAE,CAAC;QACR,IAAI,CAAC,SAAS,GAAG,KAAK,CAAC,IAAI,CAAC;IAC9B,CAAC;CACF,CAAA;AAVY,gBAAgB;IAD5B,KAAK,EAAE;qCAOa,WAAW;GANnB,gBAAgB,CAU5B"}
@@ -0,0 +1,7 @@
1
+ import { AccessToken } from '../models/AccessToken.js';
2
+ import { AccessTokenEvent } from './AccessTokenEvent.js';
3
+ export declare class AccessTokenRoleGranted extends AccessTokenEvent {
4
+ Role: string;
5
+ constructor(token: AccessToken, Role: string);
6
+ }
7
+ //# sourceMappingURL=AccessTokenRoleGranted.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AccessTokenRoleGranted.d.ts","sourceRoot":"","sources":["../../../src/events/AccessTokenRoleGranted.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAEzD,qBACa,sBAAuB,SAAQ,gBAAgB;IACnB,IAAI,EAAE,MAAM;IAAnD,YAAY,KAAK,EAAE,WAAW,EAAS,IAAI,EAAE,MAAM,EAElD;CACF"}
@@ -0,0 +1,24 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ 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;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ var __metadata = (this && this.__metadata) || function (k, v) {
8
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
+ };
10
+ import { Event } from '@spinajs/queue';
11
+ import { AccessToken } from '../models/AccessToken.js';
12
+ import { AccessTokenEvent } from './AccessTokenEvent.js';
13
+ let AccessTokenRoleGranted = class AccessTokenRoleGranted extends AccessTokenEvent {
14
+ constructor(token, Role) {
15
+ super(token);
16
+ this.Role = Role;
17
+ }
18
+ };
19
+ AccessTokenRoleGranted = __decorate([
20
+ Event(),
21
+ __metadata("design:paramtypes", [AccessToken, String])
22
+ ], AccessTokenRoleGranted);
23
+ export { AccessTokenRoleGranted };
24
+ //# sourceMappingURL=AccessTokenRoleGranted.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AccessTokenRoleGranted.js","sourceRoot":"","sources":["../../../src/events/AccessTokenRoleGranted.ts"],"names":[],"mappings":";;;;;;;;;AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AACvC,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAGlD,IAAM,sBAAsB,GAA5B,MAAM,sBAAuB,SAAQ,gBAAgB;IAC1D,YAAY,KAAkB,EAAS,IAAY;QACjD,KAAK,CAAC,KAAK,CAAC,CAAC;oBADwB,IAAI;IAE3C,CAAC;CACF,CAAA;AAJY,sBAAsB;IADlC,KAAK,EAAE;qCAEa,WAAW;GADnB,sBAAsB,CAIlC"}
@@ -0,0 +1,7 @@
1
+ import { AccessToken } from '../models/AccessToken.js';
2
+ import { AccessTokenEvent } from './AccessTokenEvent.js';
3
+ export declare class AccessTokenRoleRevoked extends AccessTokenEvent {
4
+ Role: string;
5
+ constructor(token: AccessToken, Role: string);
6
+ }
7
+ //# sourceMappingURL=AccessTokenRoleRevoked.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AccessTokenRoleRevoked.d.ts","sourceRoot":"","sources":["../../../src/events/AccessTokenRoleRevoked.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAEzD,qBACa,sBAAuB,SAAQ,gBAAgB;IACnB,IAAI,EAAE,MAAM;IAAnD,YAAY,KAAK,EAAE,WAAW,EAAS,IAAI,EAAE,MAAM,EAElD;CACF"}
@@ -0,0 +1,24 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ 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;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ var __metadata = (this && this.__metadata) || function (k, v) {
8
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
+ };
10
+ import { Event } from '@spinajs/queue';
11
+ import { AccessToken } from '../models/AccessToken.js';
12
+ import { AccessTokenEvent } from './AccessTokenEvent.js';
13
+ let AccessTokenRoleRevoked = class AccessTokenRoleRevoked extends AccessTokenEvent {
14
+ constructor(token, Role) {
15
+ super(token);
16
+ this.Role = Role;
17
+ }
18
+ };
19
+ AccessTokenRoleRevoked = __decorate([
20
+ Event(),
21
+ __metadata("design:paramtypes", [AccessToken, String])
22
+ ], AccessTokenRoleRevoked);
23
+ export { AccessTokenRoleRevoked };
24
+ //# sourceMappingURL=AccessTokenRoleRevoked.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AccessTokenRoleRevoked.js","sourceRoot":"","sources":["../../../src/events/AccessTokenRoleRevoked.ts"],"names":[],"mappings":";;;;;;;;;AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AACvC,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAGlD,IAAM,sBAAsB,GAA5B,MAAM,sBAAuB,SAAQ,gBAAgB;IAC1D,YAAY,KAAkB,EAAS,IAAY;QACjD,KAAK,CAAC,KAAK,CAAC,CAAC;oBADwB,IAAI;IAE3C,CAAC;CACF,CAAA;AAJY,sBAAsB;IADlC,KAAK,EAAE;qCAEa,WAAW;GADnB,sBAAsB,CAIlC"}
@@ -0,0 +1,6 @@
1
+ export * from './AccessTokenEvent.js';
2
+ export * from './AccessTokenCreated.js';
3
+ export * from './AccessTokenDeleted.js';
4
+ export * from './AccessTokenRoleGranted.js';
5
+ export * from './AccessTokenRoleRevoked.js';
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/events/index.ts"],"names":[],"mappings":"AAAA,cAAc,uBAAuB,CAAC;AACtC,cAAc,yBAAyB,CAAC;AACxC,cAAc,yBAAyB,CAAC;AACxC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,6BAA6B,CAAC"}
@@ -0,0 +1,6 @@
1
+ export * from './AccessTokenEvent.js';
2
+ export * from './AccessTokenCreated.js';
3
+ export * from './AccessTokenDeleted.js';
4
+ export * from './AccessTokenRoleGranted.js';
5
+ export * from './AccessTokenRoleRevoked.js';
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/events/index.ts"],"names":[],"mappings":"AAAA,cAAc,uBAAuB,CAAC;AACtC,cAAc,yBAAyB,CAAC;AACxC,cAAc,yBAAyB,CAAC;AACxC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,6BAA6B,CAAC"}
@@ -0,0 +1,12 @@
1
+ import { AccessTokenGenerationProvider, IGeneratedToken } from './interfaces.js';
2
+ /**
3
+ * Default token algorithm: `<prefix>` + N crypto-random bytes base64url encoded.
4
+ * The stable prefix makes leaked tokens findable by secret scanners.
5
+ */
6
+ export declare class SecureRandomTokenProvider extends AccessTokenGenerationProvider {
7
+ protected Prefix: string;
8
+ protected Length: number;
9
+ generate(): Promise<IGeneratedToken>;
10
+ hash(plaintext: string): string;
11
+ }
12
+ //# sourceMappingURL=generator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generator.d.ts","sourceRoot":"","sources":["../../src/generator.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,6BAA6B,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAEjF;;;GAGG;AACH,qBACa,yBAA0B,SAAQ,6BAA6B;IAE1E,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC;IAGzB,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC;IAEZ,QAAQ,IAAI,OAAO,CAAC,eAAe,CAAC,CAGhD;IAEM,IAAI,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAErC;CACF"}
@@ -0,0 +1,39 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ 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;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ var __metadata = (this && this.__metadata) || function (k, v) {
8
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
+ };
10
+ import { randomBytes, createHash } from 'crypto';
11
+ import { Injectable } from '@spinajs/di';
12
+ import { Config } from '@spinajs/configuration';
13
+ import { AccessTokenGenerationProvider } from './interfaces.js';
14
+ /**
15
+ * Default token algorithm: `<prefix>` + N crypto-random bytes base64url encoded.
16
+ * The stable prefix makes leaked tokens findable by secret scanners.
17
+ */
18
+ let SecureRandomTokenProvider = class SecureRandomTokenProvider extends AccessTokenGenerationProvider {
19
+ async generate() {
20
+ const plaintext = `${this.Prefix}${randomBytes(this.Length).toString('base64url')}`;
21
+ return { Plaintext: plaintext, Hash: this.hash(plaintext) };
22
+ }
23
+ hash(plaintext) {
24
+ return createHash('sha256').update(plaintext).digest('hex');
25
+ }
26
+ };
27
+ __decorate([
28
+ Config('rbac.token.prefix', { defaultValue: 'spt_' }),
29
+ __metadata("design:type", String)
30
+ ], SecureRandomTokenProvider.prototype, "Prefix", void 0);
31
+ __decorate([
32
+ Config('rbac.token.length', { defaultValue: 32 }),
33
+ __metadata("design:type", Number)
34
+ ], SecureRandomTokenProvider.prototype, "Length", void 0);
35
+ SecureRandomTokenProvider = __decorate([
36
+ Injectable(AccessTokenGenerationProvider)
37
+ ], SecureRandomTokenProvider);
38
+ export { SecureRandomTokenProvider };
39
+ //# sourceMappingURL=generator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generator.js","sourceRoot":"","sources":["../../src/generator.ts"],"names":[],"mappings":";;;;;;;;;AAAA,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AACjD,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAEhD,OAAO,EAAE,6BAA6B,EAAmB,MAAM,iBAAiB,CAAC;AAEjF;;;GAGG;AAEI,IAAM,yBAAyB,GAA/B,MAAM,yBAA0B,SAAQ,6BAA6B;IAOnE,KAAK,CAAC,QAAQ;QACnB,MAAM,SAAS,GAAG,GAAG,IAAI,CAAC,MAAM,GAAG,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC;QACpF,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC;IAC9D,CAAC;IAEM,IAAI,CAAC,SAAiB;QAC3B,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAC9D,CAAC;CACF,CAAA;AAbW;IADT,MAAM,CAAC,mBAAmB,EAAE,EAAE,YAAY,EAAE,MAAM,EAAE,CAAC;;yDAC7B;AAGf;IADT,MAAM,CAAC,mBAAmB,EAAE,EAAE,YAAY,EAAE,EAAE,EAAE,CAAC;;yDACzB;AALd,yBAAyB;IADrC,UAAU,CAAC,6BAA6B,CAAC;GAC7B,yBAAyB,CAerC"}
@@ -0,0 +1,20 @@
1
+ import './generator.js';
2
+ import './middlewares.js';
3
+ export * from './interfaces.js';
4
+ export * from './models/AccessToken.js';
5
+ export * from './migrations/RbacHttpTokenInitial_2026_08_11_01_00_00.js';
6
+ export * from './generator.js';
7
+ export * from './events/index.js';
8
+ export * from './actions.js';
9
+ export * from './middlewares.js';
10
+ export * from './policies/TokenPolicy.js';
11
+ export * from './policies/NoTokenAuthPolicy.js';
12
+ export * from './policies/NoImpersonationPolicy.js';
13
+ export * from './controllers/AccessTokenController.js';
14
+ export * from './dto/create-token-dto.js';
15
+ export * from './cli/CreateToken.js';
16
+ export * from './cli/DeleteToken.js';
17
+ export * from './cli/GrantTokenRole.js';
18
+ export * from './cli/RevokeTokenRole.js';
19
+ export * from './cli/DeleteExpiredTokens.js';
20
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAGA,OAAO,gBAAgB,CAAC;AACxB,OAAO,kBAAkB,CAAC;AAE1B,cAAc,iBAAiB,CAAC;AAChC,cAAc,yBAAyB,CAAC;AACxC,cAAc,0DAA0D,CAAC;AACzE,cAAc,gBAAgB,CAAC;AAC/B,cAAc,mBAAmB,CAAC;AAClC,cAAc,cAAc,CAAC;AAC7B,cAAc,kBAAkB,CAAC;AACjC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,iCAAiC,CAAC;AAChD,cAAc,qCAAqC,CAAC;AACpD,cAAc,wCAAwC,CAAC;AACvD,cAAc,2BAA2B,CAAC;AAC1C,cAAc,sBAAsB,CAAC;AACrC,cAAc,sBAAsB,CAAC;AACrC,cAAc,yBAAyB,CAAC;AACxC,cAAc,0BAA0B,CAAC;AACzC,cAAc,8BAA8B,CAAC"}
@@ -0,0 +1,23 @@
1
+ // Side effect imports - these modules register Injectables ( the token
2
+ // generator and the token authorization middleware ) the moment they are
3
+ // loaded, so they must run even if a consumer imports nothing from them.
4
+ import './generator.js';
5
+ import './middlewares.js';
6
+ export * from './interfaces.js';
7
+ export * from './models/AccessToken.js';
8
+ export * from './migrations/RbacHttpTokenInitial_2026_08_11_01_00_00.js';
9
+ export * from './generator.js';
10
+ export * from './events/index.js';
11
+ export * from './actions.js';
12
+ export * from './middlewares.js';
13
+ export * from './policies/TokenPolicy.js';
14
+ export * from './policies/NoTokenAuthPolicy.js';
15
+ export * from './policies/NoImpersonationPolicy.js';
16
+ export * from './controllers/AccessTokenController.js';
17
+ export * from './dto/create-token-dto.js';
18
+ export * from './cli/CreateToken.js';
19
+ export * from './cli/DeleteToken.js';
20
+ export * from './cli/GrantTokenRole.js';
21
+ export * from './cli/RevokeTokenRole.js';
22
+ export * from './cli/DeleteExpiredTokens.js';
23
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,uEAAuE;AACvE,yEAAyE;AACzE,yEAAyE;AACzE,OAAO,gBAAgB,CAAC;AACxB,OAAO,kBAAkB,CAAC;AAE1B,cAAc,iBAAiB,CAAC;AAChC,cAAc,yBAAyB,CAAC;AACxC,cAAc,0DAA0D,CAAC;AACzE,cAAc,gBAAgB,CAAC;AAC/B,cAAc,mBAAmB,CAAC;AAClC,cAAc,cAAc,CAAC;AAC7B,cAAc,kBAAkB,CAAC;AACjC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,iCAAiC,CAAC;AAChD,cAAc,qCAAqC,CAAC;AACpD,cAAc,wCAAwC,CAAC;AACvD,cAAc,2BAA2B,CAAC;AAC1C,cAAc,sBAAsB,CAAC;AACrC,cAAc,sBAAsB,CAAC;AACrC,cAAc,yBAAyB,CAAC;AACxC,cAAc,0BAA0B,CAAC;AACzC,cAAc,8BAA8B,CAAC"}
@@ -0,0 +1,57 @@
1
+ export interface IGeneratedToken {
2
+ /**
3
+ * Full token as handed to the user, e.g. `spt_<base64url>`. Shown exactly once.
4
+ */
5
+ Plaintext: string;
6
+ /**
7
+ * SHA-256 hex digest of the plaintext - the only thing that is persisted.
8
+ */
9
+ Hash: string;
10
+ }
11
+ /**
12
+ * Token generation algorithm. Replaceable via config
13
+ * `rbac.token.generation.service` - same pattern as `rbac.password.service`.
14
+ */
15
+ export declare abstract class AccessTokenGenerationProvider {
16
+ /**
17
+ * Generates a fresh token. Plaintext leaves the server once; only the hash is stored.
18
+ */
19
+ abstract generate(): Promise<IGeneratedToken>;
20
+ /**
21
+ * Deterministic hash of a presented plaintext, used for DB lookup.
22
+ */
23
+ abstract hash(plaintext: string): string;
24
+ }
25
+ /**
26
+ * Marker stored on request async storage when a request was authenticated
27
+ * with an access token instead of a session.
28
+ */
29
+ export interface ITokenAuthInfo {
30
+ /**
31
+ * Uuid of the AccessToken row - safe to log; never the token itself.
32
+ */
33
+ Uuid: string;
34
+ }
35
+ declare module '@spinajs/rbac' {
36
+ interface IRbacAsyncStorage {
37
+ /**
38
+ * Set by TokenAuthMiddleware when the request carries a valid access token.
39
+ */
40
+ TokenAuth?: ITokenAuthInfo;
41
+ }
42
+ }
43
+ /**
44
+ * The http request-local storage is a SEPARATE interface from rbac's
45
+ * `IRbacAsyncStorage` ( `@spinajs/rbac-http` augments it the same way with
46
+ * User / Session / ActiveRole ), so the marker has to be declared on both -
47
+ * the one above for rbac's execution context, this one for `req.storage`.
48
+ */
49
+ declare module '@spinajs/http' {
50
+ interface IActionLocalStoregeContext {
51
+ /**
52
+ * Set by TokenAuthMiddleware when the request carries a valid access token.
53
+ */
54
+ TokenAuth?: ITokenAuthInfo;
55
+ }
56
+ }
57
+ //# sourceMappingURL=interfaces.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interfaces.d.ts","sourceRoot":"","sources":["../../src/interfaces.ts"],"names":[],"mappings":"AAUA,MAAM,WAAW,eAAe;IAC9B;;OAEG;IACH,SAAS,EAAE,MAAM,CAAC;IAElB;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;GAGG;AACH,8BAAsB,6BAA6B;IACjD;;OAEG;IACH,SAAgB,QAAQ,IAAI,OAAO,CAAC,eAAe,CAAC,CAAC;IAErD;;OAEG;IACH,SAAgB,IAAI,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAAC;CACjD;AAED;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC7B;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;CACd;AAED,OAAO,QAAQ,eAAe,CAAC;IAC7B,UAAU,iBAAiB;QACzB;;WAEG;QACH,SAAS,CAAC,EAAE,cAAc,CAAC;KAC5B;CACF;AAED;;;;;GAKG;AACH,OAAO,QAAQ,eAAe,CAAC;IAC7B,UAAU,0BAA0B;QAClC;;WAEG;QACH,SAAS,CAAC,EAAE,cAAc,CAAC;KAC5B;CACF"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Token generation algorithm. Replaceable via config
3
+ * `rbac.token.generation.service` - same pattern as `rbac.password.service`.
4
+ */
5
+ export class AccessTokenGenerationProvider {
6
+ }
7
+ //# sourceMappingURL=interfaces.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interfaces.js","sourceRoot":"","sources":["../../src/interfaces.ts"],"names":[],"mappings":"AAsBA;;;GAGG;AACH,MAAM,OAAgB,6BAA6B;CAUlD"}
@@ -0,0 +1,76 @@
1
+ import * as express from 'express';
2
+ import { Log } from '@spinajs/log';
3
+ import { Request as sRequest, ServerMiddleware } from '@spinajs/http';
4
+ import { User } from '@spinajs/rbac';
5
+ import './interfaces.js';
6
+ /**
7
+ * Authenticates requests carrying an access token in `Authorization: Bearer`
8
+ * or the configured fallback header. Runs AFTER RbacMiddleware ( Order 0 )
9
+ * so a session, when present, always wins - a request cannot mix both.
10
+ *
11
+ * On success `req.storage.User` carries the owner with Role narrowed to the
12
+ * token's effective roles, so every downstream permission check ( RbacPolicy
13
+ * helpers, orm rbac query middleware, ownership ) works unchanged.
14
+ *
15
+ * `req.storage.ActiveRole` is deliberately CLEARED, and that is load bearing.
16
+ * Both consumers of the field resolve the roles to authorize with as
17
+ * `ActiveRole ? [ActiveRole] : User.Role` ( `checkRoutePermission` in
18
+ * `rbac-http/src/policies/RbacPolicy.ts`, and the orm rbac query middleware in
19
+ * `rbac/src/middleware.ts` ), so whatever single role sits there collapses the
20
+ * request down to that one role.
21
+ *
22
+ * A session can afford that collapse because it can switch its active role at
23
+ * runtime ( `POST /auth/active-role` ), so the narrowing is both deliberate and
24
+ * reversible. A token carries no session and has no way to switch, so picking
25
+ * one of its roles - the first, arbitrarily - would permanently authorize the
26
+ * token with a strict subset of what it was issued for: a token holding
27
+ * `[ 'user', 'admin' ]` would never satisfy an admin-only grant.
28
+ *
29
+ * Leaving it undefined makes both consumers fall back to `User.Role`, which the
30
+ * narrowing above has ALREADY reduced to exactly the effective role set - the
31
+ * intersection of what the token carries and its owner still holds. That is the
32
+ * correct authorization scope for a token, and nothing wider.
33
+ *
34
+ * The field has to be assigned `undefined` rather than skipped: `RbacMiddleware`
35
+ * runs first and, on a session-less request, stamps the GUEST account's first
36
+ * role into it, which would otherwise survive into the token's own request.
37
+ *
38
+ * Never throws: an invalid token leaves the request as guest and lets the
39
+ * route's policy produce the rejection.
40
+ */
41
+ export declare class TokenAuthMiddleware extends ServerMiddleware {
42
+ protected Log: Log;
43
+ protected HeaderName: string;
44
+ protected LastUsedUpdateInterval: number;
45
+ constructor();
46
+ before(): (req: sRequest, res: express.Response, next: express.NextFunction) => void;
47
+ after(): null;
48
+ /**
49
+ * Narrows the loaded owner to the token's effective roles WITHOUT letting the
50
+ * narrowing reach the database.
51
+ *
52
+ * `Role` is a real `@Set()` column, and this very instance is what controllers
53
+ * receive through the `@User()` route argument. `update()` writes whatever
54
+ * differs from the model's snapshot, so a controller doing an unrelated edit
55
+ * ( "change my login" ) and calling `.update()` would silently persist the
56
+ * narrowed list - permanently stripping every role the token did not carry.
57
+ *
58
+ * Re-taking the snapshot right after the narrowing makes it invisible to that
59
+ * diff: the instance then behaves exactly like a freshly loaded row whose roles
60
+ * happen to be the effective ones, and a later `.update()` writes only what the
61
+ * controller itself changed. The full instance is kept rather than copied so
62
+ * that `Id`, `Password`, the `Metadata` relation and the prototype accessors
63
+ * ( `IsBanned`, `can()` ) all survive - `dehydrate()` drops the `@Hidden()`
64
+ * columns, so a dehydrate/rehydrate copy would arrive without `Id`.
65
+ *
66
+ * `takeSnapshot()` also discards the relation baselines, which the orm's
67
+ * subject builder needs to tell an already-persisted related row from a new
68
+ * one, so they are recorded again immediately.
69
+ */
70
+ protected narrowRoles(user: User, roles: string[]): User;
71
+ /**
72
+ * Bearer scheme first, configured fallback header second.
73
+ */
74
+ protected extract(req: sRequest): string | null;
75
+ }
76
+ //# sourceMappingURL=middlewares.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"middlewares.d.ts","sourceRoot":"","sources":["../../src/middlewares.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,SAAS,CAAC;AAGnC,OAAO,EAAE,GAAG,EAAU,MAAM,cAAc,CAAC;AAC3C,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAEtE,OAAO,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAGrC,OAAO,iBAAiB,CAAC;AAQzB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,qBACa,mBAAoB,SAAQ,gBAAgB;IAEvD,SAAS,CAAC,GAAG,EAAE,GAAG,CAAC;IAGnB,SAAS,CAAC,UAAU,EAAE,MAAM,CAAC;IAG7B,SAAS,CAAC,sBAAsB,EAAE,MAAM,CAAC;IAEzC,cAIC;IAEM,MAAM,IAAI,CAAC,GAAG,EAAE,QAAQ,EAAE,GAAG,EAAE,OAAO,CAAC,QAAQ,EAAE,IAAI,EAAE,OAAO,CAAC,YAAY,KAAK,IAAI,CAkD1F;IAEM,KAAK,IAAI,IAAI,CAEnB;IAED;;;;;;;;;;;;;;;;;;;;;OAqBG;IACH,SAAS,CAAC,WAAW,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI,CASvD;IAED;;OAEG;IACH,SAAS,CAAC,OAAO,CAAC,GAAG,EAAE,QAAQ,GAAG,MAAM,GAAG,IAAI,CAgB9C;CACF"}
@@ -0,0 +1,178 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ 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;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ var __metadata = (this && this.__metadata) || function (k, v) {
8
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
+ };
10
+ import { Injectable } from '@spinajs/di';
11
+ import { Config } from '@spinajs/configuration';
12
+ import { Log, Logger } from '@spinajs/log';
13
+ import { ServerMiddleware } from '@spinajs/http';
14
+ import { ErrorCode } from '@spinajs/exceptions';
15
+ import { validateToken, touchToken } from './actions.js';
16
+ import './interfaces.js';
17
+ /**
18
+ * `Authorization: Bearer <token>`. RFC 7235 makes the scheme name
19
+ * case-insensitive, and clients do send `bearer`.
20
+ */
21
+ const BEARER_SCHEME = /^bearer\s+/i;
22
+ /**
23
+ * Authenticates requests carrying an access token in `Authorization: Bearer`
24
+ * or the configured fallback header. Runs AFTER RbacMiddleware ( Order 0 )
25
+ * so a session, when present, always wins - a request cannot mix both.
26
+ *
27
+ * On success `req.storage.User` carries the owner with Role narrowed to the
28
+ * token's effective roles, so every downstream permission check ( RbacPolicy
29
+ * helpers, orm rbac query middleware, ownership ) works unchanged.
30
+ *
31
+ * `req.storage.ActiveRole` is deliberately CLEARED, and that is load bearing.
32
+ * Both consumers of the field resolve the roles to authorize with as
33
+ * `ActiveRole ? [ActiveRole] : User.Role` ( `checkRoutePermission` in
34
+ * `rbac-http/src/policies/RbacPolicy.ts`, and the orm rbac query middleware in
35
+ * `rbac/src/middleware.ts` ), so whatever single role sits there collapses the
36
+ * request down to that one role.
37
+ *
38
+ * A session can afford that collapse because it can switch its active role at
39
+ * runtime ( `POST /auth/active-role` ), so the narrowing is both deliberate and
40
+ * reversible. A token carries no session and has no way to switch, so picking
41
+ * one of its roles - the first, arbitrarily - would permanently authorize the
42
+ * token with a strict subset of what it was issued for: a token holding
43
+ * `[ 'user', 'admin' ]` would never satisfy an admin-only grant.
44
+ *
45
+ * Leaving it undefined makes both consumers fall back to `User.Role`, which the
46
+ * narrowing above has ALREADY reduced to exactly the effective role set - the
47
+ * intersection of what the token carries and its owner still holds. That is the
48
+ * correct authorization scope for a token, and nothing wider.
49
+ *
50
+ * The field has to be assigned `undefined` rather than skipped: `RbacMiddleware`
51
+ * runs first and, on a session-less request, stamps the GUEST account's first
52
+ * role into it, which would otherwise survive into the token's own request.
53
+ *
54
+ * Never throws: an invalid token leaves the request as guest and lets the
55
+ * route's policy produce the rejection.
56
+ */
57
+ let TokenAuthMiddleware = class TokenAuthMiddleware extends ServerMiddleware {
58
+ constructor() {
59
+ super();
60
+ // After RbacMiddleware ( Order 0 ): session auth takes precedence.
61
+ this.Order = 1;
62
+ }
63
+ before() {
64
+ return async (req, res, next) => {
65
+ try {
66
+ // Session user already authenticated - tokens do not apply.
67
+ if (req.storage?.Session) {
68
+ return next();
69
+ }
70
+ const plaintext = this.extract(req);
71
+ if (!plaintext) {
72
+ return next();
73
+ }
74
+ let result;
75
+ try {
76
+ result = await validateToken(plaintext);
77
+ }
78
+ catch (err) {
79
+ // Deliberately vague towards the client; specific in the log. The uuid
80
+ // is what makes a rejection actionable ( "which key broke" ) and is
81
+ // safe to write down - `validateToken` attaches it as `data.token` on
82
+ // every failure past the lookup. The presented plaintext is NEVER
83
+ // logged, here or anywhere else.
84
+ const data = err instanceof ErrorCode ? err.data : undefined;
85
+ this.Log.warn(`Access token rejected: ${err.message}`, { Ip: req.ip, Token: data?.token });
86
+ return next();
87
+ }
88
+ req.storage.User = this.narrowRoles(result.User, result.EffectiveRoles);
89
+ req.storage.TokenAuth = { Uuid: result.Token.Uuid };
90
+ // CLEARED, not merely left alone - see the class docblock for why a
91
+ // token must carry no active role at all. `RbacMiddleware` has already
92
+ // run by now and, finding no session, wrote the GUEST user's first role
93
+ // here ( `rbac-http/src/middlewares.ts`, the `else` branch ). Leaving
94
+ // that in place would authorize every token request as `guest`.
95
+ req.storage.ActiveRole = undefined;
96
+ // Token-authenticated responses must never land in a shared cache.
97
+ res.setHeader('Cache-Control', 'no-store');
98
+ // Fire-and-forget throttled usage stamp. A non-Error rejection has no
99
+ // `.message`; reading one off it would throw inside the handler and
100
+ // surface as an unhandled rejection.
101
+ void touchToken(result.Token, this.LastUsedUpdateInterval).catch((err) => this.Log.warn(`Failed to update token LastUsedAt: ${err instanceof Error ? err.message : String(err)}`, { Token: result.Token.Uuid }));
102
+ next();
103
+ }
104
+ catch (err) {
105
+ next(err);
106
+ }
107
+ };
108
+ }
109
+ after() {
110
+ return null;
111
+ }
112
+ /**
113
+ * Narrows the loaded owner to the token's effective roles WITHOUT letting the
114
+ * narrowing reach the database.
115
+ *
116
+ * `Role` is a real `@Set()` column, and this very instance is what controllers
117
+ * receive through the `@User()` route argument. `update()` writes whatever
118
+ * differs from the model's snapshot, so a controller doing an unrelated edit
119
+ * ( "change my login" ) and calling `.update()` would silently persist the
120
+ * narrowed list - permanently stripping every role the token did not carry.
121
+ *
122
+ * Re-taking the snapshot right after the narrowing makes it invisible to that
123
+ * diff: the instance then behaves exactly like a freshly loaded row whose roles
124
+ * happen to be the effective ones, and a later `.update()` writes only what the
125
+ * controller itself changed. The full instance is kept rather than copied so
126
+ * that `Id`, `Password`, the `Metadata` relation and the prototype accessors
127
+ * ( `IsBanned`, `can()` ) all survive - `dehydrate()` drops the `@Hidden()`
128
+ * columns, so a dehydrate/rehydrate copy would arrive without `Id`.
129
+ *
130
+ * `takeSnapshot()` also discards the relation baselines, which the orm's
131
+ * subject builder needs to tell an already-persisted related row from a new
132
+ * one, so they are recorded again immediately.
133
+ */
134
+ narrowRoles(user, roles) {
135
+ user.Role = roles;
136
+ user.takeSnapshot();
137
+ for (const [name] of user.ModelDescriptor?.Relations ?? []) {
138
+ user.snapshotRelation(name);
139
+ }
140
+ return user;
141
+ }
142
+ /**
143
+ * Bearer scheme first, configured fallback header second.
144
+ */
145
+ extract(req) {
146
+ // A header sent twice arrives as an array. Anything that is not a single
147
+ // string is malformed and has to read as "no token presented" - calling
148
+ // `.startsWith` / `.trim` on it would throw, and this middleware is
149
+ // contractually not allowed to turn a bad request into a 500.
150
+ const header = (name) => {
151
+ const value = req.headers?.[name];
152
+ return typeof value === 'string' ? value : null;
153
+ };
154
+ const auth = header('authorization');
155
+ if (auth && BEARER_SCHEME.test(auth)) {
156
+ return auth.replace(BEARER_SCHEME, '').trim() || null;
157
+ }
158
+ return header(this.HeaderName.toLowerCase())?.trim() || null;
159
+ }
160
+ };
161
+ __decorate([
162
+ Logger('rbac-http-token'),
163
+ __metadata("design:type", Log)
164
+ ], TokenAuthMiddleware.prototype, "Log", void 0);
165
+ __decorate([
166
+ Config('rbac.token.headerName', { defaultValue: 'x-api-key' }),
167
+ __metadata("design:type", String)
168
+ ], TokenAuthMiddleware.prototype, "HeaderName", void 0);
169
+ __decorate([
170
+ Config('rbac.token.lastUsedUpdateInterval', { defaultValue: 60 }),
171
+ __metadata("design:type", Number)
172
+ ], TokenAuthMiddleware.prototype, "LastUsedUpdateInterval", void 0);
173
+ TokenAuthMiddleware = __decorate([
174
+ Injectable(ServerMiddleware),
175
+ __metadata("design:paramtypes", [])
176
+ ], TokenAuthMiddleware);
177
+ export { TokenAuthMiddleware };
178
+ //# sourceMappingURL=middlewares.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"middlewares.js","sourceRoot":"","sources":["../../src/middlewares.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import { OrmMigration, OrmDriver } from '@spinajs/orm';
2
+ export declare class RbacHttpTokenInitial_2026_08_11_01_00_00 extends OrmMigration {
3
+ up(connection: OrmDriver): Promise<void>;
4
+ down(_connection: OrmDriver): Promise<void>;
5
+ }
6
+ //# sourceMappingURL=RbacHttpTokenInitial_2026_08_11_01_00_00.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RbacHttpTokenInitial_2026_08_11_01_00_00.d.ts","sourceRoot":"","sources":["../../../src/migrations/RbacHttpTokenInitial_2026_08_11_01_00_00.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,SAAS,EAAa,MAAM,cAAc,CAAC;AAElE,qBACa,wCAAyC,SAAQ,YAAY;IAC3D,EAAE,CAAC,UAAU,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAkBpD;IAGY,IAAI,CAAC,WAAW,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAAG;CAC5D"}