@solidxai/core 0.1.13-beta.15 → 0.1.13-beta.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +576 -0
- package/dist/constants/media-file-types.d.ts +2 -0
- package/dist/constants/media-file-types.d.ts.map +1 -1
- package/dist/constants/media-file-types.js +26 -7
- package/dist/constants/media-file-types.js.map +1 -1
- package/dist/helpers/file-download.helper.d.ts.map +1 -1
- package/dist/helpers/file-download.helper.js +6 -1
- package/dist/helpers/file-download.helper.js.map +1 -1
- package/dist/services/media-storage.utils.d.ts +1 -0
- package/dist/services/media-storage.utils.d.ts.map +1 -1
- package/dist/services/media-storage.utils.js +12 -1
- package/dist/services/media-storage.utils.js.map +1 -1
- package/dist/services/module-metadata.service.d.ts.map +1 -1
- package/dist/services/module-metadata.service.js +2 -1
- package/dist/services/module-metadata.service.js.map +1 -1
- package/dist/services/setting.service.d.ts.map +1 -1
- package/dist/services/setting.service.js +2 -1
- package/dist/services/setting.service.js.map +1 -1
- package/package.json +1 -1
- package/src/constants/media-file-types.ts +58 -9
- package/src/helpers/file-download.helper.ts +15 -1
- package/src/services/media-storage.utils.ts +26 -1
- package/src/services/module-metadata.service.ts +3 -1
- package/src/services/setting.service.ts +3 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"setting.service.js","sourceRoot":"","sources":["../../src/services/setting.service.ts"],"names":[],"mappings":"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","sourcesContent":["import { BadRequestException, ForbiddenException, Inject, Injectable } from '@nestjs/common';\nimport { InjectRepository } from '@nestjs/typeorm';\nimport { Repository } from 'typeorm';\nimport * as fsPromises from 'fs/promises';\nimport { ERROR_MESSAGES } from 'src/constants/error-messages';\nimport { CreateSettingDto } from 'src/dtos/create-setting.dto';\nimport { GetMcpUrlDto } from 'src/dtos/get-mcp-url.dto';\nimport { User } from 'src/entities/user.entity';\nimport { SettingRepository } from '../repository/setting.repository';\nimport { FILE_SERVICE, IFileService, FILE_STORAGE_PATH_BUILDER, IStoragePathBuilder } from './file';\nimport { Setting } from '../entities/setting.entity';\nimport { RequestContextService } from './request-context.service';\nimport { SolidRegistry } from 'src/helpers/solid-registry';\nimport { AdminSettingDefinition, AdminSettingsResponse, ISettingsProvider, NoInfer, SettingControlType, SettingDefinition, SettingLevel } from '../interfaces';\nimport { ModuleMetadataRepository } from 'src/repository/module-metadata.repository';\nimport type { SolidCoreSetting } from './settings/default-settings-provider.service';\nimport { Logger } from '@nestjs/common';\nimport { EncryptionService } from './encryption.service';\n\n\n@Injectable()\nexport class SettingService {\n private readonly _logger = new Logger(SettingService.name);\n\n private settings: SettingDefinition[] = [];\n private settingsByKey = new Map<string, SettingDefinition>();\n private readonly encryptionService: EncryptionService | null;\n\n private readonly arrayKeysToSkip = new Set([\n 'authenticationPasswordRegex',\n 'authenticationPasswordRegexErrorMessage',\n 'authenticationPasswordComplexityDescription',\n ]);\n\n constructor(\n @Inject(FILE_SERVICE) readonly fileService: IFileService,\n @Inject(FILE_STORAGE_PATH_BUILDER) readonly pathBuilder: IStoragePathBuilder,\n readonly solidRegistry: SolidRegistry,\n readonly repo: SettingRepository,\n readonly moduleMetadataRepo: ModuleMetadataRepository,\n private readonly requestContextService: RequestContextService,\n @InjectRepository(User) private readonly userRepository: Repository<User>,\n ) {\n const encKey = process.env.APP_ENCRYPTION_KEY;\n this.encryptionService = encKey ? new EncryptionService(encKey) : null;\n if (!encKey) this._logger.warn('APP_ENCRYPTION_KEY is not set — encrypted settings will not be decrypted');\n }\n\n private async getSettingsFromDb(): Promise<Setting[]> {\n const settings = await this.repo.find({ relations: ['user'] });\n return settings;\n }\n\n private async getSettingsFromDbForSeeding(): Promise<Setting[]> {\n return this.repo.find({ relations: ['moduleMetadata'] });\n }\n\n private parseSettingValue(value: string, key: string): any {\n try {\n return JSON.parse(value);\n } catch {\n if (value === 'true' || value === 'false') {\n return value === 'true';\n }\n if (!isNaN(Number(value)) && value.trim() !== '') {\n return Number(value);\n }\n if (!this.arrayKeysToSkip.has(key) && value.includes(',')) {\n return value.split(',').map(item => item.trim());\n }\n return value;\n }\n }\n\n private buildSettingLabel(key: string): string {\n return key\n .replace(/([a-z0-9])([A-Z])/g, '$1 $2')\n .replace(/[-_]+/g, ' ')\n .replace(/\\s+/g, ' ')\n .trim()\n .replace(/\\b\\w/g, (match) => match.toUpperCase());\n }\n\n private inferControlType(setting: SettingDefinition): SettingControlType {\n if (setting.controlType) {\n return setting.controlType;\n }\n\n if (setting.options?.length) {\n return 'selectionStatic';\n }\n\n if (typeof setting.value === 'boolean') {\n return 'boolean';\n }\n\n if (typeof setting.value === 'number') {\n return 'numeric';\n }\n\n return 'shortText';\n }\n\n private toAdminSettingDefinition(setting: SettingDefinition): AdminSettingDefinition {\n return {\n ...setting,\n label: setting.label ?? this.buildSettingLabel(setting.key),\n controlType: this.inferControlType(setting),\n editable: setting.level === SettingLevel.SystemAdminEditable,\n };\n }\n\n /**\n * Reads all registered providers and gathers settings from across the running platform.\n * This is the superset of all possible settings. \n * @returns \n */\n private getAllSettingsFromProviders(): SettingDefinition[] {\n // get all settings from registry \n const allSettingsProviders = this.solidRegistry.getSettingsProviders();\n const settings: SettingDefinition[] = [];\n const seenKeys = new Map<string, { setting: SettingDefinition; providerName?: string }>();\n for (const wrapper of allSettingsProviders) {\n const instance = wrapper.instance as ISettingsProvider;\n // if (!instance?.getSettings) continue;\n for (const setting of instance.getSettings()) {\n const existing = seenKeys.get(setting.key);\n if (existing) {\n throw new Error(\n `Duplicate setting key detected: ${setting.key}. ` +\n `First: ${JSON.stringify(existing.setting)} from provider: ${existing.providerName ?? \"unknown\"}. ` +\n `Second: ${JSON.stringify(setting)} from provider: ${wrapper.name ?? \"unknown\"}.`\n );\n }\n seenKeys.set(setting.key, { setting, providerName: wrapper.name });\n settings.push(setting);\n }\n }\n\n return settings\n }\n\n /**\n * public method that gets all settings in the system, this includes settings from solid-core and any consuming projects.\n * this means that the settings returned are the ones provided by ISettingsProvider, merged with values if any from the database. \n * \n * @returns \n */\n getAllSettings(): SettingDefinition[] {\n return this.settings;\n }\n\n async updateSettingsCache(): Promise<void> {\n this._logger.debug(`updating settings cache...`);\n const settingsFromDb = await this.getSettingsFromDb();\n const settingsFromProviders = this.getAllSettingsFromProviders();\n const settingsFromDbByKey = new Map(settingsFromDb.map(setting => [setting.key, setting]));\n\n this.settings = settingsFromProviders.map(setting => {\n const settingFromDb = settingsFromDbByKey.get(setting.key);\n const valueFromDb = settingFromDb?.value;\n if (settingFromDb?.key && valueFromDb !== undefined && valueFromDb !== null) {\n let rawValue = valueFromDb;\n if (settingFromDb.encrypted && this.encryptionService) {\n try {\n rawValue = this.encryptionService.decrypt(rawValue);\n } catch {\n this._logger.warn(`Failed to decrypt setting \"${setting.key}\" — using raw value`);\n }\n }\n const parsedValue = typeof rawValue === 'string' ? this.parseSettingValue(rawValue, settingFromDb.key) : rawValue;\n return { ...setting, value: parsedValue };\n }\n return setting;\n });\n\n // Also keep a key vs SettingDefinition map...\n this.settingsByKey = new Map(this.settings.map(setting => [setting.key, setting]));\n }\n\n private isDisallowedSettingKey(key: string, settingLevelsToDisallow: SettingLevel[]): boolean {\n if (!key) {\n return false;\n }\n const setting = this.settingsByKey.get(key);\n // return setting ? [SettingLevel.SystemEnv, SettingLevel.SystemAdminReadonly].includes(setting.level) : false;\n return setting ? settingLevelsToDisallow.includes(setting.level) : false;\n }\n\n /**\n * 1. \n * This method will seed (insert only) settings that are introduced in code but do not already exist in the database. \n * Also this method only deals with settings with level system-admin-editable & internal-user.\n */\n async seedSystemAdminEditableAndAboveSettings(): Promise<void> {\n // Seed only settings with level system-admin-editable & internal-user, \n // so basically settings which are either system-admin-editable and above.\n const saEditableAndAbove = this.getAllSettingsFromProviders().filter(i => [SettingLevel.SystemAdminEditable, SettingLevel.InternalUser].includes(i.level));\n\n // Get hold of the current values from the database.\n const existingSettingsFromDb: Setting[] = await this.getSettingsFromDbForSeeding();\n\n // const existingKeysFromDb = new Set(existingSettingsFromDb.map(s => s.key));\n const existingSettingsFromDbByKey = new Map(existingSettingsFromDb.map(setting => [setting.key, setting]));\n const settingsToCreate: Setting[] = [];\n const settingsToUpdate: Setting[] = [];\n const moduleNames = Array.from(\n new Set(\n saEditableAndAbove\n .map(setting => setting.moduleName)\n .filter((moduleName): moduleName is string => !!moduleName)\n )\n );\n const moduleMetadataByName = new Map<string, Awaited<ReturnType<ModuleMetadataRepository['findOneBy']>>>();\n\n await Promise.all(\n moduleNames.map(async (moduleName) => {\n const moduleMetadata = await this.moduleMetadataRepo.findOneBy({ name: moduleName });\n moduleMetadataByName.set(moduleName, moduleMetadata);\n })\n );\n\n for (const { key, value, level, moduleName, encrypted } of saEditableAndAbove) {\n const moduleMetadata = moduleName ? moduleMetadataByName.get(moduleName) : null;\n if (!existingSettingsFromDbByKey.has(key)) {\n const setting = new Setting();\n setting.key = key;\n setting.level = level;\n setting.encrypted = !!encrypted;\n if (moduleMetadata)\n setting.moduleMetadata = moduleMetadata;\n\n let rawValue: string | null;\n if (typeof value === 'boolean') {\n rawValue = value.toString();\n } else if (Array.isArray(value)) {\n rawValue = value.join(',');\n } else if (value === null || value === undefined) {\n rawValue = null;\n } else {\n rawValue = String(value);\n }\n\n if (encrypted && this.encryptionService && rawValue !== null) {\n rawValue = this.encryptionService.encrypt(rawValue);\n }\n setting.value = rawValue;\n\n settingsToCreate.push(setting);\n }\n else {\n const setting = existingSettingsFromDbByKey.get(key);\n const existingModuleMetadataId = setting.moduleMetadata?.id ?? null;\n const nextModuleMetadataId = moduleMetadata?.id ?? null;\n const levelChanged = setting.level !== level;\n const encryptedChanged = setting.encrypted !== !!encrypted;\n const moduleChanged = !!moduleMetadata && existingModuleMetadataId !== nextModuleMetadataId;\n\n if (!levelChanged && !encryptedChanged && !moduleChanged) {\n continue;\n }\n\n setting.level = level;\n setting.encrypted = !!encrypted;\n if (moduleMetadata) {\n setting.moduleMetadata = moduleMetadata;\n }\n settingsToUpdate.push(setting);\n }\n }\n\n if (settingsToCreate.length > 0) {\n await this.repo.save(settingsToCreate);\n }\n\n if (settingsToUpdate.length > 0) {\n await this.repo.save(settingsToUpdate);\n }\n }\n\n /**\n * 2. \n * Method used from the solid-core-ui to fetch available settings. \n * Here we are returning settings other than system-env.\n * \n * @returns \n */\n async getNonEncryptedSystemAdminReadonlyAndAboveSettings(): Promise<AdminSettingsResponse> {\n const activeUser = this.requestContextService.getActiveUser();\n const hasViewEncryptedPermission = !!activeUser?.permissions?.includes('settings:view_encrypted');\n\n const data = this.settings\n .filter(i => i.level !== \"system-env\")\n .filter(i => hasViewEncryptedPermission || !i.encrypted)\n .filter((setting) => [SettingLevel.SystemAdminReadonly, SettingLevel.SystemAdminEditable].includes(setting.level))\n .map((setting) => this.toAdminSettingDefinition(setting))\n .sort((left, right) => {\n const groupCompare = (left.group ?? '').localeCompare(right.group ?? '');\n if (groupCompare !== 0) {\n return groupCompare;\n }\n\n const leftSort = left.sortOrder ?? Number.MAX_SAFE_INTEGER;\n const rightSort = right.sortOrder ?? Number.MAX_SAFE_INTEGER;\n if (leftSort !== rightSort) {\n return leftSort - rightSort;\n }\n\n return left.label!.localeCompare(right.label!);\n });\n\n return { data };\n }\n\n /**\n * 3. \n * This method updates settings from the admin user interface. \n * Most likely settings with level system-admin-editable & internal-user are the ones that will get modified here. \n * \n * @param settings \n * @param uploadedFiles \n * @returns \n */\n async updateSettings(settings: CreateSettingDto[] = [], uploadedFiles: Array<Express.Multer.File> = []): Promise<Setting[]> {\n const activeUser = this.requestContextService.getActiveUser();\n const userId = activeUser?.sub;\n\n const restrictedKeys = new Set<string>();\n\n settings.forEach(setting => {\n if (this.isDisallowedSettingKey(setting.key, [SettingLevel.SystemEnv, SettingLevel.SystemAdminReadonly])) {\n restrictedKeys.add(setting.key);\n }\n });\n uploadedFiles.forEach(file => {\n if (this.isDisallowedSettingKey(file.fieldname, [SettingLevel.SystemEnv, SettingLevel.SystemAdminReadonly])) {\n restrictedKeys.add(file.fieldname);\n }\n });\n\n if (restrictedKeys.size > 0) {\n throw new BadRequestException(`${ERROR_MESSAGES.FORBIDDEN}: Settings ${Array.from(restrictedKeys).join(', ')} cannot be modified.`);\n }\n\n // const existingSettings = await this.repo.find();\n const existingSettings: Setting[] = await this.getSettingsFromDb();\n\n const settingsToUpdate: Setting[] = [];\n const settingsToCreate: Setting[] = [];\n\n let user: User | null = null;\n const hasUserSettings = settings.some(dto => dto.type === 'user');\n if (hasUserSettings && userId) {\n user = await this.userRepository.findOne({ where: { id: userId } });\n }\n\n // Handle uploaded files\n if (uploadedFiles?.length) {\n for (const file of uploadedFiles) {\n const settingKey = file.fieldname;\n const relativeFileName = `${file.filename}-${file.originalname}`;\n\n // Read file from local disk (where Multer stores uploads) and write to storage\n // The path builder constructs the provider-appropriate storage path\n const fileContent = await fsPromises.readFile(file.path);\n const storagePath = this.pathBuilder.build(relativeFileName);\n const fileUrl = await this.fileService.write(storagePath, fileContent, { contentType: file.mimetype });\n // Delete the temp file from local disk\n await fsPromises.unlink(file.path);\n\n const matchedDto = settings.find(dto => dto.key === settingKey);\n const settingType = matchedDto?.type ?? 'system';\n\n const existingSetting = existingSettings.find(s => s.key === settingKey);\n if (existingSetting) {\n existingSetting.value = fileUrl;\n existingSetting.type = settingType;\n settingsToUpdate.push(existingSetting);\n } else {\n const newSetting = new Setting();\n newSetting.key = settingKey;\n newSetting.value = fileUrl;\n newSetting.type = settingType;\n\n if (settingType === 'user' && user) {\n newSetting.user = user;\n }\n\n settingsToCreate.push(newSetting);\n }\n }\n }\n\n // Handle non-file settings\n for (const settingDto of settings) {\n if (uploadedFiles?.some(file => file.fieldname === settingDto.key)) {\n continue; // skip if already handled via file\n }\n\n const key = settingDto.key;\n const rawValue = settingDto.value;\n let value = rawValue === null || rawValue === undefined ? null : String(rawValue);\n\n const settingType = settingDto.type ?? 'system';\n const definition = this.settingsByKey.get(key);\n const shouldEncrypt = !!definition?.encrypted && this.encryptionService !== null && value !== null;\n\n if (shouldEncrypt) {\n value = this.encryptionService.encrypt(value);\n }\n\n const existingSetting = existingSettings.find(s => s.key === key);\n if (existingSetting) {\n existingSetting.value = value;\n existingSetting.type = settingType;\n existingSetting.encrypted = shouldEncrypt;\n settingsToUpdate.push(existingSetting);\n } else {\n const newSetting = new Setting();\n newSetting.key = key;\n newSetting.value = value;\n newSetting.type = settingType;\n newSetting.encrypted = shouldEncrypt;\n\n if (settingType === 'user' && user) {\n newSetting.user = user;\n }\n\n settingsToCreate.push(newSetting);\n }\n }\n\n if (settingsToUpdate.length > 0) {\n await this.repo.save(settingsToUpdate);\n }\n\n if (settingsToCreate.length > 0) {\n await this.repo.save(settingsToCreate);\n }\n await this.updateSettingsCache();\n\n return [...settingsToUpdate, ...settingsToCreate];\n }\n\n /**\n * 4. \n * @param settingKey \n * @returns \n */\n getConfigValue<T = never>(settingKey: NoInfer<T>) {\n const cachedSetting = this.settingsByKey.get(settingKey as string);\n if (cachedSetting) {\n return cachedSetting.value;\n }\n\n return null;\n\n // const cachedSetting = this.settings.find(setting => setting.key === settingKey);\n // if (cachedSetting) {\n // return cachedSetting.value;\n // }\n\n // // This is probably not needed at all, but leaving it here as a backup for scenarios like \n // // if getConfigValue<SolidCoreSetting>() is called before onApplicationBootstrap() runs or if the cache refresh fails. \n // const getAllSettings = this.getAllSettingsFromProviders();\n // const settingValue = getAllSettings.find(i => (i.key == settingKey))\n // return settingValue?.value;\n }\n\n async getMcpUrl(getMcpUrlDto: GetMcpUrlDto, solidRequestContext: any = {}): Promise<any> {\n\n const { showHeader, inListView } = getMcpUrlDto;\n\n const mcpEnabled = this.getConfigValue<SolidCoreSetting>('mcpEnabled');\n if (mcpEnabled === 'false' || mcpEnabled === false) {\n throw new ForbiddenException(ERROR_MESSAGES.FORBIDDEN);\n }\n\n if (solidRequestContext.activeUser) {\n const permissionNames = [\"SettingController.getMcpUrl\"];\n const matchingPermssions = solidRequestContext.activeUser.permissions.filter((p: any) => permissionNames.includes(p));\n const hasPermission = matchingPermssions.length > 0;\n if (!hasPermission) {\n throw new BadRequestException(ERROR_MESSAGES.FORBIDDEN);\n }\n }\n const apiKey = this.getConfigValue<SolidCoreSetting>('mcpApiKey');\n const userId = solidRequestContext.activeUser.sub;\n const mcpServerUrl = this.getConfigValue<SolidCoreSetting>('mcpServerUrl');\n return { mcpUrl: `${mcpServerUrl}/static/frontend.html?solidx-mcp-api-key=${apiKey}&solidx-user-id=${userId}&solidx-show-header=${showHeader}&solidx-in-list-view=${inListView}` };\n }\n\n}\n"]}
|
|
1
|
+
{"version":3,"file":"setting.service.js","sourceRoot":"","sources":["../../src/services/setting.service.ts"],"names":[],"mappings":"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","sourcesContent":["import { BadRequestException, ForbiddenException, Inject, Injectable } from '@nestjs/common';\nimport { InjectRepository } from '@nestjs/typeorm';\nimport { Repository } from 'typeorm';\nimport * as fsPromises from 'fs/promises';\nimport { ERROR_MESSAGES } from 'src/constants/error-messages';\nimport { CreateSettingDto } from 'src/dtos/create-setting.dto';\nimport { GetMcpUrlDto } from 'src/dtos/get-mcp-url.dto';\nimport { User } from 'src/entities/user.entity';\nimport { SettingRepository } from '../repository/setting.repository';\nimport { FILE_SERVICE, IFileService, FILE_STORAGE_PATH_BUILDER, IStoragePathBuilder } from './file';\nimport { Setting } from '../entities/setting.entity';\nimport { RequestContextService } from './request-context.service';\nimport { SolidRegistry } from 'src/helpers/solid-registry';\nimport { AdminSettingDefinition, AdminSettingsResponse, ISettingsProvider, NoInfer, SettingControlType, SettingDefinition, SettingLevel } from '../interfaces';\nimport { ModuleMetadataRepository } from 'src/repository/module-metadata.repository';\nimport type { SolidCoreSetting } from './settings/default-settings-provider.service';\nimport { Logger } from '@nestjs/common';\nimport { EncryptionService } from './encryption.service';\nimport { sanitizeStoredMediaFileName } from './media-storage.utils';\n\n\n@Injectable()\nexport class SettingService {\n private readonly _logger = new Logger(SettingService.name);\n\n private settings: SettingDefinition[] = [];\n private settingsByKey = new Map<string, SettingDefinition>();\n private readonly encryptionService: EncryptionService | null;\n\n private readonly arrayKeysToSkip = new Set([\n 'authenticationPasswordRegex',\n 'authenticationPasswordRegexErrorMessage',\n 'authenticationPasswordComplexityDescription',\n ]);\n\n constructor(\n @Inject(FILE_SERVICE) readonly fileService: IFileService,\n @Inject(FILE_STORAGE_PATH_BUILDER) readonly pathBuilder: IStoragePathBuilder,\n readonly solidRegistry: SolidRegistry,\n readonly repo: SettingRepository,\n readonly moduleMetadataRepo: ModuleMetadataRepository,\n private readonly requestContextService: RequestContextService,\n @InjectRepository(User) private readonly userRepository: Repository<User>,\n ) {\n const encKey = process.env.APP_ENCRYPTION_KEY;\n this.encryptionService = encKey ? new EncryptionService(encKey) : null;\n if (!encKey) this._logger.warn('APP_ENCRYPTION_KEY is not set — encrypted settings will not be decrypted');\n }\n\n private async getSettingsFromDb(): Promise<Setting[]> {\n const settings = await this.repo.find({ relations: ['user'] });\n return settings;\n }\n\n private async getSettingsFromDbForSeeding(): Promise<Setting[]> {\n return this.repo.find({ relations: ['moduleMetadata'] });\n }\n\n private parseSettingValue(value: string, key: string): any {\n try {\n return JSON.parse(value);\n } catch {\n if (value === 'true' || value === 'false') {\n return value === 'true';\n }\n if (!isNaN(Number(value)) && value.trim() !== '') {\n return Number(value);\n }\n if (!this.arrayKeysToSkip.has(key) && value.includes(',')) {\n return value.split(',').map(item => item.trim());\n }\n return value;\n }\n }\n\n private buildSettingLabel(key: string): string {\n return key\n .replace(/([a-z0-9])([A-Z])/g, '$1 $2')\n .replace(/[-_]+/g, ' ')\n .replace(/\\s+/g, ' ')\n .trim()\n .replace(/\\b\\w/g, (match) => match.toUpperCase());\n }\n\n private inferControlType(setting: SettingDefinition): SettingControlType {\n if (setting.controlType) {\n return setting.controlType;\n }\n\n if (setting.options?.length) {\n return 'selectionStatic';\n }\n\n if (typeof setting.value === 'boolean') {\n return 'boolean';\n }\n\n if (typeof setting.value === 'number') {\n return 'numeric';\n }\n\n return 'shortText';\n }\n\n private toAdminSettingDefinition(setting: SettingDefinition): AdminSettingDefinition {\n return {\n ...setting,\n label: setting.label ?? this.buildSettingLabel(setting.key),\n controlType: this.inferControlType(setting),\n editable: setting.level === SettingLevel.SystemAdminEditable,\n };\n }\n\n /**\n * Reads all registered providers and gathers settings from across the running platform.\n * This is the superset of all possible settings. \n * @returns \n */\n private getAllSettingsFromProviders(): SettingDefinition[] {\n // get all settings from registry \n const allSettingsProviders = this.solidRegistry.getSettingsProviders();\n const settings: SettingDefinition[] = [];\n const seenKeys = new Map<string, { setting: SettingDefinition; providerName?: string }>();\n for (const wrapper of allSettingsProviders) {\n const instance = wrapper.instance as ISettingsProvider;\n // if (!instance?.getSettings) continue;\n for (const setting of instance.getSettings()) {\n const existing = seenKeys.get(setting.key);\n if (existing) {\n throw new Error(\n `Duplicate setting key detected: ${setting.key}. ` +\n `First: ${JSON.stringify(existing.setting)} from provider: ${existing.providerName ?? \"unknown\"}. ` +\n `Second: ${JSON.stringify(setting)} from provider: ${wrapper.name ?? \"unknown\"}.`\n );\n }\n seenKeys.set(setting.key, { setting, providerName: wrapper.name });\n settings.push(setting);\n }\n }\n\n return settings\n }\n\n /**\n * public method that gets all settings in the system, this includes settings from solid-core and any consuming projects.\n * this means that the settings returned are the ones provided by ISettingsProvider, merged with values if any from the database. \n * \n * @returns \n */\n getAllSettings(): SettingDefinition[] {\n return this.settings;\n }\n\n async updateSettingsCache(): Promise<void> {\n this._logger.debug(`updating settings cache...`);\n const settingsFromDb = await this.getSettingsFromDb();\n const settingsFromProviders = this.getAllSettingsFromProviders();\n const settingsFromDbByKey = new Map(settingsFromDb.map(setting => [setting.key, setting]));\n\n this.settings = settingsFromProviders.map(setting => {\n const settingFromDb = settingsFromDbByKey.get(setting.key);\n const valueFromDb = settingFromDb?.value;\n if (settingFromDb?.key && valueFromDb !== undefined && valueFromDb !== null) {\n let rawValue = valueFromDb;\n if (settingFromDb.encrypted && this.encryptionService) {\n try {\n rawValue = this.encryptionService.decrypt(rawValue);\n } catch {\n this._logger.warn(`Failed to decrypt setting \"${setting.key}\" — using raw value`);\n }\n }\n const parsedValue = typeof rawValue === 'string' ? this.parseSettingValue(rawValue, settingFromDb.key) : rawValue;\n return { ...setting, value: parsedValue };\n }\n return setting;\n });\n\n // Also keep a key vs SettingDefinition map...\n this.settingsByKey = new Map(this.settings.map(setting => [setting.key, setting]));\n }\n\n private isDisallowedSettingKey(key: string, settingLevelsToDisallow: SettingLevel[]): boolean {\n if (!key) {\n return false;\n }\n const setting = this.settingsByKey.get(key);\n // return setting ? [SettingLevel.SystemEnv, SettingLevel.SystemAdminReadonly].includes(setting.level) : false;\n return setting ? settingLevelsToDisallow.includes(setting.level) : false;\n }\n\n /**\n * 1. \n * This method will seed (insert only) settings that are introduced in code but do not already exist in the database. \n * Also this method only deals with settings with level system-admin-editable & internal-user.\n */\n async seedSystemAdminEditableAndAboveSettings(): Promise<void> {\n // Seed only settings with level system-admin-editable & internal-user, \n // so basically settings which are either system-admin-editable and above.\n const saEditableAndAbove = this.getAllSettingsFromProviders().filter(i => [SettingLevel.SystemAdminEditable, SettingLevel.InternalUser].includes(i.level));\n\n // Get hold of the current values from the database.\n const existingSettingsFromDb: Setting[] = await this.getSettingsFromDbForSeeding();\n\n // const existingKeysFromDb = new Set(existingSettingsFromDb.map(s => s.key));\n const existingSettingsFromDbByKey = new Map(existingSettingsFromDb.map(setting => [setting.key, setting]));\n const settingsToCreate: Setting[] = [];\n const settingsToUpdate: Setting[] = [];\n const moduleNames = Array.from(\n new Set(\n saEditableAndAbove\n .map(setting => setting.moduleName)\n .filter((moduleName): moduleName is string => !!moduleName)\n )\n );\n const moduleMetadataByName = new Map<string, Awaited<ReturnType<ModuleMetadataRepository['findOneBy']>>>();\n\n await Promise.all(\n moduleNames.map(async (moduleName) => {\n const moduleMetadata = await this.moduleMetadataRepo.findOneBy({ name: moduleName });\n moduleMetadataByName.set(moduleName, moduleMetadata);\n })\n );\n\n for (const { key, value, level, moduleName, encrypted } of saEditableAndAbove) {\n const moduleMetadata = moduleName ? moduleMetadataByName.get(moduleName) : null;\n if (!existingSettingsFromDbByKey.has(key)) {\n const setting = new Setting();\n setting.key = key;\n setting.level = level;\n setting.encrypted = !!encrypted;\n if (moduleMetadata)\n setting.moduleMetadata = moduleMetadata;\n\n let rawValue: string | null;\n if (typeof value === 'boolean') {\n rawValue = value.toString();\n } else if (Array.isArray(value)) {\n rawValue = value.join(',');\n } else if (value === null || value === undefined) {\n rawValue = null;\n } else {\n rawValue = String(value);\n }\n\n if (encrypted && this.encryptionService && rawValue !== null) {\n rawValue = this.encryptionService.encrypt(rawValue);\n }\n setting.value = rawValue;\n\n settingsToCreate.push(setting);\n }\n else {\n const setting = existingSettingsFromDbByKey.get(key);\n const existingModuleMetadataId = setting.moduleMetadata?.id ?? null;\n const nextModuleMetadataId = moduleMetadata?.id ?? null;\n const levelChanged = setting.level !== level;\n const encryptedChanged = setting.encrypted !== !!encrypted;\n const moduleChanged = !!moduleMetadata && existingModuleMetadataId !== nextModuleMetadataId;\n\n if (!levelChanged && !encryptedChanged && !moduleChanged) {\n continue;\n }\n\n setting.level = level;\n setting.encrypted = !!encrypted;\n if (moduleMetadata) {\n setting.moduleMetadata = moduleMetadata;\n }\n settingsToUpdate.push(setting);\n }\n }\n\n if (settingsToCreate.length > 0) {\n await this.repo.save(settingsToCreate);\n }\n\n if (settingsToUpdate.length > 0) {\n await this.repo.save(settingsToUpdate);\n }\n }\n\n /**\n * 2. \n * Method used from the solid-core-ui to fetch available settings. \n * Here we are returning settings other than system-env.\n * \n * @returns \n */\n async getNonEncryptedSystemAdminReadonlyAndAboveSettings(): Promise<AdminSettingsResponse> {\n const activeUser = this.requestContextService.getActiveUser();\n const hasViewEncryptedPermission = !!activeUser?.permissions?.includes('settings:view_encrypted');\n\n const data = this.settings\n .filter(i => i.level !== \"system-env\")\n .filter(i => hasViewEncryptedPermission || !i.encrypted)\n .filter((setting) => [SettingLevel.SystemAdminReadonly, SettingLevel.SystemAdminEditable].includes(setting.level))\n .map((setting) => this.toAdminSettingDefinition(setting))\n .sort((left, right) => {\n const groupCompare = (left.group ?? '').localeCompare(right.group ?? '');\n if (groupCompare !== 0) {\n return groupCompare;\n }\n\n const leftSort = left.sortOrder ?? Number.MAX_SAFE_INTEGER;\n const rightSort = right.sortOrder ?? Number.MAX_SAFE_INTEGER;\n if (leftSort !== rightSort) {\n return leftSort - rightSort;\n }\n\n return left.label!.localeCompare(right.label!);\n });\n\n return { data };\n }\n\n /**\n * 3. \n * This method updates settings from the admin user interface. \n * Most likely settings with level system-admin-editable & internal-user are the ones that will get modified here. \n * \n * @param settings \n * @param uploadedFiles \n * @returns \n */\n async updateSettings(settings: CreateSettingDto[] = [], uploadedFiles: Array<Express.Multer.File> = []): Promise<Setting[]> {\n const activeUser = this.requestContextService.getActiveUser();\n const userId = activeUser?.sub;\n\n const restrictedKeys = new Set<string>();\n\n settings.forEach(setting => {\n if (this.isDisallowedSettingKey(setting.key, [SettingLevel.SystemEnv, SettingLevel.SystemAdminReadonly])) {\n restrictedKeys.add(setting.key);\n }\n });\n uploadedFiles.forEach(file => {\n if (this.isDisallowedSettingKey(file.fieldname, [SettingLevel.SystemEnv, SettingLevel.SystemAdminReadonly])) {\n restrictedKeys.add(file.fieldname);\n }\n });\n\n if (restrictedKeys.size > 0) {\n throw new BadRequestException(`${ERROR_MESSAGES.FORBIDDEN}: Settings ${Array.from(restrictedKeys).join(', ')} cannot be modified.`);\n }\n\n // const existingSettings = await this.repo.find();\n const existingSettings: Setting[] = await this.getSettingsFromDb();\n\n const settingsToUpdate: Setting[] = [];\n const settingsToCreate: Setting[] = [];\n\n let user: User | null = null;\n const hasUserSettings = settings.some(dto => dto.type === 'user');\n if (hasUserSettings && userId) {\n user = await this.userRepository.findOne({ where: { id: userId } });\n }\n\n // Handle uploaded files\n if (uploadedFiles?.length) {\n for (const file of uploadedFiles) {\n const settingKey = file.fieldname;\n // originalname is attacker-controlled and feeds straight into a storage path.\n const relativeFileName = `${file.filename}-${sanitizeStoredMediaFileName(file.originalname)}`;\n\n // Read file from local disk (where Multer stores uploads) and write to storage\n // The path builder constructs the provider-appropriate storage path\n const fileContent = await fsPromises.readFile(file.path);\n const storagePath = this.pathBuilder.build(relativeFileName);\n const fileUrl = await this.fileService.write(storagePath, fileContent, { contentType: file.mimetype });\n // Delete the temp file from local disk\n await fsPromises.unlink(file.path);\n\n const matchedDto = settings.find(dto => dto.key === settingKey);\n const settingType = matchedDto?.type ?? 'system';\n\n const existingSetting = existingSettings.find(s => s.key === settingKey);\n if (existingSetting) {\n existingSetting.value = fileUrl;\n existingSetting.type = settingType;\n settingsToUpdate.push(existingSetting);\n } else {\n const newSetting = new Setting();\n newSetting.key = settingKey;\n newSetting.value = fileUrl;\n newSetting.type = settingType;\n\n if (settingType === 'user' && user) {\n newSetting.user = user;\n }\n\n settingsToCreate.push(newSetting);\n }\n }\n }\n\n // Handle non-file settings\n for (const settingDto of settings) {\n if (uploadedFiles?.some(file => file.fieldname === settingDto.key)) {\n continue; // skip if already handled via file\n }\n\n const key = settingDto.key;\n const rawValue = settingDto.value;\n let value = rawValue === null || rawValue === undefined ? null : String(rawValue);\n\n const settingType = settingDto.type ?? 'system';\n const definition = this.settingsByKey.get(key);\n const shouldEncrypt = !!definition?.encrypted && this.encryptionService !== null && value !== null;\n\n if (shouldEncrypt) {\n value = this.encryptionService.encrypt(value);\n }\n\n const existingSetting = existingSettings.find(s => s.key === key);\n if (existingSetting) {\n existingSetting.value = value;\n existingSetting.type = settingType;\n existingSetting.encrypted = shouldEncrypt;\n settingsToUpdate.push(existingSetting);\n } else {\n const newSetting = new Setting();\n newSetting.key = key;\n newSetting.value = value;\n newSetting.type = settingType;\n newSetting.encrypted = shouldEncrypt;\n\n if (settingType === 'user' && user) {\n newSetting.user = user;\n }\n\n settingsToCreate.push(newSetting);\n }\n }\n\n if (settingsToUpdate.length > 0) {\n await this.repo.save(settingsToUpdate);\n }\n\n if (settingsToCreate.length > 0) {\n await this.repo.save(settingsToCreate);\n }\n await this.updateSettingsCache();\n\n return [...settingsToUpdate, ...settingsToCreate];\n }\n\n /**\n * 4. \n * @param settingKey \n * @returns \n */\n getConfigValue<T = never>(settingKey: NoInfer<T>) {\n const cachedSetting = this.settingsByKey.get(settingKey as string);\n if (cachedSetting) {\n return cachedSetting.value;\n }\n\n return null;\n\n // const cachedSetting = this.settings.find(setting => setting.key === settingKey);\n // if (cachedSetting) {\n // return cachedSetting.value;\n // }\n\n // // This is probably not needed at all, but leaving it here as a backup for scenarios like \n // // if getConfigValue<SolidCoreSetting>() is called before onApplicationBootstrap() runs or if the cache refresh fails. \n // const getAllSettings = this.getAllSettingsFromProviders();\n // const settingValue = getAllSettings.find(i => (i.key == settingKey))\n // return settingValue?.value;\n }\n\n async getMcpUrl(getMcpUrlDto: GetMcpUrlDto, solidRequestContext: any = {}): Promise<any> {\n\n const { showHeader, inListView } = getMcpUrlDto;\n\n const mcpEnabled = this.getConfigValue<SolidCoreSetting>('mcpEnabled');\n if (mcpEnabled === 'false' || mcpEnabled === false) {\n throw new ForbiddenException(ERROR_MESSAGES.FORBIDDEN);\n }\n\n if (solidRequestContext.activeUser) {\n const permissionNames = [\"SettingController.getMcpUrl\"];\n const matchingPermssions = solidRequestContext.activeUser.permissions.filter((p: any) => permissionNames.includes(p));\n const hasPermission = matchingPermssions.length > 0;\n if (!hasPermission) {\n throw new BadRequestException(ERROR_MESSAGES.FORBIDDEN);\n }\n }\n const apiKey = this.getConfigValue<SolidCoreSetting>('mcpApiKey');\n const userId = solidRequestContext.activeUser.sub;\n const mcpServerUrl = this.getConfigValue<SolidCoreSetting>('mcpServerUrl');\n return { mcpUrl: `${mcpServerUrl}/static/frontend.html?solidx-mcp-api-key=${apiKey}&solidx-user-id=${userId}&solidx-show-header=${showHeader}&solidx-in-list-view=${inListView}` };\n }\n\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@solidxai/core",
|
|
3
|
-
"version": "0.1.13-beta.
|
|
3
|
+
"version": "0.1.13-beta.16",
|
|
4
4
|
"description": "This module is a NestJS module containing all the required core providers required by a Solid application",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -29,17 +29,66 @@ export const DANGEROUS_MIME_TYPES = new Set([
|
|
|
29
29
|
'image/svg+xml', 'text/html', 'application/xhtml+xml',
|
|
30
30
|
]);
|
|
31
31
|
|
|
32
|
-
|
|
32
|
+
/**
|
|
33
|
+
* Reduces a client-supplied name to the name that will actually be resolved on disk, so
|
|
34
|
+
* extension checks can't be dodged by decorating it. Each step defends a known bypass:
|
|
35
|
+
*
|
|
36
|
+
* - `../../evil.exe` -> only the final path segment is the file name.
|
|
37
|
+
* - `evil.exe\0.png` -> a NUL truncates the name at the syscall/filesystem layer, so
|
|
38
|
+
* anything after it is invisible to the OS but visible to naive
|
|
39
|
+
* validation.
|
|
40
|
+
* - `evil.exe::$DATA` -> NTFS alternate data stream suffix; the file on disk is evil.exe.
|
|
41
|
+
* - `evil.exe.` / `.exe ` -> Windows silently strips trailing dots and spaces when resolving
|
|
42
|
+
* a path, so these land on disk as evil.exe.
|
|
43
|
+
*/
|
|
44
|
+
export function normalizeUploadedFileName(fileName?: string | null): string {
|
|
33
45
|
if (!fileName) {
|
|
34
|
-
return
|
|
46
|
+
return '';
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
let name = String(fileName).split(/[/\\]/).pop() ?? '';
|
|
50
|
+
|
|
51
|
+
const nulIndex = name.indexOf('\0');
|
|
52
|
+
if (nulIndex >= 0) {
|
|
53
|
+
name = name.slice(0, nulIndex);
|
|
35
54
|
}
|
|
36
55
|
|
|
37
|
-
const
|
|
38
|
-
if (
|
|
56
|
+
const streamIndex = name.indexOf(':');
|
|
57
|
+
if (streamIndex >= 0) {
|
|
58
|
+
name = name.slice(0, streamIndex);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return name.replace(/[\s.]+$/, '');
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* The effective extension - what the OS/browser will treat the file as. Used for media
|
|
66
|
+
* category resolution and inline-safety decisions. Always normalizes first, so
|
|
67
|
+
* `evil.exe.` resolves to `exe` rather than to nothing.
|
|
68
|
+
*/
|
|
69
|
+
export function getLowercaseFileExtension(fileName?: string | null): string | undefined {
|
|
70
|
+
const name = normalizeUploadedFileName(fileName);
|
|
71
|
+
|
|
72
|
+
const lastDotIndex = name.lastIndexOf('.');
|
|
73
|
+
if (lastDotIndex < 0 || lastDotIndex === name.length - 1) {
|
|
39
74
|
return undefined;
|
|
40
75
|
}
|
|
41
76
|
|
|
42
|
-
return
|
|
77
|
+
return name.slice(lastDotIndex + 1).toLowerCase();
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Every dot-delimited segment after the stem, lowercased. The danger check uses this rather
|
|
82
|
+
* than only the effective extension so a dangerous type buried in a double extension
|
|
83
|
+
* (`evil.exe.png`, `shell.php.jpg`) is still caught - several servers and browsers resolve
|
|
84
|
+
* such names by an earlier segment than the last one.
|
|
85
|
+
*
|
|
86
|
+
* The stem is skipped so an innocuous file that merely starts with a keyword (`exe.png`)
|
|
87
|
+
* isn't rejected.
|
|
88
|
+
*/
|
|
89
|
+
export function getLowercaseFileExtensionSegments(fileName?: string | null): string[] {
|
|
90
|
+
const segments = normalizeUploadedFileName(fileName).toLowerCase().split('.');
|
|
91
|
+
return segments.slice(1).filter(segment => segment.length > 0);
|
|
43
92
|
}
|
|
44
93
|
|
|
45
94
|
/** Minimal shape of an uploaded file, so this module stays free of framework imports. */
|
|
@@ -57,12 +106,12 @@ export function getUploadedFileName(file?: UploadedFileLike | null): string {
|
|
|
57
106
|
/**
|
|
58
107
|
* Single predicate for "must never be stored". Shared by every upload entry point
|
|
59
108
|
* (MediaFieldCrudManager, chatter attachments) so the rules can't drift between them.
|
|
60
|
-
*
|
|
61
|
-
* application/octet-stream on an .html file) can't bypass it.
|
|
109
|
+
* Extensions are checked before mimetype so a spoofed Content-Type (e.g.
|
|
110
|
+
* application/octet-stream, or image/png, on an .html file) can't bypass it.
|
|
62
111
|
*/
|
|
63
112
|
export function isDangerousMediaFile(file?: UploadedFileLike | null): boolean {
|
|
64
|
-
const
|
|
65
|
-
if (
|
|
113
|
+
const segments = getLowercaseFileExtensionSegments(getUploadedFileName(file));
|
|
114
|
+
if (segments.some(segment => DANGEROUS_EXTENSIONS.has(segment))) {
|
|
66
115
|
return true;
|
|
67
116
|
}
|
|
68
117
|
|
|
@@ -9,6 +9,20 @@ export interface FileDownloadHeaderOptions {
|
|
|
9
9
|
crossOriginResourcePolicy?: boolean;
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
+
/**
|
|
13
|
+
* Builds an RFC 6266 Content-Disposition value. The file name is attacker-controlled (it comes
|
|
14
|
+
* from the uploaded originalFileName), so it can't be interpolated raw: a quote would close the
|
|
15
|
+
* quoted-string early and let the rest of the name forge further header parameters. The ASCII
|
|
16
|
+
* fallback is stripped to a safe subset and the real name is carried in the RFC 5987
|
|
17
|
+
* `filename*` parameter, which is also what preserves non-ASCII names correctly.
|
|
18
|
+
*/
|
|
19
|
+
function buildContentDisposition(disposition: "inline" | "attachment", fileName: string): string {
|
|
20
|
+
const name = (fileName || "file").replace(/[\r\n]/g, "");
|
|
21
|
+
const asciiFallback = name.replace(/[^\x20-\x7E]/g, "_").replace(/["\\]/g, "_") || "file";
|
|
22
|
+
|
|
23
|
+
return `${disposition}; filename="${asciiFallback}"; filename*=UTF-8''${encodeURIComponent(name)}`;
|
|
24
|
+
}
|
|
25
|
+
|
|
12
26
|
/**
|
|
13
27
|
* Single place that stamps the response headers for every streamed file download, so the
|
|
14
28
|
* security headers can't be applied to one endpoint and forgotten on the next.
|
|
@@ -16,7 +30,7 @@ export interface FileDownloadHeaderOptions {
|
|
|
16
30
|
export function setFileDownloadHeaders(res: Response, options: FileDownloadHeaderOptions): void {
|
|
17
31
|
const disposition = options.disposition ?? "attachment";
|
|
18
32
|
|
|
19
|
-
res.setHeader("Content-Disposition",
|
|
33
|
+
res.setHeader("Content-Disposition", buildContentDisposition(disposition, options.fileName));
|
|
20
34
|
res.setHeader("Content-Type", options.mimeType);
|
|
21
35
|
res.setHeader("Access-Control-Expose-Headers", "Content-Disposition, Content-Type");
|
|
22
36
|
|
|
@@ -5,6 +5,11 @@ import { MediaStorageProviderMetadata } from 'src/entities/media-storage-provide
|
|
|
5
5
|
import { SettingService } from 'src/services/setting.service';
|
|
6
6
|
import { DEFAULT_MEDIA_FILE_STORAGE_DIR } from 'src/services/settings/default-settings-provider.service';
|
|
7
7
|
import type { SolidCoreSetting } from 'src/services/settings/default-settings-provider.service';
|
|
8
|
+
import { normalizeUploadedFileName } from 'src/constants/media-file-types';
|
|
9
|
+
|
|
10
|
+
// Keeps the joined path well clear of filesystem NAME_MAX (255 on ext4/APFS) once the
|
|
11
|
+
// multer hash prefix and separator are added.
|
|
12
|
+
const MAX_STORED_FILE_NAME_LENGTH = 150;
|
|
8
13
|
|
|
9
14
|
|
|
10
15
|
export interface MediaRecordCreateInput {
|
|
@@ -18,9 +23,29 @@ export interface MediaRecordCreateInput {
|
|
|
18
23
|
originalFileName?: string;
|
|
19
24
|
}
|
|
20
25
|
|
|
26
|
+
/**
|
|
27
|
+
* Reduces a client-supplied name to something safe to interpolate into a filesystem path.
|
|
28
|
+
* `originalname` is fully attacker-controlled, so without this a name like
|
|
29
|
+
* `../../../../tmp/pwned.png` escapes the media storage directory entirely - the multer hash
|
|
30
|
+
* prefix does not contain it, because the leading `..` simply cancels the prefix segment.
|
|
31
|
+
*
|
|
32
|
+
* Everything outside a conservative allowlist becomes `_`; the result can never contain a
|
|
33
|
+
* path separator, so the joined path always stays inside the storage root.
|
|
34
|
+
*/
|
|
35
|
+
export function sanitizeStoredMediaFileName(originalName?: string | null): string {
|
|
36
|
+
const sanitized = normalizeUploadedFileName(originalName)
|
|
37
|
+
.replace(/[^A-Za-z0-9._-]/g, '_')
|
|
38
|
+
// Collapse any run of dots so no `..` segment can survive.
|
|
39
|
+
.replace(/\.{2,}/g, '.')
|
|
40
|
+
.replace(/^[._-]+/, '')
|
|
41
|
+
.slice(0, MAX_STORED_FILE_NAME_LENGTH);
|
|
42
|
+
|
|
43
|
+
return sanitized || 'file';
|
|
44
|
+
}
|
|
45
|
+
|
|
21
46
|
// Builds the stored file name format shared by media storage implementations.
|
|
22
47
|
export function buildStoredMediaFileName(file: Pick<Express.Multer.File, 'filename' | 'originalname'>): string {
|
|
23
|
-
return `${file.filename}-${file.originalname}`;
|
|
48
|
+
return `${file.filename}-${sanitizeStoredMediaFileName(file.originalname)}`;
|
|
24
49
|
}
|
|
25
50
|
|
|
26
51
|
// Resolves the on-disk path for a media file based on settings and provider visibility.
|
|
@@ -18,6 +18,7 @@ import { ModuleMetadataHelperService } from 'src/helpers/module-metadata-helper.
|
|
|
18
18
|
import { ModuleMetadataRepository } from 'src/repository/module-metadata.repository';
|
|
19
19
|
import { PermissionMetadataSeederService } from 'src/seeders/permission-metadata-seeder.service';
|
|
20
20
|
import { DiskFileService } from 'src/services/file';
|
|
21
|
+
import { sanitizeStoredMediaFileName } from 'src/services/media-storage.utils';
|
|
21
22
|
import { BasicFilterDto } from '../dtos/basic-filters.dto';
|
|
22
23
|
import { UpdateModuleMetadataDto } from '../dtos/update-module-metadata.dto';
|
|
23
24
|
import {
|
|
@@ -609,7 +610,8 @@ export class ModuleMetadataService {
|
|
|
609
610
|
}
|
|
610
611
|
|
|
611
612
|
private getFileName(file: Express.Multer.File): string {
|
|
612
|
-
|
|
613
|
+
// originalname is attacker-controlled and feeds straight into a storage path.
|
|
614
|
+
return `${file.filename}-${sanitizeStoredMediaFileName(file.originalname)}`;
|
|
613
615
|
}
|
|
614
616
|
|
|
615
617
|
}
|
|
@@ -16,6 +16,7 @@ import { ModuleMetadataRepository } from 'src/repository/module-metadata.reposit
|
|
|
16
16
|
import type { SolidCoreSetting } from './settings/default-settings-provider.service';
|
|
17
17
|
import { Logger } from '@nestjs/common';
|
|
18
18
|
import { EncryptionService } from './encryption.service';
|
|
19
|
+
import { sanitizeStoredMediaFileName } from './media-storage.utils';
|
|
19
20
|
|
|
20
21
|
|
|
21
22
|
@Injectable()
|
|
@@ -358,7 +359,8 @@ export class SettingService {
|
|
|
358
359
|
if (uploadedFiles?.length) {
|
|
359
360
|
for (const file of uploadedFiles) {
|
|
360
361
|
const settingKey = file.fieldname;
|
|
361
|
-
|
|
362
|
+
// originalname is attacker-controlled and feeds straight into a storage path.
|
|
363
|
+
const relativeFileName = `${file.filename}-${sanitizeStoredMediaFileName(file.originalname)}`;
|
|
362
364
|
|
|
363
365
|
// Read file from local disk (where Multer stores uploads) and write to storage
|
|
364
366
|
// The path builder constructs the provider-appropriate storage path
|