Skip to content

Commit 952515c

Browse files
committed
CCR feedback on escaping file names
1 parent cafbd94 commit 952515c

File tree

2 files changed

+53
-2
lines changed

2 files changed

+53
-2
lines changed

src/common/utils.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1009,8 +1009,16 @@ export function escapeRegExp(string: string) {
10091009
return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
10101010
}
10111011

1012-
function escapeHtmlAttr(value: string): string {
1013-
return value.replace(/&/g, '&amp;').replace(/"/g, '&quot;').replace(/'/g, '&#39;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
1012+
export function escapeHtmlAttr(value: string): string {
1013+
const escapedCharacters: Record<string, string> = {
1014+
'&': '&amp;',
1015+
'"': '&quot;',
1016+
'\'': '&#39;',
1017+
'<': '&lt;',
1018+
'>': '&gt;',
1019+
};
1020+
1021+
return value.replace(/[&"'<>]/g, (char) => escapedCharacters[char]);
10141022
}
10151023

10161024
export function truncate(value: string, maxLength: number, suffix = '...'): string {

src/test/common/utils.test.ts

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,14 @@ describe('utils', () => {
132132
assert(result.includes('link text'));
133133
assert(result.includes('data-local-file="src/file.ts"'));
134134
});
135+
136+
it('should escape HTML special characters in file paths', async () => {
137+
const html = makePermalink('src/file&name"test.ts', 10);
138+
const result = await utils.processPermalinks(html, repoName, authority, async () => true);
139+
140+
assert(result.includes('data-local-file="src/file&amp;name&quot;test.ts"'));
141+
assert(!result.includes('data-local-file="src/file&name"test.ts"'));
142+
});
135143
});
136144

137145
describe('processDiffLinks', () => {
@@ -233,5 +241,40 @@ describe('utils', () => {
233241
assert(result.includes('data-local-file="src/found.ts"'));
234242
assert(!result.includes('data-local-file="src/other.ts"'));
235243
});
244+
245+
it('should escape HTML special characters in file names', async () => {
246+
const hashMap: Record<string, string> = { [diffHash]: 'src/file&name"test.ts' };
247+
const html = makeDiffLink(diffHash, 10);
248+
const result = await utils.processDiffLinks(html, repoOwner, repoName, authority, hashMap, prNumber);
249+
250+
assert(result.includes('data-local-file="src/file&amp;name&quot;test.ts"'));
251+
assert(!result.includes('data-local-file="src/file&name"test.ts"'));
252+
});
253+
});
254+
255+
describe('escapeHtmlAttr', () => {
256+
it('should escape ampersands', () => {
257+
assert.strictEqual(utils.escapeHtmlAttr('foo&bar'), 'foo&amp;bar');
258+
});
259+
260+
it('should escape double quotes', () => {
261+
assert.strictEqual(utils.escapeHtmlAttr('foo"bar'), 'foo&quot;bar');
262+
});
263+
264+
it('should escape single quotes', () => {
265+
assert.strictEqual(utils.escapeHtmlAttr('foo\'bar'), 'foo&#39;bar');
266+
});
267+
268+
it('should escape angle brackets', () => {
269+
assert.strictEqual(utils.escapeHtmlAttr('<script>'), '&lt;script&gt;');
270+
});
271+
272+
it('should escape all special characters together', () => {
273+
assert.strictEqual(utils.escapeHtmlAttr('a&b"c\'d<e>f'), 'a&amp;b&quot;c&#39;d&lt;e&gt;f');
274+
});
275+
276+
it('should return the same string when no special characters', () => {
277+
assert.strictEqual(utils.escapeHtmlAttr('normal-file.ts'), 'normal-file.ts');
278+
});
236279
});
237280
});

0 commit comments

Comments
 (0)