@spinajs/rbac 2.0.480 → 2.0.482

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 (93) hide show
  1. package/lib/cjs/actions.d.ts.map +1 -1
  2. package/lib/cjs/actions.js +32 -6
  3. package/lib/cjs/actions.js.map +1 -1
  4. package/lib/cjs/cli/ActivateUser.js +1 -1
  5. package/lib/cjs/cli/ActivateUser.js.map +1 -1
  6. package/lib/cjs/cli/BanUser.js +1 -1
  7. package/lib/cjs/cli/BanUser.js.map +1 -1
  8. package/lib/cjs/config/rbac.d.ts +11 -1
  9. package/lib/cjs/config/rbac.d.ts.map +1 -1
  10. package/lib/cjs/config/rbac.js +12 -3
  11. package/lib/cjs/config/rbac.js.map +1 -1
  12. package/lib/cjs/cron/DeactivatePasswords.d.ts.map +1 -1
  13. package/lib/cjs/cron/DeactivatePasswords.js +6 -2
  14. package/lib/cjs/cron/DeactivatePasswords.js.map +1 -1
  15. package/lib/cjs/index.d.ts +6 -0
  16. package/lib/cjs/index.d.ts.map +1 -1
  17. package/lib/cjs/index.js +6 -0
  18. package/lib/cjs/index.js.map +1 -1
  19. package/lib/cjs/interfaces.d.ts +63 -37
  20. package/lib/cjs/interfaces.d.ts.map +1 -1
  21. package/lib/cjs/interfaces.js +43 -1
  22. package/lib/cjs/interfaces.js.map +1 -1
  23. package/lib/cjs/middleware.d.ts +23 -1
  24. package/lib/cjs/middleware.d.ts.map +1 -1
  25. package/lib/cjs/middleware.js +158 -104
  26. package/lib/cjs/middleware.js.map +1 -1
  27. package/lib/cjs/models/User.d.ts.map +1 -1
  28. package/lib/cjs/models/User.js +15 -1
  29. package/lib/cjs/models/User.js.map +1 -1
  30. package/lib/cjs/ownership.d.ts +2 -0
  31. package/lib/cjs/ownership.d.ts.map +1 -0
  32. package/lib/cjs/ownership.js +46 -0
  33. package/lib/cjs/ownership.js.map +1 -0
  34. package/lib/cjs/session-codec.d.ts +15 -0
  35. package/lib/cjs/session-codec.d.ts.map +1 -0
  36. package/lib/cjs/session-codec.js +59 -0
  37. package/lib/cjs/session-codec.js.map +1 -0
  38. package/lib/cjs/session-expiration.d.ts +40 -0
  39. package/lib/cjs/session-expiration.d.ts.map +1 -0
  40. package/lib/cjs/session-expiration.js +93 -0
  41. package/lib/cjs/session-expiration.js.map +1 -0
  42. package/lib/cjs/session.d.ts +38 -18
  43. package/lib/cjs/session.d.ts.map +1 -1
  44. package/lib/cjs/session.js +91 -50
  45. package/lib/cjs/session.js.map +1 -1
  46. package/lib/mjs/actions.d.ts.map +1 -1
  47. package/lib/mjs/actions.js +32 -6
  48. package/lib/mjs/actions.js.map +1 -1
  49. package/lib/mjs/cli/ActivateUser.js +1 -1
  50. package/lib/mjs/cli/ActivateUser.js.map +1 -1
  51. package/lib/mjs/cli/BanUser.js +1 -1
  52. package/lib/mjs/cli/BanUser.js.map +1 -1
  53. package/lib/mjs/config/rbac.d.ts +11 -1
  54. package/lib/mjs/config/rbac.d.ts.map +1 -1
  55. package/lib/mjs/config/rbac.js +12 -3
  56. package/lib/mjs/config/rbac.js.map +1 -1
  57. package/lib/mjs/cron/DeactivatePasswords.d.ts.map +1 -1
  58. package/lib/mjs/cron/DeactivatePasswords.js +6 -2
  59. package/lib/mjs/cron/DeactivatePasswords.js.map +1 -1
  60. package/lib/mjs/index.d.ts +6 -0
  61. package/lib/mjs/index.d.ts.map +1 -1
  62. package/lib/mjs/index.js +6 -0
  63. package/lib/mjs/index.js.map +1 -1
  64. package/lib/mjs/interfaces.d.ts +63 -37
  65. package/lib/mjs/interfaces.d.ts.map +1 -1
  66. package/lib/mjs/interfaces.js +41 -0
  67. package/lib/mjs/interfaces.js.map +1 -1
  68. package/lib/mjs/middleware.d.ts +23 -1
  69. package/lib/mjs/middleware.d.ts.map +1 -1
  70. package/lib/mjs/middleware.js +158 -104
  71. package/lib/mjs/middleware.js.map +1 -1
  72. package/lib/mjs/models/User.d.ts.map +1 -1
  73. package/lib/mjs/models/User.js +15 -1
  74. package/lib/mjs/models/User.js.map +1 -1
  75. package/lib/mjs/ownership.d.ts +2 -0
  76. package/lib/mjs/ownership.d.ts.map +1 -0
  77. package/lib/mjs/ownership.js +44 -0
  78. package/lib/mjs/ownership.js.map +1 -0
  79. package/lib/mjs/session-codec.d.ts +15 -0
  80. package/lib/mjs/session-codec.d.ts.map +1 -0
  81. package/lib/mjs/session-codec.js +55 -0
  82. package/lib/mjs/session-codec.js.map +1 -0
  83. package/lib/mjs/session-expiration.d.ts +40 -0
  84. package/lib/mjs/session-expiration.d.ts.map +1 -0
  85. package/lib/mjs/session-expiration.js +90 -0
  86. package/lib/mjs/session-expiration.js.map +1 -0
  87. package/lib/mjs/session.d.ts +38 -18
  88. package/lib/mjs/session.d.ts.map +1 -1
  89. package/lib/mjs/session.js +89 -47
  90. package/lib/mjs/session.js.map +1 -1
  91. package/lib/tsconfig.cjs.tsbuildinfo +1 -1
  92. package/lib/tsconfig.mjs.tsbuildinfo +1 -1
  93. package/package.json +15 -12
