Skip to content

Commit

Permalink
Make links https only (#9)
Browse files Browse the repository at this point in the history
Add url validators with strict schemes parameter, update model definition, migrations, tests
  • Loading branch information
Alschn authored Nov 28, 2023
1 parent 597fe34 commit dd75732
Show file tree
Hide file tree
Showing 4 changed files with 35 additions and 3 deletions.
4 changes: 2 additions & 2 deletions links/migrations/0001_initial.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
import django.utils.timezone
import django.core.validators


class Migration(migrations.Migration):
Expand All @@ -22,7 +22,7 @@ class Migration(migrations.Migration):
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('title', models.CharField(max_length=127)),
('description', models.TextField(blank=True, default='', max_length=1000)),
('url', models.URLField()),
('url', models.URLField(validators=[django.core.validators.URLValidator(schemes=('https',))])),
('source_type', models.CharField(choices=[('YT', 'YouTube'), ('SP', 'Spotify'), ('UN', 'Unknown')], max_length=2)),
('created_at', models.DateTimeField(auto_now_add=True)),
('updated_at', models.DateTimeField(auto_now=True)),
Expand Down
7 changes: 6 additions & 1 deletion links/models/link.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,21 @@
from django.core import validators
from django.db import models
from django.utils.translation import gettext_lazy as _


class Link(models.Model):
ALLOWED_SCHEMES = ('https',)

class SourceType(models.TextChoices):
YOUTUBE = 'YT', _('YouTube')
SPOTIFY = 'SP', _('Spotify')
UNKNOWN = 'UN', _('Unknown')

title = models.CharField(max_length=127)
description = models.TextField(max_length=1000, blank=True, default='')
url = models.URLField()
url = models.URLField(
validators=[validators.URLValidator(schemes=ALLOWED_SCHEMES)],
)
source_type = models.CharField(choices=SourceType.choices, max_length=2)
user = models.ForeignKey(
'accounts.User',
Expand Down
5 changes: 5 additions & 0 deletions links/serializers/link.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from urllib.parse import urlparse

from django.contrib.auth import get_user_model
from django.core import validators
from django.db import transaction
from django.utils.translation import gettext_lazy as _
from rest_framework import serializers
Expand Down Expand Up @@ -52,6 +53,7 @@ class Meta:
'updated_at',
)
extra_kwargs = {
'url': {'validators': [validators.URLValidator(schemes=Link.ALLOWED_SCHEMES)]},
'source_type': {'read_only': True, 'required': False},
'user': {'read_only': True, 'required': False},
'track': {'read_only': True, 'required': False},
Expand Down Expand Up @@ -91,6 +93,9 @@ class LinkCreateResultSerializer(LinkCreateSerializer):
# do not use elsewhere
task_id = serializers.CharField(read_only=True)

class Meta(LinkCreateSerializer.Meta):
fields = LinkCreateSerializer.Meta.fields + ('task_id',)


def get_source_type_from_url(url: str) -> Link.SourceType:
parsed = urlparse(url)
Expand Down
22 changes: 22 additions & 0 deletions links/tests/test_links_views.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
from unittest.mock import patch

from django.core.exceptions import ValidationError
from django.core.validators import URLValidator
from django.test import TestCase, override_settings
from rest_framework import status
from rest_framework.reverse import reverse_lazy
Expand Down Expand Up @@ -155,3 +157,23 @@ def test_create_link_link_request_does_not_belong_to_user(self):
)
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
self.assertIn('link_request', response.json())

def test_create_link_http(self):
link_request = LinkRequestFactory(user=self.user)
url = 'http://localhost:8000'

validator = URLValidator(schemes=Link.ALLOWED_SCHEMES)
with self.assertRaises(ValidationError):
validator(url)

self.client.force_login(self.user)
response = self.client.post(
self.links_list_url,
data={
'link_request': link_request.id,
'title': 'HTTP link test',
'url': url
},
)
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
self.assertIn('url', response.json())

0 comments on commit dd75732

Please sign in to comment.