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

Add ban appeal notice to ban messages #990

Merged
merged 3 commits into from
Jan 1, 2024
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
4 changes: 3 additions & 1 deletion server/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,9 @@ def __init__(self, ban_expiry, ban_reason, *args, **kwargs):
def message(self):
return (
f"You are banned from FAF {self._ban_duration_text()}. <br>"
f"Reason: <br>{self.ban_reason}"
f"Reason: <br>{self.ban_reason}<br><br>"
"<i>If you would like to appeal this ban, please send an email to: "
"[email protected]</i>"
)

def _ban_duration_text(self):
Expand Down
25 changes: 23 additions & 2 deletions server/lobbyconnection.py
Original file line number Diff line number Diff line change
Expand Up @@ -516,16 +516,37 @@ async def command_auth(self, message):

async with self._db.acquire() as conn:
result = await conn.execute(
select(t_login.c.login)
select(
t_login.c.login,
lobby_ban.c.reason,
lobby_ban.c.expires_at
)
.select_from(t_login.outerjoin(lobby_ban))
.where(t_login.c.id == player_id)
.order_by(lobby_ban.c.expires_at.desc())
)
row = result.fetchone()

if not row:
self._logger.warning("User id not found in database possible fraudulent token: %s", player_id)
self._logger.warning(
"User id %s not found in database! Possible fraudulent "
"token: %s",
player_id,
token
)
raise AuthenticationError("Cannot find user id", auth_method)

username = row.login
ban_reason = row.reason
ban_expiry = row.expires_at

now = datetime.utcnow()
if ban_reason is not None and now < ban_expiry:
self._logger.debug(
"Rejected login from banned user: %s, %s, %s",
player_id, username, self.session
)
raise BanError(ban_expiry, ban_reason)

# DEPRECATED: IRC passwords are handled outside of the lobby server.
# This message remains here for backwards compatibility, but the data
Expand Down
65 changes: 54 additions & 11 deletions tests/integration_tests/test_login.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
)


async def test_server_invalid_login(lobby_server):
async def test_server_login_invalid(lobby_server):
proto = await connect_client(lobby_server)
# Try a user that doesn't exist
await perform_login(proto, ("Cat", "epic"))
Expand Down Expand Up @@ -39,7 +39,46 @@ async def test_server_ban(lobby_server, user):
assert msg == {
"command": "notice",
"style": "error",
"text": "You are banned from FAF forever. <br>Reason: <br>Test permanent ban"
"text": (
"You are banned from FAF forever. <br>Reason: <br>Test permanent ban"
"<br><br><i>If you would like to appeal this ban, please send an "
"email to: [email protected]</i>"
)
}


@pytest.mark.parametrize("user", [
("Dostya", 2),
("ban_long_time", 203)
])
async def test_server_ban_token(lobby_server, user, jwk_priv_key, jwk_kid):
user_name, user_id = user
proto = await connect_client(lobby_server)
await proto.send_message({
"command": "auth",
"version": "1.0.0-dev",
"user_agent": "faf-client",
"token": jwt.encode({
"sub": user_id,
"user_name": user_name,
"scp": ["lobby"],
"exp": int(time() + 1000),
"authorities": [],
"non_locked": True,
"jti": "",
"client_id": ""
}, jwk_priv_key, algorithm="RS256", headers={"kid": jwk_kid}),
"unique_id": "some_id"
})
msg = await proto.read_message()
assert msg == {
"command": "notice",
"style": "error",
"text": (
"You are banned from FAF forever. <br>Reason: <br>Test permanent ban"
"<br><br><i>If you would like to appeal this ban, please send an "
"email to: [email protected]</i>"
)
}


Expand All @@ -53,7 +92,7 @@ async def test_server_ban_revoked_or_expired(lobby_server, user):
assert msg["login"] == user


async def test_server_valid_login(lobby_server):
async def test_server_login_valid(lobby_server):
proto = await connect_client(lobby_server)
await perform_login(proto, ("Rhiza", "puff_the_magic_dragon"))
msg = await proto.read_message()
Expand Down Expand Up @@ -98,7 +137,7 @@ async def test_server_valid_login(lobby_server):
}