@@ -0,0 +1,59 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.encodeSessionData = encodeSessionData;
4
+ exports.decodeSessionData = decodeSessionData;
5
+ const luxon_1 = require("luxon");
6
+ const util_1 = require("@spinajs/util");
7
+ /**
8
+ * Shared session-data serialization codec (fixes B5 — symmetric write/read).
9
+ *
10
+ * Persistent session stores (db / dynamodb / redis) use this pair so the
11
+ * `replacer` used on write and the `reviver` used on read are symmetric and
12
+ * structural types survive the round-trip:
13
+ * - `Map` / `Set` via the shared @spinajs/util replacer/reviver,
14
+ * - luxon `DateTime` via a tagged wrapper.
15
+ *
16
+ * The in-memory store keeps live objects and does not use this codec.
17
+ */
18
+ const DATETIME_TAG = 'DateTime';
19
+ /**
20
+ * `JSON.stringify` replacer. Must read the RAW value from the holder (`this`)
21
+ * because luxon's `DateTime.prototype.toJSON` would otherwise stringify the
22
+ * DateTime to an ISO string before we can tag it.
23
+ */
24
+ function sessionReplacer(key, value) {
25
+ const raw = this[key];
26
+ if (raw instanceof luxon_1.DateTime) {
27
+ return { dataType: DATETIME_TAG, value: raw.toISO() };
28
+ }
29
+ return (0, util_1.replacer)(key, value);
30
+ }
31
+ /**
32
+ * `JSON.parse` reviver paired with {@link sessionReplacer}.
33
+ */
34
+ function sessionReviver(key, value) {
35
+ if (value && typeof value === 'object' && value.dataType === DATETIME_TAG) {
36
+ return luxon_1.DateTime.fromISO(value.value);
37
+ }
38
+ return (0, util_1.reviver)(key, value);
39
+ }
40
+ /**
41
+ * Serializes a session `Data` map to a JSON string, preserving `Map` / `Set` /
42
+ * `DateTime` values.
43
+ *
44
+ * @param data - the session data map
45
+ */
46
+ function encodeSessionData(data) {
47
+ return JSON.stringify({ dataType: 'Map', value: Array.from(data.entries()) }, sessionReplacer);
48
+ }
49
+ /**
50
+ * Restores a session `Data` map from a JSON string produced by
51
+ * {@link encodeSessionData}.
52
+ *
53
+ * @param json - the serialized session data
54
+ */
55
+ function decodeSessionData(json) {
56
+ const parsed = JSON.parse(json, sessionReviver);
57
+ return parsed instanceof Map ? parsed : new Map();
58
+ }
59
+ //# sourceMappingURL=session-codec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-codec.js","sourceRoot":"","sources":["../../src/session-codec.ts"],"names":[],"mappings":";;AA8CA,8CAEC;AAQD,8CAGC;AA3DD,iCAAiC;AACjC,wCAAkG;AAElG;;;;;;;;;;GAUG;AAEH,MAAM,YAAY,GAAG,UAAU,CAAC;AAEhC;;;;GAIG;AACH,SAAS,eAAe,CAAgC,GAAW,EAAE,KAAc;IACjF,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC;IACtB,IAAI,GAAG,YAAY,gBAAQ,EAAE,CAAC;QAC5B,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,KAAK,EAAE,GAAG,CAAC,KAAK,EAAE,EAAE,CAAC;IACxD,CAAC;IACD,OAAO,IAAA,eAAY,EAAC,GAAG,EAAE,KAAK,CAAC,CAAC;AAClC,CAAC;AAED;;GAEG;AACH,SAAS,cAAc,CAAC,GAAW,EAAE,KAAgC;IACnE,IAAI,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAK,KAAyB,CAAC,QAAQ,KAAK,YAAY,EAAE,CAAC;QAC/F,OAAO,gBAAQ,CAAC,OAAO,CAAE,KAAyB,CAAC,KAAe,CAAC,CAAC;IACtE,CAAC;IACD,OAAO,IAAA,cAAW,EAAC,GAAG,EAAE,KAAwB,CAAC,CAAC;AACpD,CAAC;AAED;;;;;GAKG;AACH,SAAgB,iBAAiB,CAAC,IAA0B;IAC1D,OAAO,IAAI,CAAC,SAAS,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,EAAE,EAAE,eAAe,CAAC,CAAC;AACjG,CAAC;AAED;;;;;GAKG;AACH,SAAgB,iBAAiB,CAAC,IAAY;IAC5C,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,cAAc,CAAC,CAAC;IAChD,OAAO,MAAM,YAAY,GAAG,CAAC,CAAC,CAAE,MAA+B,CAAC,CAAC,CAAC,IAAI,GAAG,EAAmB,CAAC;AAC/F,CAAC"}
@@ -0,0 +1,40 @@
1
+ import { DateTime } from 'luxon';
2
+ import { ISession, SessionExpirationProvider } from './interfaces.js';
3
+ /**
4
+ * Absolute expiration: the session dies at a fixed instant from creation and is
5
+ * never extended. `touch` is therefore a no-op (renew returns the current
6
+ * Expiration unchanged).
7
+ *
8
+ * Settings: `rbac.session.expiration.ttl` (minutes).
9
+ */
10
+ export declare class AbsoluteExpiration extends SessionExpirationProvider {
11
+ protected Ttl: number;
12
+ initial(session: ISession): DateTime | undefined;
13
+ renew(session: ISession): DateTime | undefined;
14
+ }
15
+ /**
16
+ * Sliding expiration: every renewal pushes the expiration to `now + ttl`, with
17
+ * no upper bound. Activity keeps the session alive indefinitely.
18
+ *
19
+ * Settings: `rbac.session.expiration.ttl` (minutes).
20
+ */
21
+ export declare class SlidingExpiration extends SessionExpirationProvider {
22
+ protected Ttl: number;
23
+ initial(_session: ISession): DateTime | undefined;
24
+ renew(_session: ISession): DateTime | undefined;
25
+ }
26
+ /**
27
+ * Sliding expiration with an absolute cap: renewal pushes the expiration to
28
+ * `now + ttl` but never past `Creation + maxLifetime`. Combines idle timeout
29
+ * with a hard session lifetime ceiling.
30
+ *
31
+ * Settings: `rbac.session.expiration.ttl` and
32
+ * `rbac.session.expiration.maxLifetime` (both minutes).
33
+ */
34
+ export declare class SlidingCappedExpiration extends SessionExpirationProvider {
35
+ protected Ttl: number;
36
+ protected MaxLifetime: number;
37
+ initial(_session: ISession): DateTime | undefined;
38
+ renew(session: ISession): DateTime | undefined;
39
+ }
40
+ //# sourceMappingURL=session-expiration.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-expiration.d.ts","sourceRoot":"","sources":["../../src/session-expiration.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAGjC,OAAO,EAAE,QAAQ,EAAE,yBAAyB,EAAE,MAAM,iBAAiB,CAAC;AAEtE;;;;;;GAMG;AACH,qBACa,kBAAmB,SAAQ,yBAAyB;IAE/D,SAAS,CAAC,GAAG,EAAG,MAAM,CAAC;IAEhB,OAAO,CAAC,OAAO,EAAE,QAAQ,GAAG,QAAQ,GAAG,SAAS;IAIhD,KAAK,CAAC,OAAO,EAAE,QAAQ,GAAG,QAAQ,GAAG,SAAS;CAItD;AAED;;;;;GAKG;AACH,qBACa,iBAAkB,SAAQ,yBAAyB;IAE9D,SAAS,CAAC,GAAG,EAAG,MAAM,CAAC;IAEhB,OAAO,CAAC,QAAQ,EAAE,QAAQ,GAAG,QAAQ,GAAG,SAAS;IAIjD,KAAK,CAAC,QAAQ,EAAE,QAAQ,GAAG,QAAQ,GAAG,SAAS;CAGvD;AAED;;;;;;;GAOG;AACH,qBACa,uBAAwB,SAAQ,yBAAyB;IAEpE,SAAS,CAAC,GAAG,EAAG,MAAM,CAAC;IAGvB,SAAS,CAAC,WAAW,EAAG,MAAM,CAAC;IAExB,OAAO,CAAC,QAAQ,EAAE,QAAQ,GAAG,QAAQ,GAAG,SAAS;IAIjD,KAAK,CAAC,OAAO,EAAE,QAAQ,GAAG,QAAQ,GAAG,SAAS;CAKtD"}
@@ -0,0 +1,93 @@
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.SlidingCappedExpiration = exports.SlidingExpiration = exports.AbsoluteExpiration = void 0;
13
+ const luxon_1 = require("luxon");
14
+ const di_1 = require("@spinajs/di");
15
+ const configuration_1 = require("@spinajs/configuration");
16
+ const interfaces_js_1 = require("./interfaces.js");
17
+ /**
18
+ * Absolute expiration: the session dies at a fixed instant from creation and is
19
+ * never extended. `touch` is therefore a no-op (renew returns the current
20
+ * Expiration unchanged).
21
+ *
22
+ * Settings: `rbac.session.expiration.ttl` (minutes).
23
+ */
24
+ let AbsoluteExpiration = class AbsoluteExpiration extends interfaces_js_1.SessionExpirationProvider {
25
+ initial(session) {
26
+ return session.Creation.plus({ minutes: this.Ttl });
27
+ }
28
+ renew(session) {
29
+ // no slide — keep whatever absolute instant was set at creation
30
+ return session.Expiration;
31
+ }
32
+ };
33
+ exports.AbsoluteExpiration = AbsoluteExpiration;
34
+ __decorate([
35
+ (0, configuration_1.Config)('rbac.session.expiration.ttl', { defaultValue: 120 }),
36
+ __metadata("design:type", Number)
37
+ ], AbsoluteExpiration.prototype, "Ttl", void 0);
38
+ exports.AbsoluteExpiration = AbsoluteExpiration = __decorate([
39
+ (0, di_1.Injectable)(interfaces_js_1.SessionExpirationProvider)
40
+ ], AbsoluteExpiration);
41
+ /**
42
+ * Sliding expiration: every renewal pushes the expiration to `now + ttl`, with
43
+ * no upper bound. Activity keeps the session alive indefinitely.
44
+ *
45
+ * Settings: `rbac.session.expiration.ttl` (minutes).
46
+ */
47
+ let SlidingExpiration = class SlidingExpiration extends interfaces_js_1.SessionExpirationProvider {
48
+ initial(_session) {
49
+ return luxon_1.DateTime.now().plus({ minutes: this.Ttl });
50
+ }
51
+ renew(_session) {
52
+ return luxon_1.DateTime.now().plus({ minutes: this.Ttl });
53
+ }
54
+ };
55
+ exports.SlidingExpiration = SlidingExpiration;
56
+ __decorate([
57
+ (0, configuration_1.Config)('rbac.session.expiration.ttl', { defaultValue: 120 }),
58
+ __metadata("design:type", Number)
59
+ ], SlidingExpiration.prototype, "Ttl", void 0);
60
+ exports.SlidingExpiration = SlidingExpiration = __decorate([
61
+ (0, di_1.Injectable)(interfaces_js_1.SessionExpirationProvider)
62
+ ], SlidingExpiration);
63
+ /**
64
+ * Sliding expiration with an absolute cap: renewal pushes the expiration to
65
+ * `now + ttl` but never past `Creation + maxLifetime`. Combines idle timeout
66
+ * with a hard session lifetime ceiling.
67
+ *
68
+ * Settings: `rbac.session.expiration.ttl` and
69
+ * `rbac.session.expiration.maxLifetime` (both minutes).
70
+ */
71
+ let SlidingCappedExpiration = class SlidingCappedExpiration extends interfaces_js_1.SessionExpirationProvider {
72
+ initial(_session) {
73
+ return luxon_1.DateTime.now().plus({ minutes: this.Ttl });
74
+ }
75
+ renew(session) {
76
+ const slide = luxon_1.DateTime.now().plus({ minutes: this.Ttl });
77
+ const cap = session.Creation.plus({ minutes: this.MaxLifetime });
78
+ return slide < cap ? slide : cap;
79
+ }
80
+ };
81
+ exports.SlidingCappedExpiration = SlidingCappedExpiration;
82
+ __decorate([
83
+ (0, configuration_1.Config)('rbac.session.expiration.ttl', { defaultValue: 120 }),
84
+ __metadata("design:type", Number)
85
+ ], SlidingCappedExpiration.prototype, "Ttl", void 0);
86
+ __decorate([
87
+ (0, configuration_1.Config)('rbac.session.expiration.maxLifetime', { defaultValue: 1440 }),
88
+ __metadata("design:type", Number)
89
+ ], SlidingCappedExpiration.prototype, "MaxLifetime", void 0);
90
+ exports.SlidingCappedExpiration = SlidingCappedExpiration = __decorate([
91
+ (0, di_1.Injectable)(interfaces_js_1.SessionExpirationProvider)
92
+ ], SlidingCappedExpiration);
93
+ //# sourceMappingURL=session-expiration.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-expiration.js","sourceRoot":"","sources":["../../src/session-expiration.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,iCAAiC;AACjC,oCAAyC;AACzC,0DAAgD;AAChD,mDAAsE;AAEtE;;;;;;GAMG;AAEI,IAAM,kBAAkB,GAAxB,MAAM,kBAAmB,SAAQ,yCAAyB;IAIxD,OAAO,CAAC,OAAiB;QAC9B,OAAO,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;IACtD,CAAC;IAEM,KAAK,CAAC,OAAiB;QAC5B,gEAAgE;QAChE,OAAO,OAAO,CAAC,UAAU,CAAC;IAC5B,CAAC;CACF,CAAA;AAZY,gDAAkB;AAEnB;IADT,IAAA,sBAAM,EAAC,6BAA6B,EAAE,EAAE,YAAY,EAAE,GAAG,EAAE,CAAC;;+CACtC;6BAFZ,kBAAkB;IAD9B,IAAA,eAAU,EAAC,yCAAyB,CAAC;GACzB,kBAAkB,CAY9B;AAED;;;;;GAKG;AAEI,IAAM,iBAAiB,GAAvB,MAAM,iBAAkB,SAAQ,yCAAyB;IAIvD,OAAO,CAAC,QAAkB;QAC/B,OAAO,gBAAQ,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;IACpD,CAAC;IAEM,KAAK,CAAC,QAAkB;QAC7B,OAAO,gBAAQ,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;IACpD,CAAC;CACF,CAAA;AAXY,8CAAiB;AAElB;IADT,IAAA,sBAAM,EAAC,6BAA6B,EAAE,EAAE,YAAY,EAAE,GAAG,EAAE,CAAC;;8CACtC;4BAFZ,iBAAiB;IAD7B,IAAA,eAAU,EAAC,yCAAyB,CAAC;GACzB,iBAAiB,CAW7B;AAED;;;;;;;GAOG;AAEI,IAAM,uBAAuB,GAA7B,MAAM,uBAAwB,SAAQ,yCAAyB;IAO7D,OAAO,CAAC,QAAkB;QAC/B,OAAO,gBAAQ,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;IACpD,CAAC;IAEM,KAAK,CAAC,OAAiB;QAC5B,MAAM,KAAK,GAAG,gBAAQ,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;QACzD,MAAM,GAAG,GAAG,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;QACjE,OAAO,KAAK,GAAG,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC;IACnC,CAAC;CACF,CAAA;AAhBY,0DAAuB;AAExB;IADT,IAAA,sBAAM,EAAC,6BAA6B,EAAE,EAAE,YAAY,EAAE,GAAG,EAAE,CAAC;;oDACtC;AAGb;IADT,IAAA,sBAAM,EAAC,qCAAqC,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC;;4DACvC;kCALpB,uBAAuB;IADnC,IAAA,eAAU,EAAC,yCAAyB,CAAC;GACzB,uBAAuB,CAgBnC"}
@@ -1,40 +1,60 @@
1
1
  import { DateTime } from 'luxon';
