mirror of
https://github.com/0xMarcio/cve.git
synced 2026-10-27 16:51:03 +00:00
Meet the query where it is written: slang, names, typos
Security slang and NVD prose rarely share a word. "sqli" found 843 CVEs where "sql injection" found 12,719, "lpe" 80 against 1,311 for "privilege escalation". A term now expands to its phrases and an entry matches on any of them, with the best-scoring form counted. A vulnerability searched by the name it is known by leads with the record it belongs to, whatever the prose and the repository names say: ghostcat put a different record first, moveit a newer one. Forty names are mapped. A term with no word in the index at all is nearly always a typo. The closest word one edit away stands in, weighed by how many records use it, and the status line says which: citrx finds citrix, fortinte fortinet, l0g4j log4j. CVE pages carry BreadcrumbList markup for the home, year and block trail, and the site publishes an OpenSearch descriptor so a browser can add it as a search engine from the address bar.
This commit is contained in:
1 parent
5f918199ab
commit
aae0c789a3
5 files changed
+202
-34
No files matched your search
@@ -386,6 +386,20 @@ def page(entry: dict, data: dict) -> str:
|
||||
}
|
||||
)
|
||||
|
||||
year, block = block_of(cid)
|
||||
trail = json_ld(
|
||||
{
|
||||
"@context": "https://schema.org",
|
||||
"@type": "BreadcrumbList",
|
||||
"itemListElement": [
|
||||
{"@type": "ListItem", "position": 1, "name": BRAND, "item": f"{SITE}/"},
|
||||
{"@type": "ListItem", "position": 2, "name": f"CVE-{year}", "item": f"{SITE}/{year}"},
|
||||
{"@type": "ListItem", "position": 3, "name": f"CVE-{year}-{block}", "item": f"{SITE}/CVE-{year}-{block}"},
|
||||
{"@type": "ListItem", "position": 4, "name": cid, "item": url},
|
||||
],
|
||||
}
|
||||
)
|
||||
|
||||
return f"""<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
@@ -411,6 +425,7 @@ def page(entry: dict, data: dict) -> str:
|
||||
{FONTS}
|
||||
<link rel="stylesheet" href="/style.css"/>
|
||||
<script type="application/ld+json">{ld}</script>
|
||||
<script type="application/ld+json">{trail}</script>
|
||||
</head>
|
||||
<body>
|
||||
{header(len(data["cves"]))}
|
||||
|
||||
+17
-1
@@ -16,7 +16,7 @@ from datetime import datetime, timezone
|
||||
ROOT = os.path.join(os.path.dirname(os.path.abspath(__file__)), os.pardir)
|
||||
sys.path.insert(0, os.path.join(ROOT, "scripts"))
|
||||
|
||||
from brand import SITE
|
||||
from brand import BRAND, DESCRIPTION, SITE
|
||||
|
||||
DOCS = os.path.join(ROOT, "docs")
|
||||
ROBOTS = os.path.join(DOCS, "robots.txt")
|
||||
@@ -48,6 +48,20 @@ def robots() -> str:
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
def opensearch() -> str:
|
||||
"""The descriptor a browser reads to offer the site as a search engine."""
|
||||
return (
|
||||
'<?xml version="1.0" encoding="UTF-8"?>\n'
|
||||
'<OpenSearchDescription xmlns="http://a9.com/-/spec/opensearch/1.1/">\n'
|
||||
f" <ShortName>{BRAND}</ShortName>\n"
|
||||
f" <Description>{DESCRIPTION}</Description>\n"
|
||||
" <InputEncoding>UTF-8</InputEncoding>\n"
|
||||
f' <Image width="16" height="16" type="image/x-icon">{SITE}/favicon.ico</Image>\n'
|
||||
f' <Url type="text/html" method="get" template="{SITE}/?q={{searchTerms}}"/>\n'
|
||||
"</OpenSearchDescription>\n"
|
||||
)
|
||||
|
||||
|
||||
def urlset(urls: list[tuple[str, str]]) -> str:
|
||||
body = "".join(
|
||||
f" <url>\n <loc>{loc}</loc>\n <lastmod>{lastmod}</lastmod>\n </url>\n"
|
||||
@@ -79,6 +93,8 @@ def main() -> int:
|
||||
|
||||
with open(ROBOTS, "w", encoding="utf-8") as handle:
|
||||
handle.write(robots())
|
||||
with open(os.path.join(DOCS, "opensearch.xml"), "w", encoding="utf-8") as handle:
|
||||
handle.write(opensearch())
|
||||
|
||||
# One sitemap per CVE year. The 50,000 URL cap makes some split necessary and
|
||||
# the year is the split the data already has, which also means a crawler only
|
||||
|
||||
Reference in new issue
Block a user