diff --git a/src/routes/v2/authenticatedSites/collectionPages.js b/src/routes/v2/authenticatedSites/collectionPages.js index 7487b6e0f..3d4872dd1 100644 --- a/src/routes/v2/authenticatedSites/collectionPages.js +++ b/src/routes/v2/authenticatedSites/collectionPages.js @@ -9,6 +9,8 @@ const { attachRollbackRouteHandlerWrapper, } = require("@middleware/routeHandler") +const { recursiveTrimAndReplaceLineBreaks } = require("@utils/yaml-utils") + const { CreatePageRequestSchema, UpdatePageRequestSchema, @@ -32,9 +34,12 @@ class CollectionPagesRouter { if (error) throw new BadRequestError(error.message) const { content: { frontMatter, pageBody }, - newFileName, + newFileName: unformattedNewFileName, } = req.body let createResp + const newFileName = recursiveTrimAndReplaceLineBreaks( + unformattedNewFileName + ) if (subcollectionName) { createResp = await this.subcollectionPageService.create( userWithSiteSessionData, @@ -42,7 +47,7 @@ class CollectionPagesRouter { fileName: newFileName, collectionName, content: pageBody, - frontMatter, + frontMatter: recursiveTrimAndReplaceLineBreaks(frontMatter), subcollectionName, } ) @@ -98,10 +103,16 @@ class CollectionPagesRouter { const { error } = UpdatePageRequestSchema.validate(req.body) if (error) throw new BadRequestError(error.message) const { - content: { frontMatter, pageBody }, + content: { frontMatter: unformattedFrontMatter, pageBody }, sha, - newFileName, + newFileName: unformattedNewFileName, } = req.body + const frontMatter = recursiveTrimAndReplaceLineBreaks( + unformattedFrontMatter + ) + const newFileName = recursiveTrimAndReplaceLineBreaks( + unformattedNewFileName + ) let updateResp if (subcollectionName) { if (newFileName) { diff --git a/src/routes/v2/authenticatedSites/collections.js b/src/routes/v2/authenticatedSites/collections.js index 618825c07..09c3f9a80 100644 --- a/src/routes/v2/authenticatedSites/collections.js +++ b/src/routes/v2/authenticatedSites/collections.js @@ -9,6 +9,8 @@ const { attachRollbackRouteHandlerWrapper, } = require("@middleware/routeHandler") +const { recursiveTrimAndReplaceLineBreaks } = require("@utils/yaml-utils") + const { CreateDirectoryRequestSchema, RenameDirectoryRequestSchema, @@ -72,7 +74,9 @@ class CollectionsRouter { userWithSiteSessionData, { collectionName, - subcollectionName: newDirectoryName, + subcollectionName: recursiveTrimAndReplaceLineBreaks( + newDirectoryName + ), objArray: items, } ) @@ -81,7 +85,7 @@ class CollectionsRouter { createResp = await this.collectionDirectoryService.createDirectory( userWithSiteSessionData, { - collectionName: newDirectoryName, + collectionName: recursiveTrimAndReplaceLineBreaks(newDirectoryName), objArray: items, } ) @@ -105,7 +109,7 @@ class CollectionsRouter { { collectionName, subcollectionName, - newDirectoryName, + newDirectoryName: recursiveTrimAndReplaceLineBreaks(newDirectoryName), } ) } else { @@ -114,7 +118,7 @@ class CollectionsRouter { githubSessionData, { collectionName, - newDirectoryName, + newDirectoryName: recursiveTrimAndReplaceLineBreaks(newDirectoryName), } ) } diff --git a/src/routes/v2/authenticatedSites/contactUs.js b/src/routes/v2/authenticatedSites/contactUs.js index 2da7c57dc..4ac38a538 100644 --- a/src/routes/v2/authenticatedSites/contactUs.js +++ b/src/routes/v2/authenticatedSites/contactUs.js @@ -9,6 +9,8 @@ const { attachRollbackRouteHandlerWrapper, } = require("@middleware/routeHandler") +const { recursiveTrimAndReplaceLineBreaks } = require("@utils/yaml-utils") + const { UpdateContactUsSchema } = require("@validators/RequestSchema") class ContactUsRouter { @@ -42,7 +44,11 @@ class ContactUsRouter { const updatedContactUsPage = await this.contactUsPageService.update( userWithSiteSessionData, - { content: pageBody, frontMatter, sha } + { + content: pageBody, + frontMatter: recursiveTrimAndReplaceLineBreaks(frontMatter), + sha, + } ) res.status(200).json(updatedContactUsPage) diff --git a/src/routes/v2/authenticatedSites/homepage.js b/src/routes/v2/authenticatedSites/homepage.js index fa6c982b9..f4f395cec 100644 --- a/src/routes/v2/authenticatedSites/homepage.js +++ b/src/routes/v2/authenticatedSites/homepage.js @@ -9,6 +9,8 @@ const { attachRollbackRouteHandlerWrapper, } = require("@middleware/routeHandler") +const { recursiveTrimAndReplaceLineBreaks } = require("@utils/yaml-utils") + const { UpdateHomepageSchema } = require("@validators/RequestSchema") class HomepageRouter { @@ -44,7 +46,7 @@ class HomepageRouter { userWithSiteSessionData, { content: pageBody, - frontMatter, + frontMatter: recursiveTrimAndReplaceLineBreaks(frontMatter), sha, } ) diff --git a/src/routes/v2/authenticatedSites/media.ts b/src/routes/v2/authenticatedSites/media.ts index 12a0890d2..785f6a451 100644 --- a/src/routes/v2/authenticatedSites/media.ts +++ b/src/routes/v2/authenticatedSites/media.ts @@ -18,6 +18,7 @@ import type { RequestHandler, } from "@root/types" import { nameAnonymousMethods } from "@root/utils/apm-utils" +import { recursiveTrimAndReplaceLineBreaks } from "@root/utils/yaml-utils" import { CreateMediaDirectoryRequestSchema, CreateMediaFileRequestSchema, @@ -154,7 +155,7 @@ export class MediaRouter { userWithSiteSessionData, githubSessionData, { - directoryName: newDirectoryName, + directoryName: recursiveTrimAndReplaceLineBreaks(newDirectoryName), objArray: items, } ) @@ -185,7 +186,7 @@ export class MediaRouter { githubSessionData, { directoryName, - newDirectoryName, + newDirectoryName: recursiveTrimAndReplaceLineBreaks(newDirectoryName), } ) @@ -270,7 +271,7 @@ export class MediaRouter { const createResp = await this.mediaFileService.create( userWithSiteSessionData, { - fileName: newFileName, + fileName: recursiveTrimAndReplaceLineBreaks(newFileName), directoryName, content, } @@ -325,7 +326,7 @@ export class MediaRouter { githubSessionData, { oldFileName: fileName, - newFileName, + newFileName: recursiveTrimAndReplaceLineBreaks(newFileName), directoryName, sha, } diff --git a/src/routes/v2/authenticatedSites/resourceCategories.js b/src/routes/v2/authenticatedSites/resourceCategories.js index 19dce7207..377db1c91 100644 --- a/src/routes/v2/authenticatedSites/resourceCategories.js +++ b/src/routes/v2/authenticatedSites/resourceCategories.js @@ -15,6 +15,8 @@ const { MoveResourceDirectoryPagesRequestSchema, } = require("@validators/RequestSchema") +const { recursiveTrimAndReplaceLineBreaks } = require("@root/utils/yaml-utils") + class ResourceCategoriesRouter { constructor({ resourceDirectoryService }) { this.resourceDirectoryService = resourceDirectoryService @@ -46,7 +48,9 @@ class ResourceCategoriesRouter { userWithSiteSessionData, { resourceRoomName, - resourceCategoryName: newDirectoryName, + resourceCategoryName: recursiveTrimAndReplaceLineBreaks( + newDirectoryName + ), } ) @@ -68,7 +72,7 @@ class ResourceCategoriesRouter { { resourceRoomName, resourceCategoryName, - newDirectoryName, + newDirectoryName: recursiveTrimAndReplaceLineBreaks(newDirectoryName), } ) diff --git a/src/routes/v2/authenticatedSites/resourcePages.js b/src/routes/v2/authenticatedSites/resourcePages.js index c4111e1bf..0c6f5e4cf 100644 --- a/src/routes/v2/authenticatedSites/resourcePages.js +++ b/src/routes/v2/authenticatedSites/resourcePages.js @@ -15,6 +15,8 @@ const { DeleteResourcePageRequestSchema, } = require("@validators/RequestSchema") +const { recursiveTrimAndReplaceLineBreaks } = require("@root/utils/yaml-utils") + class ResourcePagesRouter { constructor({ resourcePageService }) { this.resourcePageService = resourcePageService @@ -36,11 +38,11 @@ class ResourcePagesRouter { const createResp = await this.resourcePageService.create( userWithSiteSessionData, { - fileName: newFileName, + fileName: recursiveTrimAndReplaceLineBreaks(newFileName), resourceRoomName, resourceCategoryName, content: pageBody, - frontMatter, + frontMatter: recursiveTrimAndReplaceLineBreaks(frontMatter), } ) @@ -84,11 +86,11 @@ class ResourcePagesRouter { userWithSiteSessionData, { oldFileName: pageName, - newFileName, + newFileName: recursiveTrimAndReplaceLineBreaks(newFileName), resourceRoomName, resourceCategoryName, content: pageBody, - frontMatter, + frontMatter: recursiveTrimAndReplaceLineBreaks(frontMatter), sha, } ) diff --git a/src/routes/v2/authenticatedSites/resourceRoom.js b/src/routes/v2/authenticatedSites/resourceRoom.js index 1e66d7371..e94f7a78d 100644 --- a/src/routes/v2/authenticatedSites/resourceRoom.js +++ b/src/routes/v2/authenticatedSites/resourceRoom.js @@ -14,6 +14,8 @@ const { RenameResourceDirectoryRequestSchema, } = require("@validators/RequestSchema") +const { recursiveTrimAndReplaceLineBreaks } = require("@root/utils/yaml-utils") + class ResourceRoomRouter { constructor({ resourceRoomDirectoryService }) { this.resourceRoomDirectoryService = resourceRoomDirectoryService @@ -57,7 +59,7 @@ class ResourceRoomRouter { const createResp = await this.resourceRoomDirectoryService.createResourceRoomDirectory( userWithSiteSessionData, { - resourceRoomName: newDirectoryName, + resourceRoomName: recursiveTrimAndReplaceLineBreaks(newDirectoryName), } ) @@ -78,7 +80,7 @@ class ResourceRoomRouter { githubSessionData, { resourceRoomName, - newDirectoryName, + newDirectoryName: recursiveTrimAndReplaceLineBreaks(newDirectoryName), } ) diff --git a/src/routes/v2/authenticatedSites/settings.js b/src/routes/v2/authenticatedSites/settings.js index 4005a3977..bc6f0dfe1 100644 --- a/src/routes/v2/authenticatedSites/settings.js +++ b/src/routes/v2/authenticatedSites/settings.js @@ -16,6 +16,7 @@ const { UpdateRepoPasswordRequestSchema, } = require("@validators/RequestSchema") +const { recursiveTrimAndReplaceLineBreaks } = require("@root/utils/yaml-utils") const { isPasswordValid } = require("@root/validators/validators") const { SettingsService } = require("@services/configServices/SettingsService") @@ -68,7 +69,9 @@ class SettingsRouter { configContent: updatedConfigContent, footerContent: updatedFooterContent, navigationContent: updatedNavigationContent, - } = SettingsService.retrieveSettingsFields(settings) + } = SettingsService.retrieveSettingsFields( + recursiveTrimAndReplaceLineBreaks(settings) + ) await this.settingsService.updateSettingsFiles(userWithSiteSessionData, { config, diff --git a/src/routes/v2/authenticatedSites/unlinkedPages.js b/src/routes/v2/authenticatedSites/unlinkedPages.js index 0b82a7ca6..918460105 100644 --- a/src/routes/v2/authenticatedSites/unlinkedPages.js +++ b/src/routes/v2/authenticatedSites/unlinkedPages.js @@ -16,6 +16,8 @@ const { MoveDirectoryPagesRequestSchema, } = require("@validators/RequestSchema") +const { recursiveTrimAndReplaceLineBreaks } = require("@root/utils/yaml-utils") + class UnlinkedPagesRouter { constructor({ unlinkedPageService, unlinkedPagesDirectoryService }) { this.unlinkedPageService = unlinkedPageService @@ -46,9 +48,9 @@ class UnlinkedPagesRouter { const createResp = await this.unlinkedPageService.create( userWithSiteSessionData, { - fileName: newFileName, + fileName: recursiveTrimAndReplaceLineBreaks(newFileName), content: pageBody, - frontMatter, + frontMatter: recursiveTrimAndReplaceLineBreaks(frontMatter), } ) @@ -88,9 +90,9 @@ class UnlinkedPagesRouter { userWithSiteSessionData, { oldFileName: pageName, - newFileName, + newFileName: recursiveTrimAndReplaceLineBreaks(newFileName), content: pageBody, - frontMatter, + frontMatter: recursiveTrimAndReplaceLineBreaks(frontMatter), sha, } ) @@ -100,7 +102,7 @@ class UnlinkedPagesRouter { { fileName: pageName, content: pageBody, - frontMatter, + frontMatter: recursiveTrimAndReplaceLineBreaks(frontMatter), sha, } ) diff --git a/src/utils/yaml-utils.ts b/src/utils/yaml-utils.ts index 9a102cf6a..e2dbfd586 100644 --- a/src/utils/yaml-utils.ts +++ b/src/utils/yaml-utils.ts @@ -2,6 +2,35 @@ import yaml from "yaml" import { sanitizer } from "@services/utilServices/Sanitizer" +const LINE_BREAK_REGEX = "[\r\n\x0B\x0C\u0085\u2028\u2029]" +const GLOBAL_LINE_BREAK_SEARCH = new RegExp(LINE_BREAK_REGEX, "gi") + +type RecursiveInput = + | string + | RecursiveInput[] + | { [key: string]: RecursiveInput } + | undefined + | null + +export const recursiveTrimAndReplaceLineBreaks = ( + obj: RecursiveInput +): RecursiveInput => { + if (typeof obj === "string") { + return obj.replaceAll(GLOBAL_LINE_BREAK_SEARCH, " ").trim() + } + if (Array.isArray(obj)) { + return obj.map((item) => recursiveTrimAndReplaceLineBreaks(item)) + } + if (typeof obj === "object" && obj !== null) { + const newObj: RecursiveInput = {} + Object.keys(obj).forEach((key) => { + newObj[key] = recursiveTrimAndReplaceLineBreaks(obj[key]) + }) + return newObj + } + return obj +} + // Note: `yaml.parse()` and `yaml.stringify()` should not be used anywhere // else in the codebase. export const sanitizedYamlParse = ( @@ -17,7 +46,13 @@ export const sanitizedYamlParse = ( : value ) -export const sanitizedYamlStringify = (prestringifiedContent: object): string => - yaml.stringify(prestringifiedContent, (key, value) => +export const sanitizedYamlStringify = ( + prestringifiedContent: RecursiveInput +): string => { + const formattedPrestringifiedContent = recursiveTrimAndReplaceLineBreaks( + prestringifiedContent + ) + return yaml.stringify(formattedPrestringifiedContent, (key, value) => typeof value === "string" && !!value ? sanitizer.sanitize(value) : value ) +}