2
2
  import { SessionProvider, ISession } from './interfaces.js';
3
- import { User } from './models/User.js';
4
3
  /**
5
4
  * Session base class
6
5
  */
7
6
  export declare class UserSession implements ISession {
8
- protected SessionExpirationTime: number;
9
7
  SessionId: string;
10
8
  /**
11
- * Expiration time for session, if null it does not expire
9
+ * User id that owns this session. Single source of truth for ownership.
12
10
  */
13
- Expiration: DateTime | undefined;
14
- Data: Map<string, unknown>;
11
+ UserId: number;
15
12
  Creation: DateTime;
16
13
  /**
17
- * User id that owns this session
14
+ * Expiration time for session, if undefined it does not expire.
15
+ * Set by the SessionProvider through the configured expiration strategy.
18
16
  */
19
- UserId: number;
17
+ Expiration: DateTime | undefined;
18
+ Data: Map<string, unknown>;
20
19
  constructor(session?: Partial<ISession>);
21
- /**
22
- * Extends lifetime of session
23
- *
24
- * @param seconds - hom mutch to extend
25
- */
26
- extend(seconds?: number): void;
27
20
  }
28
21
  /**
29
- * Simple session storage in memory, for testing or rapid prototyping
22
+ * Derives the `ssid` cookie `maxAge` (milliseconds) from a session's real
23
+ * `Expiration` (fixes B1 — the cookie previously always died at
24
+ * `expiration * 1000` ms i.e. ~2 minutes). Returns `undefined` for a
25
+ * never-expiring session (a session cookie), and never a negative value.
26
+ *
27
+ * @param session - the session whose expiry drives the cookie lifetime
28
+ */
29
+ export declare function sessionCookieMaxAge(session: ISession): number | undefined;
30
+ /**
31
+ * Session-fixation protection helper. Mints a NEW session id, copies the
32
+ * ownership identity and data across, deletes the old id and persists the new
33
+ * one. Apply on privilege elevation (login already mints a fresh session, but
34
+ * 2FA-authorize and role-switch elevate an existing one).
35
+ *
36
+ * The returned session carries a new `SessionId` so the caller can reset the
37
+ * `ssid` cookie. `Expiration` is left unset so `save` schedules a fresh one via
38
+ * the configured strategy (`Creation` is preserved, so a capped lifetime window
39
+ * is not extended).
40
+ *
41
+ * @param provider - the active session store
42
+ * @param session - the session to regenerate
43
+ */
44
+ export declare function regenerateSession(provider: SessionProvider, session: ISession): Promise<ISession>;
45
+ /**
46
+ * Simple session storage in memory, for testing or rapid prototyping.
47
+ * Keeps live session objects (no serialization).
30
48
  */
