From fb06ea6f2ec48d178ad3ecffb7b339df0a6fb966 Mon Sep 17 00:00:00 2001 From: umeshmore45 Date: Tue, 10 Dec 2024 02:12:08 +0530 Subject: [PATCH] refactor code --- api/src/constants/index.ts | 66 +++++++++---------- api/src/services/migration.service.ts | 24 +++++-- api/src/utils/content-type-creator.utils.ts | 10 ++- api/src/utils/custom-logger.utils.ts | 16 ++++- api/src/utils/entries-field-creator.utils.ts | 10 ++- api/src/utils/test-folder-creator.utils.ts | 26 ++++---- .../src/commands/auth/login.ts | 2 +- 7 files changed, 91 insertions(+), 63 deletions(-) diff --git a/api/src/constants/index.ts b/api/src/constants/index.ts index 322f3ba11..3b2592318 100644 --- a/api/src/constants/index.ts +++ b/api/src/constants/index.ts @@ -1,11 +1,11 @@ export const CS_REGIONS = ["NA", "EU", "AZURE_NA", "AZURE_EU", "GCP_NA"]; export const CMS = { - CONTENTFUL:"contentful", - SITECORE_V8:"sitecore v8", - SITECORE_V9:"sitecore v9", - SITECORE_V10:"sitecore v10", - WORDPRESS:"wordpress", - AEM:"aem", + CONTENTFUL: "contentful", + SITECORE_V8: "sitecore v8", + SITECORE_V9: "sitecore v9", + SITECORE_V10: "sitecore v10", + WORDPRESS: "wordpress", + AEM: "aem", } export const MODULES = [ "Project", @@ -92,7 +92,7 @@ export const HTTP_TEXTS = { "Project Deleted Successfully", PROJECT_REVERT: "Project Reverted Successfully", - LOGS_NOT_FOUND: + LOGS_NOT_FOUND: "Sorry, no logs found for requested stack migration.", MIGRATION_EXECUTION_KEY_UPDATED: "Project's migration execution key updated successfully" @@ -177,47 +177,47 @@ export const LOCALE_MAPPER: any = { export const CHUNK_SIZE = 1048576; export const MIGRATION_DATA_CONFIG = { - DATA :"./cmsMigrationData", + DATA: "./cmsMigrationData", BACKUP_DATA: "migration-data", BACKUP_LOG_DIR: "logs", BACKUP_FOLDER_NAME: "import", BACKUP_FILE_NAME: "success.log", - LOCALE_DIR_NAME : "locales", - LOCALE_FILE_NAME : "locales.json", - LOCALE_MASTER_LOCALE : "master-locale.json", - LOCALE_CF_LANGUAGE : "language.json", + LOCALE_DIR_NAME: "locales", + LOCALE_FILE_NAME: "locales.json", + LOCALE_MASTER_LOCALE: "master-locale.json", + LOCALE_CF_LANGUAGE: "language.json", - WEBHOOKS_DIR_NAME : "webhooks", - WEBHOOKS_FILE_NAME : "webhooks.json", + WEBHOOKS_DIR_NAME: "webhooks", + WEBHOOKS_FILE_NAME: "webhooks.json", - ENVIRONMENTS_DIR_NAME : "environments", - ENVIRONMENTS_FILE_NAME : "environments.json", + ENVIRONMENTS_DIR_NAME: "environments", + ENVIRONMENTS_FILE_NAME: "environments.json", - CONTENT_TYPES_DIR_NAME : "content_types", - CONTENT_TYPES_FILE_NAME : "contenttype.json", - CONTENT_TYPES_MASTER_FILE : "contenttypes.json", - CONTENT_TYPES_SCHEMA_FILE : "schema.json", + CONTENT_TYPES_DIR_NAME: "content_types", + CONTENT_TYPES_FILE_NAME: "contenttype.json", + CONTENT_TYPES_MASTER_FILE: "contenttypes.json", + CONTENT_TYPES_SCHEMA_FILE: "schema.json", - REFERENCES_DIR_NAME : "reference", - REFERENCES_FILE_NAME : "reference.json", + REFERENCES_DIR_NAME: "reference", + REFERENCES_FILE_NAME: "reference.json", - RTE_REFERENCES_DIR_NAME : "rteReference", - RTE_REFERENCES_FILE_NAME : "rteReference.json", + RTE_REFERENCES_DIR_NAME: "rteReference", + RTE_REFERENCES_FILE_NAME: "rteReference.json", - ASSETS_DIR_NAME : "assets", - ASSETS_FILE_NAME : "assets.json", + ASSETS_DIR_NAME: "assets", + ASSETS_FILE_NAME: "assets.json", // ASSETS_SCHEMA_FILE : "index.json", - ASSETS_SCHEMA_FILE : "index.json", - ASSETS_FAILED_FILE : "cs_failed.json", - ASSETS_METADATA_FILE :"metadata.json", + ASSETS_SCHEMA_FILE: "index.json", + ASSETS_FAILED_FILE: "cs_failed.json", + ASSETS_METADATA_FILE: "metadata.json", - ENTRIES_DIR_NAME : "entries", - ENTRIES_MASTER_FILE : "index.json", + ENTRIES_DIR_NAME: "entries", + ENTRIES_MASTER_FILE: "index.json", - GLOBAL_FIELDS_DIR_NAME : "global_fields", - GLOBAL_FIELDS_FILE_NAME : "globalfields.json", + GLOBAL_FIELDS_DIR_NAME: "global_fields", + GLOBAL_FIELDS_FILE_NAME: "globalfields.json", EXPORT_INFO_FILE: "export-info.json" } \ No newline at end of file diff --git a/api/src/services/migration.service.ts b/api/src/services/migration.service.ts index 63c0f6084..14fd79b6d 100644 --- a/api/src/services/migration.service.ts +++ b/api/src/services/migration.service.ts @@ -306,15 +306,25 @@ const startMigration = async (req: Request): Promise => { } const getLogs = async (req: Request): Promise => { - const orgId = req?.params?.orgId; - const projectId = req?.params?.projectId; - const stackId = req?.params?.stackId; + const projectId = path.basename(req?.params?.projectId); + const stackId = path.basename(req?.params?.stackId); const srcFunc = "getLogs"; - const { region, user_id } = req?.body?.token_payload ?? {}; + + if (projectId.includes('..') || stackId.includes('..')) { + throw new BadRequestError("Invalid projectId or stackId"); + } + try { - const loggerPath = path.join(process.cwd(), 'logs', projectId, `${stackId}.log`); - if (fs.existsSync(loggerPath)) { - const logs = fs.readFileSync(loggerPath, 'utf-8'); + const logsDir = path.join(process.cwd(), 'logs'); + const loggerPath = path.join(logsDir, projectId, `${stackId}.log`); + const absolutePath = path.resolve(loggerPath); // Resolve the absolute path + + if (!absolutePath.startsWith(logsDir)) { + throw new BadRequestError("Access to this file is not allowed."); + } + + if (fs.existsSync(absolutePath)) { + const logs = await fs.promises.readFile(absolutePath, 'utf8'); const logEntries = logs .split('\n') .map(line => { diff --git a/api/src/utils/content-type-creator.utils.ts b/api/src/utils/content-type-creator.utils.ts index 574c43c86..d02d1ba63 100644 --- a/api/src/utils/content-type-creator.utils.ts +++ b/api/src/utils/content-type-creator.utils.ts @@ -433,9 +433,13 @@ const convertToSchemaFormate = ({ field, advanced = true }: any) => { if ((field?.advanced?.embedObjects?.length === undefined) || (field?.advanced?.embedObjects?.length === 0) || (field?.advanced?.embedObjects?.length === 1 && field?.advanced?.embedObjects?.[0] === 'sys_assets')) { - delete htmlField?.reference_to; - delete htmlField?.field_metadata?.embed_entry; - delete htmlField?.field_metadata?.ref_multiple_content_types; + if (htmlField) { + delete htmlField.reference_to; + if (htmlField.field_metadata) { + delete htmlField.field_metadata.embed_entry; + delete htmlField.field_metadata.ref_multiple_content_types; + } + } } return htmlField; } diff --git a/api/src/utils/custom-logger.utils.ts b/api/src/utils/custom-logger.utils.ts index 01a365e4d..a7cabf237 100644 --- a/api/src/utils/custom-logger.utils.ts +++ b/api/src/utils/custom-logger.utils.ts @@ -3,6 +3,15 @@ import path from "path"; import { createLogger, format, transports } from "winston"; import logger from './logger.js'; +// Utility function to safely join and resolve paths +const safeJoin = (basePath: string, ...paths: string[]) => { + const resolvedPath = path.resolve(basePath, ...paths); // Resolve absolute path + if (!resolvedPath.startsWith(basePath)) { + throw new Error('Invalid file path'); + } + return resolvedPath; +}; + const fileExists = async (path: string): Promise => { try { @@ -19,8 +28,11 @@ const fileExists = async (path: string): Promise => { */ const customLogger = async (projectId: string, apiKey: string, level: string, message: string) => { try { - const logDir = path.join(process.cwd(), 'logs', projectId); - const logFilePath = path.join(logDir, `${apiKey}.log`); + // Sanitize inputs to prevent path traversal + const sanitizedProjectId = path.basename(projectId); // Strip any path traversal attempts + const sanitizedApiKey = path.basename(apiKey); // Strip any path traversal attempts + const logDir = path.join(process.cwd(), 'logs', sanitizedProjectId); + const logFilePath = safeJoin(logDir, `${sanitizedApiKey}.log`); // Ensure log directory exists, using async/await with fs.promises if (!fs.existsSync(logDir)) { await fs.promises.mkdir(logDir, { recursive: true }); diff --git a/api/src/utils/entries-field-creator.utils.ts b/api/src/utils/entries-field-creator.utils.ts index 6e938582b..79131b7a6 100644 --- a/api/src/utils/entries-field-creator.utils.ts +++ b/api/src/utils/entries-field-creator.utils.ts @@ -178,7 +178,8 @@ export const entriesFieldCreator = async ({ field, content, idCorrector, allAsse switch (field?.contentstackFieldType) { case 'multi_line_text': - case 'single_line_text': { + case 'single_line_text': + case 'text': { return content; } @@ -222,14 +223,14 @@ export const entriesFieldCreator = async ({ field, content, idCorrector, allAsse case 'file': { const fileData = attachJsonRte({ content }); - fileData?.children?.forEach((item: any) => { + for (const item of fileData?.children ?? []) { if (item?.attrs?.['redactor-attributes']?.mediaid) { const assetUid = idCorrector({ id: item?.attrs?.['redactor-attributes']?.mediaid }); return allAssetJSON?.[assetUid] ?? null; } else { console.info('more', item?.attrs) } - }) + } return null; } @@ -276,9 +277,6 @@ export const entriesFieldCreator = async ({ field, content, idCorrector, allAsse return refs; } - case 'text': { - return content; - } case 'global_field': { const globalFieldsSchema = contentTypes?.find?.((gfd: any) => diff --git a/api/src/utils/test-folder-creator.utils.ts b/api/src/utils/test-folder-creator.utils.ts index 498368f52..8e83f670e 100644 --- a/api/src/utils/test-folder-creator.utils.ts +++ b/api/src/utils/test-folder-creator.utils.ts @@ -132,10 +132,9 @@ const lookForReference = async ( ) => { for (const child of field?.schema ?? []) { switch (child?.data_type) { - case 'reference': { - break; - } - case 'global_field': { + case 'reference': + case 'global_field': + case 'blocks': { break; } case 'json': { @@ -155,9 +154,6 @@ const lookForReference = async ( } break; } - case 'blocks': { - break; - } case 'group': { lookForReference(child, finalData); break; @@ -173,9 +169,15 @@ const lookForReference = async ( } }) if (refs?.length === 0) { - delete child?.field_metadata?.embed_entry; - delete child?.field_metadata?.ref_multiple_content_types; - delete child?.reference_to; + if (child?.field_metadata) { + delete child.field_metadata.embed_entry; + delete child.field_metadata.ref_multiple_content_types; + } + if (child?.reference_to) { + delete child.reference_to; + } + } else { + child.reference_to = refs } break; } @@ -215,8 +217,10 @@ const sortContentType = async (baseDir: string, finalData: any) => { } } + export const testFolderCreator = async ({ destinationStackId }: any) => { - const baseDir = path.join(MIGRATION_DATA_CONFIG.DATA, destinationStackId); + const sanitizedStackId = path.basename(destinationStackId); + const baseDir = path.join(MIGRATION_DATA_CONFIG.DATA, sanitizedStackId); const entryDelete = path.join(process.cwd(), baseDir, ENTRIES_DIR_NAME); const entrySave = path.join(baseDir, ENTRIES_DIR_NAME); const entriesPath = path.join(process.cwd(), baseDir, ENTRIES_DIR_NAME); diff --git a/cli/packages/contentstack-auth/src/commands/auth/login.ts b/cli/packages/contentstack-auth/src/commands/auth/login.ts index 5ddf7feb7..f067a032a 100644 --- a/cli/packages/contentstack-auth/src/commands/auth/login.ts +++ b/cli/packages/contentstack-auth/src/commands/auth/login.ts @@ -90,7 +90,7 @@ export default class LoginCommand extends BaseCommand { } catch (error) { let errorMessage = formatError(error) || 'Something went wrong while logging. Please try again.'; this.logger.error('login failed', errorMessage); - cliux.error('CLI_AUTH_LOGIN_FAILED Umesh'); + cliux.error('CLI_AUTH_LOGIN_FAILED'); cliux.error(errorMessage); process.exit(); }