Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace old OAuth 2 hooks with new ones #1681

Merged
merged 2 commits into from
Dec 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions misago/hooks.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,6 @@

new_registrations_validators = []

oauth2_user_data_filters = []
oauth2_validators = []

post_search_filters = []
post_validators = []

Expand Down
2 changes: 2 additions & 0 deletions misago/oauth2/hooks/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
from .filter_user_data import filter_user_data_hook
from .validate_user_data import validate_user_data_hook
47 changes: 47 additions & 0 deletions misago/oauth2/hooks/filter_user_data.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
from typing import Optional, Protocol

from django.http import HttpRequest

from ...plugins.hooks import FilterHook
from ...users.models import User


class FilterUserDataHookAction(Protocol):
def __call__(
self,
request: HttpRequest,
user: Optional[User],
user_data: dict,
) -> dict:
pass


class FilterUserDataHookFilter(Protocol):
def __call__(
self,
action: FilterUserDataHookAction,
request: HttpRequest,
user: Optional[User],
user_data: dict,
) -> dict:
pass


class FilterUserDataHook(
FilterHook[FilterUserDataHookAction, FilterUserDataHookFilter]
):
__slots__ = FilterHook.__slots__

def __call__(
self,
action: FilterUserDataHookAction,
request: HttpRequest,
user: Optional[User],
user_data: dict,
*args,
**kwargs,
) -> dict:
return super().__call__(action, request, user, user_data, *args, **kwargs)


filter_user_data_hook = FilterUserDataHook()
52 changes: 52 additions & 0 deletions misago/oauth2/hooks/validate_user_data.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
from typing import Optional, Protocol

from django.http import HttpRequest

from ...plugins.hooks import FilterHook
from ...users.models import User


class ValidateUserDataHookAction(Protocol):
def __call__(
self,
request: HttpRequest,
user: Optional[User],
user_data: dict,
response_json: dict,
) -> dict:
pass


class ValidateUserDataHookFilter(Protocol):
def __call__(
self,
action: ValidateUserDataHookAction,
request: HttpRequest,
user: Optional[User],
user_data: dict,
response_json: dict,
) -> dict:
pass


class ValidateUserDataHook(
FilterHook[ValidateUserDataHookAction, ValidateUserDataHookFilter]
):
__slots__ = FilterHook.__slots__

def __call__(
self,
action: ValidateUserDataHookAction,
request: HttpRequest,
user: Optional[User],
user_data: dict,
response_json: dict,
*args,
**kwargs,
) -> dict:
return super().__call__(
action, request, user, user_data, response_json, *args, **kwargs
)


validate_user_data_hook = ValidateUserDataHook()
13 changes: 13 additions & 0 deletions misago/oauth2/tests/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
from unittest.mock import patch

import pytest


def noop_filter_user_data(request, user, user_data):
return user_data


@pytest.fixture
def disable_user_data_filters():
with patch("misago.oauth2.validation.filter_user_data", noop_filter_user_data):
yield
33 changes: 12 additions & 21 deletions misago/oauth2/tests/test_user_creation_from_data.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from unittest.mock import Mock, patch
from unittest.mock import Mock

import pytest
from django.contrib.auth import get_user_model
Expand Down Expand Up @@ -92,29 +92,20 @@ def test_user_is_created_with_admin_activation_from_valid_data(db, dynamic_setti
assert user.requires_activation == User.ACTIVATION_ADMIN


def user_noop_filter(*args):
pass


def test_user_name_conflict_during_creation_from_valid_data_is_handled(
user, dynamic_settings
user, dynamic_settings, disable_user_data_filters
):
with pytest.raises(OAuth2UserDataValidationError) as excinfo:
# Custom filters disable build in filters
with patch(
"misago.oauth2.validation.oauth2_user_data_filters",
[user_noop_filter],
):
get_user_from_data(
Mock(settings=dynamic_settings, user_ip="83.0.0.1"),
{
"id": "1234",
"name": user.username,
"email": "[email protected]",
"avatar": None,
},
{},
)
get_user_from_data(
Mock(settings=dynamic_settings, user_ip="83.0.0.1"),
{
"id": "1234",
"name": user.username,
"email": "[email protected]",
"avatar": None,
},
{},
)

assert excinfo.value.error_list == [
"Your username returned by the provider is not available for use on this site."
Expand Down
118 changes: 0 additions & 118 deletions misago/oauth2/tests/test_user_data_filter.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
from unittest.mock import patch

from ..validation import filter_user_data


Expand Down Expand Up @@ -204,78 +202,6 @@ def user_email_filter(request, user, user_data):
}


def test_new_user_data_is_filtered_using_custom_filters(db, request):
def user_is_none_filter(request, user, user_data):
assert user is None

with patch(
"misago.oauth2.validation.oauth2_user_data_filters",
[
user_request_filter,
user_is_none_filter,
user_id_filter,
user_name_filter,
user_email_filter,
],
):
filtered_data = filter_user_data(
request,
None,
{
"id": "1234",
"name": "New User",
"email": "[email protected]",
"avatar": None,
},
)

assert filtered_data == {
"id": "4321",
"name": "resU weN",
"email": "[email protected]",
"avatar": None,
}


def test_existing_user_data_is_filtered_using_custom_filters(user, request):
def user_is_set_filter(request, user_obj, user_data):
assert user_obj == user
return {
"id": str(user_obj.id),
"name": user_data["name"],
"email": user_data["email"],
"avatar": user_data["avatar"],
}

with patch(
"misago.oauth2.validation.oauth2_user_data_filters",
[
user_request_filter,
user_is_set_filter,
user_id_filter,
user_name_filter,
user_email_filter,
],
):
filtered_data = filter_user_data(
request,
user,
{
"id": "1234",
"name": "New User",
"email": "[email protected]",
"avatar": None,
},
)

assert filtered_data == {
"id": "".join(reversed(str(user.id))),
"name": "resU weN",
"email": "[email protected]",
"avatar": None,
}


def test_original_user_data_is_not_mutated_by_default_filters(user, request):
user_data = {
"id": "1234",
Expand All @@ -298,47 +224,3 @@ def test_original_user_data_is_not_mutated_by_default_filters(user, request):
"email": "[email protected]",
"avatar": None,
}


def test_original_user_data_is_not_mutated_by_custom_filters(user, request):
def user_is_set_filter(request, user_obj, user_data):
assert user_obj == user
return {
"id": str(user_obj.id),
"name": user_data["name"],
"email": user_data["email"],
"avatar": user_data["avatar"],
}

user_data = {
"id": "1234",
"name": "New User",
"email": "[email protected]",
"avatar": None,
}

with patch(
"misago.oauth2.validation.oauth2_user_data_filters",
[
user_request_filter,
user_is_set_filter,
user_id_filter,
user_name_filter,
user_email_filter,
],
):
filtered_data = filter_user_data(request, user, user_data)

assert filtered_data == {
"id": "".join(reversed(str(user.id))),
"name": "resU weN",
"email": "[email protected]",
"avatar": None,
}

assert user_data == {
"id": "1234",
"name": "New User",
"email": "[email protected]",
"avatar": None,
}
Loading