31
49
  export declare class MemorySessionStore extends SessionProvider<ISession> {
32
50
  protected Sessions: Map<string, ISession>;
33
- truncate(): Promise<void>;
34
- touch(session: ISession): Promise<void>;
35
51
  restore(sessionId: string): Promise<ISession | null>;
52
+ save(session: ISession): Promise<void>;
53
+ touch(session: ISession): Promise<boolean>;
36
54
  delete(sessionId: string): Promise<void>;
37
- save(idOrSession: ISession | string, data?: object): Promise<void>;
38
- logsOut(user: User): Promise<void>;
55
+ deleteByUser(userId: number): Promise<void>;
56
+ listByUser(userId: number): Promise<ISession[]>;
57
+ truncate(): Promise<void>;
58
+ private expirationEquals;
39
59
  }
40
60
  //# sourceMappingURL=session.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../src/session.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACjC,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAK5D,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAExC;;GAEG;AACH,qBACa,WAAY,YAAW,QAAQ;IAE1C,SAAS,CAAC,qBAAqB,EAAE,MAAM,CAAC;IAEjC,SAAS,EAAE,MAAM,CAAY;IAEpC;;OAEG;IACI,UAAU,EAAE,QAAQ,GAAG,SAAS,CAAa;IAE7C,IAAI,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAAa;IAEvC,QAAQ,EAAE,QAAQ,CAAkB;IAE3C;;OAEG;IACI,MAAM,EAAE,MAAM,CAAC;gBAEV,OAAO,CAAC,EAAE,OAAO,CAAC,QAAQ,CAAC;IAMvC;;;;OAIG;IACI,MAAM,CAAC,OAAO,CAAC,EAAE,MAAM;CAG/B;AAED;;GAEG;AACH,qBACa,kBAAmB,SAAQ,eAAe,CAAC,QAAQ,CAAC;IAE/D,SAAS,CAAC,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,CAA+B;IAE3D,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAIzB,KAAK,CAAC,OAAO,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IAIvC,OAAO,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC;IAYpD,MAAM,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAMxC,IAAI,CAAC,WAAW,EAAE,QAAQ,GAAG,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAYxE,OAAO,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;CAgB1C"}