async def test_server_valid_login_admin(lobby_server):
async def test_server_login_valid_admin(lobby_server):
proto = await connect_client(lobby_server)
await perform_login(proto, ("test", "test_password"))
msg = await proto.read_message()
Expand Down Expand Up @@ -143,7 +182,7 @@ async def test_server_valid_login_admin(lobby_server):
}


async def test_server_valid_login_moderator(lobby_server):
async def test_server_login_valid_moderator(lobby_server):
proto = await connect_client(lobby_server)
await perform_login(proto, ("moderator", "moderator"))
msg = await proto.read_message()
Expand Down Expand Up @@ -202,7 +241,7 @@ async def test_policy_server_contacted(lobby_server, policy_server, player_servi
policy_server.verify.assert_called_once()


async def test_server_double_login(lobby_server):
async def test_server_login_double(lobby_server):
proto = await connect_client(lobby_server)
await perform_login(proto, ("test", "test_password"))
msg = await proto.read_message()
Expand All @@ -222,7 +261,7 @@ async def test_server_double_login(lobby_server):
}


async def test_server_valid_login_with_token(lobby_server, jwk_priv_key, jwk_kid):
async def test_server_login_token_valid(lobby_server, jwk_priv_key, jwk_kid):
proto = await connect_client(lobby_server)
await proto.send_message({
"command": "auth",
Expand Down Expand Up @@ -285,7 +324,7 @@ async def test_server_valid_login_with_token(lobby_server, jwk_priv_key, jwk_kid
}


async def test_server_login_bad_id_in_token(lobby_server, jwk_priv_key, jwk_kid):
async def test_server_login_token_bad_id(lobby_server, jwk_priv_key, jwk_kid):
proto = await connect_client(lobby_server)
await proto.send_message({
"command": "auth",
Expand All @@ -311,7 +350,7 @@ async def test_server_login_bad_id_in_token(lobby_server, jwk_priv_key, jwk_kid)
}


async def test_server_login_expired_token(lobby_server, jwk_priv_key, jwk_kid):
async def test_server_login_token_expired(lobby_server, jwk_priv_key, jwk_kid):
proto = await connect_client(lobby_server)
await proto.send_message({
"command": "auth",
Expand All @@ -333,7 +372,7 @@ async def test_server_login_expired_token(lobby_server, jwk_priv_key, jwk_kid):
}


async def test_server_login_malformed_token(lobby_server, jwk_priv_key, jwk_kid):
async def test_server_login_token_malformed(lobby_server, jwk_priv_key, jwk_kid):
"""This scenario could only happen if the hydra signed a token that
was missing critical data"""
proto = await connect_client(lobby_server)
Expand All @@ -355,7 +394,11 @@ async def test_server_login_malformed_token(lobby_server, jwk_priv_key, jwk_kid)
}


async def test_server_login_lobby_scope_missing(lobby_server, jwk_priv_key, jwk_kid):
async def test_server_login_token_lobby_scope_missing(
lobby_server,
jwk_priv_key,
jwk_kid,
):
"""This scenario could only happen if the hydra signed a token that
was missing critical data"""
proto = await connect_client(lobby_server)
Expand Down
6 changes: 5 additions & 1 deletion tests/integration_tests/test_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -793,7 +793,11 @@ async def test_server_ban_prevents_hosting(lobby_server, database, command):
assert msg == {
"command": "notice",
"style": "error",
"text": "You are banned from FAF forever. <br>Reason: <br>Test live ban"
"text": (
"You are banned from FAF forever. <br>Reason: <br>Test live ban<br>"
"<br><i>If you would like to appeal this ban, please send an email "
"to: [email protected]</i>"
)
}


Expand Down
5 changes: 4 additions & 1 deletion tests/unit_tests/test_lobbyconnection.py
Original file line number Diff line number Diff line change
Expand Up @@ -1076,8 +1076,11 @@ async def test_abort_connection_if_banned(
lobbyconnection.player.id = 203
with pytest.raises(BanError) as banned_error:
await lobbyconnection.abort_connection_if_banned()
assert banned_error.value.message() == \
assert banned_error.value.message() == (
"You are banned from FAF forever. <br>Reason: <br>Test permanent ban"
"<br><br><i>If you would like to appeal this ban, please send an email "
"to: [email protected]</i>"
)

# test user who is banned for another 46 hours
lobbyconnection.player.id = 204
Expand Down