diff --git a/devel/reports.py b/devel/reports.py
index ca8e9369..8d67eb33 100644
--- a/devel/reports.py
+++ b/devel/reports.py
@@ -21,8 +21,8 @@ def __init__(self, href, title, desc):
self.desc = desc
def __str__(self):
- link = '%s'
- return format_html(link % (self.href, self.title, self.desc))
+ return format_html('{desc}',
+ href=self.href, title=self.title, desc=self.desc)
def linkify_non_reproducible_packages(statuses):
diff --git a/devel/tests/test_reports.py b/devel/tests/test_reports.py
index 96b85a74..62729deb 100644
--- a/devel/tests/test_reports.py
+++ b/devel/tests/test_reports.py
@@ -1,6 +1,7 @@
from django.contrib.auth.models import User
from django.test import TransactionTestCase
+from devel.reports import Linkify
from packages.models import PackageRelation
@@ -98,3 +99,12 @@ def test_report_pkgbases_filtered_by_maintainer(self):
f'/devel/reports/old/{self.user.username}/pkgbases/')
self.assertEqual(response.status_code, 200)
self.assertEqual(response.content.decode().strip(), 'linux')
+
+
+def test_linkify_escapes_html():
+ link = Linkify(href='">', title='
', desc='xss')
+ result = str(link)
+ assert '')
+ return format_html('', link=link)
@register.simple_tag
diff --git a/news/views.py b/news/views.py
index a8009427..b961afcc 100644
--- a/news/views.py
+++ b/news/views.py
@@ -1,5 +1,6 @@
from django import forms
from django.conf import settings
+from django.contrib.auth.decorators import login_required
from django.core.mail import EmailMessage
from django.http import HttpResponse
from django.shortcuts import get_object_or_404, redirect
@@ -82,6 +83,7 @@ def view_redirect(request, object_id):
return redirect(newsitem, permanent=True)
+@login_required
@require_POST
def preview(request):
data = request.POST.get('data', '')
diff --git a/pyproject.toml b/pyproject.toml
index 1c0e4217..90d880a6 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -7,7 +7,7 @@ requires-python = ">=3.13"
dependencies = [
"bencode-py==4.1.0",
"bleach==6.4.0",
- "django==5.2.16",
+ "django==5.2.17",
"django-countries==8.2.0",
"django-csp==4.0",
"django-prometheus==2.5.0",
diff --git a/sitestatic/homepage.js b/sitestatic/homepage.js
index 35dfb0ea..d6e17828 100644
--- a/sitestatic/homepage.js
+++ b/sitestatic/homepage.js
@@ -51,11 +51,24 @@
ul.style.display = "block";
const fragment = document.createDocumentFragment();
- for (let i = 0; i < pkgs.length; i++) {
+ for (const pkgname of pkgs) {
const item = document.createElement("li");
- const text = pkgs[i].replace(letter, `${letter}`);
- item.innerHTML = `${text}`;
- item.setAttribute('data-value', pkgs[i]);
+ const anchor = document.createElement("a");
+ anchor.href = "#";
+
+ const matchIndex = pkgname.indexOf(letter);
+ if (matchIndex !== -1) {
+ anchor.appendChild(document.createTextNode(pkgname.slice(0, matchIndex)));
+ const bold = document.createElement("b");
+ bold.textContent = pkgname.slice(matchIndex, matchIndex + letter.length);
+ anchor.appendChild(bold);
+ anchor.appendChild(document.createTextNode(pkgname.slice(matchIndex + letter.length)));
+ } else {
+ anchor.textContent = pkgname;
+ }
+
+ item.appendChild(anchor);
+ item.setAttribute('data-value', pkgname);
fragment.appendChild(item);
}
diff --git a/uv.lock b/uv.lock
index 810eaf1e..a93fcebf 100644
--- a/uv.lock
+++ b/uv.lock
@@ -80,7 +80,7 @@ smtp = [
requires-dist = [
{ name = "bencode-py", specifier = "==4.1.0" },
{ name = "bleach", specifier = "==6.4.0" },
- { name = "django", specifier = "==5.2.16" },
+ { name = "django", specifier = "==5.2.17" },
{ name = "django-countries", specifier = "==8.2.0" },
{ name = "django-csp", specifier = "==4.0" },
{ name = "django-ninja", specifier = "==1.6.2" },
@@ -351,16 +351,16 @@ wheels = [
[[package]]
name = "django"
-version = "5.2.16"
+version = "5.2.17"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "asgiref" },
{ name = "sqlparse" },
{ name = "tzdata", marker = "sys_platform == 'win32'" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/a9/26/889449d521ae508b26de715954faecd8bcf3f740affb81b2d146a83b42a5/django-5.2.16.tar.gz", hash = "sha256:59ea02020c3136fce14bef0bbece21a10a4febef5eed1c51c22ae468efa22200", size = 10890894, upload-time = "2026-07-07T13:52:17.005Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/d5/d8/43e9d000519adceb189620b6869ff88031e046df91c2e9da72f8f6918399/django-5.2.17.tar.gz", hash = "sha256:9d4d93be539a18ab80d058eb515900e10951e04c537c5a6b394fc49528d3251f", size = 10889740, upload-time = "2026-08-04T15:04:03.173Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/4e/13/1e5e3e4c15dcecb04281b3cb2a46a4670e1cef131068e202f6040df19224/django-5.2.16-py3-none-any.whl", hash = "sha256:04f354bf9d807a86ad1a8392fe3808d362358a8eafc322848e0e43e59b24371d", size = 8311943, upload-time = "2026-07-07T13:52:11.223Z" },
+ { url = "https://files.pythonhosted.org/packages/df/f8/ce120525ca78f12b07daf65786679c5d0b54a75285a8958d3ae55e39da35/django-5.2.17-py3-none-any.whl", hash = "sha256:f04fb3b36ee119e1af4fa1d397d5fd6cf12700f49321e84d4f4c642c5b1973db", size = 8315563, upload-time = "2026-08-04T15:03:59.1Z" },
]
[[package]]