1
+ {"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../src/session.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACjC,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAI5D;;GAEG;AACH,qBACa,WAAY,YAAW,QAAQ;IACnC,SAAS,EAAE,MAAM,CAAY;IAEpC;;OAEG;IACI,MAAM,EAAE,MAAM,CAAC;IAEf,QAAQ,EAAE,QAAQ,CAAkB;IAE3C;;;OAGG;IACI,UAAU,EAAE,QAAQ,GAAG,SAAS,CAAa;IAE7C,IAAI,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAAa;gBAElC,OAAO,CAAC,EAAE,OAAO,CAAC,QAAQ,CAAC;CAKxC;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,QAAQ,GAAG,MAAM,GAAG,SAAS,CAKzE;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAsB,iBAAiB,CAAC,QAAQ,EAAE,eAAe,EAAE,OAAO,EAAE,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,CAWvG;AAED;;;GAGG;AACH,qBACa,kBAAmB,SAAQ,eAAe,CAAC,QAAQ,CAAC;IAC/D,SAAS,CAAC,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,CAA+B;IAE3D,OAAO,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC;IAepD,IAAI,CAAC,OAAO,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IAWtC,KAAK,CAAC,OAAO,EAAE,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC;IAc1C,MAAM,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIxC,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAQ3C,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC;IAU/C,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAItC,OAAO,CAAC,gBAAgB;CAMzB"}
@@ -8,102 +8,143 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
8
8
  var __metadata = (this && this.__metadata) || function (k, v) {
9
9
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
10
  };
11
- var __importDefault = (this && this.__importDefault) || function (mod) {
12
- return (mod && mod.__esModule) ? mod : { "default": mod };
13
- };
14
11
  Object.defineProperty(exports, "__esModule", { value: true });
