Fix for xss on author page

This commit is contained in:
Ozzie Isaacs
2026-08-01 18:06:49 +02:00
parent b549da05df
commit a07affbd12
4 changed files with 43 additions and 10 deletions
+34 -2
View File
@@ -22,6 +22,7 @@ import inspect
import json
import os
import sys
from urllib.parse import urlsplit
from flask import Blueprint, request, url_for, make_response, jsonify
from .cw_login import current_user
@@ -38,6 +39,37 @@ meta = Blueprint("metadata", __name__)
log = logger.create()
def _safe_metadata_url(value):
if not isinstance(value, str):
return ""
value = value.strip()
if not value:
return ""
parsed = urlsplit(value)
if parsed.scheme in ("http", "https"):
return value
if not parsed.scheme and value.startswith("/"):
return value
return ""
def _sanitize_metadata_record(record):
record["url"] = _safe_metadata_url(record.get("url"))
record["cover"] = _safe_metadata_url(record.get("cover"))
source = record.get("source")
if isinstance(source, dict):
source["link"] = _safe_metadata_url(source.get("link"))
return record
def _serialize_metadata_records(records):
return [
_sanitize_metadata_record(asdict(record))
for record in (records or [])
if record
]
try:
from dataclasses import asdict
except ImportError:
@@ -114,7 +146,7 @@ def metadata_change_active_provider(prov_name):
provider = next((c for c in cl if c.__id__ == prov_name), None)
if provider is not None:
data = provider.search(new_state.get("query", ""))
return make_response(jsonify([asdict(x) for x in data]))
return make_response(jsonify(_serialize_metadata_records(data)))
return ""
@@ -135,5 +167,5 @@ def metadata_search():
if active.get(c.__id__, True)
}
for future in concurrent.futures.as_completed(meta):
data.extend([asdict(x) for x in (future.result() or []) if x])
data.extend(_serialize_metadata_records(future.result()))
return make_response(jsonify(data))
+1 -1
View File
@@ -36,7 +36,7 @@
<div class="cover">
<a href="{{ url_for('web.show_book', book_id=entry.Books.id) }}" {% if simple==false %}data-toggle="modal" data-target="#bookDetailsModal" data-remote="false"{% endif %}>
<span class="img" title="{{entry.Books.title}}">
{{ image.book_cover(entry.Books, alt=author.name|safe) }}
{{ image.book_cover(entry.Books, alt=author.name) }}
{% if entry[2] == True %}<span class="badge read glyphicon glyphicon-ok"></span>{% endif %}
</span>
</a>
+7 -7
View File
@@ -263,26 +263,26 @@
{% block js %}
<script type="text/template" id="template-book-result">
<li class="media" data-related="<%= source.id %>">
<li class="media" data-related="<%- source.id %>">
<img class="pull-left img-responsive"
data-toggle="modal"
data-target="#metaModal"
src="<%= cover || "{{ url_for('static', filename='img/academicpaper.svg') }}" %>"
src="<%- cover || '{{ url_for('static', filename='img/academicpaper.svg') }}' %>"
alt="Cover"
>
<div class="media-body">
<h4 class="media-heading">
<a class="meta_title" href="<%= url %>" target="_blank" rel="noopener"><%= title %></a>
<a class="meta_title" href="<%- url %>" target="_blank" rel="noopener"><%- title %></a>
</h4>
<p class="meta_author">{{_('Author')}}<%= authors.join(" & ") %></p>
<p class="meta_author">{{_('Author')}}<%- authors.join(" & ") %></p>
<% if (publisher) { %>
<p class="meta_publisher">{{_('Publisher')}}<%= publisher %></p>
<p class="meta_publisher">{{_('Publisher')}}<%- publisher %></p>
<% } %>
<% if (description) { %>
<p class="meta_description">{{_('Description')}}: <%= description %></p>
<p class="meta_description">{{_('Description')}}: <%- description %></p>
<% } %>
<p>{{_('Source')}}:
<a class="meta_source" href="<%= source.link %>" target="_blank" rel="noopener"><%= source.description %></a>
<a class="meta_source" href="<%- source.link %>" target="_blank" rel="noopener"><%- source.description %></a>
</p>
</div>
</li>
+1
View File
@@ -353,6 +353,7 @@
</div>
</div>
</div>
</div>
{% endblock %}
{% block js %}