@solidxai/core 0.1.13-beta.17 → 0.1.13-beta.19

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 (37) hide show
  1. package/CHANGELOG.md +1162 -0
  2. package/dist/config/cache.options.d.ts.map +1 -1
  3. package/dist/config/cache.options.js +2 -2
  4. package/dist/config/cache.options.js.map +1 -1
  5. package/dist/constants/media-file-types.d.ts.map +1 -1
  6. package/dist/constants/media-file-types.js +19 -1
  7. package/dist/constants/media-file-types.js.map +1 -1
  8. package/dist/controllers/authentication.controller.d.ts +1 -1
  9. package/dist/controllers/authentication.controller.d.ts.map +1 -1
  10. package/dist/controllers/authentication.controller.js +4 -3
  11. package/dist/controllers/authentication.controller.js.map +1 -1
  12. package/dist/helpers/solid-microservice-adapter.service.d.ts.map +1 -1
  13. package/dist/helpers/solid-microservice-adapter.service.js +1 -1
  14. package/dist/helpers/solid-microservice-adapter.service.js.map +1 -1
  15. package/dist/interfaces/active-user-data.interface.d.ts +1 -0
  16. package/dist/interfaces/active-user-data.interface.d.ts.map +1 -1
  17. package/dist/interfaces/active-user-data.interface.js.map +1 -1
  18. package/dist/services/api-key.service.d.ts.map +1 -1
  19. package/dist/services/api-key.service.js +1 -1
  20. package/dist/services/api-key.service.js.map +1 -1
  21. package/dist/services/authentication.service.d.ts +5 -4
  22. package/dist/services/authentication.service.d.ts.map +1 -1
  23. package/dist/services/authentication.service.js +50 -19
  24. package/dist/services/authentication.service.js.map +1 -1
  25. package/dist/services/refresh-token-ids-storage.service.d.ts +25 -6
  26. package/dist/services/refresh-token-ids-storage.service.d.ts.map +1 -1
  27. package/dist/services/refresh-token-ids-storage.service.js +80 -42
  28. package/dist/services/refresh-token-ids-storage.service.js.map +1 -1
  29. package/package.json +2 -2
  30. package/src/config/cache.options.ts +9 -1
  31. package/src/constants/media-file-types.ts +27 -1
  32. package/src/controllers/authentication.controller.ts +5 -2
  33. package/src/helpers/solid-microservice-adapter.service.ts +6 -1
  34. package/src/interfaces/active-user-data.interface.ts +9 -0
  35. package/src/services/api-key.service.ts +13 -1
  36. package/src/services/authentication.service.ts +127 -36
  37. package/src/services/refresh-token-ids-storage.service.ts +229 -90