15
12
  exports.MemorySessionStore = exports.UserSession = void 0;
13
+ exports.sessionCookieMaxAge = sessionCookieMaxAge;
14
+ exports.regenerateSession = regenerateSession;
16
15
  const luxon_1 = require("luxon");
17
16
  const interfaces_js_1 = require("./interfaces.js");
18
17
  const di_1 = require("@spinajs/di");
19
- const configuration_1 = require("@spinajs/configuration");
20
18
  const uuid_1 = require("uuid");
21
- const lodash_1 = __importDefault(require("lodash"));
22
19
  /**
23
20
  * Session base class
24
21
  */
25
22
  let UserSession = class UserSession {
26
23
  constructor(session) {
27
24
  this.SessionId = (0, uuid_1.v4)();
25
+ this.Creation = luxon_1.DateTime.now();
28
26
  /**
29
- * Expiration time for session, if null it does not expire
27
+ * Expiration time for session, if undefined it does not expire.
28
+ * Set by the SessionProvider through the configured expiration strategy.
30
29
  */
31
30
  this.Expiration = undefined;
32
31
  this.Data = new Map();
33
- this.Creation = luxon_1.DateTime.now();
34
32
  if (session) {
35
33
  Object.assign(this, session);
36
34
  }
37
35
  }
38
- /**
39
- * Extends lifetime of session
40
- *
41
- * @param seconds - hom mutch to extend
42
- */
43
- extend(seconds) {
44
- this.Expiration = luxon_1.DateTime.now().plus({ seconds: seconds ? seconds : this.SessionExpirationTime });
45
- }
46
36
  };
47
37
  exports.UserSession = UserSession;
48
- __decorate([
49
- (0, configuration_1.Config)('rbac.session.expiration'),
50
- __metadata("design:type", Number)
51
- ], UserSession.prototype, "SessionExpirationTime", void 0);
52
38
  exports.UserSession = UserSession = __decorate([
53
39
  (0, di_1.NewInstance)(),
54
40
  __metadata("design:paramtypes", [Object])
55
41
  ], UserSession);
56
42
  /**
57
- * Simple session storage in memory, for testing or rapid prototyping
43
+ * Derives the `ssid` cookie `maxAge` (milliseconds) from a session's real
44
+ * `Expiration` (fixes B1 — the cookie previously always died at
45
+ * `expiration * 1000` ms i.e. ~2 minutes). Returns `undefined` for a
46
+ * never-expiring session (a session cookie), and never a negative value.
47
+ *
48
+ * @param session - the session whose expiry drives the cookie lifetime
49
+ */
50
+ function sessionCookieMaxAge(session) {
51
+ if (!session.Expiration) {
52
+ return undefined;
53
+ }
54
+ return Math.max(0, Math.floor(session.Expiration.diff(luxon_1.DateTime.now()).milliseconds));
55
+ }
56
+ /**
57
+ * Session-fixation protection helper. Mints a NEW session id, copies the
58
+ * ownership identity and data across, deletes the old id and persists the new
59
+ * one. Apply on privilege elevation (login already mints a fresh session, but
60
+ * 2FA-authorize and role-switch elevate an existing one).
61
+ *
62
+ * The returned session carries a new `SessionId` so the caller can reset the
63
+ * `ssid` cookie. `Expiration` is left unset so `save` schedules a fresh one via
64
+ * the configured strategy (`Creation` is preserved, so a capped lifetime window
65
+ * is not extended).
66
+ *
67
+ * @param provider - the active session store
68
+ * @param session - the session to regenerate
69
+ */
70
+ async function regenerateSession(provider, session) {
71
+ const regenerated = new UserSession({
72
+ UserId: session.UserId,
73
+ Creation: session.Creation,
74
+ Data: new Map(session.Data),
75
+ });
76
+ await provider.delete(session.SessionId);
77
+ await provider.save(regenerated);
78
+ return regenerated;
79
+ }
80
+ /**
81
+ * Simple session storage in memory, for testing or rapid prototyping.
82
+ * Keeps live session objects (no serialization).
58
83
  */
