aboutsummaryrefslogtreecommitdiff
path: root/middleware/authentication.py
blob: afd15b1eb1232793bc83b0a4bc069a6c7a68170f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
import json
from django.utils import timezone
from datetime import timedelta
from django.shortcuts import render
from django.contrib.auth import logout
from authentication.utils import (
    get_redirect_uri,
    get_discord_user,
)


class AuthMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        # Skip authentication if the path contains "admin" or is not a view
        if (
            "admin" in request.path
            or "auth" in request.path
            or "favicon.ico" in request.path
            or not hasattr(request, "user")
        ):
            response = self.get_response(request)
            return response

        if (
            not request.user.is_authenticated
            or not request.user.discord_id
            or not request.user.discord_access_token
        ):
            logout(request)
            request.session["next"] = request.get_full_path()
            return render(request, "messages/unauthorized.html", {"redirect_uri": get_redirect_uri()})

        # Check the verification cookie
        verification_cookie = request.COOKIES.get("guild_verified")
        if verification_cookie:
            try:
                cookie_data = json.loads(verification_cookie)
                verified_at = timezone.datetime.fromisoformat(
                    cookie_data["verified_at"]
                )
                if timezone.now() > verified_at + timedelta(hours=24):
                    # Verification expired, need to re-check
                    pass
            except (json.JSONDecodeError, ValueError):
                # Cookie is invalid or expired, need to re-check
                pass
        else:
            # No verification cookie, need to check guild membership
            pass

        if not verification_cookie or not self._is_authorized(request):
            user = get_discord_user(
                access_token=request.user.discord_access_token,
                token_type=request.user.discord_token_type,
            )

            if not user["is_authorized"]:
                logout(request)
                request.session["next"] = request.get_full_path()
                response = render(request, "messages/unauthorized.html", {"redirect_uri": get_redirect_uri()})
                response.delete_cookie("guild_verified")  # Ensure cookie is removed
                return response

            # Set the verification cookie
            response = self.get_response(request)
            response.set_cookie(
                "guild_verified",
                json.dumps({"verified_at": timezone.now().isoformat()}),
                max_age=24 * 60 * 60 if not user["rate_limited"] else 60 * 60,  # 24 hours or 1 hour if rate limited
                httponly=True,  # Cookie cannot be accessed via JavaScript
                secure=True,  # Ensure cookie is sent over HTTPS
            )
            return response

        response = self.get_response(request)
        return response

    def _is_authorized(self, request):
        # Check if the user is authorized based on the current cookie or session
        # This function should ideally be a lightweight check
        return True