Skip to content
Snippets Groups Projects
utils.py 3.25 KiB
Newer Older
  • Learn to ignore specific revisions
  • import unicodedata
    import re
    
    from django.conf import settings
    
    
    from funkwhale_api.common import session
    
    from funkwhale_api.moderation import models as moderation_models
    
    from . import signing
    
    
    
    def full_url(path):
        """
        Given a relative path, return a full url usable for federation purpose
        """
    
        if path.startswith("http://") or path.startswith("https://"):
            return path
    
        root = settings.FUNKWHALE_URL
    
    Eliot Berriot's avatar
    Eliot Berriot committed
        if path.startswith("/") and root.endswith("/"):
    
    Eliot Berriot's avatar
    Eliot Berriot committed
        elif not path.startswith("/") and not root.endswith("/"):
            return root + "/" + path
    
    
    
    def clean_wsgi_headers(raw_headers):
        """
        Convert WSGI headers from CONTENT_TYPE to Content-Type notation
        """
        cleaned = {}
    
    Eliot Berriot's avatar
    Eliot Berriot committed
        non_prefixed = ["content_type", "content_length"]
    
        for raw_header, value in raw_headers.items():
            h = raw_header.lower()
    
    Eliot Berriot's avatar
    Eliot Berriot committed
            if not h.startswith("http_") and h not in non_prefixed:
    
    Eliot Berriot's avatar
    Eliot Berriot committed
            words = h.replace("http_", "", 1).split("_")
            cleaned_header = "-".join([w.capitalize() for w in words])
    
            cleaned[cleaned_header] = value
    
        return cleaned
    
    
    
    def slugify_username(username):
        """
        Given a username such as "hello M. world", returns a username
        suitable for federation purpose (hello_M_world).
    
        Preserves the original case.
    
        Code is borrowed from django's slugify function.
        """
    
        value = str(username)
        value = (
            unicodedata.normalize("NFKD", value).encode("ascii", "ignore").decode("ascii")
        )
        value = re.sub(r"[^\w\s-]", "", value).strip()
        return re.sub(r"[-\s]+", "_", value)
    
        fid, actor, serializer_class=None, queryset=None, apply_instance_policies=True
    
    Eliot Berriot's avatar
    Eliot Berriot committed
        from . import activity
    
    
        policies = moderation_models.InstancePolicy.objects.active().filter(block_all=True)
        if apply_instance_policies and policies.matching_url(fid):
            raise exceptions.BlockedActorOrDomain()
    
        if queryset:
            try:
                # queryset can also be a Model class
                existing = queryset.filter(fid=fid).first()
            except AttributeError:
                existing = queryset.objects.filter(fid=fid).first()
            if existing:
                return existing
    
        auth = (
            None if not actor else signing.get_auth(actor.private_key, actor.private_key_id)
        )
        response = session.get_session().get(
            fid,
            auth=auth,
            timeout=5,
            verify=settings.EXTERNAL_REQUESTS_VERIFY_SSL,
            headers={
                "Accept": "application/activity+json",
                "Content-Type": "application/activity+json",
            },
        )
        response.raise_for_status()
        data = response.json()
    
    
        # we match against moderation policies here again, because the FID of the returned
        # object may not be the same as the URL used to access it
        try:
            id = data["id"]
        except KeyError:
            pass
        else:
    
            if apply_instance_policies and activity.should_reject(fid=id, payload=data):
    
                raise exceptions.BlockedActorOrDomain()
    
        if not serializer_class:
            return data
    
        serializer = serializer_class(data=data, context={"fetch_actor": actor})
    
        serializer.is_valid(raise_exception=True)
        return serializer.save()