From ecc976e7d2f4fdef15782616c1851f17261973df Mon Sep 17 00:00:00 2001 From: Antonella Sgarlatta Date: Tue, 17 Jun 2025 11:39:47 -0300 Subject: [PATCH 1/5] fix(SNOTES-480): display tag title as string in delete dialog --- packages/styles/src/Alert/Alert.ts | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/packages/styles/src/Alert/Alert.ts b/packages/styles/src/Alert/Alert.ts index fcb7dc2e16a..fdef3666818 100644 --- a/packages/styles/src/Alert/Alert.ts +++ b/packages/styles/src/Alert/Alert.ts @@ -105,14 +105,14 @@ export class SKAlert { } const titleTemplate = this.title ? `
- ${this.title} +
` : '' const messageTemplate = this.text - ? `

${this.text}

` + ? `

` : '' const template = ` @@ -164,6 +164,17 @@ export class SKAlert { this.element.className = 'sn-component' this.element.innerHTML = this.templateString().trim() + const titleElement = this.element.querySelector('#title') + const messageElement = this.element.querySelector('#message') + + if (titleElement) { + titleElement.textContent = this.title || '' + } + + if (messageElement) { + messageElement.textContent = this.text || '' + } + onElement.appendChild(this.element) if (this.buttons && this.buttons.length) { From 39c069e467ba9f8f29a996a9c9d8c2832507e653 Mon Sep 17 00:00:00 2001 From: Antonella Sgarlatta Date: Tue, 17 Jun 2025 17:24:46 -0300 Subject: [PATCH 2/5] Revert "fix(SNOTES-480): display tag title as string in delete dialog" This reverts commit ecc976e7d2f4fdef15782616c1851f17261973df. --- packages/styles/src/Alert/Alert.ts | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/packages/styles/src/Alert/Alert.ts b/packages/styles/src/Alert/Alert.ts index fdef3666818..fcb7dc2e16a 100644 --- a/packages/styles/src/Alert/Alert.ts +++ b/packages/styles/src/Alert/Alert.ts @@ -105,14 +105,14 @@ export class SKAlert { } const titleTemplate = this.title ? `
- + ${this.title}
` : '' const messageTemplate = this.text - ? `

` + ? `

${this.text}

