@solidxai/core 0.1.8-beta.9 → 0.1.8

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 (131) hide show
  1. package/README.md +197 -0
  2. package/dist/controllers/authentication.controller.d.ts +32 -2
  3. package/dist/controllers/authentication.controller.d.ts.map +1 -1
  4. package/dist/controllers/authentication.controller.js +80 -3
  5. package/dist/controllers/authentication.controller.js.map +1 -1
  6. package/dist/dtos/create-api-key.dto.d.ts +5 -0
  7. package/dist/dtos/create-api-key.dto.d.ts.map +1 -0
  8. package/dist/dtos/create-api-key.dto.js +34 -0
  9. package/dist/dtos/create-api-key.dto.js.map +1 -0
  10. package/dist/dtos/register-private.dto.d.ts +3 -5
  11. package/dist/dtos/register-private.dto.d.ts.map +1 -1
  12. package/dist/dtos/register-private.dto.js +6 -18
  13. package/dist/dtos/register-private.dto.js.map +1 -1
  14. package/dist/dtos/sso-exchange.dto.d.ts +4 -0
  15. package/dist/dtos/sso-exchange.dto.d.ts.map +1 -0
  16. package/dist/dtos/sso-exchange.dto.js +26 -0
  17. package/dist/dtos/sso-exchange.dto.js.map +1 -0
  18. package/dist/dtos/update-api-key.dto.d.ts +4 -0
  19. package/dist/dtos/update-api-key.dto.d.ts.map +1 -0
  20. package/dist/dtos/update-api-key.dto.js +28 -0
  21. package/dist/dtos/update-api-key.dto.js.map +1 -0
  22. package/dist/entities/setting.entity.d.ts +1 -0
  23. package/dist/entities/setting.entity.d.ts.map +1 -1
  24. package/dist/entities/setting.entity.js +5 -1
  25. package/dist/entities/setting.entity.js.map +1 -1
  26. package/dist/entities/user-api-key.entity.d.ts +12 -0
  27. package/dist/entities/user-api-key.entity.d.ts.map +1 -0
  28. package/dist/entities/user-api-key.entity.js +62 -0
  29. package/dist/entities/user-api-key.entity.js.map +1 -0
  30. package/dist/entities/user.entity.d.ts +3 -0
  31. package/dist/entities/user.entity.d.ts.map +1 -1
  32. package/dist/entities/user.entity.js +12 -1
  33. package/dist/entities/user.entity.js.map +1 -1
  34. package/dist/enums/auth-type.enum.d.ts +2 -1
  35. package/dist/enums/auth-type.enum.d.ts.map +1 -1
  36. package/dist/enums/auth-type.enum.js +2 -1
  37. package/dist/enums/auth-type.enum.js.map +1 -1
  38. package/dist/guards/api-key.guard.d.ts +11 -0
  39. package/dist/guards/api-key.guard.d.ts.map +1 -0
  40. package/dist/guards/api-key.guard.js +43 -0
  41. package/dist/guards/api-key.guard.js.map +1 -0
  42. package/dist/guards/authentication.guard.d.ts +4 -2
  43. package/dist/guards/authentication.guard.d.ts.map +1 -1
  44. package/dist/guards/authentication.guard.js +7 -3
  45. package/dist/guards/authentication.guard.js.map +1 -1
  46. package/dist/index.d.ts +2 -0
  47. package/dist/index.d.ts.map +1 -1
  48. package/dist/index.js +2 -0
  49. package/dist/index.js.map +1 -1
  50. package/dist/interfaces.d.ts +12 -0
  51. package/dist/interfaces.d.ts.map +1 -1
  52. package/dist/interfaces.js.map +1 -1
  53. package/dist/jobs/database/chatter-queue-publisher-database.service.d.ts +1 -1
  54. package/dist/jobs/database/chatter-queue-publisher-database.service.d.ts.map +1 -1
  55. package/dist/jobs/database/chatter-queue-publisher-database.service.js.map +1 -1
  56. package/dist/jobs/database/chatter-queue-subscriber-database.service.d.ts +1 -1
  57. package/dist/jobs/database/chatter-queue-subscriber-database.service.d.ts.map +1 -1
  58. package/dist/jobs/database/chatter-queue-subscriber-database.service.js.map +1 -1
  59. package/dist/jobs/rabbitmq/chatter-queue-publisher.service.d.ts +1 -12
  60. package/dist/jobs/rabbitmq/chatter-queue-publisher.service.d.ts.map +1 -1
  61. package/dist/jobs/rabbitmq/chatter-queue-publisher.service.js.map +1 -1
  62. package/dist/jobs/rabbitmq/chatter-queue-subscriber.service.d.ts +1 -1
  63. package/dist/jobs/rabbitmq/chatter-queue-subscriber.service.d.ts.map +1 -1
  64. package/dist/jobs/rabbitmq/chatter-queue-subscriber.service.js.map +1 -1
  65. package/dist/jobs/redis/chatter-queue-subscriber-redis.service.d.ts +1 -1
  66. package/dist/jobs/redis/chatter-queue-subscriber-redis.service.d.ts.map +1 -1
  67. package/dist/jobs/redis/chatter-queue-subscriber-redis.service.js.map +1 -1
  68. package/dist/repository/user-api-key.repository.d.ts +12 -0
  69. package/dist/repository/user-api-key.repository.d.ts.map +1 -0
  70. package/dist/repository/user-api-key.repository.js +34 -0
  71. package/dist/repository/user-api-key.repository.js.map +1 -0
  72. package/dist/seeders/seed-data/solid-core-metadata.json +128 -0
  73. package/dist/services/api-key.service.d.ts +20 -0
  74. package/dist/services/api-key.service.d.ts.map +1 -0
  75. package/dist/services/api-key.service.js +98 -0
  76. package/dist/services/api-key.service.js.map +1 -0
  77. package/dist/services/authentication.service.d.ts +19 -1
  78. package/dist/services/authentication.service.d.ts.map +1 -1
  79. package/dist/services/authentication.service.js +31 -5
  80. package/dist/services/authentication.service.js.map +1 -1
  81. package/dist/services/encryption.service.d.ts +8 -0
  82. package/dist/services/encryption.service.d.ts.map +1 -0
  83. package/dist/services/encryption.service.js +75 -0
  84. package/dist/services/encryption.service.js.map +1 -0
  85. package/dist/services/setting.service.d.ts +1 -0
  86. package/dist/services/setting.service.d.ts.map +1 -1
  87. package/dist/services/setting.service.js +35 -7
  88. package/dist/services/setting.service.js.map +1 -1
  89. package/dist/services/settings/default-settings-provider.service.d.ts +12 -0
  90. package/dist/services/settings/default-settings-provider.service.d.ts.map +1 -1
  91. package/dist/services/settings/default-settings-provider.service.js +4 -3
  92. package/dist/services/settings/default-settings-provider.service.js.map +1 -1
  93. package/dist/services/sso-code-storage.service.d.ts +15 -0
  94. package/dist/services/sso-code-storage.service.d.ts.map +1 -0
  95. package/dist/services/sso-code-storage.service.js +47 -0
  96. package/dist/services/sso-code-storage.service.js.map +1 -0
  97. package/dist/solid-core.module.d.ts.map +1 -1
  98. package/dist/solid-core.module.js +10 -0
  99. package/dist/solid-core.module.js.map +1 -1
  100. package/dist/subscribers/audit.subscriber.d.ts +1 -1
  101. package/dist/subscribers/audit.subscriber.d.ts.map +1 -1
  102. package/dist/subscribers/audit.subscriber.js.map +1 -1
  103. package/package.json +1 -1
  104. package/src/controllers/authentication.controller.ts +59 -3
  105. package/src/dtos/create-api-key.dto.ts +14 -0
  106. package/src/dtos/register-private.dto.ts +5 -14
  107. package/src/dtos/sso-exchange.dto.ts +7 -0
  108. package/src/dtos/update-api-key.dto.ts +9 -0
  109. package/src/entities/setting.entity.ts +3 -0
  110. package/src/entities/user-api-key.entity.ts +37 -0
  111. package/src/entities/user.entity.ts +8 -0
  112. package/src/enums/auth-type.enum.ts +1 -0
  113. package/src/guards/api-key.guard.ts +32 -0
  114. package/src/guards/authentication.guard.ts +6 -3
  115. package/src/index.ts +2 -0
  116. package/src/interfaces.ts +16 -0
  117. package/src/jobs/database/chatter-queue-publisher-database.service.ts +1 -1
  118. package/src/jobs/database/chatter-queue-subscriber-database.service.ts +1 -1
  119. package/src/jobs/rabbitmq/chatter-queue-publisher.service.ts +1 -15
  120. package/src/jobs/rabbitmq/chatter-queue-subscriber.service.ts +1 -1
  121. package/src/jobs/redis/chatter-queue-subscriber-redis.service.ts +1 -1
  122. package/src/repository/user-api-key.repository.ts +17 -0
  123. package/src/seeders/seed-data/solid-core-metadata.json +128 -0
  124. package/src/services/api-key.service.ts +111 -0
  125. package/src/services/authentication.service.ts +35 -3
  126. package/src/services/encryption.service.ts +43 -0
  127. package/src/services/setting.service.ts +38 -9
  128. package/src/services/settings/default-settings-provider.service.ts +4 -3
  129. package/src/services/sso-code-storage.service.ts +36 -0
  130. package/src/solid-core.module.ts +10 -0
  131. package/src/subscribers/audit.subscriber.ts +1 -1
