Skip to content

Commit

Permalink
fix: use signed URL for smoelenboek photo's (#72)
Browse files Browse the repository at this point in the history
  • Loading branch information
rmoesbergen authored May 4, 2024
1 parent 5a3a2ac commit 102bc2f
Show file tree
Hide file tree
Showing 5 changed files with 54 additions and 18 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/pull-request.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ jobs:
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
pip install pylint==3.0.3 pylint-django==2.5.5 black==23.1.0
pip install pylint==3.0.3 pylint-django==2.5.5 black==24.4.2
- name: Run pylint and black
run: |
Expand Down
44 changes: 36 additions & 8 deletions LedenAdministratie/api.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
import hashlib
import hmac
import imghdr

from django.conf import settings
from django.db.models import Q
from django.http import HttpResponse, JsonResponse, HttpResponseForbidden
from django.utils import timezone
from django.views import View
from oauth2_provider.views import ProtectedResourceView, ScopedProtectedResourceView

from LedenAdministratie.models import Member
Expand All @@ -10,33 +16,55 @@

class ApiV1Smoelenboek(ProtectedResourceView):
def get(self, request, *args, **kwargs):
large = request.GET.get("large", "0") == "1"
large = request.GET.get("large", "0")
members = Member.objects.filter(
Q(afmeld_datum__gt=timezone.now()) | Q(afmeld_datum=None)
).order_by("first_name")

response = []
expiry = int((timezone.now() + timezone.timedelta(days=1)).timestamp())
for member in members:
if large:
photo = member.foto
else:
photo = member.thumbnail
if photo is None:
photo = member.foto
# Generate a signed URL for the image
url = request.build_absolute_uri(f"{member.id}/{expiry}/?large={large}")
signature = hmac.new(
settings.SECRET_KEY.encode(), url.encode(), hashlib.sha256
).hexdigest()
url += f"&signature={signature}"

memberdict = {
"id": member.id,
"user_id": f"idp-{member.user.pk}",
"first_name": member.first_name,
"last_name": member.last_name,
"types": ",".join([tmptype.slug for tmptype in member.types.all()]),
"photo": img2base64(photo),
"photo": url,
}
response.append(memberdict)

return JsonResponse(data=response, safe=False)


class ApiV1SmoelenboekSigned(View):
def get(self, request, *args, **kwargs):
# Validate signature and expiry datetime
signature = request.GET.get("signature", "")
url = request.build_absolute_uri().replace(f"&signature={signature}", "")
new_signature = hmac.new(
settings.SECRET_KEY.encode(), url.encode(), hashlib.sha256
).hexdigest()
if new_signature != signature:
return HttpResponseForbidden()
if timezone.now().timestamp() > kwargs.get("expiry", 0):
return HttpResponseForbidden()

# Return the image if all is OK
large = request.GET.get("large", "0") == "1"
member = Member.objects.get(id=kwargs.get("pk"))
photo = member.foto if large else member.thumbnail
content_type = imghdr.what(None, photo)
return HttpResponse(photo, content_type=f"image/{content_type}")


class ApiV1SmoelenboekUser(ProtectedResourceView):
def get(self, request, *args, **kwargs):
large = request.GET.get("large", "0") == "1"
Expand Down
14 changes: 8 additions & 6 deletions LedenAdministratie/oidc.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,14 @@ def get_additional_claims(self) -> dict:
"media": lambda request: True,
"account_type": lambda request: request.user.member.idp_types(),
"days": lambda request: request.user.member.days,
"stripcard": lambda request: {
"count": request.user.member.active_stripcard.count,
"used": request.user.member.active_stripcard.used,
}
if request.user.member.active_stripcard
else None,
"stripcard": lambda request: (
{
"count": request.user.member.active_stripcard.count,
"used": request.user.member.active_stripcard.used,
}
if request.user.member.active_stripcard
else None
),
}

def validate_user(
Expand Down
6 changes: 6 additions & 0 deletions LedenAdministratie/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
1. Add an import: from blog import urls as blog_urls
2. Add a URL to urlpatterns: url(r'^blog/', include(blog_urls))
"""

from django.contrib import admin
from django.urls import path, include
from two_factor.urls import urlpatterns as tf_urls
Expand Down Expand Up @@ -98,6 +99,11 @@
path("email/log/", views.EmailLogView.as_view(), name="email_log"),
path("settings/", views.SettingsView.as_view(), name="settings"),
path("api/v1/smoelenboek/", api.ApiV1Smoelenboek.as_view()),
path(
"api/v1/smoelenboek/<int:pk>/<int:expiry>/",
api.ApiV1SmoelenboekSigned.as_view(),
name="smoelenboek_signed",
),
path("api/v1/smoelenboek/<int:pk>/", api.ApiV1SmoelenboekUser.as_view()),
path("api/v1/member/details", api.ApiV1UserDetails.as_view()),
path("o/", include("oauth2_provider.urls", namespace="oauth2_provider")),
Expand Down
6 changes: 3 additions & 3 deletions LedenAdministratie/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -233,9 +233,9 @@ def get_context_data(self, **kwargs):
if self.kwargs.get("member_id"):
context["member"] = Member.objects.get(pk=self.kwargs["member_id"])
else:
context["form"].fields[
"members"
].queryset = InvoiceTool.get_members_invoice_type(self.invoice_type)
context["form"].fields["members"].queryset = (
InvoiceTool.get_members_invoice_type(self.invoice_type)
)

self.lines = self.LinesFormSet(
initial=InvoiceTool.get_defaults_for_invoice_type(
Expand Down

0 comments on commit 102bc2f

Please sign in to comment.