Skip to content

Commit 743e9cb

Browse files
authored
fix: escape HTML in search keywords (#2586)
1 parent 5448d93 commit 743e9cb

File tree

5 files changed

+33
-13
lines changed

5 files changed

+33
-13
lines changed

src/core/event/index.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { isMobile, mobileBreakpoint } from '../util/env.js';
22
import * as dom from '../util/dom.js';
3+
import { stripUrlExceptId } from '../router/util.js';
34

45
/** @typedef {import('../Docsify.js').Constructor} Constructor */
56

@@ -474,6 +475,8 @@ export function Events(Base) {
474475
return;
475476
}
476477

478+
href = stripUrlExceptId(href);
479+
477480
const oldActive = dom.find(sidebar, 'li.active');
478481
const newActive = dom
479482
.find(

src/core/render/compiler/heading.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import {
44
getAndRemoveDocsifyIgnoreConfig,
55
} from '../utils.js';
66
import { slugify } from '../slugify.js';
7+
import { stripUrlExceptId } from '../../router/util.js';
78

89
export const headingCompiler = ({ renderer, router, compiler }) =>
910
(renderer.heading = function ({ tokens, depth }) {
@@ -20,7 +21,7 @@ export const headingCompiler = ({ renderer, router, compiler }) =>
2021
nextToc.ignoreSubHeading = ignoreSubHeading;
2122
const slug = slugify(config.id || str);
2223
const url = router.toURL(router.getCurrentPath(), { id: slug });
23-
nextToc.slug = url;
24+
nextToc.slug = stripUrlExceptId(url);
2425
compiler.toc.push(nextToc);
2526

2627
// Note: tabindex="-1" allows programmatically focusing on heading

src/core/router/util.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,22 @@ export function stringifyQuery(obj, ignores = []) {
4040
return qs.length ? `?${qs.join('&')}` : '';
4141
}
4242

43+
export function stripUrlExceptId(str) {
44+
const [path, queryString] = str.split('?');
45+
if (!queryString) {
46+
return str;
47+
}
48+
49+
const params = new URLSearchParams(queryString);
50+
const id = params.get('id');
51+
52+
if (id !== null) {
53+
return `${path}?id=${id}`;
54+
}
55+
56+
return path;
57+
}
58+
4359
export const isAbsolutePath = cached(path => {
4460
return /(:|(\/{2}))/g.test(path);
4561
});

src/plugins/search/component.js

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { search } from './search.js';
1+
import { escapeHtml, search } from './search.js';
22
import cssText from './style.css';
33

44
let NO_DATA_TEXT = '';
@@ -75,11 +75,11 @@ function bindEvents() {
7575
let timeId;
7676

7777
/**
78-
Prevent to Fold sidebar.
79-
80-
When searching on the mobile end,
81-
the sidebar is collapsed when you click the INPUT box,
82-
making it impossible to search.
78+
* Prevent to Fold sidebar.
79+
*
80+
* When searching on the mobile end,
81+
* the sidebar is collapsed when you click the INPUT box,
82+
* making it impossible to search.
8383
*/
8484
Docsify.dom.on(
8585
$search,
@@ -129,10 +129,10 @@ export function init(opts, vm) {
129129
return;
130130
}
131131

132-
const keywords = vm.router.parse().query.s;
132+
const keywords = vm.router.parse().query.s || '';
133133

134134
Docsify.dom.style(cssText);
135-
tpl(vm, keywords);
135+
tpl(vm, escapeHtml(keywords));
136136
bindEvents();
137137
keywords && setTimeout(_ => doSearch(keywords), 500);
138138
}

src/plugins/search/search.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import {
55
import { markdownToTxt } from './markdown-to-txt.js';
66
import Dexie from 'dexie';
77

8-
let INDEXES = {};
8+
let INDEXES = [];
99

1010
const db = new Dexie('docsify');
1111
db.version(1).stores({
@@ -48,7 +48,7 @@ function resolveIndexKey(namespace) {
4848
: LOCAL_STORAGE.INDEX_KEY;
4949
}
5050

51-
function escapeHtml(string) {
51+
export function escapeHtml(string) {
5252
const entityMap = {
5353
'&': '&',
5454
'<': '&lt;',
@@ -102,7 +102,7 @@ function getListData(token) {
102102
export function genIndex(path, content = '', router, depth, indexKey) {
103103
const tokens = window.marked.lexer(content);
104104
const slugify = window.Docsify.slugify;
105-
const index = {};
105+
const index = [];
106106
let slug;
107107
let title = '';
108108

@@ -299,7 +299,7 @@ export async function init(config, vm) {
299299
INDEXES = await getData(indexKey);
300300

301301
if (isExpired) {
302-
INDEXES = {};
302+
INDEXES = [];
303303
} else if (!isAuto) {
304304
return;
305305
}

0 commit comments

Comments
 (0)