@@ -15,6 +15,7 @@ import { ISettingsProvider, NoInfer, SettingDefinition, SettingLevel } from '../
15
15
  import { ModuleMetadataRepository } from 'src/repository/module-metadata.repository';
16
16
  import type { SolidCoreSetting } from './settings/default-settings-provider.service';
17
17
  import { Logger } from '@nestjs/common';
18
+ import { EncryptionService } from './encryption.service';
18
19
 
19
20
 
20
21
  @Injectable()
@@ -23,6 +24,7 @@ export class SettingService {
23
24
 
24
25
  private settings: SettingDefinition[] = [];
25
26
  private settingsByKey = new Map<string, SettingDefinition>();
27
+ private readonly encryptionService: EncryptionService | null;
26
28
 
27
29
  private readonly arrayKeysToSkip = new Set([
28
30
  'authenticationPasswordRegex',
@@ -38,7 +40,11 @@ export class SettingService {
38
40
  readonly moduleMetadataRepo: ModuleMetadataRepository,
39
41
  private readonly requestContextService: RequestContextService,
40
42
  @InjectRepository(User) private readonly userRepository: Repository<User>,
41
- ) { }
43
+ ) {
44
+ const encKey = process.env.APP_ENCRYPTION_KEY;
45
+ this.encryptionService = encKey ? new EncryptionService(encKey) : null;
46
+ if (!encKey) this._logger.warn('APP_ENCRYPTION_KEY is not set — encrypted settings will not be decrypted');
47
+ }
42
48
 
43
49
  private async getSettingsFromDb(): Promise<Setting[]> {
44
50
  const settings = await this.repo.find({ relations: ['user'] });
@@ -112,7 +118,15 @@ export class SettingService {
112
118
  const settingFromDb = settingsFromDbByKey.get(setting.key);
113
119
  const valueFromDb = settingFromDb?.value;
114
120
  if (settingFromDb?.key && valueFromDb !== undefined && valueFromDb !== null) {
115
- const parsedValue = typeof valueFromDb === 'string' ? this.parseSettingValue(valueFromDb, settingFromDb.key) : valueFromDb;
121
+ let rawValue = valueFromDb;
122
+ if (settingFromDb.encrypted && this.encryptionService) {
123
+ try {
124
+ rawValue = this.encryptionService.decrypt(rawValue);
125
+ } catch {
126
+ this._logger.warn(`Failed to decrypt setting "${setting.key}" — using raw value`);
127
+ }
128
+ }
129
+ const parsedValue = typeof rawValue === 'string' ? this.parseSettingValue(rawValue, settingFromDb.key) : rawValue;
116
130
  return { ...setting, value: parsedValue };
117
131
  }
118
132
  return setting;
@@ -149,30 +163,38 @@ export class SettingService {
149
163
  const settingsToMutate: Setting[] = [];
150
164
  // const settingsToUpdate: Setting[] = [];
151
165
 
152
- for (const { key, value, level, moduleName } of saEditableAndAbove) {
166
+ for (const { key, value, level, moduleName, encrypted } of saEditableAndAbove) {
153
167
  const moduleMetadata = await this.moduleMetadataRepo.findOneBy({ name: moduleName });
154
168
  if (!existingSettingsFromDbByKey.has(key)) {
155
169
  const setting = new Setting();
156
170
  setting.key = key;
157
171
  setting.level = level;
172
+ setting.encrypted = !!encrypted;
158
173
  if (moduleMetadata)
159
174
  setting.moduleMetadata = moduleMetadata;
160
175
 
176
+ let rawValue: string | null;
161
177
  if (typeof value === 'boolean') {
162
- setting.value = value.toString();
178
+ rawValue = value.toString();
163
179
  } else if (Array.isArray(value)) {
164
- setting.value = value.join(',');
180
+ rawValue = value.join(',');
165
181
  } else if (value === null || value === undefined) {
166
- setting.value = null;
182
+ rawValue = null;
167
183
  } else {
168
- setting.value = String(value);
184
+ rawValue = String(value);
169
185
  }
170
186
 
187
+ if (encrypted && this.encryptionService && rawValue !== null) {
188
+ rawValue = this.encryptionService.encrypt(rawValue);
189
+ }
190
+ setting.value = rawValue;
191
+
171
192
  settingsToMutate.push(setting);
172
193
  }
173
194
  else {
174
195
  const setting = existingSettingsFromDbByKey.get(key);
175
196
  setting.level = level;
197
+ setting.encrypted = !!encrypted;
176
198
  if (moduleMetadata)
177
199
  setting.moduleMetadata = moduleMetadata;
178
200
  settingsToMutate.push(setting);
@@ -289,22 +311,29 @@ export class SettingService {
289
311
  }
290
312
 
291
313
  const key = settingDto.key;
292
- // const value = settingDto.value ?? '';
293
314
  const rawValue = settingDto.value;
294
- const value = rawValue === null || rawValue === undefined ? null : String(rawValue);
315
+ let value = rawValue === null || rawValue === undefined ? null : String(rawValue);
295
316
 
296
317
  const settingType = settingDto.type ?? 'system';
318
+ const definition = this.settingsByKey.get(key);
319
+ const shouldEncrypt = !!definition?.encrypted && this.encryptionService !== null && value !== null;
320
+
321
+ if (shouldEncrypt) {
322
+ value = this.encryptionService.encrypt(value);
323
+ }
297
324
 
298
325
  const existingSetting = existingSettings.find(s => s.key === key);
299
326
  if (existingSetting) {
300
327
  existingSetting.value = value;
301
328
  existingSetting.type = settingType;
329
+ existingSetting.encrypted = shouldEncrypt;
302
330
  settingsToUpdate.push(existingSetting);
303
331
  } else {
304
332
  const newSetting = new Setting();
305
333
  newSetting.key = key;
306
334
  newSetting.value = value;
307
335
  newSetting.type = settingType;
336
+ newSetting.encrypted = shouldEncrypt;
308
337
 
309
338
  if (settingType === 'user' && user) {
310
339
  newSetting.user = user;
@@ -35,12 +35,13 @@ const getSolidCoreSettings = (isProd: boolean) => ([
35
35
  {
36
36
  moduleName: "solid-core", key: "solidXGenAiCodeBuilderConfig", value: JSON.stringify({
37
37
  models: {
38
- default: { providerKey: "", behavior: { streaming: false, custom: "" } },
39
- fast: { providerKey: "", behavior: { streaming: false, custom: "" } },
38
+ default: { providerId: "", model: "", behavior: { streaming: false, custom: "" } },
39
+ fast: { providerId: "", model: "", behavior: { streaming: false, custom: "" } },
40
40
  },
41
41
  providers: {},
42
- }), level: SettingLevel.SystemAdminEditable
42
+ }), level: SettingLevel.SystemAdminEditable, encrypted: true
43
43
  },
44
+ { moduleName: "solid-core", key: "appEncryptionKey", value: process.env.APP_ENCRYPTION_KEY, level: SettingLevel.SystemEnv },
44
45
  { moduleName: "solid-core", key: "mcpEnabled", value: process.env.MCP_ENABLED || false, level: SettingLevel.SystemAdminReadonly },
45
46
  { moduleName: "solid-core", key: "mcpServerUrl", value: process.env.MCP_SERVER_URL, level: SettingLevel.SystemAdminReadonly },
46
47
  { moduleName: "solid-core", key: "mcpApiKey", value: process.env.MCP_API_KEY, level: SettingLevel.SystemEnv },
@@ -0,0 +1,36 @@
1
+ import { CACHE_MANAGER } from '@nestjs/cache-manager';
2
+ import { Inject, Injectable, UnauthorizedException } from '@nestjs/common';
3
+ import { Cache } from 'cache-manager';
4
+ import { randomBytes } from 'crypto';
5
+
6
+ const SSO_CODE_TTL_MS = 60 * 1000; // 60 seconds
7
+
8
+ interface SsoCodeEntry {
9
+ userId: number;
10
+ accessToken: string;
11
+ refreshToken: string;
12
+ }
13
+
14
+ @Injectable()
15
+ export class SsoCodeStorageService {
16
+ constructor(@Inject(CACHE_MANAGER) private cacheManager: Cache) {}
17
+
18
+ async generateCode(userId: number, accessToken: string, refreshToken: string): Promise<string> {
19
+ const code = randomBytes(32).toString('hex');
20
+ await this.cacheManager.set(this.getKey(code), { userId, accessToken, refreshToken }, SSO_CODE_TTL_MS);
21
+ return code;
22
+ }
23
+
24
+ async consumeCode(code: string): Promise<SsoCodeEntry> {
25
+ const entry = await this.cacheManager.get<SsoCodeEntry>(this.getKey(code));
26
+ if (!entry) {
27
+ throw new UnauthorizedException('Invalid or expired SSO code');
28
+ }
29
+ await this.cacheManager.del(this.getKey(code));
30
+ return entry;
31
+ }
32
+
33
+ private getKey(code: string): string {
34
+ return `sso-code-${code}`;
35
+ }
36
+ }
@@ -78,6 +78,7 @@ import { MqMessageQueue } from './entities/mq-message-queue.entity';
78
78
  import { MqMessage } from './entities/mq-message.entity';
79
79
  import { SmsTemplate } from './entities/sms-template.entity';
80
80
  import { AccessTokenGuard } from './guards/access-token.guard';
81
+ import { ApiKeyGuard } from './guards/api-key.guard';
81
82
  import { AuthenticationGuard } from './guards/authentication.guard';
82
83
  import { PermissionsGuard } from './guards/permissions.guard';
83
84
  import { SolidRegistry } from './helpers/solid-registry';
@@ -126,6 +127,7 @@ import { TwilioSmsQueuePublisherRedis } from './jobs/redis/twilio-sms-publisher-
126
127
  import { TwilioSmsQueueSubscriberRedis } from './jobs/redis/twilio-sms-subscriber-redis.service';
127
128
  import { UserRegistrationListener } from './listeners/user-registration.listener';
128
129
  import { GoogleOauthStrategy } from './passport-strategies/google-oauth.strategy';
130
+ import { ApiKeyService } from './services/api-key.service';
129
131
  import { AuthenticationService } from './services/authentication.service';
130
132
  import { BcryptService } from './services/bcrypt.service';
131
133
  import { UuidExternalIdEntityComputedFieldProvider } from './services/computed-fields/entity/uuid-externalid-entity-computed-field-provider.service';
@@ -140,6 +142,7 @@ import { MqMessageQueueService } from './services/mq-message-queue.service';
140
142
  import { MqMessageService } from './services/mq-message.service';
141
143
  import { PdfService } from './services/pdf.service';
142
144
  import { RefreshTokenIdsStorageService } from './services/refresh-token-ids-storage.service';
145
+ import { SsoCodeStorageService } from './services/sso-code-storage.service';
143
146
  import { ListOfModelsSelectionProvider } from './services/selection-providers/list-of-models-selection-provider.service';
144
147
  import { TinyUrlService } from './services/short-url/tiny-url.service';
145
148
  import { SmsTemplateService } from './services/sms-template.service';
@@ -205,6 +208,7 @@ import { SecurityRule } from './entities/security-rule.entity';
205
208
  import { Setting } from './entities/setting.entity';
206
209
  import { UserActivityHistory } from './entities/user-activity-history.entity';
207
210
  import { UserViewMetadata } from './entities/user-view-metadata.entity';
211
+ import { UserApiKey } from './entities/user-api-key.entity';
208
212
  import { User } from './entities/user.entity';
209
213
  import { HttpExceptionFilter } from './filters/http-exception.filter';
210
214
  import { ModelMetadataHelperService } from './helpers/model-metadata-helper.service';
@@ -284,6 +288,7 @@ import { SettingRepository } from './repository/setting.repository';
284
288
  import { SmsTemplateRepository } from './repository/sms-template.repository';
285
289
  import { UserActivityHistoryRepository } from './repository/user-activity-history.repository';
286
290
  import { UserViewMetadataRepository } from './repository/user-view-metadata.repository';
291
+ import { UserApiKeyRepository } from './repository/user-api-key.repository';
287
292
  import { UserRepository } from './repository/user.repository';
288
293
  import { ViewMetadataRepository } from './repository/view-metadata.repository';
289
294
  import { PermissionMetadataSeederService } from './seeders/permission-metadata-seeder.service';
@@ -415,6 +420,7 @@ import { Entity } from 'typeorm';
415
420
  Setting,
416
421
  SmsTemplate,
417
422
  User,
423
+ UserApiKey,
418
424
  UserActivityHistory,
419
425
  UserViewMetadata,
420
426
  ViewMetadata,
@@ -627,9 +633,12 @@ import { Entity } from 'typeorm';
627
633
  LocaleListSelectionProvider,
628
634
  SoftDeleteAwareEventSubscriber,
629
635
  AccessTokenGuard,
636
+ ApiKeyGuard,
637
+ ApiKeyService,
630
638
  AuthenticationService,
631
639
  GoogleAuthenticationController,
632
640
  RefreshTokenIdsStorageService,
641
+ SsoCodeStorageService,
633
642
  GoogleOauthStrategy,
634
643
  UserRegistrationListener,
635
644
  TestQueuePublisher,
@@ -679,6 +688,7 @@ import { Entity } from 'typeorm';
679
688
  RoleMetadataService,
680
689
  PermissionMetadataSeederService,
681
690
  UserService,
691
+ UserApiKeyRepository,
682
692
  UserRepository,
683
693
  SettingService,
684
694
  ConcatComputedFieldProvider,
@@ -2,7 +2,7 @@ import { Injectable, Logger, Scope } from '@nestjs/common';
2
2
  import { lowerFirst } from 'src/helpers/string.helper';
3
3
  import { SolidRegistry } from 'src/helpers/solid-registry';
4
4
  import { DataSource, EntityMetadata, EntitySubscriberInterface, InsertEvent, RemoveEvent, UpdateEvent } from 'typeorm';
5
- import { AuditQueuePayload } from 'src/jobs/rabbitmq/chatter-queue-publisher.service';
5
+ import { AuditQueuePayload } from 'src/interfaces';
6
6
  import { RequestContextService } from 'src/services/request-context.service';
7
7
  import { PublisherFactory } from 'src/services/queues/publisher-factory.service';
8
8