Construct absolute URLs with the correct protocol and port

This commit is contained in:
Bart Schuurmans 2024-04-07 17:22:29 +02:00
parent 3aefbb548e
commit c42db40a63
14 changed files with 55 additions and 73 deletions

View file

@ -4,7 +4,7 @@ from django.template.loader import get_template
from bookwyrm import models, settings
from bookwyrm.tasks import app, EMAIL
from bookwyrm.settings import DOMAIN
from bookwyrm.settings import DOMAIN, BASE_URL
def email_data():
@ -14,6 +14,7 @@ def email_data():
"site_name": site.name,
"logo": site.logo_small_url,
"domain": DOMAIN,
"base_url": BASE_URL,
"user": None,
}

View file

@ -12,7 +12,7 @@ from model_utils import FieldTracker
from bookwyrm.connectors.abstract_connector import get_data
from bookwyrm.preview_images import generate_site_preview_image_task
from bookwyrm.settings import DOMAIN, ENABLE_PREVIEW_IMAGES, STATIC_FULL_URL
from bookwyrm.settings import BASE_URL, ENABLE_PREVIEW_IMAGES, STATIC_FULL_URL
from bookwyrm.settings import RELEASE_API
from bookwyrm.tasks import app, MISC
from .base_model import BookWyrmModel, new_access_code
@ -188,7 +188,7 @@ class SiteInvite(models.Model):
@property
def link(self):
"""formats the invite link"""
return f"https://{DOMAIN}/invite/{self.code}"
return f"{BASE_URL}/invite/{self.code}"
class InviteRequest(BookWyrmModel):
@ -235,7 +235,7 @@ class PasswordReset(models.Model):
@property
def link(self):
"""formats the invite link"""
return f"https://{DOMAIN}/password-reset/{self.code}"
return f"{BASE_URL}/password-reset/{self.code}"
# pylint: disable=unused-argument

View file

@ -19,7 +19,7 @@ from bookwyrm.connectors import get_data, ConnectorException
from bookwyrm.models.shelf import Shelf
from bookwyrm.models.status import Status
from bookwyrm.preview_images import generate_user_preview_image_task
from bookwyrm.settings import DOMAIN, ENABLE_PREVIEW_IMAGES, USE_HTTPS, LANGUAGES
from bookwyrm.settings import BASE_URL, DOMAIN, ENABLE_PREVIEW_IMAGES, USE_HTTPS, LANGUAGES
from bookwyrm.signatures import create_key_pair
from bookwyrm.tasks import app, MISC
from bookwyrm.utils import regex
@ -214,8 +214,7 @@ class User(OrderedCollectionPageMixin, AbstractUser):
@property
def confirmation_link(self):
"""helper for generating confirmation links"""
link = site_link()
return f"{link}/confirm-email/{self.confirmation_code}"
return f"{BASE_URL}/confirm-email/{self.confirmation_code}"
@property
def following_link(self):

View file