` : '' const template = ` @@ -164,17 +164,6 @@ export class SKAlert { this.element.className = 'sn-component' this.element.innerHTML = this.templateString().trim() - const titleElement = this.element.querySelector('#title') - const messageElement = this.element.querySelector('#message') - - if (titleElement) { - titleElement.textContent = this.title || '' - } - - if (messageElement) { - messageElement.textContent = this.text || '' - } - onElement.appendChild(this.element) if (this.buttons && this.buttons.length) { From 65656af62ba3a28fcedee55c14fe5be082ea0cbe Mon Sep 17 00:00:00 2001 From: Antonella Sgarlatta Date: Tue, 17 Jun 2025 17:36:14 -0300 Subject: [PATCH 3/5] fix(SNOTES-480): escape html when interpolating titles --- packages/utils/src/Domain/Utils/Utils.ts | 6 +++++- packages/web/src/javascripts/Constants/Strings.ts | 15 +++++++++------ .../javascripts/Controllers/FilesController.ts | 6 +++--- 3 files changed, 17 insertions(+), 10 deletions(-) diff --git a/packages/utils/src/Domain/Utils/Utils.ts b/packages/utils/src/Domain/Utils/Utils.ts index e5f921dbe79..7325b9c922e 100644 --- a/packages/utils/src/Domain/Utils/Utils.ts +++ b/packages/utils/src/Domain/Utils/Utils.ts @@ -1,6 +1,6 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import { sanitize } from 'dompurify' -import { find, isArray, mergeWith, remove, uniq, uniqWith } from 'lodash' +import { escape, find, isArray, mergeWith, remove, uniq, uniqWith } from 'lodash' import { AnyRecord } from '@standardnotes/common' const collator = typeof Intl !== 'undefined' ? new Intl.Collator('en', { numeric: true }) : undefined @@ -612,6 +612,10 @@ export function sanitizeHtmlString(html: string): string { return sanitize(html) } +export function escapeHtmlString(html: string): string { + return escape(html) +} + let sharedDateFormatter: unknown export function dateToLocalizedString(date: Date): string { if (typeof Intl !== 'undefined' && Intl.DateTimeFormat && typeof navigator !== 'undefined') { diff --git a/packages/web/src/javascripts/Constants/Strings.ts b/packages/web/src/javascripts/Constants/Strings.ts index 3ec6d5c99a4..7ed4bb8d9ce 100644 --- a/packages/web/src/javascripts/Constants/Strings.ts +++ b/packages/web/src/javascripts/Constants/Strings.ts @@ -1,4 +1,4 @@ -import { Platform, SNApplication } from '@standardnotes/snjs' +import { escapeHtmlString, Platform, SNApplication } from '@standardnotes/snjs' import { getPlatform, isDesktopApplication } from '../Utils' /** @generic */ @@ -39,9 +39,10 @@ export const STRING_EDIT_LOCKED_ATTEMPT = export const STRING_RESTORE_LOCKED_ATTEMPT = "This note has editing disabled. If you'd like to restore it to a previous revision, enable editing and try again." export function StringDeleteNote(title: string, permanently: boolean) { + const escapedTitle = escapeHtmlString(title) return permanently - ? `Are you sure you want to permanently delete ${title}?` - : `Are you sure you want to move ${title} to the trash?` + ? `Are you sure you want to permanently delete ${escapedTitle}?` + : `Are you sure you want to move ${escapedTitle} to the trash?` } export function StringEmptyTrash(count: number) { return `Are you sure you want to permanently delete ${count} note(s)?` @@ -135,9 +136,10 @@ export const StringUtils = { }, deleteNotes(permanently: boolean, notesCount = 1, title?: string): string { if (notesCount === 1) { + const escapedTitle = escapeHtmlString(title || '') return permanently - ? `Are you sure you want to permanently delete ${title}?` - : `Are you sure you want to move ${title} to the trash?` + ? `Are you sure you want to permanently delete ${escapedTitle}?` + : `Are you sure you want to move ${escapedTitle} to the trash?` } else { return permanently ? 'Are you sure you want to permanently delete these notes?' @@ -145,7 +147,8 @@ export const StringUtils = { } }, deleteFile(title: string): string { - return `Are you sure you want to permanently delete ${title}?` + const escapedTitle = escapeHtmlString(title) + return `Are you sure you want to permanently delete ${escapedTitle}?` }, archiveLockedNotesAttempt(archive: boolean, notesCount = 1): string { const archiveString = archive ? 'archive' : 'unarchive' diff --git a/packages/web/src/javascripts/Controllers/FilesController.ts b/packages/web/src/javascripts/Controllers/FilesController.ts index 591ddf1f30a..0e0e44ab649 100644 --- a/packages/web/src/javascripts/Controllers/FilesController.ts +++ b/packages/web/src/javascripts/Controllers/FilesController.ts @@ -16,7 +16,7 @@ import { import { Strings, StringUtils } from '@/Constants/Strings' import { concatenateUint8Arrays } from '@/Utils/ConcatenateUint8Arrays' import { ClassicFileReader, StreamingFileReader, StreamingFileSaver, ClassicFileSaver } from '@standardnotes/filepicker' -import { parseAndCreateZippableFileName, parseFileName } from '@standardnotes/utils' +import { escapeHtmlString, parseAndCreateZippableFileName, parseFileName } from '@standardnotes/utils' import { AlertService, ChallengeReason, @@ -168,7 +168,7 @@ export class FilesController extends AbstractViewController { const shouldDelete = await confirmDialog({ - text: `Are you sure you want to permanently delete "${file.name}"?`, + text: StringUtils.deleteFile(file.name), confirmButtonStyle: 'danger', }) if (shouldDelete) { @@ -440,7 +440,7 @@ export class FilesController extends AbstractViewController Date: Tue, 17 Jun 2025 17:49:13 -0300 Subject: [PATCH 4/5] fix(SNOTES-480): use string utils --- packages/web/src/javascripts/Constants/Strings.ts | 7 +++++++ .../web/src/javascripts/Controllers/FilesController.ts | 4 ++-- .../Controllers/Navigation/NavigationController.ts | 4 ++-- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/packages/web/src/javascripts/Constants/Strings.ts b/packages/web/src/javascripts/Constants/Strings.ts index 7ed4bb8d9ce..3a8964f1478 100644 --- a/packages/web/src/javascripts/Constants/Strings.ts +++ b/packages/web/src/javascripts/Constants/Strings.ts @@ -161,4 +161,11 @@ export const StringUtils = { ? "This note has editing disabled. If you'd like to delete it, enable editing, and try again." : "One or more of these notes have editing disabled. If you'd like to delete them, make sure editing is enabled on all of them, and try again." }, + deleteTag(title: string): string { + const escapedTitle = escapeHtmlString(title) + return `Delete tag "${escapedTitle}"?` + }, + cannotUploadFile(name: string): string { + const escapedName = escapeHtmlString(name) + return `Cannot upload file "${escapedName}"`} } diff --git a/packages/web/src/javascripts/Controllers/FilesController.ts b/packages/web/src/javascripts/Controllers/FilesController.ts index 0e0e44ab649..0101111a17b 100644 --- a/packages/web/src/javascripts/Controllers/FilesController.ts +++ b/packages/web/src/javascripts/Controllers/FilesController.ts @@ -16,7 +16,7 @@ import { import { Strings, StringUtils } from '@/Constants/Strings' import { concatenateUint8Arrays } from '@/Utils/ConcatenateUint8Arrays' import { ClassicFileReader, StreamingFileReader, StreamingFileSaver, ClassicFileSaver } from '@standardnotes/filepicker' -import { escapeHtmlString, parseAndCreateZippableFileName, parseFileName } from '@standardnotes/utils' +import { parseAndCreateZippableFileName, parseFileName } from '@standardnotes/utils' import { AlertService, ChallengeReason, @@ -440,7 +440,7 @@ export class FilesController extends AbstractViewController Date: Wed, 18 Jun 2025 11:05:02 -0300 Subject: [PATCH 5/5] fix(SNOTES-480): fix lint errors --- packages/web/src/javascripts/Constants/Strings.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/web/src/javascripts/Constants/Strings.ts b/packages/web/src/javascripts/Constants/Strings.ts index 3a8964f1478..770b3686822 100644 --- a/packages/web/src/javascripts/Constants/Strings.ts +++ b/packages/web/src/javascripts/Constants/Strings.ts @@ -167,5 +167,6 @@ export const StringUtils = { }, cannotUploadFile(name: string): string { const escapedName = escapeHtmlString(name) - return `Cannot upload file "${escapedName}"`} + return `Cannot upload file "${escapedName}"` + }, }