Durcit le formulaire de recherche
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
|
||||
const HIGHLIGHT_START = "__MEILI_HIGHLIGHT_START__";
|
||||
const HIGHLIGHT_END = "__MEILI_HIGHLIGHT_END__";
|
||||
const MAX_SEARCH_QUERY_LENGTH = 200;
|
||||
|
||||
/**
|
||||
* Lit la configuration exposee par le template Hugo.
|
||||
@@ -65,6 +66,58 @@ function readSearchQuery(queryParam) {
|
||||
return rawValue.trim();
|
||||
}
|
||||
|
||||
/**
|
||||
* Indique si la requete est acceptable pour le frontend.
|
||||
* @param {string} query Texte recherche.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function isSearchQueryValid(query) {
|
||||
return query.length > 0 && query.length <= MAX_SEARCH_QUERY_LENGTH;
|
||||
}
|
||||
|
||||
/**
|
||||
* Valide un chemin interne renvoye par l'index.
|
||||
* @param {unknown} rawPath Chemin brut.
|
||||
* @returns {string}
|
||||
*/
|
||||
function normalizeInternalPath(rawPath) {
|
||||
if (typeof rawPath !== "string") {
|
||||
return "";
|
||||
}
|
||||
|
||||
const trimmedPath = rawPath.trim();
|
||||
if (trimmedPath.length === 0 || trimmedPath.startsWith("/") === false) {
|
||||
return "";
|
||||
}
|
||||
|
||||
if (trimmedPath.startsWith("//") || trimmedPath.includes("\\") || trimmedPath.includes("?") || trimmedPath.includes("#")) {
|
||||
return "";
|
||||
}
|
||||
|
||||
try {
|
||||
const parsed = new URL(trimmedPath, window.location.origin);
|
||||
if (parsed.origin !== window.location.origin) {
|
||||
return "";
|
||||
}
|
||||
|
||||
if (parsed.username.length > 0 || parsed.password.length > 0) {
|
||||
return "";
|
||||
}
|
||||
|
||||
if (parsed.search.length > 0 || parsed.hash.length > 0) {
|
||||
return "";
|
||||
}
|
||||
|
||||
if (parsed.pathname !== trimmedPath) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return parsed.pathname;
|
||||
} catch (_error) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Construit le payload envoye a Meilisearch.
|
||||
* @param {string} query Texte recherche.
|
||||
@@ -202,11 +255,12 @@ function normalizeHit(hit) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (typeof hit.path !== "string" || hit.path.trim().length === 0) {
|
||||
const normalizedPath = normalizeInternalPath(hit.path);
|
||||
if (normalizedPath.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let title = hit.path.trim();
|
||||
let title = normalizedPath;
|
||||
if (typeof hit.title === "string" && hit.title.trim().length > 0) {
|
||||
title = hit.title.trim();
|
||||
}
|
||||
@@ -230,7 +284,7 @@ function normalizeHit(hit) {
|
||||
titleMarkup,
|
||||
summary,
|
||||
summaryMarkup,
|
||||
path: hit.path.trim(),
|
||||
path: normalizedPath,
|
||||
section,
|
||||
published_at: publishedAt,
|
||||
};
|
||||
@@ -627,6 +681,13 @@ async function initSearchPage() {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isSearchQueryValid(query) === false) {
|
||||
updateStatus(status, "Requete trop longue.");
|
||||
setSectionVisibility(listingSection, false);
|
||||
clearNode(results);
|
||||
return;
|
||||
}
|
||||
|
||||
updateStatus(status, "Recherche en cours...");
|
||||
|
||||
const response = await fetchAllSearchResults(config, query);
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
<strong>{{ $site.Title }}</strong>
|
||||
</a>
|
||||
<form class="site-search" role="search" method="get" action="{{ $site.Params.search.action | relURL }}" aria-label="Recherche">
|
||||
<input id="header-search-input" type="search" name="{{ $site.Params.search.param }}" required aria-label="Recherche">
|
||||
<input id="header-search-input" type="search" name="{{ $site.Params.search.param }}" required maxlength="200" aria-label="Recherche">
|
||||
<button type="submit" class="ui-button" aria-label="Lancer la recherche" title="Lancer la recherche">
|
||||
<svg viewBox="0 0 24 24" aria-hidden="true">
|
||||
<path d="M11 4a7 7 0 1 0 4.9 12l4.5 4.5 1.4-1.4-4.5-4.5A7 7 0 0 0 11 4Zm0 2a5 5 0 1 1 0 10 5 5 0 0 1 0-10Z"></path>
|
||||
|
||||
Reference in New Issue
Block a user