@ -2,10 +2,10 @@
<div style="font-family: BlinkMacSystemFont,-apple-system,'Segoe UI',Roboto,Oxygen,Ubuntu,Cantarell,'Fira Sans','Droid Sans','Helvetica Neue',Helvetica,Arial,sans-serif; border-radius: 6px; background-color: #efefef; max-width: 632px;">
<div style="padding: 1rem; overflow: auto;">
<div style="float: left; margin-right: 1rem;">
<a style="color: #3273dc;" href="https://{{ domain }}" style="text-decoration: none;"><img src="{{ logo }}" alt="logo" loading="lazy" decoding="async"></a>
<a style="color: #3273dc;" href="{{ base_url }}" style="text-decoration: none;"><img src="{{ logo }}" alt="logo" loading="lazy" decoding="async"></a>
</div>
<div>
<a style="color: black; text-decoration: none" href="https://{{ domain }}" style="text-decoration: none;"><strong>{{ site_name }}</strong><br>
<a style="color: black; text-decoration: none" href="{{ base_url }}" style="text-decoration: none;"><strong>{{ site_name }}</strong><br>
{{ domain }}</a>
</div>
</div>
@ -18,9 +18,9 @@
</div>
<div style="padding: 1rem; font-size: 0.8rem;">
<p style="margin: 0; color: #333;">{% blocktrans %}BookWyrm hosted on <a style="color: #3273dc;" href="https://{{ domain }}">{{ site_name }}</a>{% endblocktrans %}</p>
<p style="margin: 0; color: #333;">{% blocktrans %}BookWyrm hosted on <a style="color: #3273dc;" href="{{ base_url }}">{{ site_name }}</a>{% endblocktrans %}</p>
{% if user %}
<p style="margin: 0; color: #333;"><a style="color: #3273dc;" href="https://{{ domain }}{% url 'prefs-profile' %}">{% trans "Email preference" %}</a></p>
<p style="margin: 0; color: #333;"><a style="color: #3273dc;" href="{{ base_url }}{% url 'prefs-profile' %}">{% trans "Email preference" %}</a></p>
{% endif %}
</div>
</div>

View file

@ -12,6 +12,6 @@
<p>
{% url 'code-of-conduct' as coc_path %}
{% url 'about' as about_path %}
{% blocktrans %}Learn more <a href="https://{{ domain }}{{ about_path }}">about {{ site_name }}</a>.{% endblocktrans %}
{% blocktrans %}Learn more <a href="{{ base_url }}{{ about_path }}">about {{ site_name }}</a>.{% endblocktrans %}
</p>
{% endblock %}

View file

@ -5,6 +5,6 @@
{{ invite_link }}
{% blocktrans %}Learn more about {{ site_name }}:{% endblocktrans %} https://{{ domain }}{% url 'about' %}
{% blocktrans %}Learn more about {{ site_name }}:{% endblocktrans %} {{ base_url }}{% url 'about' %}
{% endblock %}

View file

@ -10,6 +10,6 @@
<Image width="16" height="16" type="image/x-icon">{{ image }}</Image>
<Url
type="text/html"
template="https://{{ DOMAIN }}{% url 'search' %}?q={searchTerms}"
template="{{ BASE_URL }}{% url 'search' %}?q={searchTerms}"
/>
</OpenSearchDescription>

View file

@ -4,7 +4,7 @@ from dataclasses import dataclass
import datetime
import json
import pathlib
import re
from urllib.parse import urlparse
from typing import List
from unittest import expectedFailure
from unittest.mock import patch
@ -22,7 +22,7 @@ from bookwyrm.activitypub.base_activity import ActivityObject
from bookwyrm.models import fields, User, Status, Edition
from bookwyrm.models.base_model import BookWyrmModel
from bookwyrm.models.activitypub_mixin import ActivitypubMixin
from bookwyrm.settings import DOMAIN
from bookwyrm.settings import PROTOCOL, NETLOC
# pylint: disable=too-many-public-methods
@patch("bookwyrm.suggested_users.rerank_suggestions_task.delay")
@ -427,12 +427,10 @@ class ModelFields(TestCase):
instance = fields.ImageField()
output = instance.field_to_activity(user.avatar)
self.assertIsNotNone(
re.match(
rf"https:\/\/{DOMAIN}\/.*\.jpg",
output.url,
)
)
parsed_url = urlparse(output.url)
self.assertEqual(parsed_url.scheme, PROTOCOL)
self.assertEqual(parsed_url.netloc, NETLOC)
self.assertRegex(parsed_url.path, r"\.jpg$")
self.assertEqual(output.name, "")
self.assertEqual(output.type, "Image")

View file