59
84
  let MemorySessionStore = class MemorySessionStore extends interfaces_js_1.SessionProvider {
60
85
  constructor() {
61
86
  super(...arguments);
62
87
  this.Sessions = new Map();
63
88
  }
64
- async truncate() {
65
- this.Sessions = new Map();
66
- }
67
- async touch(session) {
68
- return this.save(session);
69
- }
70
89
  async restore(sessionId) {
71
- if (this.Sessions.has(sessionId)) {
72
- const session = this.Sessions.get(sessionId);
73
- if (!session.Expiration || session.Expiration > luxon_1.DateTime.now()) {
74
- return session;
75
- }
90
+ const session = this.Sessions.get(sessionId);
91
+ if (!session) {
76
92
  return null;
77
93
  }
78
- return null;
79
- }
80
- async delete(sessionId) {
81
- if (this.Sessions.has(sessionId)) {
94
+ // an expired row is treated as absent (and evicted)
95
+ if (this.isExpired(session)) {
82
96
  this.Sessions.delete(sessionId);
97
+ return null;
83
98
  }
99
+ return session;
84
100
  }
85
- async save(idOrSession, data) {
86
- if (lodash_1.default.isString(idOrSession)) {
87
- const s = this.Sessions.get(idOrSession);
88
- for (const key in data) {
89
- s.Data.set(key, data[key]);
90
- }
101
+ async save(session) {
102
+ // A brand-new session without a scheduled expiration gets its initial
103
+ // expiration from the strategy. An already-scheduled expiration is
104
+ // persisted verbatim (fixes B3 never recompute on every save).
105
+ if (session.Expiration === undefined) {
106
+ this.applyInitialExpiration(session);
91
107
  }
92
- else {
93
- this.Sessions.set(idOrSession.SessionId, idOrSession);
108
+ this.Sessions.set(session.SessionId, session);
109
+ }
110
+ async touch(session) {
111
+ const current = session.Expiration;
112
+ const renewed = this.Expiration.renew(session);
113
+ // no change (e.g. AbsoluteExpiration) — skip the write, report false
114
+ if (this.expirationEquals(current, renewed)) {
115
+ return false;
94
116
  }
117
+ session.Expiration = renewed;
118
+ this.Sessions.set(session.SessionId, session);
119
+ return true;
120
+ }
121
+ async delete(sessionId) {
122
+ this.Sessions.delete(sessionId);
95
123
  }
96
- logsOut(user) {
97
- const sessionsToDelete = [];
124
+ async deleteByUser(userId) {
98
125
  for (const [key, session] of this.Sessions.entries()) {
99
- if (session.UserId === user.Id) {
100
- sessionsToDelete.push(key);
126
+ if (session.UserId === userId) {
127
+ this.Sessions.delete(key);
101
128
  }
102
129
  }
103
- for (const sessionId of sessionsToDelete) {
104
- this.Sessions.delete(sessionId);
130
+ }
131
+ async listByUser(userId) {
132
+ const result = [];
133
+ for (const session of this.Sessions.values()) {
134
+ if (session.UserId === userId && !this.isExpired(session)) {
135
+ result.push(session);
136
+ }
137
+ }
138
+ return result;
139
+ }
140
+ async truncate() {
141
+ this.Sessions = new Map();
142
+ }
143
+ expirationEquals(a, b) {
144
+ if (a === undefined || b === undefined) {
145
+ return a === b;
105
146
  }
106
- return Promise.resolve();
147
+ return a.toMillis() === b.toMillis();
107
148
  }
108
149
  };
109
150
  exports.MemorySessionStore = MemorySessionStore;
@@ -1 +1 @@
1
- {"version":3,"file":"session.js","sourceRoot":"","sources":["../../src/session.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"session.js","sourceRoot":"","sources":["../../src/session.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"actions.d.ts","sourceRoot":"","sources":["../../src/actions.ts"],"names":[],"mappings":"AAKA,OAAO,EAAwB,IAAI,EAAY,MAAM,kBAAkB,CAAC;AAGxE,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AASlD,oBAAY,OAAO;IACjB,eAAe,IAAA;IAEf,eAAe,IAAA;IAEf,qCAAqC,IAAA;IAErC,gBAAgB,IAAA;IAEhB,qBAAqB,IAAA;IAErB,iBAAiB,IAAA;IAEjB,aAAa,IAAA;IAEb,oBAAoB,IAAA;IAEpB,wBAAwB,IAAA;IAExB,sBAAsB,IAAA;IAEtB,mBAAmB,KAAA;IAEnB,YAAY,KAAA;CACb;AAED;;;;GAIG;AAEH;;;;;GAKG;AACH,wBAAgB,gBAAgB,qBAiB/B;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,yGAEhD;AAID;;;;;;GAMG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,GAAG,MAAM,uBAWrD;AAID;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,GAAG,CAAA;CAAE,EAAE,EAAE,KAAK,GAAE,GAAU,IAC9E,GAAG,IAAI,mBAoBtB;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,IAC1B,GAAG,IAAI,kBAMtB;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,WAAW,EAAE,gBAAgB,GAAG,SAAS,GAAG,SAAS,GAAG,aAAa,GAAG,WAAW,GAAG,SAAS,GAAG,UAAU,GAAG,QAAQ,GAAG,oBAAoB,GAAG,iBAAiB,IAO9K,GAAG,IAAI,mBAmBtB;AAED;;;;;;GAMG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC,SAAS,CAAC,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,IACtD,GAAG,IAAI,mBAItB;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC,IAAI,CAAC,IACjC,GAAG,IAAI,mBAItB;AAED;;;;;;;GAOG;AACH,wBAAgB,KAAK,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,CAQ7E;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,CAQpF;AAED;;;;GAIG;AAEH;;;;;GAKG;AACH,wBAAsB,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,oBAEhE;AAED;;;;;GAKG;AACH,wBAAsB,UAAU,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAElF;AAED;;GAEG;AACH,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,EAAE,IAAI,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;AAEjE;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;CAAE,GAAG,OAAO,CAAC;IAAE,IAAI,EAAE,IAAI,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CA6DvL;AAED;;;;;GAKG;AACH,wBAAsB,UAAU,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAOlF;AAED;;;;;;;GAOG;AACH,wBAAsB,KAAK,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CASpF;AAED;;;;;;;GAOG;AACH,wBAAsB,MAAM,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAS5F;AAED;;;;;;;;GAQG;AACH,wBAAsB,GAAG,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,EAAE,MAAM,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAsB/G;AAED;;;;;;GAMG;AACH,wBAAsB,KAAK,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAW7E;AAED;;;;;;GAMG;AACH,wBAAsB,qBAAqB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,oBAY7E;AAED;;;;;;;GAOG;AACH,wBAAsB,oBAAoB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,oBA4BhH;AAED;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,CAAC,CAAC,EAAE,IAAI,KAAK,OAAO,CAAC,IAAI,CAAC,CAmB3E;AAED;;;;;GAKG;AACH,wBAAsB,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAEtF;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,IAG9B,GAAG,IAAI,KAAG,OAAO,CAAC,OAAO,CAAC,CAGzC;AAED;;;;;;;;;GASG;AACH,wBAAsB,KAAK,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAwB/F"}
1
+ {"version":3,"file":"actions.d.ts","sourceRoot":"","sources":["../../src/actions.ts"],"names":[],"mappings":"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"}
@@ -6,6 +6,8 @@ import { _ev } from '@spinajs/queue';
6
6
  import { USER_COMMON_METADATA, User, UserBase } from './models/User.js';
7
7
  import { _cfg, _service } from '@spinajs/configuration';
8
8
  import { UserActivated, UserBanned, UserChanged, UserCreated, UserDeactivated, UserDeleted, UserLogged, UserPasswordChangeRequest, UserPasswordChanged, UserRoleGranted, UserRoleRevoked, UserUnbanned } from './events/index.js';
9
+ import { DI } from '@spinajs/di';
10
+ import { Configuration } from '@spinajs/configuration';
9
11
  import { AuthProvider, PasswordProvider, PasswordValidationProvider } from './interfaces.js';
10
12
  import { DateTime } from 'luxon';
11
13
  import { ErrorCode } from '@spinajs/exceptions';
@@ -213,6 +215,20 @@ export async function activate(identifier) {
213
215
  export async function deactivate(identifier) {
214
216
  return _chain(_user(identifier), _user_update({ IsActive: false }), _user_ev(UserDeactivated), _user_email('deactivated'));
215
217
  }
218
+ /**
219
+ * Reads a create-middleware list from configuration.
220
+ *
221
+ * NOTE: we deliberately do NOT use `_cfg(path, [])` here. `_cfg` wraps its
222
+ * result in `_non_nil()`, which rejects empty arrays — so an unset or
223
+ * empty `beforeCreate` / `afterCreate` (the default in the shipped config)
224
+ * would throw and break user creation. Reading the value directly keeps an
225
+ * empty list as a valid "no middleware" result.
226
+ */
227
+ function _create_middleware(path) {
228
+ const cfg = DI.get(Configuration);
229
+ const mw = cfg?.get(path, []);
230
+ return Array.isArray(mw) ? mw : [];
231
+ }
216
232
  /**
217
233
  * Creates a new user account.
218
234
  *
@@ -248,11 +264,11 @@ export async function create(email, login, password, roles, id, metadata) {
248
264
  Uuid: uuidv4(),
249
265
  })),
250
266
  // run before create middleware
251
- (u) => _chain(_cfg('rbac.actions.create.beforeCreate', []), (beforeCreate) => _chain(u, ...beforeCreate)),
267
+ (u) => _chain(u, ..._create_middleware('rbac.actions.create.beforeCreate')),
252
268
  // insert to db
253
269
  _insert(), _either(() => metadata !== undefined, _set_user_meta(metadata ? Object.entries(metadata).map(([key, value]) => ({ key, value })) : []), async (u) => u),
254
270
  // run after create middleware
255
- (u) => _chain(_cfg('rbac.actions.create.afterCreate', []), (afterCreate) => _chain(u, ...afterCreate)),
271
+ (u) => _chain(u, ..._create_middleware('rbac.actions.create.afterCreate')),
256
272
  // send event
257
273
  _user_ev(UserCreated, (u) => u.toJSON()),
258
274
  // send email
@@ -327,11 +343,21 @@ export async function ban(identifier, reason, duration) {
327
343
  * @returns
328
344
  */
329
345
  export async function unban(identifier) {
330
- return _chain(_user(identifier), (u) => {
346
+ return _chain(_user(identifier),
347
+ // guard must return the user so the chain can keep flowing it downstream
348
+ _tap(async (u) => {
331
349
  if (!u.Metadata[USER_COMMON_METADATA.USER_BAN_IS_BANNED]) {
332
350
  throw new ErrorCode(E_CODES.E_USER_BANNED, `User is already unbanned`, { user: u });
333
351
  }
334
- }, _set_user_meta('/^user:ban/', null), _user_ev(UserUnbanned));
352
+ }),
353
+ // actually remove the ban metadata from the DB. Assigning a regex-like
354
+ // string key never cleared anything; delete() removes each key from store.
355
+ _tap(async (u) => {
356
+ await u.Metadata.delete(USER_COMMON_METADATA.USER_BAN_IS_BANNED);
357
+ await u.Metadata.delete(USER_COMMON_METADATA.USER_BAN_START_DATE);
358
+ await u.Metadata.delete(USER_COMMON_METADATA.USER_BAN_DURATION);
359
+ await u.Metadata.delete(USER_COMMON_METADATA.USER_BAN_REASON);
360
+ }), _user_ev(UserUnbanned));
335
361
  }
336
362
  /**
337
363
  * Initiates a password-change request for a user.
@@ -341,7 +367,7 @@ export async function unban(identifier) {
341
367
  * @param identifier - numeric id, uuid / email / login string, or an existing {@link User} instance
342
368
  */
343
369
  export async function passwordChangeRequest(identifier) {
344
- const pwdWaitTime = await _cfg('rbac.password.reset_wait_time')();
370
+ const pwdWaitTime = await _cfg('rbac.password.passwordResetWaitTime')();
345
371
  return _chain(_user(identifier), _set_user_meta([
346
372
  { key: USER_COMMON_METADATA.USER_PWD_RESET_START_DATE, value: DateTime.now() },
347
373
  { key: USER_COMMON_METADATA.USER_PWD_RESET_TOKEN, value: uuidv4() },
@@ -358,7 +384,7 @@ export async function passwordChangeRequest(identifier) {
358
384
  */
359
385
  export async function confirmPasswordReset(identifier, newPassword, token) {
360
386
  return _chain(_user(identifier), _tap((u) => _chain(u, _zip(_get_user_meta(USER_COMMON_METADATA.USER_PWD_RESET_START_DATE), _get_user_meta(USER_COMMON_METADATA.USER_PWD_RESET_WAIT_TIME)), ([dueDate, waitTime]) => {
361
- if (dueDate.plus(waitTime) < DateTime.now()) {
387
+ if (dueDate.plus({ seconds: waitTime }) < DateTime.now()) {
362
388
  throw new ErrorCode(E_CODES.E_TOKEN_EXPIRED, `Password change token expired, token expiration date is: ${dueDate.toISO()}`, {
363
389
  dueDate,
364
390
  waitTime,