@@ -1 +1 @@
1
- {"version":3,"file":"cache.options.d.ts","sourceRoot":"","sources":["../../src/config/cache.options.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AAKhE,eAAO,MAAM,mBAAmB,EAAE,uBAmBjC,CAAC"}
1
+ {"version":3,"file":"cache.options.d.ts","sourceRoot":"","sources":["../../src/config/cache.options.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AAahE,eAAO,MAAM,mBAAmB,EAAE,uBAmBjC,CAAC"}
@@ -2,7 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.CacheManagerOptions = void 0;
4
4
  const config_1 = require("@nestjs/config");
5
- const cache_manager_redis_store_1 = require("cache-manager-redis-store");
5
+ const cache_manager_redis_yet_1 = require("cache-manager-redis-yet");
6
6
  const environment_helper_1 = require("../helpers/environment.helper");
7
7
  exports.CacheManagerOptions = {
8
8
  isGlobal: true,
@@ -21,7 +21,7 @@ exports.CacheManagerOptions = {
21
21
  inject: [config_1.ConfigService],
22
22
  };
23
23
  async function createRedisStore(configService) {
24
- return await (0, cache_manager_redis_store_1.redisStore)({
24
+ return await (0, cache_manager_redis_yet_1.redisStore)({
25
25
  socket: {
26
26
  host: configService.get('REDIS_HOST'),
27
27
  port: parseInt(configService.get('REDIS_PORT')),
@@ -1 +1 @@
1
- {"version":3,"file":"cache.options.js","sourceRoot":"","sources":["../../src/config/cache.options.ts"],"names":[],"mappings":";;;AACA,2CAA6D;AAC7D,yEAAuD;AACvD,sEAAmE;AAEtD,QAAA,mBAAmB,GAA4B;IACxD,QAAQ,EAAE,IAAI;IACd,OAAO,EAAE,CAAC,qBAAY,CAAC;IACvB,UAAU,EAAE,KAAK,EAAE,aAA4B,EAAE,EAAE;QAG/C,IAAI,CAAC,IAAA,sCAAiB,EAAC,aAAa,CAAC,EAAE,CAAC;YACpC,OAAO;gBACH,GAAG,EAAE,CAAC;aACT,CAAA;QACL,CAAC;QAGD,MAAM,KAAK,GAAG,MAAM,gBAAgB,CAAC,aAAa,CAAC,CAAC;QACpD,OAAO;YACH,KAAK,EAAE,GAAG,EAAE,CAAC,KAAK;SACrB,CAAC;IACN,CAAC;IACD,MAAM,EAAE,CAAC,sBAAa,CAAC;CAC1B,CAAC;AAEF,KAAK,UAAU,gBAAgB,CAAC,aAA4D;IACxF,OAAO,MAAM,IAAA,sCAAU,EAAC;QACpB,MAAM,EAAE;YACJ,IAAI,EAAE,aAAa,CAAC,GAAG,CAAS,YAAY,CAAC;YAC7C,IAAI,EAAE,QAAQ,CAAC,aAAa,CAAC,GAAG,CAAS,YAAY,CAAE,CAAC;SAC3D;KACJ,CAAC,CAAC;AACP,CAAC","sourcesContent":["import { CacheModuleAsyncOptions } from '@nestjs/cache-manager';\nimport { ConfigModule, ConfigService } from '@nestjs/config';\nimport { redisStore } from 'cache-manager-redis-store';\nimport { isRedisConfigured } from 'src/helpers/environment.helper';\n\nexport const CacheManagerOptions: CacheModuleAsyncOptions = {\n isGlobal: true,\n imports: [ConfigModule],\n useFactory: async (configService: ConfigService) => {\n\n // This defaults to in-memory cache\n if (!isRedisConfigured(configService)) {\n return {\n ttl: 0\n }\n }\n\n // If redis is configured we use that...\n const store = await createRedisStore(configService);\n return {\n store: () => store,\n };\n },\n inject: [ConfigService],\n};\n\nasync function createRedisStore(configService: ConfigService<Record<string, unknown>, false>) {\n return await redisStore({\n socket: {\n host: configService.get<string>('REDIS_HOST'),\n port: parseInt(configService.get<string>('REDIS_PORT')!),\n },\n });\n}\n"]}
1
+ {"version":3,"file":"cache.options.js","sourceRoot":"","sources":["../../src/config/cache.options.ts"],"names":[],"mappings":";;;AACA,2CAA6D;AAS7D,qEAAqD;AACrD,sEAAmE;AAEtD,QAAA,mBAAmB,GAA4B;IACxD,QAAQ,EAAE,IAAI;IACd,OAAO,EAAE,CAAC,qBAAY,CAAC;IACvB,UAAU,EAAE,KAAK,EAAE,aAA4B,EAAE,EAAE;QAG/C,IAAI,CAAC,IAAA,sCAAiB,EAAC,aAAa,CAAC,EAAE,CAAC;YACpC,OAAO;gBACH,GAAG,EAAE,CAAC;aACT,CAAA;QACL,CAAC;QAGD,MAAM,KAAK,GAAG,MAAM,gBAAgB,CAAC,aAAa,CAAC,CAAC;QACpD,OAAO;YACH,KAAK,EAAE,GAAG,EAAE,CAAC,KAAK;SACrB,CAAC;IACN,CAAC;IACD,MAAM,EAAE,CAAC,sBAAa,CAAC;CAC1B,CAAC;AAEF,KAAK,UAAU,gBAAgB,CAAC,aAA4D;IACxF,OAAO,MAAM,IAAA,oCAAU,EAAC;QACpB,MAAM,EAAE;YACJ,IAAI,EAAE,aAAa,CAAC,GAAG,CAAS,YAAY,CAAC;YAC7C,IAAI,EAAE,QAAQ,CAAC,aAAa,CAAC,GAAG,CAAS,YAAY,CAAE,CAAC;SAC3D;KACJ,CAAC,CAAC;AACP,CAAC","sourcesContent":["import { CacheModuleAsyncOptions } from '@nestjs/cache-manager';\nimport { ConfigModule, ConfigService } from '@nestjs/config';\n// cache-manager-redis-yet, not cache-manager-redis-store. The latter stops at\n// 3.0.1 and implements the cache-manager v4 store contract: it expects an\n// options object and reads `options.ttl` in seconds. cache-manager v5 calls\n// `store.set(key, value, ttl)` with a bare number of milliseconds, so that\n// store found no `.ttl`, fell back to an unset default, and issued a plain\n// `SET` - silently discarding every TTL passed anywhere in the app and leaving\n// Redis keys that never expire. redis-yet implements the v5 contract and\n// writes with `PX`, so millisecond TTLs land correctly.\nimport { redisStore } from 'cache-manager-redis-yet';\nimport { isRedisConfigured } from 'src/helpers/environment.helper';\n\nexport const CacheManagerOptions: CacheModuleAsyncOptions = {\n isGlobal: true,\n imports: [ConfigModule],\n useFactory: async (configService: ConfigService) => {\n\n // This defaults to in-memory cache\n if (!isRedisConfigured(configService)) {\n return {\n ttl: 0\n }\n }\n\n // If redis is configured we use that...\n const store = await createRedisStore(configService);\n return {\n store: () => store,\n };\n },\n inject: [ConfigService],\n};\n\nasync function createRedisStore(configService: ConfigService<Record<string, unknown>, false>) {\n return await redisStore({\n socket: {\n host: configService.get<string>('REDIS_HOST'),\n port: parseInt(configService.get<string>('REDIS_PORT')!),\n },\n });\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"media-file-types.d.ts","sourceRoot":"","sources":["../../src/constants/media-file-types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG,OAAO,GAAG,OAAO,GAAG,MAAM,GAAG,KAAK,CAAC;AAEzE,eAAO,MAAM,gBAAgB,qDAAsD,CAAC;AAapF,eAAO,MAAM,oBAAoB,aAI/B,CAAC;AAQH,eAAO,MAAM,oBAAoB,aAE/B,CAAC;AAcH,wBAAgB,yBAAyB,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAkB1E;AAOD,wBAAgB,yBAAyB,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,GAAG,SAAS,CAStF;AAWD,wBAAgB,iCAAiC,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,EAAE,CAGpF;AAGD,MAAM,WAAW,gBAAgB;IAC7B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACrB;AAGD,wBAAgB,mBAAmB,CAAC,IAAI,CAAC,EAAE,gBAAgB,GAAG,IAAI,GAAG,MAAM,CAE1E;AAQD,wBAAgB,oBAAoB,CAAC,IAAI,CAAC,EAAE,gBAAgB,GAAG,IAAI,GAAG,OAAO,CAO5E;AASD,eAAO,MAAM,iBAAiB,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAM3D,CAAC;AAMF,eAAO,MAAM,sBAAsB,aAKjC,CAAC"}
1
+ {"version":3,"file":"media-file-types.d.ts","sourceRoot":"","sources":["../../src/constants/media-file-types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG,OAAO,GAAG,OAAO,GAAG,MAAM,GAAG,KAAK,CAAC;AAEzE,eAAO,MAAM,gBAAgB,qDAAsD,CAAC;AAapF,eAAO,MAAM,oBAAoB,aAI/B,CAAC;AAQH,eAAO,MAAM,oBAAoB,aAE/B,CAAC;AAuCH,wBAAgB,yBAAyB,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAmB1E;AAOD,wBAAgB,yBAAyB,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,GAAG,SAAS,CAStF;AAWD,wBAAgB,iCAAiC,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,EAAE,CAGpF;AAGD,MAAM,WAAW,gBAAgB;IAC7B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACrB;AAGD,wBAAgB,mBAAmB,CAAC,IAAI,CAAC,EAAE,gBAAgB,GAAG,IAAI,GAAG,MAAM,CAE1E;AAQD,wBAAgB,oBAAoB,CAAC,IAAI,CAAC,EAAE,gBAAgB,GAAG,IAAI,GAAG,OAAO,CAO5E;AASD,eAAO,MAAM,iBAAiB,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAM3D,CAAC;AAMF,eAAO,MAAM,sBAAsB,aAKjC,CAAC"}
@@ -20,11 +20,29 @@ exports.DANGEROUS_EXTENSIONS = new Set([
20
20
  exports.DANGEROUS_MIME_TYPES = new Set([
21
21
  'image/svg+xml', 'text/html', 'application/xhtml+xml',
22
22
  ]);
23
+ function decodePercentEncodingSafely(name) {
24
+ let decoded = name;
25
+ for (let i = 0; i < 3; i++) {
26
+ let next;
27
+ try {
28
+ next = decodeURIComponent(decoded);
29
+ }
30
+ catch {
31
+ return decoded;
32
+ }
33
+ if (next === decoded) {
34
+ return decoded;
35
+ }
36
+ decoded = next;
37
+ }
38
+ return decoded;
39
+ }
23
40
  function normalizeUploadedFileName(fileName) {
24
41
  if (!fileName) {
25
42
  return '';
26
43
  }
27
- let name = String(fileName).split(/[/\\]/).pop() ?? '';
44
+ let name = decodePercentEncodingSafely(String(fileName));
45
+ name = name.split(/[/\\]/).pop() ?? '';
28
46
  const nulIndex = name.indexOf('\0');
29
47
  if (nulIndex >= 0) {
30
48
  name = name.slice(0, nulIndex);
@@ -1 +1 @@
1
- {"version":3,"file":"media-file-types.js","sourceRoot":"","sources":["../../src/constants/media-file-types.ts"],"names":[],"mappings":";;;AA2CA,8DAkBC;AAOD,8DASC;AAWD,8EAGC;AAUD,kDAEC;AAQD,oDAOC;AApHY,QAAA,gBAAgB,GAAG,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,CAAU,CAAC;AAEpF,MAAM,gBAAgB,GAAG,CAAC,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;AAC9F,MAAM,gBAAgB,GAAG,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;AAC7E,MAAM,gBAAgB,GAAG,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC;AAClG,MAAM,mBAAmB,GAAG,CAAC,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC;AAC1H,MAAM,aAAa,GAAG,KAAK,CAAC;AAOf,QAAA,oBAAoB,GAAG,IAAI,GAAG,CAAC;IACxC,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK;IACpC,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM;IACjD,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK;CACjD,CAAC,CAAC;AAQU,QAAA,oBAAoB,GAAG,IAAI,GAAG,CAAC;IACxC,eAAe,EAAE,WAAW,EAAE,uBAAuB;CACxD,CAAC,CAAC;AAcH,SAAgB,yBAAyB,CAAC,QAAwB;IAC9D,IAAI,CAAC,QAAQ,EAAE,CAAC;QACZ,OAAO,EAAE,CAAC;IACd,CAAC;IAED,IAAI,IAAI,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC;IAEvD,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IACpC,IAAI,QAAQ,IAAI,CAAC,EAAE,CAAC;QAChB,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;IACnC,CAAC;IAED,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IACtC,IAAI,WAAW,IAAI,CAAC,EAAE,CAAC;QACnB,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,WAAW,CAAC,CAAC;IACtC,CAAC;IAED,OAAO,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;AACvC,CAAC;AAOD,SAAgB,yBAAyB,CAAC,QAAwB;IAC9D,MAAM,IAAI,GAAG,yBAAyB,CAAC,QAAQ,CAAC,CAAC;IAEjD,MAAM,YAAY,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;IAC3C,IAAI,YAAY,GAAG,CAAC,IAAI,YAAY,KAAK,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvD,OAAO,SAAS,CAAC;IACrB,CAAC;IAED,OAAO,IAAI,CAAC,KAAK,CAAC,YAAY,GAAG,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC;AACtD,CAAC;AAWD,SAAgB,iCAAiC,CAAC,QAAwB;IACtE,MAAM,QAAQ,GAAG,yBAAyB,CAAC,QAAQ,CAAC,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC9E,OAAO,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;AACnE,CAAC;AAUD,SAAgB,mBAAmB,CAAC,IAA8B;IAC9D,OAAO,IAAI,EAAE,YAAY,IAAI,IAAI,EAAE,QAAQ,IAAI,EAAE,CAAC;AACtD,CAAC;AAQD,SAAgB,oBAAoB,CAAC,IAA8B;IAC/D,MAAM,QAAQ,GAAG,iCAAiC,CAAC,mBAAmB,CAAC,IAAI,CAAC,CAAC,CAAC;IAC9E,IAAI,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,4BAAoB,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC;QAC9D,OAAO,IAAI,CAAC;IAChB,CAAC;IAED,OAAO,4BAAoB,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,QAAQ,IAAI,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC;AACjF,CAAC;AASY,QAAA,iBAAiB,GAAkC;IAC5D,GAAG,MAAM,CAAC,WAAW,CAAC,gBAAgB,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,GAAG,EAAE,OAAgB,CAAC,CAAC,CAAC;IAC7E,GAAG,MAAM,CAAC,WAAW,CAAC,gBAAgB,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,GAAG,EAAE,OAAgB,CAAC,CAAC,CAAC;IAC7E,GAAG,MAAM,CAAC,WAAW,CAAC,gBAAgB,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,GAAG,EAAE,OAAgB,CAAC,CAAC,CAAC;IAC7E,GAAG,MAAM,CAAC,WAAW,CAAC,mBAAmB,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,GAAG,EAAE,MAAe,CAAC,CAAC,CAAC;IAC/E,CAAC,aAAa,CAAC,EAAE,KAAK;CACzB,CAAC;AAMW,QAAA,sBAAsB,GAAG,IAAI,GAAG,CAAS;IAClD,GAAG,gBAAgB;IACnB,GAAG,gBAAgB;IACnB,GAAG,gBAAgB;IACnB,aAAa;CAChB,CAAC,CAAC","sourcesContent":["export type MediaCategory = 'image' | 'audio' | 'video' | 'file' | 'pdf';\n\nexport const MEDIA_CATEGORIES = ['image', 'audio', 'video', 'file', 'pdf'] as const;\n\nconst IMAGE_EXTENSIONS = ['png', 'jpg', 'jpeg', 'webp', 'gif', 'bmp', 'tiff', 'heic', 'heif'];\nconst AUDIO_EXTENSIONS = ['mp3', 'wav', 'ogg', 'aac', 'm4a', 'flac', 'webm'];\nconst VIDEO_EXTENSIONS = ['mp4', 'mov', 'avi', 'mkv', 'mpeg', 'mpg', '3gp', '3g2', 'webm', 'ogg'];\nconst DOCUMENT_EXTENSIONS = ['txt', 'md', 'csv', 'json', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'zip', 'rar', '7z'];\nconst PDF_EXTENSION = 'pdf';\n\n/**\n * Extensions that must never be accepted as media uploads, regardless of declared mimetype or\n * admin-configured mediaTypes allowlist. Checked before any other resolution so a spoofed\n * Content-Type (e.g. application/octet-stream on an .html file) can't bypass this.\n */\nexport const DANGEROUS_EXTENSIONS = new Set([\n 'html', 'htm', 'xhtml', 'svg', 'xml',\n 'js', 'mjs', 'php', 'phtml', 'jsp', 'asp', 'aspx',\n 'exe', 'sh', 'bat', 'cmd', 'ps1', 'jar', 'dll',\n]);\n\n\n/**\n * Mimetypes that are never safe to accept, regardless of extension. These render as active\n * content in a browser (svg can carry <script>), so they are rejected even when the filename\n * looks harmless. Kept alongside DANGEROUS_EXTENSIONS so upload paths check both.\n */\nexport const DANGEROUS_MIME_TYPES = new Set([\n 'image/svg+xml', 'text/html', 'application/xhtml+xml',\n]);\n\n/**\n * Reduces a client-supplied name to the name that will actually be resolved on disk, so\n * extension checks can't be dodged by decorating it. Each step defends a known bypass:\n *\n * - `../../evil.exe` -> only the final path segment is the file name.\n * - `evil.exe\\0.png` -> a NUL truncates the name at the syscall/filesystem layer, so\n * anything after it is invisible to the OS but visible to naive\n * validation.\n * - `evil.exe::$DATA` -> NTFS alternate data stream suffix; the file on disk is evil.exe.\n * - `evil.exe.` / `.exe ` -> Windows silently strips trailing dots and spaces when resolving\n * a path, so these land on disk as evil.exe.\n */\nexport function normalizeUploadedFileName(fileName?: string | null): string {\n if (!fileName) {\n return '';\n }\n\n let name = String(fileName).split(/[/\\\\]/).pop() ?? '';\n\n const nulIndex = name.indexOf('\\0');\n if (nulIndex >= 0) {\n name = name.slice(0, nulIndex);\n }\n\n const streamIndex = name.indexOf(':');\n if (streamIndex >= 0) {\n name = name.slice(0, streamIndex);\n }\n\n return name.replace(/[\\s.]+$/, '');\n}\n\n/**\n * The effective extension - what the OS/browser will treat the file as. Used for media\n * category resolution and inline-safety decisions. Always normalizes first, so\n * `evil.exe.` resolves to `exe` rather than to nothing.\n */\nexport function getLowercaseFileExtension(fileName?: string | null): string | undefined {\n const name = normalizeUploadedFileName(fileName);\n\n const lastDotIndex = name.lastIndexOf('.');\n if (lastDotIndex < 0 || lastDotIndex === name.length - 1) {\n return undefined;\n }\n\n return name.slice(lastDotIndex + 1).toLowerCase();\n}\n\n/**\n * Every dot-delimited segment after the stem, lowercased. The danger check uses this rather\n * than only the effective extension so a dangerous type buried in a double extension\n * (`evil.exe.png`, `shell.php.jpg`) is still caught - several servers and browsers resolve\n * such names by an earlier segment than the last one.\n *\n * The stem is skipped so an innocuous file that merely starts with a keyword (`exe.png`)\n * isn't rejected.\n */\nexport function getLowercaseFileExtensionSegments(fileName?: string | null): string[] {\n const segments = normalizeUploadedFileName(fileName).toLowerCase().split('.');\n return segments.slice(1).filter(segment => segment.length > 0);\n}\n\n/** Minimal shape of an uploaded file, so this module stays free of framework imports. */\nexport interface UploadedFileLike {\n mimetype?: string;\n originalname?: string;\n filename?: string;\n}\n\n/** originalname is the client-supplied name; filename is multer's on-disk name. */\nexport function getUploadedFileName(file?: UploadedFileLike | null): string {\n return file?.originalname ?? file?.filename ?? '';\n}\n\n/**\n * Single predicate for \"must never be stored\". Shared by every upload entry point\n * (MediaFieldCrudManager, chatter attachments) so the rules can't drift between them.\n * Extensions are checked before mimetype so a spoofed Content-Type (e.g.\n * application/octet-stream, or image/png, on an .html file) can't bypass it.\n */\nexport function isDangerousMediaFile(file?: UploadedFileLike | null): boolean {\n const segments = getLowercaseFileExtensionSegments(getUploadedFileName(file));\n if (segments.some(segment => DANGEROUS_EXTENSIONS.has(segment))) {\n return true;\n }\n\n return DANGEROUS_MIME_TYPES.has((file?.mimetype || '').toLowerCase().trim());\n}\n\n/**\n * Single source of truth for extension -> coarse media category. Shared by upload-time\n * validation (MediaFieldCrudManager) and serve-time header hardening (ServeStaticModule), so\n * both agree on which extensions belong to which category and neither drifts out of sync.\n * webm/ogg are shared between AUDIO_EXTENSIONS and VIDEO_EXTENSIONS - last one wins here, they\n * default to 'video' since that's the more common upload case.\n */\nexport const EXT_TO_MEDIA_TYPE: Record<string, MediaCategory> = {\n ...Object.fromEntries(IMAGE_EXTENSIONS.map((ext) => [ext, 'image' as const])),\n ...Object.fromEntries(AUDIO_EXTENSIONS.map((ext) => [ext, 'audio' as const])),\n ...Object.fromEntries(VIDEO_EXTENSIONS.map((ext) => [ext, 'video' as const])),\n ...Object.fromEntries(DOCUMENT_EXTENSIONS.map((ext) => [ext, 'file' as const])),\n [PDF_EXTENSION]: 'pdf',\n};\n\n/**\n * Extensions safe to serve inline with their natural Content-Type; everything else served from\n * media-files-storage is forced to application/octet-stream + Content-Disposition: attachment.\n */\nexport const INLINE_SAFE_EXTENSIONS = new Set<string>([\n ...IMAGE_EXTENSIONS,\n ...AUDIO_EXTENSIONS,\n ...VIDEO_EXTENSIONS,\n PDF_EXTENSION,\n]);\n"]}
1
+ {"version":3,"file":"media-file-types.js","sourceRoot":"","sources":["../../src/constants/media-file-types.ts"],"names":[],"mappings":"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","sourcesContent":["export type MediaCategory = 'image' | 'audio' | 'video' | 'file' | 'pdf';\n\nexport const MEDIA_CATEGORIES = ['image', 'audio', 'video', 'file', 'pdf'] as const;\n\nconst IMAGE_EXTENSIONS = ['png', 'jpg', 'jpeg', 'webp', 'gif', 'bmp', 'tiff', 'heic', 'heif'];\nconst AUDIO_EXTENSIONS = ['mp3', 'wav', 'ogg', 'aac', 'm4a', 'flac', 'webm'];\nconst VIDEO_EXTENSIONS = ['mp4', 'mov', 'avi', 'mkv', 'mpeg', 'mpg', '3gp', '3g2', 'webm', 'ogg'];\nconst DOCUMENT_EXTENSIONS = ['txt', 'md', 'csv', 'json', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'zip', 'rar', '7z'];\nconst PDF_EXTENSION = 'pdf';\n\n/**\n * Extensions that must never be accepted as media uploads, regardless of declared mimetype or\n * admin-configured mediaTypes allowlist. Checked before any other resolution so a spoofed\n * Content-Type (e.g. application/octet-stream on an .html file) can't bypass this.\n */\nexport const DANGEROUS_EXTENSIONS = new Set([\n 'html', 'htm', 'xhtml', 'svg', 'xml',\n 'js', 'mjs', 'php', 'phtml', 'jsp', 'asp', 'aspx',\n 'exe', 'sh', 'bat', 'cmd', 'ps1', 'jar', 'dll',\n]);\n\n\n/**\n * Mimetypes that are never safe to accept, regardless of extension. These render as active\n * content in a browser (svg can carry <script>), so they are rejected even when the filename\n * looks harmless. Kept alongside DANGEROUS_EXTENSIONS so upload paths check both.\n */\nexport const DANGEROUS_MIME_TYPES = new Set([\n 'image/svg+xml', 'text/html', 'application/xhtml+xml',\n]);\n\n/**\n * Percent-decodes a filename, repeating a bounded number of times so a double-encoded payload\n * (`%252e` -> `%2e` -> `.`) survives a single pass through a proxy/framework that already\n * decoded once. Malformed escape sequences are left as-is rather than thrown, since this runs\n * on attacker-controlled input and a literal `%` in a filename (`100%done.pdf`) is legal.\n */\nfunction decodePercentEncodingSafely(name: string): string {\n let decoded = name;\n for (let i = 0; i < 3; i++) {\n let next: string;\n try {\n next = decodeURIComponent(decoded);\n } catch {\n return decoded;\n }\n if (next === decoded) {\n return decoded;\n }\n decoded = next;\n }\n return decoded;\n}\n\n/**\n * Reduces a client-supplied name to the name that will actually be resolved on disk, so\n * extension checks can't be dodged by decorating it. Each step defends a known bypass:\n *\n * - `evil.exe%2e` -> percent-encoding a trailing dot (or anything else) hides the real\n * extension from naive string matching; decode before inspecting it.\n * - `../../evil.exe` -> only the final path segment is the file name.\n * - `evil.exe\\0.png` -> a NUL truncates the name at the syscall/filesystem layer, so\n * anything after it is invisible to the OS but visible to naive\n * validation.\n * - `evil.exe::$DATA` -> NTFS alternate data stream suffix; the file on disk is evil.exe.\n * - `evil.exe.` / `.exe ` -> Windows silently strips trailing dots and spaces when resolving\n * a path, so these land on disk as evil.exe.\n */\nexport function normalizeUploadedFileName(fileName?: string | null): string {\n if (!fileName) {\n return '';\n }\n\n let name = decodePercentEncodingSafely(String(fileName));\n name = name.split(/[/\\\\]/).pop() ?? '';\n\n const nulIndex = name.indexOf('\\0');\n if (nulIndex >= 0) {\n name = name.slice(0, nulIndex);\n }\n\n const streamIndex = name.indexOf(':');\n if (streamIndex >= 0) {\n name = name.slice(0, streamIndex);\n }\n\n return name.replace(/[\\s.]+$/, '');\n}\n\n/**\n * The effective extension - what the OS/browser will treat the file as. Used for media\n * category resolution and inline-safety decisions. Always normalizes first, so\n * `evil.exe.` resolves to `exe` rather than to nothing.\n */\nexport function getLowercaseFileExtension(fileName?: string | null): string | undefined {\n const name = normalizeUploadedFileName(fileName);\n\n const lastDotIndex = name.lastIndexOf('.');\n if (lastDotIndex < 0 || lastDotIndex === name.length - 1) {\n return undefined;\n }\n\n return name.slice(lastDotIndex + 1).toLowerCase();\n}\n\n/**\n * Every dot-delimited segment after the stem, lowercased. The danger check uses this rather\n * than only the effective extension so a dangerous type buried in a double extension\n * (`evil.exe.png`, `shell.php.jpg`) is still caught - several servers and browsers resolve\n * such names by an earlier segment than the last one.\n *\n * The stem is skipped so an innocuous file that merely starts with a keyword (`exe.png`)\n * isn't rejected.\n */\nexport function getLowercaseFileExtensionSegments(fileName?: string | null): string[] {\n const segments = normalizeUploadedFileName(fileName).toLowerCase().split('.');\n return segments.slice(1).filter(segment => segment.length > 0);\n}\n\n/** Minimal shape of an uploaded file, so this module stays free of framework imports. */\nexport interface UploadedFileLike {\n mimetype?: string;\n originalname?: string;\n filename?: string;\n}\n\n/** originalname is the client-supplied name; filename is multer's on-disk name. */\nexport function getUploadedFileName(file?: UploadedFileLike | null): string {\n return file?.originalname ?? file?.filename ?? '';\n}\n\n/**\n * Single predicate for \"must never be stored\". Shared by every upload entry point\n * (MediaFieldCrudManager, chatter attachments) so the rules can't drift between them.\n * Extensions are checked before mimetype so a spoofed Content-Type (e.g.\n * application/octet-stream, or image/png, on an .html file) can't bypass it.\n */\nexport function isDangerousMediaFile(file?: UploadedFileLike | null): boolean {\n const segments = getLowercaseFileExtensionSegments(getUploadedFileName(file));\n if (segments.some(segment => DANGEROUS_EXTENSIONS.has(segment))) {\n return true;\n }\n\n return DANGEROUS_MIME_TYPES.has((file?.mimetype || '').toLowerCase().trim());\n}\n\n/**\n * Single source of truth for extension -> coarse media category. Shared by upload-time\n * validation (MediaFieldCrudManager) and serve-time header hardening (ServeStaticModule), so\n * both agree on which extensions belong to which category and neither drifts out of sync.\n * webm/ogg are shared between AUDIO_EXTENSIONS and VIDEO_EXTENSIONS - last one wins here, they\n * default to 'video' since that's the more common upload case.\n */\nexport const EXT_TO_MEDIA_TYPE: Record<string, MediaCategory> = {\n ...Object.fromEntries(IMAGE_EXTENSIONS.map((ext) => [ext, 'image' as const])),\n ...Object.fromEntries(AUDIO_EXTENSIONS.map((ext) => [ext, 'audio' as const])),\n ...Object.fromEntries(VIDEO_EXTENSIONS.map((ext) => [ext, 'video' as const])),\n ...Object.fromEntries(DOCUMENT_EXTENSIONS.map((ext) => [ext, 'file' as const])),\n [PDF_EXTENSION]: 'pdf',\n};\n\n/**\n * Extensions safe to serve inline with their natural Content-Type; everything else served from\n * media-files-storage is forced to application/octet-stream + Content-Disposition: attachment.\n */\nexport const INLINE_SAFE_EXTENSIONS = new Set<string>([\n ...IMAGE_EXTENSIONS,\n ...AUDIO_EXTENSIONS,\n ...VIDEO_EXTENSIONS,\n PDF_EXTENSION,\n]);\n"]}
@@ -64,7 +64,7 @@ export declare class AuthenticationController {
64
64
  };
65
65
  refreshToken: string;
66
66
  }>;
67
- logout(refreshToken: string): Promise<{
67
+ logout(refreshToken: string, allDevices?: boolean): Promise<{
68
68
  message: string;
69
69
  }>;
70
70
  generateApiKey(dto: CreateApiKeyDto, activeUser: ActiveUserData): Promise<{
@@ -1 +1 @@
1
- {"version":3,"file":"authentication.controller.d.ts","sourceRoot":"","sources":["../../src/controllers/authentication.controller.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAGnC,OAAO,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAChE,OAAO,EAAE,wBAAwB,EAAE,MAAM,qCAAqC,CAAC;AAC/E,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAC7D,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAC7D,OAAO,EAAE,yBAAyB,EAAE,MAAM,sCAAsC,CAAC;AACjF,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAC5D,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC1D,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAChD,OAAO,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AAClE,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,MAAM,0CAA0C,CAAC;AAC1E,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAC5D,OAAO,EAAE,qBAAqB,EAAE,MAAM,oCAAoC,CAAC;AAI3E,qBAIa,wBAAwB;IAI7B,OAAO,CAAC,QAAQ,CAAC,WAAW;IAC5B,OAAO,CAAC,QAAQ,CAAC,aAAa;IAJlC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA6C;gBAG/C,WAAW,EAAE,qBAAqB,EAClC,aAAa,EAAE,aAAa;IAMjD,MAAM,CAAS,SAAS,EAAE,SAAS;IAMnC,aAAa,CAAS,SAAS,EAAE,kBAAkB,EAAgB,UAAU,EAAE,cAAc;IAQvF,MAAM,CACoB,QAAQ,EAAE,QAAQ,EACtC,SAAS,EAAE,SAAS;;;;;;;;;;;;IAqBhC,aAAa,CAAS,eAAe,EAAE,eAAe;;;;IAOtD,sBAAsB,CAAS,yBAAyB,EAAE,yBAAyB;;;;;;;;;;;IAOnF,qBAAqB,CAAS,wBAAwB,EAAE,wBAAwB;;;;;;;IAMhF,cAAc,CAAS,iBAAiB,EAAE,iBAAiB,EAAgB,UAAU,EAAE,cAAc;IAMrG,EAAE,CACgB,UAAU,EAAE,cAAc;;;;;;;;;;IAStC,MAAM,CAAuB,YAAY,EAAE,MAAM;;;IAOvD,cAAc,CACF,GAAG,EAAE,eAAe,EACd,UAAU,EAAE,cAAc;;;;IAQ5C,qBAAqB,CACc,MAAM,EAAE,MAAM,EACrC,GAAG,EAAE,eAAe;;;;IAQhC,YAAY,CACmB,EAAE,EAAE,MAAM,EAC7B,GAAG,EAAE,eAAe,EACd,UAAU,EAAE,cAAc;IAQtC,QAAQ,CAA4B,MAAM,EAAE,MAAM;;;;;;;;;;;;IAMxD,eAAe,CACG,UAAU,EAAE,cAAc,EACd,aAAa,EAAE,MAAM;;;IASnD,eAAe,CAAS,cAAc,EAAE,cAAc;;;;;;;;;;;;CAGzD"}
1
+ {"version":3,"file":"authentication.controller.d.ts","sourceRoot":"","sources":["../../src/controllers/authentication.controller.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAGnC,OAAO,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAChE,OAAO,EAAE,wBAAwB,EAAE,MAAM,qCAAqC,CAAC;AAC/E,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAC7D,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAC7D,OAAO,EAAE,yBAAyB,EAAE,MAAM,sCAAsC,CAAC;AACjF,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAC5D,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC1D,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAChD,OAAO,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AAClE,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,MAAM,0CAA0C,CAAC;AAC1E,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAC5D,OAAO,EAAE,qBAAqB,EAAE,MAAM,oCAAoC,CAAC;AAI3E,qBAIa,wBAAwB;IAI7B,OAAO,CAAC,QAAQ,CAAC,WAAW;IAC5B,OAAO,CAAC,QAAQ,CAAC,aAAa;IAJlC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA6C;gBAG/C,WAAW,EAAE,qBAAqB,EAClC,aAAa,EAAE,aAAa;IAMjD,MAAM,CAAS,SAAS,EAAE,SAAS;IAMnC,aAAa,CAAS,SAAS,EAAE,kBAAkB,EAAgB,UAAU,EAAE,cAAc;IAQvF,MAAM,CACoB,QAAQ,EAAE,QAAQ,EACtC,SAAS,EAAE,SAAS;;;;;;;;;;;;IAqBhC,aAAa,CAAS,eAAe,EAAE,eAAe;;;;IAOtD,sBAAsB,CAAS,yBAAyB,EAAE,yBAAyB;;;;;;;;;;;IAOnF,qBAAqB,CAAS,wBAAwB,EAAE,wBAAwB;;;;;;;IAMhF,cAAc,CAAS,iBAAiB,EAAE,iBAAiB,EAAgB,UAAU,EAAE,cAAc;IAMrG,EAAE,CACgB,UAAU,EAAE,cAAc;;;;;;;;;;IAStC,MAAM,CACc,YAAY,EAAE,MAAM,EACtB,UAAU,CAAC,EAAE,OAAO;;;IAQ5C,cAAc,CACF,GAAG,EAAE,eAAe,EACd,UAAU,EAAE,cAAc;;;;IAQ5C,qBAAqB,CACc,MAAM,EAAE,MAAM,EACrC,GAAG,EAAE,eAAe;;;;IAQhC,YAAY,CACmB,EAAE,EAAE,MAAM,EAC7B,GAAG,EAAE,eAAe,EACd,UAAU,EAAE,cAAc;IAQtC,QAAQ,CAA4B,MAAM,EAAE,MAAM;;;;;;;;;;;;IAMxD,eAAe,CACG,UAAU,EAAE,cAAc,EACd,aAAa,EAAE,MAAM;;;IASnD,eAAe,CAAS,cAAc,EAAE,cAAc;;;;;;;;;;;;CAGzD"}
@@ -61,8 +61,8 @@ let AuthenticationController = AuthenticationController_1 = class Authentication
61
61
  me(activeUser) {
62
62
  return this.authService.me(activeUser);
63
63
  }
64
- async logout(refreshToken) {
65
- return this.authService.logout(refreshToken);
64
+ async logout(refreshToken, allDevices) {
65
+ return this.authService.logout(refreshToken, allDevices === true);
66
66
  }
67
67
  generateApiKey(dto, activeUser) {
68
68
  return this.apiKeyService.generate(activeUser.sub, dto);
@@ -169,8 +169,9 @@ __decorate([
169
169
  (0, common_1.HttpCode)(common_1.HttpStatus.OK),
170
170
  openapi.ApiResponse({ status: common_1.HttpStatus.OK }),
171
171
  __param(0, (0, common_1.Body)('refreshToken')),
172
+ __param(1, (0, common_1.Body)('allDevices')),
172
173
  __metadata("design:type", Function),
173
- __metadata("design:paramtypes", [String]),
174
+ __metadata("design:paramtypes", [String, Boolean]),
174
175
  __metadata("design:returntype", Promise)
175
176
  ], AuthenticationController.prototype, "logout", null);
176
177
  __decorate([
@@ -1 +1 @@
1
- {"version":3,"file":"authentication.controller.js","sourceRoot":"","sources":["../../src/controllers/authentication.controller.ts"],"names":[],"mappings":"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","sourcesContent":["import { Body, Controller, Get, HttpCode, HttpStatus, Logger, Param, ParseIntPipe, Patch, Post, Res, Headers } from '@nestjs/common';\nimport { ApiBearerAuth, ApiHeader, ApiTags } from '@nestjs/swagger';\nimport { Response } from 'express';\nimport { ActiveUser } from \"../decorators/active-user.decorator\";\nimport { Public } from '../decorators/public.decorator';\nimport { ChangePasswordDto } from \"../dtos/change-password.dto\";\nimport { ConfirmForgotPasswordDto } from '../dtos/confirm-forgot-password.dto';\nimport { CreateApiKeyDto } from '../dtos/create-api-key.dto';\nimport { UpdateApiKeyDto } from '../dtos/update-api-key.dto';\nimport { InitiateForgotPasswordDto } from '../dtos/initiate-forgot-password.dto';\nimport { RefreshTokenDto } from '../dtos/refresh-token.dto';\nimport { SsoExchangeDto } from '../dtos/sso-exchange.dto';\nimport { SignInDto } from '../dtos/sign-in.dto';\nimport { RegisterPrivateDto } from '../dtos/register-private.dto';\nimport { SignUpDto } from '../dtos/sign-up.dto';\nimport { ActiveUserData } from \"../interfaces/active-user-data.interface\";\nimport { ApiKeyService } from '../services/api-key.service';\nimport { AuthenticationService } from '../services/authentication.service';\n\n\n// @Auth(AuthType.None)\n@Controller('iam')\n@ApiTags(\"Solid Core\")\n// @UseGuards(ThrottlerGuard)\n// @SkipThrottle({login: true, short: true, burst: true, sustained: true}) // disable all sets by default for this controller\nexport class AuthenticationController {\n private readonly logger = new Logger(AuthenticationController.name);\n\n constructor(\n private readonly authService: AuthenticationService,\n private readonly apiKeyService: ApiKeyService,\n ) { }\n\n @Public()\n // @SkipThrottle({ login: false, short: true, burst: true, sustained: true }) //Enable the login throttle only\n @Post('register')\n signUp(@Body() signUpDto: SignUpDto) {\n return this.authService.signUp(signUpDto);\n }\n\n @ApiBearerAuth(\"jwt\")\n @Post('register-private')\n signUpPrivate(@Body() signUpDto: RegisterPrivateDto, @ActiveUser() activeUser: ActiveUserData) {\n return this.authService.signUp(signUpDto, activeUser);\n }\n\n @Public()\n // @SkipThrottle({ login: false, short: true, burst: true, sustained: true }) //Enable the login throttle only\n @HttpCode(HttpStatus.OK) // by default @Post does 201, we wanted 200 - hence using @HttpCode(HttpStatus.OK)\n @Post('authenticate')\n async signIn(\n @Res({ passthrough: true }) response: Response,\n @Body() signInDto: SignInDto\n ) {\n // This means that we are passing the token back in plain text. \n // This is less secure. \n // console.log(\"signInDto in Signin Controller\", signInDto);\n\n return this.authService.signIn(signInDto);\n\n // This means we are setting the token as a http only cookie.\n // const accessToken = await this.authService.signIn(signInDto);\n // response.cookie('accessToken', accessToken, {\n // secure: true,\n // httpOnly: true,\n // sameSite: true,\n // });\n }\n\n @Public()\n // @SkipThrottle({ login: false, short: true, burst: true, sustained: true }) //Enable the login throttle only\n @HttpCode(HttpStatus.OK) // changed since the default is 201\n @Post('refresh-tokens')\n refreshTokens(@Body() refreshTokenDto: RefreshTokenDto) {\n return this.authService.refreshTokens(refreshTokenDto);\n }\n\n @Public()\n // @SkipThrottle({ login: false, short: true, burst: true, sustained: true }) //Enable the login throttle only\n @Post('initiate/forgot-password')\n initiateForgotPassword(@Body() initiateForgotPasswordDto: InitiateForgotPasswordDto) {\n return this.authService.initiateForgotPassword(initiateForgotPasswordDto);\n }\n\n @Public()\n // @SkipThrottle({ login: false, short: true, burst: true, sustained: true }) //Enable the login throttle only\n @Post('confirm/forgot-password')\n confirmForgotPassword(@Body() confirmForgotPasswordDto: ConfirmForgotPasswordDto) {\n return this.authService.confirmForgotPassword(confirmForgotPasswordDto);\n }\n\n @ApiBearerAuth(\"jwt\")\n @Post('change-password')\n changePassword(@Body() changePasswordDto: ChangePasswordDto, @ActiveUser() activeUser: ActiveUserData) {\n return this.authService.changePassword(changePasswordDto, activeUser);\n }\n\n @ApiBearerAuth(\"jwt\")\n @Get('me')\n me(\n @ActiveUser() activeUser: ActiveUserData\n ) {\n return this.authService.me(activeUser);\n }\n\n @ApiBearerAuth(\"jwt\")\n @Post('logout')\n @Public()\n @HttpCode(HttpStatus.OK)\n async logout(@Body('refreshToken') refreshToken: string) {\n return this.authService.logout(refreshToken);\n }\n\n @ApiBearerAuth(\"jwt\")\n @Post('api-keys')\n @HttpCode(HttpStatus.CREATED)\n generateApiKey(\n @Body() dto: CreateApiKeyDto,\n @ActiveUser() activeUser: ActiveUserData,\n ) {\n return this.apiKeyService.generate(activeUser.sub, dto);\n }\n\n @ApiBearerAuth(\"jwt\")\n @Post('api-keys/users/:userId')\n @HttpCode(HttpStatus.CREATED)\n generateApiKeyForUser(\n @Param('userId', ParseIntPipe) userId: number,\n @Body() dto: CreateApiKeyDto,\n ) {\n return this.apiKeyService.generate(userId, dto);\n }\n\n @ApiBearerAuth(\"jwt\")\n @Patch('api-keys/:id')\n @HttpCode(HttpStatus.OK)\n updateApiKey(\n @Param('id', ParseIntPipe) id: number,\n @Body() dto: UpdateApiKeyDto,\n @ActiveUser() activeUser: ActiveUserData,\n ) {\n return this.apiKeyService.updateKey(id, activeUser.sub, dto);\n }\n\n @Public()\n @ApiHeader({ name: 'solidx-api-key', required: true, description: 'API key for authenticating the request' })\n @Get('api-keys/me')\n async apiKeyMe(@Headers('solidx-api-key') apiKey: string) {\n return this.apiKeyService.apiKeyMe(apiKey);\n }\n\n @Post('sso/code')\n @HttpCode(HttpStatus.OK)\n generateSsoCode(\n @ActiveUser() activeUser: ActiveUserData, \n @Headers('authorization') authorization: string,\n ) {\n const rawAccessToken = authorization?.replace(/^Bearer\\s+/i, '');\n return this.authService.generateSsoCode(activeUser, rawAccessToken);\n }\n\n @Public()\n @Post('sso/exchange')\n @HttpCode(HttpStatus.OK)\n exchangeSsoCode(@Body() ssoExchangeDto: SsoExchangeDto) {\n return this.authService.exchangeSsoCode(ssoExchangeDto.code);\n }\n}\n"]}
1
+ {"version":3,"file":"authentication.controller.js","sourceRoot":"","sources":["../../src/controllers/authentication.controller.ts"],"names":[],"mappings":"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","sourcesContent":["import { Body, Controller, Get, HttpCode, HttpStatus, Logger, Param, ParseIntPipe, Patch, Post, Res, Headers } from '@nestjs/common';\nimport { ApiBearerAuth, ApiHeader, ApiTags } from '@nestjs/swagger';\nimport { Response } from 'express';\nimport { ActiveUser } from \"../decorators/active-user.decorator\";\nimport { Public } from '../decorators/public.decorator';\nimport { ChangePasswordDto } from \"../dtos/change-password.dto\";\nimport { ConfirmForgotPasswordDto } from '../dtos/confirm-forgot-password.dto';\nimport { CreateApiKeyDto } from '../dtos/create-api-key.dto';\nimport { UpdateApiKeyDto } from '../dtos/update-api-key.dto';\nimport { InitiateForgotPasswordDto } from '../dtos/initiate-forgot-password.dto';\nimport { RefreshTokenDto } from '../dtos/refresh-token.dto';\nimport { SsoExchangeDto } from '../dtos/sso-exchange.dto';\nimport { SignInDto } from '../dtos/sign-in.dto';\nimport { RegisterPrivateDto } from '../dtos/register-private.dto';\nimport { SignUpDto } from '../dtos/sign-up.dto';\nimport { ActiveUserData } from \"../interfaces/active-user-data.interface\";\nimport { ApiKeyService } from '../services/api-key.service';\nimport { AuthenticationService } from '../services/authentication.service';\n\n\n// @Auth(AuthType.None)\n@Controller('iam')\n@ApiTags(\"Solid Core\")\n// @UseGuards(ThrottlerGuard)\n// @SkipThrottle({login: true, short: true, burst: true, sustained: true}) // disable all sets by default for this controller\nexport class AuthenticationController {\n private readonly logger = new Logger(AuthenticationController.name);\n\n constructor(\n private readonly authService: AuthenticationService,\n private readonly apiKeyService: ApiKeyService,\n ) { }\n\n @Public()\n // @SkipThrottle({ login: false, short: true, burst: true, sustained: true }) //Enable the login throttle only\n @Post('register')\n signUp(@Body() signUpDto: SignUpDto) {\n return this.authService.signUp(signUpDto);\n }\n\n @ApiBearerAuth(\"jwt\")\n @Post('register-private')\n signUpPrivate(@Body() signUpDto: RegisterPrivateDto, @ActiveUser() activeUser: ActiveUserData) {\n return this.authService.signUp(signUpDto, activeUser);\n }\n\n @Public()\n // @SkipThrottle({ login: false, short: true, burst: true, sustained: true }) //Enable the login throttle only\n @HttpCode(HttpStatus.OK) // by default @Post does 201, we wanted 200 - hence using @HttpCode(HttpStatus.OK)\n @Post('authenticate')\n async signIn(\n @Res({ passthrough: true }) response: Response,\n @Body() signInDto: SignInDto\n ) {\n // This means that we are passing the token back in plain text. \n // This is less secure. \n // console.log(\"signInDto in Signin Controller\", signInDto);\n\n return this.authService.signIn(signInDto);\n\n // This means we are setting the token as a http only cookie.\n // const accessToken = await this.authService.signIn(signInDto);\n // response.cookie('accessToken', accessToken, {\n // secure: true,\n // httpOnly: true,\n // sameSite: true,\n // });\n }\n\n @Public()\n // @SkipThrottle({ login: false, short: true, burst: true, sustained: true }) //Enable the login throttle only\n @HttpCode(HttpStatus.OK) // changed since the default is 201\n @Post('refresh-tokens')\n refreshTokens(@Body() refreshTokenDto: RefreshTokenDto) {\n return this.authService.refreshTokens(refreshTokenDto);\n }\n\n @Public()\n // @SkipThrottle({ login: false, short: true, burst: true, sustained: true }) //Enable the login throttle only\n @Post('initiate/forgot-password')\n initiateForgotPassword(@Body() initiateForgotPasswordDto: InitiateForgotPasswordDto) {\n return this.authService.initiateForgotPassword(initiateForgotPasswordDto);\n }\n\n @Public()\n // @SkipThrottle({ login: false, short: true, burst: true, sustained: true }) //Enable the login throttle only\n @Post('confirm/forgot-password')\n confirmForgotPassword(@Body() confirmForgotPasswordDto: ConfirmForgotPasswordDto) {\n return this.authService.confirmForgotPassword(confirmForgotPasswordDto);\n }\n\n @ApiBearerAuth(\"jwt\")\n @Post('change-password')\n changePassword(@Body() changePasswordDto: ChangePasswordDto, @ActiveUser() activeUser: ActiveUserData) {\n return this.authService.changePassword(changePasswordDto, activeUser);\n }\n\n @ApiBearerAuth(\"jwt\")\n @Get('me')\n me(\n @ActiveUser() activeUser: ActiveUserData\n ) {\n return this.authService.me(activeUser);\n }\n\n @ApiBearerAuth(\"jwt\")\n @Post('logout')\n @Public()\n @HttpCode(HttpStatus.OK)\n async logout(\n @Body('refreshToken') refreshToken: string,\n @Body('allDevices') allDevices?: boolean,\n ) {\n return this.authService.logout(refreshToken, allDevices === true);\n }\n\n @ApiBearerAuth(\"jwt\")\n @Post('api-keys')\n @HttpCode(HttpStatus.CREATED)\n generateApiKey(\n @Body() dto: CreateApiKeyDto,\n @ActiveUser() activeUser: ActiveUserData,\n ) {\n return this.apiKeyService.generate(activeUser.sub, dto);\n }\n\n @ApiBearerAuth(\"jwt\")\n @Post('api-keys/users/:userId')\n @HttpCode(HttpStatus.CREATED)\n generateApiKeyForUser(\n @Param('userId', ParseIntPipe) userId: number,\n @Body() dto: CreateApiKeyDto,\n ) {\n return this.apiKeyService.generate(userId, dto);\n }\n\n @ApiBearerAuth(\"jwt\")\n @Patch('api-keys/:id')\n @HttpCode(HttpStatus.OK)\n updateApiKey(\n @Param('id', ParseIntPipe) id: number,\n @Body() dto: UpdateApiKeyDto,\n @ActiveUser() activeUser: ActiveUserData,\n ) {\n return this.apiKeyService.updateKey(id, activeUser.sub, dto);\n }\n\n @Public()\n @ApiHeader({ name: 'solidx-api-key', required: true, description: 'API key for authenticating the request' })\n @Get('api-keys/me')\n async apiKeyMe(@Headers('solidx-api-key') apiKey: string) {\n return this.apiKeyService.apiKeyMe(apiKey);\n }\n\n @Post('sso/code')\n @HttpCode(HttpStatus.OK)\n generateSsoCode(\n @ActiveUser() activeUser: ActiveUserData, \n @Headers('authorization') authorization: string,\n ) {\n const rawAccessToken = authorization?.replace(/^Bearer\\s+/i, '');\n return this.authService.generateSsoCode(activeUser, rawAccessToken);\n }\n\n @Public()\n @Post('sso/exchange')\n @HttpCode(HttpStatus.OK)\n exchangeSsoCode(@Body() ssoExchangeDto: SsoExchangeDto) {\n return this.authService.exchangeSsoCode(ssoExchangeDto.code);\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"solid-microservice-adapter.service.d.ts","sourceRoot":"","sources":["../../src/helpers/solid-microservice-adapter.service.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAEtC,MAAM,WAAW,oBAAoB;IACnC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,mBAAmB,EAAE,OAAO,CAAC;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,aAAa,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,qBAAqB;IACpC,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,iBAAiB,CAAC;CACzB;AAED,qBACa,wBAAwB;IAIA,OAAO,CAAC,QAAQ,CAAC,YAAY;IAHhE,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA6C;IACpE,OAAO,CAAC,OAAO,CAAC,CAAS;gBAE2B,YAAY,EAAE,KAAK;IAEvE,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAK3B,YAAY,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,EAAE,oBAAoB,GAAG,OAAO,CAAC,qBAAqB,CAAC;IA0CvG,OAAO,CAAC,eAAe;IAIvB,OAAO,CAAC,gBAAgB;IAgBxB,OAAO,CAAC,iBAAiB;CAK1B"}
1
+ {"version":3,"file":"solid-microservice-adapter.service.d.ts","sourceRoot":"","sources":["../../src/helpers/solid-microservice-adapter.service.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAEtC,MAAM,WAAW,oBAAoB;IACnC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,mBAAmB,EAAE,OAAO,CAAC;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,aAAa,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,qBAAqB;IACpC,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,iBAAiB,CAAC;CACzB;AAED,qBACa,wBAAwB;IAIA,OAAO,CAAC,QAAQ,CAAC,YAAY;IAHhE,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA6C;IACpE,OAAO,CAAC,OAAO,CAAC,CAAS;gBAE2B,YAAY,EAAE,KAAK;IAEvE,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAK3B,YAAY,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,EAAE,oBAAoB,GAAG,OAAO,CAAC,qBAAqB,CAAC;IA+CvG,OAAO,CAAC,eAAe;IAIvB,OAAO,CAAC,gBAAgB;IAgBxB,OAAO,CAAC,iBAAiB;CAK1B"}
@@ -61,7 +61,7 @@ let SolidMicroserviceAdapter = SolidMicroserviceAdapter_1 = class SolidMicroserv
61
61
  const responseData = response.data;
62
62
  const ttlSeconds = this.getJwtTtlSeconds(responseData?.data?.accessToken);
63
63
  if (ttlSeconds && ttlSeconds > 0) {
64
- await this.cacheManager.set(cacheKey, responseData, ttlSeconds);
64
+ await this.cacheManager.set(cacheKey, responseData, ttlSeconds * 1000);
65
65
  }
66
66
  return responseData;
67
67
  }
@@ -1 +1 @@
1
- {"version":3,"file":"solid-microservice-adapter.service.js","sourceRoot":"","sources":["../../src/helpers/solid-microservice-adapter.service.ts"],"names":[],"mappings":"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","sourcesContent":["import { CACHE_MANAGER } from '@nestjs/cache-manager';\nimport { Inject, Injectable, Logger, Scope } from '@nestjs/common';\nimport axios from 'axios';\nimport { Cache } from 'cache-manager';\n\nexport interface SolidxIamAuthRequest {\n email?: string;\n username?: string;\n password: string;\n}\n\nexport interface SolidxIamUser {\n email: string;\n mobile: string;\n username: string;\n forcePasswordChange: boolean;\n id: number;\n roles: string[];\n}\n\nexport interface SolidxIamAuthData {\n user: SolidxIamUser;\n accessToken: string;\n refreshToken: string;\n}\n\nexport interface SolidxIamAuthResponse {\n statusCode: number;\n message: string[];\n error: string;\n data: SolidxIamAuthData;\n}\n\n@Injectable({ scope: Scope.TRANSIENT })\nexport class SolidMicroserviceAdapter {\n private readonly logger = new Logger(SolidMicroserviceAdapter.name);\n private baseUrl?: string;\n\n constructor(@Inject(CACHE_MANAGER) private readonly cacheManager: Cache) {}\n\n setBaseUrl(baseUrl: string): this {\n this.baseUrl = baseUrl;\n return this;\n }\n\n async authenticate({ email, username, password }: SolidxIamAuthRequest): Promise<SolidxIamAuthResponse> {\n if (!password) {\n throw new Error('password is required for IAM authentication');\n }\n if (!email && !username) {\n throw new Error('email or username is required for IAM authentication');\n }\n\n const cacheKey = this.getAuthCacheKey(email, username);\n const cachedResponse = (await this.cacheManager.get(cacheKey)) as SolidxIamAuthResponse | undefined;\n if (cachedResponse) {\n this.logger.debug(`IAM auth cache hit for ${cacheKey}`);\n return cachedResponse;\n }\n this.logger.debug(`IAM auth cache miss for ${cacheKey}`);\n\n if (!this.baseUrl) {\n throw new Error('baseUrl must be set before IAM authentication');\n }\n\n const payload: SolidxIamAuthRequest = { password };\n if (email) payload.email = email;\n if (username) payload.username = username;\n\n this.logger.debug(`Requesting IAM access token from ${this.baseUrl}/api/iam/authenticate`);\n\n const response = await axios.post(`${this.baseUrl}/api/iam/authenticate`, payload, {\n timeout: 10000,\n headers: {\n 'Content-Type': 'application/json',\n },\n });\n\n const responseData = response.data as SolidxIamAuthResponse;\n const ttlSeconds = this.getJwtTtlSeconds(responseData?.data?.accessToken);\n if (ttlSeconds && ttlSeconds > 0) {\n await this.cacheManager.set(cacheKey, responseData, ttlSeconds);\n }\n\n return responseData;\n }\n\n private getAuthCacheKey(email?: string, username?: string): string {\n return `iam-auth:${email ?? ''}:${username ?? ''}`;\n }\n\n private getJwtTtlSeconds(accessToken?: string): number | undefined {\n if (!accessToken) return undefined;\n const parts = accessToken.split('.');\n if (parts.length < 2) return undefined;\n try {\n const payloadJson = Buffer.from(this.base64UrlToBase64(parts[1]), 'base64').toString('utf-8');\n const payload = JSON.parse(payloadJson) as { exp?: number };\n if (!payload?.exp || typeof payload.exp !== 'number') return undefined;\n const nowSeconds = Math.floor(Date.now() / 1000);\n const ttl = payload.exp - nowSeconds - 10;\n return ttl > 0 ? ttl : undefined;\n } catch {\n return undefined;\n }\n }\n\n private base64UrlToBase64(value: string): string {\n const normalized = value.replace(/-/g, '+').replace(/_/g, '/');\n const padLength = (4 - (normalized.length % 4)) % 4;\n return normalized + '='.repeat(padLength);\n }\n}\n"]}
1
+ {"version":3,"file":"solid-microservice-adapter.service.js","sourceRoot":"","sources":["../../src/helpers/solid-microservice-adapter.service.ts"],"names":[],"mappings":"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","sourcesContent":["import { CACHE_MANAGER } from '@nestjs/cache-manager';\nimport { Inject, Injectable, Logger, Scope } from '@nestjs/common';\nimport axios from 'axios';\nimport { Cache } from 'cache-manager';\n\nexport interface SolidxIamAuthRequest {\n email?: string;\n username?: string;\n password: string;\n}\n\nexport interface SolidxIamUser {\n email: string;\n mobile: string;\n username: string;\n forcePasswordChange: boolean;\n id: number;\n roles: string[];\n}\n\nexport interface SolidxIamAuthData {\n user: SolidxIamUser;\n accessToken: string;\n refreshToken: string;\n}\n\nexport interface SolidxIamAuthResponse {\n statusCode: number;\n message: string[];\n error: string;\n data: SolidxIamAuthData;\n}\n\n@Injectable({ scope: Scope.TRANSIENT })\nexport class SolidMicroserviceAdapter {\n private readonly logger = new Logger(SolidMicroserviceAdapter.name);\n private baseUrl?: string;\n\n constructor(@Inject(CACHE_MANAGER) private readonly cacheManager: Cache) {}\n\n setBaseUrl(baseUrl: string): this {\n this.baseUrl = baseUrl;\n return this;\n }\n\n async authenticate({ email, username, password }: SolidxIamAuthRequest): Promise<SolidxIamAuthResponse> {\n if (!password) {\n throw new Error('password is required for IAM authentication');\n }\n if (!email && !username) {\n throw new Error('email or username is required for IAM authentication');\n }\n\n const cacheKey = this.getAuthCacheKey(email, username);\n const cachedResponse = (await this.cacheManager.get(cacheKey)) as SolidxIamAuthResponse | undefined;\n if (cachedResponse) {\n this.logger.debug(`IAM auth cache hit for ${cacheKey}`);\n return cachedResponse;\n }\n this.logger.debug(`IAM auth cache miss for ${cacheKey}`);\n\n if (!this.baseUrl) {\n throw new Error('baseUrl must be set before IAM authentication');\n }\n\n const payload: SolidxIamAuthRequest = { password };\n if (email) payload.email = email;\n if (username) payload.username = username;\n\n this.logger.debug(`Requesting IAM access token from ${this.baseUrl}/api/iam/authenticate`);\n\n const response = await axios.post(`${this.baseUrl}/api/iam/authenticate`, payload, {\n timeout: 10000,\n headers: {\n 'Content-Type': 'application/json',\n },\n });\n\n const responseData = response.data as SolidxIamAuthResponse;\n const ttlSeconds = this.getJwtTtlSeconds(responseData?.data?.accessToken);\n if (ttlSeconds && ttlSeconds > 0) {\n // cache-manager v5 expects milliseconds. This previously passed seconds,\n // which the old Redis store discarded outright - so the entry simply\n // never expired. Now that TTLs are honoured, passing seconds unconverted\n // would expire the cached token ~1000x too early and re-authenticate\n // against IAM on nearly every call.\n await this.cacheManager.set(cacheKey, responseData, ttlSeconds * 1000);\n }\n\n return responseData;\n }\n\n private getAuthCacheKey(email?: string, username?: string): string {\n return `iam-auth:${email ?? ''}:${username ?? ''}`;\n }\n\n private getJwtTtlSeconds(accessToken?: string): number | undefined {\n if (!accessToken) return undefined;\n const parts = accessToken.split('.');\n if (parts.length < 2) return undefined;\n try {\n const payloadJson = Buffer.from(this.base64UrlToBase64(parts[1]), 'base64').toString('utf-8');\n const payload = JSON.parse(payloadJson) as { exp?: number };\n if (!payload?.exp || typeof payload.exp !== 'number') return undefined;\n const nowSeconds = Math.floor(Date.now() / 1000);\n const ttl = payload.exp - nowSeconds - 10;\n return ttl > 0 ? ttl : undefined;\n } catch {\n return undefined;\n }\n }\n\n private base64UrlToBase64(value: string): string {\n const normalized = value.replace(/-/g, '+').replace(/_/g, '/');\n const padLength = (4 - (normalized.length % 4)) % 4;\n return normalized + '='.repeat(padLength);\n }\n}\n"]}
@@ -3,6 +3,7 @@ export interface ActiveUserData {
3
3
  username: string;
4
4
  email: string;
5
5
  sessionId?: string;
6
+ deviceKey?: string;
6
7
  roles: string[];
7
8
  permissions: string[];
8
9
  }
@@ -1 +1 @@
1
- {"version":3,"file":"active-user-data.interface.d.ts","sourceRoot":"","sources":["../../src/interfaces/active-user-data.interface.ts"],"names":[],"mappings":"AACA,MAAM,WAAW,cAAc;IAK7B,GAAG,EAAE,MAAM,CAAC;IAKZ,QAAQ,EAAE,MAAM,CAAC;IAKjB,KAAK,EAAE,MAAM,CAAC;IAMd,SAAS,CAAC,EAAE,MAAM,CAAC;IAMnB,KAAK,EAAE,MAAM,EAAE,CAAC;IAOhB,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB"}
1
+ {"version":3,"file":"active-user-data.interface.d.ts","sourceRoot":"","sources":["../../src/interfaces/active-user-data.interface.ts"],"names":[],"mappings":"AACA,MAAM,WAAW,cAAc;IAK7B,GAAG,EAAE,MAAM,CAAC;IAKZ,QAAQ,EAAE,MAAM,CAAC;IAKjB,KAAK,EAAE,MAAM,CAAC;IAMd,SAAS,CAAC,EAAE,MAAM,CAAC;IASnB,SAAS,CAAC,EAAE,MAAM,CAAC;IAMnB,KAAK,EAAE,MAAM,EAAE,CAAC;IAOhB,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB"}
@@ -1 +1 @@
1
- {"version":3,"file":"active-user-data.interface.js","sourceRoot":"","sources":["../../src/interfaces/active-user-data.interface.ts"],"names":[],"mappings":"","sourcesContent":["\nexport interface ActiveUserData {\n /**\n * The \"subject\" of the token. The value of this property is the user ID\n * that granted this token.\n */\n sub: number;\n\n /**\n * The subject's (user) username.\n */\n username: string;\n\n /**\n * The subject's (user) email.\n */\n email: string;\n\n /**\n * Logical login session identifier used to invalidate older sessions when\n * concurrent logins are disabled.\n */\n sessionId?: string;\n\n /**\n * The subject's (user) roles.\n * These are part of the JWT token, we simply decode them.\n */\n roles: string[];\n\n /**\n * The subject's (user) permissions.\n * These are not part of the JWT token, we query them from the database each time the access-token guard is run. \n * So basically each time an authenticated request is initiated, we end up loading all the users permissions.\n */\n permissions: string[];\n}\n"]}
1
+ {"version":3,"file":"active-user-data.interface.js","sourceRoot":"","sources":["../../src/interfaces/active-user-data.interface.ts"],"names":[],"mappings":"","sourcesContent":["\nexport interface ActiveUserData {\n /**\n * The \"subject\" of the token. The value of this property is the user ID\n * that granted this token.\n */\n sub: number;\n\n /**\n * The subject's (user) username.\n */\n username: string;\n\n /**\n * The subject's (user) email.\n */\n email: string;\n\n /**\n * Logical login session identifier used to invalidate older sessions when\n * concurrent logins are disabled.\n */\n sessionId?: string;\n\n /**\n * Identifies which per-device refresh-token bucket this session belongs to.\n * Present only while concurrent logins are permitted; mutually exclusive with\n * sessionId, which exists only when they are not. Carried on the access token\n * so bearer-authenticated endpoints that need this session's refresh token\n * can find it.\n */\n deviceKey?: string;\n\n /**\n * The subject's (user) roles.\n * These are part of the JWT token, we simply decode them.\n */\n roles: string[];\n\n /**\n * The subject's (user) permissions.\n * These are not part of the JWT token, we query them from the database each time the access-token guard is run. \n * So basically each time an authenticated request is initiated, we end up loading all the users permissions.\n */\n permissions: string[];\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"api-key.service.d.ts","sourceRoot":"","sources":["../../src/services/api-key.service.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAC9D,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAC9D,OAAO,EAAE,UAAU,EAAE,MAAM,kCAAkC,CAAC;AAE9D,OAAO,EAAE,cAAc,EAAE,MAAM,2CAA2C,CAAC;AAC3E,OAAO,EAAE,oBAAoB,EAAE,MAAM,wCAAwC,CAAC;AAC9E,OAAO,EAAE,yBAAyB,EAAE,MAAM,0CAA0C,CAAC;AACrF,OAAO,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AACjE,OAAO,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAEhE,qBACa,aAAa;IAIlB,OAAO,CAAC,QAAQ,CAAC,gBAAgB;IACjC,OAAO,CAAC,QAAQ,CAAC,yBAAyB;IAC1C,OAAO,CAAC,QAAQ,CAAC,qBAAqB;IACtC,OAAO,CAAC,QAAQ,CAAC,cAAc;IANnC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAkC;gBAGpC,gBAAgB,EAAE,oBAAoB,EACtC,yBAAyB,EAAE,yBAAyB,EACpD,qBAAqB,EAAE,qBAAqB,EAC5C,cAAc,EAAE,cAAc;IAG7C,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,eAAe,GAAG,OAAO,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,UAAU,CAAA;KAAE,CAAC;IA+B/F,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;IAkCjD,SAAS,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC;IAkB1E,QAAQ,CAAC,MAAM,EAAE,MAAM;;;;;;;;;;;;IAoC7B,OAAO,CAAC,IAAI;CAGf"}
1
+ {"version":3,"file":"api-key.service.d.ts","sourceRoot":"","sources":["../../src/services/api-key.service.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAC9D,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAC9D,OAAO,EAAE,UAAU,EAAE,MAAM,kCAAkC,CAAC;AAE9D,OAAO,EAAE,cAAc,EAAE,MAAM,2CAA2C,CAAC;AAC3E,OAAO,EAAE,oBAAoB,EAAE,MAAM,wCAAwC,CAAC;AAC9E,OAAO,EAAE,yBAAyB,EAAE,MAAM,0CAA0C,CAAC;AACrF,OAAO,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AACjE,OAAO,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAEhE,qBACa,aAAa;IAIlB,OAAO,CAAC,QAAQ,CAAC,gBAAgB;IACjC,OAAO,CAAC,QAAQ,CAAC,yBAAyB;IAC1C,OAAO,CAAC,QAAQ,CAAC,qBAAqB;IACtC,OAAO,CAAC,QAAQ,CAAC,cAAc;IANnC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAkC;gBAGpC,gBAAgB,EAAE,oBAAoB,EACtC,yBAAyB,EAAE,yBAAyB,EACpD,qBAAqB,EAAE,qBAAqB,EAC5C,cAAc,EAAE,cAAc;IAG7C,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,eAAe,GAAG,OAAO,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,UAAU,CAAA;KAAE,CAAC;IA+B/F,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;IAkCjD,SAAS,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC;IAkB1E,QAAQ,CAAC,MAAM,EAAE,MAAM;;;;;;;;;;;;IAgD7B,OAAO,CAAC,IAAI;CAGf"}
@@ -106,7 +106,7 @@ let ApiKeyService = ApiKeyService_1 = class ApiKeyService {
106
106
  throw new common_1.UnauthorizedException(error_messages_1.ERROR_MESSAGES.INVALID_CREDENTIALS);
107
107
  }
108
108
  const user = apiKeyRecord.user;
109
- const tokens = await this.authenticationService.generateTokens(user);
109
+ const tokens = await this.authenticationService.generateTokens(user, `apikey-${apiKeyRecord.id}`);
110
110
  return {
111
111
  user: {
112
112
  email: user.email,
@@ -1 +1 @@
1
- {"version":3,"file":"api-key.service.js","sourceRoot":"","sources":["../../src/services/api-key.service.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n ForbiddenException,\n Injectable,\n Logger,\n NotFoundException,\n UnauthorizedException,\n} from '@nestjs/common';\nimport { createHash, randomBytes } from 'crypto';\nimport { ERROR_MESSAGES } from 'src/constants/error-messages';\nimport { CreateApiKeyDto } from 'src/dtos/create-api-key.dto';\nimport { UpdateApiKeyDto } from 'src/dtos/update-api-key.dto';\nimport { UserApiKey } from 'src/entities/user-api-key.entity';\nimport { User } from 'src/entities/user.entity';\nimport { ActiveUserData } from 'src/interfaces/active-user-data.interface';\nimport { UserApiKeyRepository } from 'src/repository/user-api-key.repository';\nimport { PermissionMetadataService } from 'src/services/permission-metadata.service';\nimport { AuthenticationService } from './authentication.service';\nimport { UserRepository } from 'src/repository/user.repository';\n\n@Injectable()\nexport class ApiKeyService {\n private readonly logger = new Logger(ApiKeyService.name);\n\n constructor(\n private readonly apiKeyRepository: UserApiKeyRepository,\n private readonly permissionMetadataService: PermissionMetadataService,\n private readonly authenticationService: AuthenticationService,\n private readonly userRepository: UserRepository,\n ) { }\n\n async generate(userId: number, dto: CreateApiKeyDto): Promise<{ apiKey: string; record: UserApiKey }> {\n const user = await this.apiKeyRepository.manager.findOne(User, {\n where: { id: userId },\n select: ['id', 'isAllowedToGenerateApiKeys'],\n });\n\n if (!user?.isAllowedToGenerateApiKeys) {\n throw new ForbiddenException('You are not allowed to generate API keys');\n }\n\n const rawKey = 'sldx_' + randomBytes(32).toString('hex');\n const hashedKey = this.hash(rawKey);\n const maskedKey = 'sldx_****' + rawKey.slice(-4);\n\n const record = this.apiKeyRepository.create({\n name: dto.name,\n hashedKey,\n maskedKey,\n isActive: true,\n expiresAt: dto.expiresAt ? new Date(dto.expiresAt) : null,\n user,\n });\n\n await this.apiKeyRepository.save(record);\n\n // Strip hashedKey from the returned record — maskedKey is all the UI needs\n delete (record as any).hashedKey;\n\n return { apiKey: rawKey, record };\n }\n\n async validate(rawKey: string): Promise<ActiveUserData> {\n const hashedKey = this.hash(rawKey);\n\n // Bypass security rules for auth validation — must find the key regardless of caller context\n const keyRecord = await this.apiKeyRepository.findOne({\n where: { hashedKey, isActive: true },\n relations: ['user', 'user.roles'],\n });\n\n if (!keyRecord) {\n throw new UnauthorizedException();\n }\n\n if (keyRecord.expiresAt && keyRecord.expiresAt < new Date()) {\n throw new UnauthorizedException('API key expired');\n }\n\n // Fire-and-forget — does not need security rule context\n this.apiKeyRepository.update(keyRecord.id, { lastUsedAt: new Date() }).catch((err) => {\n this.logger.warn(`Failed to update lastUsedAt for key ${keyRecord.id}: ${err.message}`);\n });\n\n const roles = (keyRecord.user.roles ?? []).map((r) => r.name);\n const permissions = await this.permissionMetadataService.findAllUsingRoles(roles);\n\n return {\n sub: keyRecord.user.id,\n username: keyRecord.user.username,\n email: keyRecord.user.email,\n roles,\n permissions: permissions.map((p) => p.name),\n };\n }\n\n async updateKey(id: number, userId: number, dto: UpdateApiKeyDto): Promise<void> {\n const keyRecord = await this.apiKeyRepository.findOne({\n where: { id, user: { id: userId } },\n });\n\n if (!keyRecord) {\n throw new NotFoundException('API key not found');\n }\n\n await this.apiKeyRepository.manager\n .createQueryBuilder()\n .update(UserApiKey)\n .set({ isActive: dto.isActive })\n .where('id = :id', { id })\n .execute();\n }\n\n\n async apiKeyMe(apiKey: string) {\n\n const hasedKey = this.hash(apiKey);\n const apiKeyRecord = await this.apiKeyRepository.findOne({\n where: {\n hashedKey: hasedKey,\n },\n relations: {\n user: {\n roles: true\n }\n }\n });\n\n if (!apiKeyRecord) {\n throw new UnauthorizedException(ERROR_MESSAGES.INVALID_CREDENTIALS);\n }\n\n const user = apiKeyRecord.user;\n\n const tokens = await this.authenticationService.generateTokens(user);\n\n\n return {\n user: {\n email: user.email,\n mobile: user.mobile,\n username: user.username,\n forcePasswordChange: user.forcePasswordChange,\n id: user.id,\n roles: user.roles.map((role) => role.name)\n },\n ...tokens\n }\n }\n\n private hash(rawKey: string): string {\n return createHash('sha256').update(rawKey).digest('hex');\n }\n}\n"]}
1
+ {"version":3,"file":"api-key.service.js","sourceRoot":"","sources":["../../src/services/api-key.service.ts"],"names":[],"mappings":";;;;;;;;;;;;;AAAA,2CAMwB;AACxB,mCAAiD;AACjD,gEAA8D;AAG9D,yEAA8D;AAC9D,yDAAgD;AAEhD,mFAA8E;AAC9E,+EAAqF;AACrF,qEAAiE;AACjE,mEAAgE;AAGzD,IAAM,aAAa,qBAAnB,MAAM,aAAa;IAGtB,YACqB,gBAAsC,EACtC,yBAAoD,EACpD,qBAA4C,EAC5C,cAA8B;QAH9B,qBAAgB,GAAhB,gBAAgB,CAAsB;QACtC,8BAAyB,GAAzB,yBAAyB,CAA2B;QACpD,0BAAqB,GAArB,qBAAqB,CAAuB;QAC5C,mBAAc,GAAd,cAAc,CAAgB;QANlC,WAAM,GAAG,IAAI,eAAM,CAAC,eAAa,CAAC,IAAI,CAAC,CAAC;IAOrD,CAAC;IAEL,KAAK,CAAC,QAAQ,CAAC,MAAc,EAAE,GAAoB;QAC/C,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,OAAO,CAAC,kBAAI,EAAE;YAC3D,KAAK,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE;YACrB,MAAM,EAAE,CAAC,IAAI,EAAE,4BAA4B,CAAC;SAC/C,CAAC,CAAC;QAEH,IAAI,CAAC,IAAI,EAAE,0BAA0B,EAAE,CAAC;YACpC,MAAM,IAAI,2BAAkB,CAAC,0CAA0C,CAAC,CAAC;QAC7E,CAAC;QAED,MAAM,MAAM,GAAG,OAAO,GAAG,IAAA,oBAAW,EAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;QACzD,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACpC,MAAM,SAAS,GAAG,WAAW,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;QAEjD,MAAM,MAAM,GAAG,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAAC;YACxC,IAAI,EAAE,GAAG,CAAC,IAAI;YACd,SAAS;YACT,SAAS;YACT,QAAQ,EAAE,IAAI;YACd,SAAS,EAAE,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,IAAI;YACzD,IAAI;SACP,CAAC,CAAC;QAEH,MAAM,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAGzC,OAAQ,MAAc,CAAC,SAAS,CAAC;QAEjC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;IACtC,CAAC;IAED,KAAK,CAAC,QAAQ,CAAC,MAAc;QACzB,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAGpC,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC;YAClD,KAAK,EAAE,EAAE,SAAS,EAAE,QAAQ,EAAE,IAAI,EAAE;YACpC,SAAS,EAAE,CAAC,MAAM,EAAE,YAAY,CAAC;SACpC,CAAC,CAAC;QAEH,IAAI,CAAC,SAAS,EAAE,CAAC;YACb,MAAM,IAAI,8BAAqB,EAAE,CAAC;QACtC,CAAC;QAED,IAAI,SAAS,CAAC,SAAS,IAAI,SAAS,CAAC,SAAS,GAAG,IAAI,IAAI,EAAE,EAAE,CAAC;YAC1D,MAAM,IAAI,8BAAqB,CAAC,iBAAiB,CAAC,CAAC;QACvD,CAAC;QAGD,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,UAAU,EAAE,IAAI,IAAI,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;YACjF,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,uCAAuC,SAAS,CAAC,EAAE,KAAK,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;QAC5F,CAAC,CAAC,CAAC;QAEH,MAAM,KAAK,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QAC9D,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,yBAAyB,CAAC,iBAAiB,CAAC,KAAK,CAAC,CAAC;QAElF,OAAO;YACH,GAAG,EAAE,SAAS,CAAC,IAAI,CAAC,EAAE;YACtB,QAAQ,EAAE,SAAS,CAAC,IAAI,CAAC,QAAQ;YACjC,KAAK,EAAE,SAAS,CAAC,IAAI,CAAC,KAAK;YAC3B,KAAK;YACL,WAAW,EAAE,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;SAC9C,CAAC;IACN,CAAC;IAED,KAAK,CAAC,SAAS,CAAC,EAAU,EAAE,MAAc,EAAE,GAAoB;QAC5D,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC;YAClD,KAAK,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE;SACtC,CAAC,CAAC;QAEH,IAAI,CAAC,SAAS,EAAE,CAAC;YACb,MAAM,IAAI,0BAAiB,CAAC,mBAAmB,CAAC,CAAC;QACrD,CAAC;QAED,MAAM,IAAI,CAAC,gBAAgB,CAAC,OAAO;aAC9B,kBAAkB,EAAE;aACpB,MAAM,CAAC,gCAAU,CAAC;aAClB,GAAG,CAAC,EAAE,QAAQ,EAAE,GAAG,CAAC,QAAQ,EAAE,CAAC;aAC/B,KAAK,CAAC,UAAU,EAAE,EAAE,EAAE,EAAE,CAAC;aACzB,OAAO,EAAE,CAAC;IACnB,CAAC;IAGD,KAAK,CAAC,QAAQ,CAAC,MAAc;QAEzB,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACnC,MAAM,YAAY,GAAG,MAAM,IAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC;YACrD,KAAK,EAAE;gBACH,SAAS,EAAE,QAAQ;aACtB;YACD,SAAS,EAAE;gBACP,IAAI,EAAE;oBACF,KAAK,EAAE,IAAI;iBACd;aACJ;SACJ,CAAC,CAAC;QAEH,IAAI,CAAC,YAAY,EAAE,CAAC;YAChB,MAAM,IAAI,8BAAqB,CAAC,+BAAc,CAAC,mBAAmB,CAAC,CAAC;QACxE,CAAC;QAED,MAAM,IAAI,GAAG,YAAY,CAAC,IAAI,CAAC;QAW/B,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,qBAAqB,CAAC,cAAc,CAC1D,IAAI,EACJ,UAAU,YAAY,CAAC,EAAE,EAAE,CAC9B,CAAC;QAGF,OAAO;YACH,IAAI,EAAE;gBACF,KAAK,EAAE,IAAI,CAAC,KAAK;gBACjB,MAAM,EAAE,IAAI,CAAC,MAAM;gBACnB,QAAQ,EAAE,IAAI,CAAC,QAAQ;gBACvB,mBAAmB,EAAE,IAAI,CAAC,mBAAmB;gBAC7C,EAAE,EAAE,IAAI,CAAC,EAAE;gBACX,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC;aAC7C;YACD,GAAG,MAAM;SACZ,CAAA;IACL,CAAC;IAEO,IAAI,CAAC,MAAc;QACvB,OAAO,IAAA,mBAAU,EAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAC7D,CAAC;CACJ,CAAA;AAhJY,sCAAa;wBAAb,aAAa;IADzB,IAAA,mBAAU,GAAE;qCAK8B,8CAAoB;QACX,uDAAyB;QAC7B,8CAAqB;QAC5B,gCAAc;GAP1C,aAAa,CAgJzB","sourcesContent":["import {\n ForbiddenException,\n Injectable,\n Logger,\n NotFoundException,\n UnauthorizedException,\n} from '@nestjs/common';\nimport { createHash, randomBytes } from 'crypto';\nimport { ERROR_MESSAGES } from 'src/constants/error-messages';\nimport { CreateApiKeyDto } from 'src/dtos/create-api-key.dto';\nimport { UpdateApiKeyDto } from 'src/dtos/update-api-key.dto';\nimport { UserApiKey } from 'src/entities/user-api-key.entity';\nimport { User } from 'src/entities/user.entity';\nimport { ActiveUserData } from 'src/interfaces/active-user-data.interface';\nimport { UserApiKeyRepository } from 'src/repository/user-api-key.repository';\nimport { PermissionMetadataService } from 'src/services/permission-metadata.service';\nimport { AuthenticationService } from './authentication.service';\nimport { UserRepository } from 'src/repository/user.repository';\n\n@Injectable()\nexport class ApiKeyService {\n private readonly logger = new Logger(ApiKeyService.name);\n\n constructor(\n private readonly apiKeyRepository: UserApiKeyRepository,\n private readonly permissionMetadataService: PermissionMetadataService,\n private readonly authenticationService: AuthenticationService,\n private readonly userRepository: UserRepository,\n ) { }\n\n async generate(userId: number, dto: CreateApiKeyDto): Promise<{ apiKey: string; record: UserApiKey }> {\n const user = await this.apiKeyRepository.manager.findOne(User, {\n where: { id: userId },\n select: ['id', 'isAllowedToGenerateApiKeys'],\n });\n\n if (!user?.isAllowedToGenerateApiKeys) {\n throw new ForbiddenException('You are not allowed to generate API keys');\n }\n\n const rawKey = 'sldx_' + randomBytes(32).toString('hex');\n const hashedKey = this.hash(rawKey);\n const maskedKey = 'sldx_****' + rawKey.slice(-4);\n\n const record = this.apiKeyRepository.create({\n name: dto.name,\n hashedKey,\n maskedKey,\n isActive: true,\n expiresAt: dto.expiresAt ? new Date(dto.expiresAt) : null,\n user,\n });\n\n await this.apiKeyRepository.save(record);\n\n // Strip hashedKey from the returned record — maskedKey is all the UI needs\n delete (record as any).hashedKey;\n\n return { apiKey: rawKey, record };\n }\n\n async validate(rawKey: string): Promise<ActiveUserData> {\n const hashedKey = this.hash(rawKey);\n\n // Bypass security rules for auth validation — must find the key regardless of caller context\n const keyRecord = await this.apiKeyRepository.findOne({\n where: { hashedKey, isActive: true },\n relations: ['user', 'user.roles'],\n });\n\n if (!keyRecord) {\n throw new UnauthorizedException();\n }\n\n if (keyRecord.expiresAt && keyRecord.expiresAt < new Date()) {\n throw new UnauthorizedException('API key expired');\n }\n\n // Fire-and-forget — does not need security rule context\n this.apiKeyRepository.update(keyRecord.id, { lastUsedAt: new Date() }).catch((err) => {\n this.logger.warn(`Failed to update lastUsedAt for key ${keyRecord.id}: ${err.message}`);\n });\n\n const roles = (keyRecord.user.roles ?? []).map((r) => r.name);\n const permissions = await this.permissionMetadataService.findAllUsingRoles(roles);\n\n return {\n sub: keyRecord.user.id,\n username: keyRecord.user.username,\n email: keyRecord.user.email,\n roles,\n permissions: permissions.map((p) => p.name),\n };\n }\n\n async updateKey(id: number, userId: number, dto: UpdateApiKeyDto): Promise<void> {\n const keyRecord = await this.apiKeyRepository.findOne({\n where: { id, user: { id: userId } },\n });\n\n if (!keyRecord) {\n throw new NotFoundException('API key not found');\n }\n\n await this.apiKeyRepository.manager\n .createQueryBuilder()\n .update(UserApiKey)\n .set({ isActive: dto.isActive })\n .where('id = :id', { id })\n .execute();\n }\n\n\n async apiKeyMe(apiKey: string) {\n\n const hasedKey = this.hash(apiKey);\n const apiKeyRecord = await this.apiKeyRepository.findOne({\n where: {\n hashedKey: hasedKey,\n },\n relations: {\n user: {\n roles: true\n }\n }\n });\n\n if (!apiKeyRecord) {\n throw new UnauthorizedException(ERROR_MESSAGES.INVALID_CREDENTIALS);\n }\n\n const user = apiKeyRecord.user;\n\n // Keyed on the API key record so every call for this key reuses one\n // refresh-token bucket. Without it each call mints a fresh key and\n // therefore a new bucket with a refreshTokenTtl lifetime - a client\n // polling this endpoint would accumulate them without bound.\n //\n // The consequence is that replicas sharing one API key share one\n // bucket and invalidate each other, which is exactly the behaviour\n // before per-device sessions existed, and is benign here: an API key\n // is a permanent credential, so a failed refresh just re-mints.\n const tokens = await this.authenticationService.generateTokens(\n user,\n `apikey-${apiKeyRecord.id}`,\n );\n\n\n return {\n user: {\n email: user.email,\n mobile: user.mobile,\n username: user.username,\n forcePasswordChange: user.forcePasswordChange,\n id: user.id,\n roles: user.roles.map((role) => role.name)\n },\n ...tokens\n }\n }\n\n private hash(rawKey: string): string {\n return createHash('sha256').update(rawKey).digest('hex');\n }\n}\n"]}
@@ -160,12 +160,12 @@ export declare class AuthenticationService {
160
160
  data: {};
161
161
  }>;
162
162
  private notifyUserOnPasswordChanged;
163
- generateTokens(user: User): Promise<{
163
+ generateTokens(user: User, deviceId?: string): Promise<{
164
164
  accessToken: string;
165
165
  refreshToken: string;
166
166
  }>;
167
- generateAccessToken(user: User, sessionId?: string): Promise<string>;
168
- generateRefreshToken(user: User, previousRefreshToken?: string): Promise<string>;
167
+ generateAccessToken(user: User, sessionId?: string, deviceKey?: string): Promise<string>;
168
+ generateRefreshToken(user: User, previousRefreshToken?: string, deviceKey?: string): Promise<string>;
169
169
  refreshTokens(refreshTokenDto: RefreshTokenDto): Promise<{
170
170
  accessToken: string;
171
171
  refreshToken: string;
@@ -235,9 +235,10 @@ export declare class AuthenticationService {
235
235
  private checkAccountBlocked;
236
236
  private incrementFailedAttempts;
237
237
  private resetFailedAttempts;
238
- logout(refreshToken: string): Promise<{
238
+ logout(refreshToken: string, allDevices?: boolean): Promise<{
239
239
  message: string;
240
240
  }>;
241
+ private verifyRefreshTokenForLogout;
241
242
  activateUser(userId: number): Promise<void>;
242
243
  me(activeUser: ActiveUserData): Promise<{
243
244
  user: {
@@ -1 +1 @@
1
- {"version":3,"file":"authentication.service.d.ts","sourceRoot":"","sources":["../../src/services/authentication.service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAY5C,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAOzC,OAAO,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AACzD,OAAO,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAChE,OAAO,EAAE,UAAU,EAAE,WAAW,EAAoB,UAAU,EAAE,MAAM,SAAS,CAAC;AAOhF,OAAO,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAChE,OAAO,EAAE,wBAAwB,EAAE,MAAM,qCAAqC,CAAC;AAC/E,OAAO,EAAE,yBAAyB,EAAE,MAAM,sCAAsC,CAAC;AACjF,OAAO,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAC/D,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACvD,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACvD,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAC5D,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAChD,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAChD,OAAO,EAAE,IAAI,EAAE,MAAM,yBAAyB,CAAC;AAE/C,OAAO,EAAE,cAAc,EAAE,MAAM,0CAA0C,CAAC;AAC1E,OAAO,EAAE,2BAA2B,EAAE,MAAM,kCAAkC,CAAC;AAC/E,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACnD,OAAO,EAEL,6BAA6B,EAC9B,MAAM,qCAAqC,CAAC;AAC7C,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AACnE,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAC9D,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACnD,OAAO,EAAE,0BAA0B,EAAE,MAAM,iCAAiC,CAAC;AAC7E,OAAO,EAAE,yBAAyB,EAAE,MAAM,+BAA+B,CAAC;AAC1E,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AACvD,OAAO,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AACjE,OAAO,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAa3D,qBACa,qBAAqB;IAI9B,OAAO,CAAC,QAAQ,CAAC,WAAW;IAE5B,OAAO,CAAC,QAAQ,CAAC,cAAc;IAC/B,OAAO,CAAC,QAAQ,CAAC,cAAc;IAC/B,OAAO,CAAC,QAAQ,CAAC,UAAU;IAC3B,OAAO,CAAC,QAAQ,CAAC,oBAAoB;IACrC,OAAO,CAAC,QAAQ,CAAC,sBAAsB;IACvC,OAAO,CAAC,QAAQ,CAAC,WAAW;IAE5B,OAAO,CAAC,QAAQ,CAAC,kBAAkB;IAEnC,OAAO,CAAC,QAAQ,CAAC,UAAU;IAC3B,OAAO,CAAC,QAAQ,CAAC,eAAe;IAChC,OAAO,CAAC,QAAQ,CAAC,YAAY;IAC7B,OAAO,CAAC,QAAQ,CAAC,cAAc;IAC/B,OAAO,CAAC,QAAQ,CAAC,mBAAmB;IACpC,OAAO,CAAC,QAAQ,CAAC,0BAA0B;IAC3C,OAAO,CAAC,QAAQ,CAAC,cAAc;IAC/B,OAAO,CAAC,QAAQ,CAAC,yBAAyB;IAG1C,OAAO,CAAC,QAAQ,CAAC,UAAU;IAC3B,OAAO,CAAC,QAAQ,CAAC,aAAa;IAzBhC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA0C;gBAG9C,WAAW,EAAE,WAAW,EAExB,cAAc,EAAE,cAAc,EAC9B,cAAc,EAAE,cAAc,EAC9B,UAAU,EAAE,UAAU,EACtB,oBAAoB,EAAE,2BAA2B,EACjD,sBAAsB,EAAE,6BAA6B,EACrD,WAAW,EAAE,WAAW,EAExB,kBAAkB,EAAE,WAAW,EAE/B,UAAU,EAAE,UAAU,EACtB,eAAe,EAAE,eAAe,EAChC,YAAY,EAAE,aAAa,EAC3B,cAAc,EAAE,cAAc,EAC9B,mBAAmB,EAAE,mBAAmB,EACxC,0BAA0B,EAAE,0BAA0B,EACtD,cAAc,EAAE,qBAAqB,EACrC,yBAAyB,EAAE,yBAAyB,EAGpD,UAAU,EAAE,UAAU,EACtB,aAAa,EAAE,aAAa;YAKjC,cAAc;IAItB,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM;YASnC,4BAA4B;IAoBpC,qBAAqB,CAAC,IAAI,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM;IAcrD,8BAA8B,CAAC,KAAK,EAAE,MAAM;YAOpC,4BAA4B;YAmB5B,wBAAwB;IAWtC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,eAAe,CAUpC;IAEG,MAAM,CACV,SAAS,EAAE,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC1C,UAAU,GAAE,cAAqB,GAChC,OAAO,CAAC,IAAI,CAAC;YAuBF,aAAa;YA6Db,6BAA6B;YAqD7B,2BAA2B;IAqCnC,sBAAsB,CAAC,CAAC,SAAS,IAAI,EACzC,SAAS,EAAE,SAAS,EACpB,gBAAgB,EAAE,WAAW,CAAC,CAAC,CAAC,EAChC,iBAAiB,EAAE,UAAU,CAAC,CAAC,CAAC,GAC/B,OAAO,CAAC,CAAC,CAAC;YAKC,iBAAiB;YAmEjB,gBAAgB;IA8B9B,gBAAgB,CAAC,MAAM,GAAE,MAAU,GAAG,MAAM;YAiB9B,+BAA+B;YAkC/B,qBAAqB;YAQrB,mBAAmB;YAQnB,kBAAkB;IAwD1B,uBAAuB,CAAC,SAAS,EAAE,YAAY;;;IAkCrD,OAAO,CAAC,4BAA4B;YAsBtB,4BAA4B;IAa1C,OAAO,CAAC,mCAAmC;YAM7B,4CAA4C;IAuB1D,OAAO,CAAC,UAAU;YAWJ,qBAAqB;YAqCrB,mCAAmC;IA+HjD,OAAO,CAAC,4BAA4B;YAkCtB,yBAAyB;IAajC,sBAAsB,CAAC,gBAAgB,EAAE,gBAAgB;;;;YAoCjD,gCAAgC;IAe9C,OAAO,CAAC,uBAAuB;IAqB/B,OAAO,CAAC,oBAAoB;IAe5B,OAAO,CAAC,wBAAwB;YAMlB,uDAAuD;YAwBvD,GAAG;IAWjB,OAAO,CAAC,kBAAkB;IAiB1B,OAAO,CAAC,gBAAgB;IAclB,MAAM,CAAC,SAAS,EAAE,SAAS;;;;;;;;;;;;IA6BjC,OAAO,CAAC,SAAS;IAajB,OAAO,CAAC,UAAU;IAWZ,gBAAgB,CAAC,SAAS,EAAE,YAAY;;;;;;;;;;IAmB9C,OAAO,CAAC,gBAAgB;YA2BV,4BAA4B;YAkB5B,gBAAgB;YAqBhB,cAAc;IAsB5B,OAAO,CAAC,qBAAqB;YAcf,6BAA6B;IAwHrC,eAAe,CAAC,gBAAgB,EAAE,gBAAgB;;;;;;;;;;;;IA2CxD,OAAO,CAAC,gBAAgB;YAqBV,aAAa;IA2B3B,OAAO,CAAC,gBAAgB;YAMV,uBAAuB;IAK/B,cAAc,CAClB,iBAAiB,EAAE,iBAAiB,EACpC,UAAU,EAAE,cAAc;YA0Dd,2BAA2B;IAiBnC,sBAAsB,CAC1B,yBAAyB,EAAE,yBAAyB;;;;;;;;;;;YAsDxC,0BAA0B;IA8DlC,qBAAqB,CACzB,wBAAwB,EAAE,wBAAwB;;;;;;;YA6DtC,2BAA2B;IA8DnC,cAAc,CAAC,IAAI,EAAE,IAAI;;;;IAoBzB,mBAAmB,CAAC,IAAI,EAAE,IAAI,EAAE,SAAS,CAAC,EAAE,MAAM;IAuBlD,oBAAoB,CAAC,IAAI,EAAE,IAAI,EAAE,oBAAoB,CAAC,EAAE,MAAM;IAkB9D,aAAa,CAAC,eAAe,EAAE,eAAe;;;;YA4DtC,SAAS;IAuBjB,uBAAuB,CAAC,IAAI,EAAE,IAAI;IAyBlC,iBAAiB,CAAC,UAAU,EAAE,MAAM;;;;;;;;;;;IAqCpC,yBAAyB,CAAC,IAAI,EAAE,IAAI;IAiCpC,mBAAmB,CAAC,UAAU,EAAE,MAAM;;;;;;;;;;;IAoCtC,0BAA0B,CAAC,IAAI,EAAE,IAAI;IA0BrC,oBAAoB,CAAC,UAAU,EAAE,MAAM;;;;;;;;;;;IAoCvC,yCAAyC,CAAC,IAAI,EAAE,IAAI;IA0CpD,mCAAmC,CAAC,UAAU,EAAE,MAAM;;;;;;;;;;;IAoCtD,gBAAgB,CAAC,UAAU,EAAE,MAAM;;;;;;;;;;;YAkC3B,iCAAiC;IAO/C,OAAO,CAAC,6BAA6B;IAQrC,OAAO,CAAC,mBAAmB;YAab,uBAAuB;YAQvB,mBAAmB;IAa3B,MAAM,CAAC,YAAY,EAAE,MAAM;;;IAwC3B,YAAY,CAAC,MAAM,EAAE,MAAM;IAS3B,EAAE,CAAC,UAAU,EAAE,cAAc;;;;;;;;;;IA+B7B,eAAe,CACnB,UAAU,EAAE,cAAc,EAC1B,cAAc,EAAE,MAAM,GACrB,OAAO,CAAC;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IAgBzB,eAAe,CAAC,IAAI,EAAE,MAAM;;;;;;;;;;;;CAYnC"}
1
+ {"version":3,"file":"authentication.service.d.ts","sourceRoot":"","sources":["../../src/services/authentication.service.ts"],"names":[],"mappings":"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"}
@@ -1101,7 +1101,7 @@ let AuthenticationService = AuthenticationService_1 = class AuthenticationServic
1101
1101
  }, this.settingService.getConfigValue("shouldQueueSms"));
1102
1102
  }
1103
1103
  }
1104
- async generateTokens(user) {
1104
+ async generateTokens(user, deviceId) {
1105
1105
  const sessionId = this.shouldPreventConcurrentLogins()
1106
1106
  ? (0, crypto_1.randomUUID)()
1107
1107
  : undefined;
@@ -1111,16 +1111,19 @@ let AuthenticationService = AuthenticationService_1 = class AuthenticationServic
1111
1111
  else {
1112
1112
  await this.activeSessionStorage.clearActiveSession(user.id);
1113
1113
  }
1114
+ const deviceKey = this.refreshTokenIdsStorage.areConcurrentLoginsAllowed()
1115
+ ? deviceId ?? (0, crypto_1.randomUUID)()
1116
+ : undefined;
1114
1117
  const [accessToken, refreshToken] = await Promise.all([
1115
- await this.generateAccessToken(user, sessionId),
1116
- await this.generateRefreshToken(user),
1118
+ await this.generateAccessToken(user, sessionId, deviceKey),
1119
+ await this.generateRefreshToken(user, undefined, deviceKey),
1117
1120
  ]);
1118
1121
  return {
1119
1122
  accessToken,
1120
1123
  refreshToken,
1121
1124
  };
1122
1125
  }
1123
- async generateAccessToken(user, sessionId) {
1126
+ async generateAccessToken(user, sessionId, deviceKey) {
1124
1127
  const userRoleNames = user.roles.map((role) => role.name);
1125
1128
  const resolvedSessionId = this.shouldPreventConcurrentLogins()
1126
1129
  ? sessionId ?? (await this.activeSessionStorage.getActiveSession(user.id))
@@ -1131,16 +1134,22 @@ let AuthenticationService = AuthenticationService_1 = class AuthenticationServic
1131
1134
  email: user.email,
1132
1135
  roles: userRoleNames,
1133
1136
  ...(resolvedSessionId ? { sessionId: resolvedSessionId } : {}),
1137
+ ...(deviceKey ? { deviceKey } : {}),
1134
1138
  });
1135
1139
  return accessToken;
1136
1140
  }
1137
- async generateRefreshToken(user, previousRefreshToken) {
1141
+ async generateRefreshToken(user, previousRefreshToken, deviceKey) {
1138
1142
  const refreshTokenId = (0, crypto_1.randomUUID)();
1139
1143
  const refreshTokenTtl = this.settingService.getConfigValue("refreshTokenTtl");
1144
+ const epoch = deviceKey
1145
+ ? await this.refreshTokenIdsStorage.getEpoch(user.id)
1146
+ : undefined;
1140
1147
  const refreshToken = await this.signToken(user.id, refreshTokenTtl, {
1141
1148
  refreshTokenId,
1149
+ ...(deviceKey ? { deviceKey } : {}),
1150
+ ...(epoch !== undefined ? { epoch } : {}),
1142
1151
  });
1143
- await this.refreshTokenIdsStorage.insert(user.id, refreshToken, previousRefreshToken);
1152
+ await this.refreshTokenIdsStorage.insert(user.id, refreshToken, previousRefreshToken, deviceKey);
1144
1153
  return refreshToken;
1145
1154
  }
1146
1155
  async refreshTokens(refreshTokenDto) {
@@ -1148,7 +1157,7 @@ let AuthenticationService = AuthenticationService_1 = class AuthenticationServic
1148
1157
  const secret = this.settingService.getConfigValue("secret");
1149
1158
  const audience = this.settingService.getConfigValue("audience");
1150
1159
  const issuer = this.settingService.getConfigValue("issuer");
1151
- const { sub } = await this.jwtService.verifyAsync(refreshTokenDto.refreshToken, {
1160
+ const { sub, deviceKey, epoch } = await this.jwtService.verifyAsync(refreshTokenDto.refreshToken, {
1152
1161
  secret,
1153
1162
  audience,
1154
1163
  issuer,
@@ -1164,11 +1173,11 @@ let AuthenticationService = AuthenticationService_1 = class AuthenticationServic
1164
1173
  if (!user) {
1165
1174
  throw new common_1.UnauthorizedException(error_messages_1.ERROR_MESSAGES.SESSION_INVALID);
1166
1175
  }
1167
- const currentRefreshToken = await this.refreshTokenIdsStorage.validateAndRotate(user, refreshTokenDto.refreshToken);
1176
+ const rotated = await this.refreshTokenIdsStorage.validateAndRotate(user, refreshTokenDto.refreshToken, { deviceKey, epoch });
1168
1177
  await this.userActivityHistoryService.logEvent("tokenRefreshed", user);
1169
1178
  return {
1170
- accessToken: await this.generateAccessToken(user),
1171
- refreshToken: currentRefreshToken,
1179
+ accessToken: await this.generateAccessToken(user, undefined, rotated.deviceKey),
1180
+ refreshToken: rotated.refreshToken,
1172
1181
  };
1173
1182
  }
1174
1183
  catch (err) {
@@ -1471,21 +1480,29 @@ let AuthenticationService = AuthenticationService_1 = class AuthenticationServic
1471
1480
  user.failedLoginAttempts = 0;
1472
1481
  await this.userRepository.update(user.id, { failedLoginAttempts: 0 });
1473
1482
  }
1474
- async logout(refreshToken) {
1483
+ async logout(refreshToken, allDevices = false) {
1475
1484
  try {
1476
- const payload = this.jwtService.decode(refreshToken);
1477
- if (!payload || !payload.sub) {
1478
- throw new common_1.UnauthorizedException(error_messages_1.ERROR_MESSAGES.INVALID_REFRESH_TOKEN);
1485
+ const payload = await this.verifyRefreshTokenForLogout(refreshToken);
1486
+ if (!payload?.sub) {
1487
+ this.logger.warn("logout called with an unverifiable refresh token");
1488
+ return { message: success_messages_1.SUCCESS_MESSAGES.LOGOUT_SUCCESS };
1479
1489
  }
1480
1490
  const userId = payload.sub;
1481
- await this.refreshTokenIdsStorage.invalidate(userId);
1491
+ if (allDevices) {
1492
+ await this.refreshTokenIdsStorage.invalidateAll(userId);
1493
+ }
1494
+ else {
1495
+ await this.refreshTokenIdsStorage.invalidate(userId, payload.deviceKey);
1496
+ }
1482
1497
  await this.activeSessionStorage.clearActiveSession(userId);
1483
1498
  const user = await this.userRepository.findOne({
1484
1499
  where: {
1485
1500
  id: userId,
1486
1501
  },
1487
1502
  });
1488
- await this.userActivityHistoryService.logEvent("logout", user);
1503
+ if (user) {
1504
+ await this.userActivityHistoryService.logEvent("logout", user);
1505
+ }
1489
1506
  return { message: success_messages_1.SUCCESS_MESSAGES.LOGOUT_SUCCESS };
1490
1507
  }
1491
1508
  catch (err) {
@@ -1495,6 +1512,20 @@ let AuthenticationService = AuthenticationService_1 = class AuthenticationServic
1495
1512
  : new common_1.InternalServerErrorException(error_messages_1.ERROR_MESSAGES.LOGOUT_FAILED);
1496
1513
  }
1497
1514
  }
1515
+ async verifyRefreshTokenForLogout(refreshToken) {
1516
+ try {
1517
+ const payload = await this.jwtService.verifyAsync(refreshToken, {
1518
+ secret: this.settingService.getConfigValue("secret"),
1519
+ audience: this.settingService.getConfigValue("audience"),
1520
+ issuer: this.settingService.getConfigValue("issuer"),
1521
+ ignoreExpiration: true,
1522
+ });
1523
+ return payload?.refreshTokenId ? payload : null;
1524
+ }
1525
+ catch {
1526
+ return null;
1527
+ }
1528
+ }
1498
1529
  async activateUser(userId) {
1499
1530
  const user = await this.userService.findOne(userId, {});
1500
1531
  if (!user) {
@@ -1512,7 +1543,7 @@ let AuthenticationService = AuthenticationService_1 = class AuthenticationServic
1512
1543
  roles: true,
1513
1544
  },
1514
1545
  });
1515
- const refreshTokenState = await this.refreshTokenIdsStorage.getCurrentRefreshTokenState(user.id);
1546
+ const refreshTokenState = await this.refreshTokenIdsStorage.getCurrentRefreshTokenState(user.id, activeUser.deviceKey);
1516
1547
  const response = {
1517
1548
  user: {
1518
1549
  email: user.email,
@@ -1521,12 +1552,12 @@ let AuthenticationService = AuthenticationService_1 = class AuthenticationServic
1521
1552
  id: user.id,
1522
1553
  roles: user.roles.map((role) => role.name),
1523
1554
  },
1524
- refreshToken: refreshTokenState.currentRefreshToken,
1555
+ refreshToken: refreshTokenState?.currentRefreshToken ?? null,
1525
1556
  };
1526
1557
  return response;
1527
1558
  }
1528
1559
  async generateSsoCode(activeUser, rawAccessToken) {
1529
- const refreshTokenState = await this.refreshTokenIdsStorage.getCurrentRefreshTokenState(activeUser.sub);
1560
+ const refreshTokenState = await this.refreshTokenIdsStorage.getCurrentRefreshTokenState(activeUser.sub, activeUser.deviceKey);
1530
1561
  if (!refreshTokenState?.currentRefreshToken) {
1531
1562
  throw new common_1.UnauthorizedException("No active session found");
1532
1563
  }