@ -79,7 +79,7 @@ class SiteModels(TestCase):
def test_site_invite_link(self):
"""invite link generator"""
invite = models.SiteInvite.objects.create(user=self.local_user, code="hello")
self.assertEqual(invite.link, f"https://{settings.DOMAIN}/invite/hello")
self.assertEqual(invite.link, f"{settings.BASE_URL}/invite/hello")
def test_invite_request(self):
"""someone wants an invite"""
@ -95,7 +95,7 @@ class SiteModels(TestCase):
"""password reset token"""
token = models.PasswordReset.objects.create(user=self.local_user, code="hello")
self.assertTrue(token.valid())
self.assertEqual(token.link, f"https://{settings.DOMAIN}/password-reset/hello")
self.assertEqual(token.link, f"{settings.BASE_URL}/password-reset/hello")
@patch("bookwyrm.suggested_users.rerank_suggestions_task.delay")
@patch("bookwyrm.suggested_users.remove_user_task.delay")

View file

@ -227,11 +227,9 @@ class Status(TestCase):
self.assertEqual(activity["sensitive"], False)
self.assertIsInstance(activity["attachment"], list)
self.assertEqual(activity["attachment"][0]["type"], "Document")
self.assertTrue(
re.match(
r"https:\/\/your.domain.here\/images\/covers\/test(_[A-z0-9]+)?.jpg",
activity["attachment"][0]["url"],
)
self.assertRegex(
activity["attachment"][0]["url"],
rf"^{settings.BASE_URL}/images/covers/test(_[A-z0-9]+)?.jpg$",
)
self.assertEqual(activity["attachment"][0]["name"], "Test Edition")
@ -263,12 +261,10 @@ class Status(TestCase):
),
)
self.assertEqual(activity["attachment"][0]["type"], "Document")
# self.assertTrue(
# re.match(
# r"https:\/\/your.domain.here\/images\/covers\/test_[A-z0-9]+.jpg",
# activity["attachment"][0].url,
# )
# )
self.assertRegex(
activity["attachment"][0]["url"],
rf"^{settings.BASE_URL}/images/covers/test_[A-z0-9]+.jpg$",
)
self.assertEqual(activity["attachment"][0]["name"], "Test Edition")
def test_quotation_to_activity(self, *_):
@ -306,11 +302,9 @@ class Status(TestCase):
),
)
self.assertEqual(activity["attachment"][0]["type"], "Document")
self.assertTrue(
re.match(
r"https:\/\/your.domain.here\/images\/covers\/test(_[A-z0-9]+)?.jpg",
activity["attachment"][0]["url"],
)
self.assertRegex(
activity["attachment"][0]["url"],
rf"^{settings.BASE_URL}/images/covers/test(_[A-z0-9]+)?.jpg$",
)
self.assertEqual(activity["attachment"][0]["name"], "Test Edition")
@ -400,11 +394,9 @@ class Status(TestCase):
)
self.assertEqual(activity["content"], "test content")
self.assertEqual(activity["attachment"][0]["type"], "Document")
self.assertTrue(
re.match(
r"https:\/\/your.domain.here\/images\/covers\/test_[A-z0-9]+.jpg",
activity["attachment"][0]["url"],
)
self.assertRegex(
activity["attachment"][0]["url"],
rf"^{settings.BASE_URL}/images/covers/test_[A-z0-9]+.jpg$",
)
self.assertEqual(activity["attachment"][0]["name"], "Test Edition")
@ -425,11 +417,9 @@ class Status(TestCase):
)
self.assertEqual(activity["content"], "test content")
self.assertEqual(activity["attachment"][0]["type"], "Document")
self.assertTrue(
re.match(
r"https:\/\/your.domain.here\/images\/covers\/test_[A-z0-9]+.jpg",
activity["attachment"][0]["url"],
)
self.assertRegex(
activity["attachment"][0]["url"],
rf"^{settings.BASE_URL}/images/covers/test_[A-z0-9]+.jpg$",
)
self.assertEqual(activity["attachment"][0]["name"], "Test Edition")
@ -448,11 +438,9 @@ class Status(TestCase):
f'rated <em><a href="{self.book.remote_id}">{self.book.title}</a></em>: 3 stars',
)
self.assertEqual(activity["attachment"][0]["type"], "Document")
self.assertTrue(
re.match(
r"https:\/\/your.domain.here\/images\/covers\/test_[A-z0-9]+.jpg",
activity["attachment"][0]["url"],
)
self.assertRegex(
activity["attachment"][0]["url"],
rf"^{settings.BASE_URL}/images/covers/test_[A-z0-9]+.jpg$",
)
self.assertEqual(activity["attachment"][0]["name"], "Test Edition")

View file

@ -2,6 +2,7 @@
import re
from django.test import TestCase
from bookwyrm.settings import BASE_URL
from bookwyrm.utils import regex
from bookwyrm.utils.validate import validate_url_domain
@ -15,10 +16,8 @@ class TestUtils(TestCase):
def test_valid_url_domain(self):
"""Check with a valid URL"""
self.assertEqual(
validate_url_domain("https://your.domain.here/legit-book-url/"),
"https://your.domain.here/legit-book-url/",
)
legit = f"{BASE_URL}/legit-book-url/"
self.assertEqual(validate_url_domain(legit), legit)
def test_invalid_url_domain(self):
"""Check with an invalid URL"""

View file

@ -8,7 +8,7 @@ from django.test.client import RequestFactory
import responses
from bookwyrm import models, views
from bookwyrm.settings import USER_AGENT, DOMAIN
from bookwyrm.settings import USER_AGENT, BASE_URL
@patch("bookwyrm.activitystreams.add_status_task.delay")
@ -288,13 +288,13 @@ class ViewsHelpers(TestCase): # pylint: disable=too-many-public-methods
def test_redirect_to_referer_valid_domain(self, *_):
"""redirect to within the app"""
request = self.factory.get("/path")
request.META = {"HTTP_REFERER": f"https://{DOMAIN}/and/a/path"}
request.META = {"HTTP_REFERER": f"{BASE_URL}/and/a/path"}
result = views.helpers.redirect_to_referer(request)
self.assertEqual(result.url, f"https://{DOMAIN}/and/a/path")
self.assertEqual(result.url, f"{BASE_URL}/and/a/path")
def test_redirect_to_referer_with_get_args(self, *_):
"""if the path has get params (like sort) they are preserved"""
request = self.factory.get("/path")
request.META = {"HTTP_REFERER": f"https://{DOMAIN}/and/a/path?sort=hello"}
request.META = {"HTTP_REFERER": f"{BASE_URL}/and/a/path?sort=hello"}
result = views.helpers.redirect_to_referer(request)
self.assertEqual(result.url, f"https://{DOMAIN}/and/a/path?sort=hello")
self.assertEqual(result.url, f"{BASE_URL}/and/a/path?sort=hello")

View file

@ -1,7 +1,7 @@
"""Validations"""
from typing import Optional
from bookwyrm.settings import DOMAIN, USE_HTTPS
from bookwyrm.settings import BASE_URL
def validate_url_domain(url: Optional[str]) -> Optional[str]:
@ -9,10 +9,7 @@ def validate_url_domain(url: Optional[str]) -> Optional[str]:
if url is None:
return None
protocol = "https://" if USE_HTTPS else "http://"
origin = f"{protocol}{DOMAIN}"
if not url.startswith(BASE_URL):
return None
if url.startswith(origin):
return url
return None
return url

View file

@ -9,7 +9,7 @@ from django.utils import timezone
from django.views.decorators.http import require_GET
from bookwyrm import models
from bookwyrm.settings import DOMAIN, VERSION, LANGUAGE_CODE
from bookwyrm.settings import BASE_URL, DOMAIN, VERSION, LANGUAGE_CODE
@require_GET
@ -34,7 +34,7 @@ def webfinger(request):
},
{
"rel": "http://ostatus.org/schema/1.0/subscribe",
"template": f"https://{DOMAIN}/ostatus_subscribe?acct={{uri}}",
"template": f"{BASE_URL}/ostatus_subscribe?acct={{uri}}",
},
],
}