mirror of
https://github.com/jkingsman/Remote-Terminal-for-MeshCore.git
synced 2026-08-07 09:13:04 +02:00
Don't use prefix matching if we can help it
This commit is contained in:
@@ -90,7 +90,7 @@ class TestCreateContact:
|
||||
|
||||
with (
|
||||
patch(
|
||||
"app.routers.contacts.ContactRepository.get_by_key_or_prefix",
|
||||
"app.routers.contacts.ContactRepository.get_by_key",
|
||||
new_callable=AsyncMock,
|
||||
return_value=None,
|
||||
),
|
||||
@@ -123,7 +123,7 @@ class TestCreateContact:
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
with patch(
|
||||
"app.routers.contacts.ContactRepository.get_by_key_or_prefix",
|
||||
"app.routers.contacts.ContactRepository.get_by_key",
|
||||
new_callable=AsyncMock,
|
||||
return_value=None,
|
||||
):
|
||||
@@ -160,7 +160,7 @@ class TestCreateContact:
|
||||
|
||||
with (
|
||||
patch(
|
||||
"app.routers.contacts.ContactRepository.get_by_key_or_prefix",
|
||||
"app.routers.contacts.ContactRepository.get_by_key",
|
||||
new_callable=AsyncMock,
|
||||
return_value=existing,
|
||||
),
|
||||
@@ -220,6 +220,30 @@ class TestGetContact:
|
||||
|
||||
assert response.status_code == 404
|
||||
|
||||
def test_get_ambiguous_prefix_returns_409(self):
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
from app.repository import AmbiguousPublicKeyPrefixError
|
||||
|
||||
with patch(
|
||||
"app.routers.contacts.ContactRepository.get_by_key_or_prefix",
|
||||
new_callable=AsyncMock,
|
||||
side_effect=AmbiguousPublicKeyPrefixError(
|
||||
"abcd12",
|
||||
[
|
||||
"abcd120000000000000000000000000000000000000000000000000000000000",
|
||||
"abcd12ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
],
|
||||
),
|
||||
):
|
||||
from app.main import app
|
||||
|
||||
client = TestClient(app)
|
||||
response = client.get("/api/contacts/abcd12")
|
||||
|
||||
assert response.status_code == 409
|
||||
assert "ambiguous" in response.json()["detail"].lower()
|
||||
|
||||
|
||||
class TestMarkRead:
|
||||
"""Test POST /api/contacts/{public_key}/mark-read."""
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
import pytest
|
||||
|
||||
from app.database import Database
|
||||
from app.repository import ContactRepository, MessageRepository
|
||||
from app.repository import AmbiguousPublicKeyPrefixError, ContactRepository, MessageRepository
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
@@ -117,3 +117,43 @@ async def test_duplicate_with_same_text_and_null_timestamp_rejected(test_db):
|
||||
received_at=received_at,
|
||||
)
|
||||
assert msg_id2 is None # duplicate rejected
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_get_by_key_prefix_returns_none_when_ambiguous(test_db):
|
||||
"""Ambiguous prefixes should not resolve to an arbitrary contact."""
|
||||
key1 = "abc1230000000000000000000000000000000000000000000000000000000000"
|
||||
key2 = "abc123ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
|
||||
|
||||
await ContactRepository.upsert({"public_key": key1, "name": "A"})
|
||||
await ContactRepository.upsert({"public_key": key2, "name": "B"})
|
||||
|
||||
contact = await ContactRepository.get_by_key_prefix("abc123")
|
||||
assert contact is None
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_get_by_key_or_prefix_raises_on_ambiguous_prefix(test_db):
|
||||
"""Prefix lookup should raise when multiple contacts match."""
|
||||
key1 = "abc1230000000000000000000000000000000000000000000000000000000000"
|
||||
key2 = "abc123ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
|
||||
|
||||
await ContactRepository.upsert({"public_key": key1, "name": "A"})
|
||||
await ContactRepository.upsert({"public_key": key2, "name": "B"})
|
||||
|
||||
with pytest.raises(AmbiguousPublicKeyPrefixError):
|
||||
await ContactRepository.get_by_key_or_prefix("abc123")
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_get_by_key_or_prefix_prefers_exact_full_key(test_db):
|
||||
"""Exact key lookup works even when the shorter prefix is ambiguous."""
|
||||
key1 = "abc1230000000000000000000000000000000000000000000000000000000000"
|
||||
key2 = "abc123ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
|
||||
|
||||
await ContactRepository.upsert({"public_key": key1, "name": "A"})
|
||||
await ContactRepository.upsert({"public_key": key2, "name": "B"})
|
||||
|
||||
contact = await ContactRepository.get_by_key_or_prefix(key2.upper())
|
||||
assert contact is not None
|
||||
assert contact.public_key == key2
|
||||
|
||||
@@ -4,6 +4,7 @@ import asyncio
|
||||
from unittest.mock import AsyncMock, MagicMock, patch
|
||||
|
||||
import pytest
|
||||
from fastapi import HTTPException
|
||||
from meshcore import EventType
|
||||
|
||||
from app.models import (
|
||||
@@ -13,6 +14,7 @@ from app.models import (
|
||||
SendChannelMessageRequest,
|
||||
SendDirectMessageRequest,
|
||||
)
|
||||
from app.repository import AmbiguousPublicKeyPrefixError
|
||||
from app.routers.messages import send_channel_message, send_direct_message
|
||||
|
||||
|
||||
@@ -123,6 +125,34 @@ class TestOutgoingDMBotTrigger:
|
||||
call_kwargs = mock_bot.call_args[1]
|
||||
assert call_kwargs["sender_name"] is None
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_send_dm_ambiguous_prefix_returns_409(self):
|
||||
"""Ambiguous destination prefix should fail instead of selecting a random contact."""
|
||||
mc = _make_mc()
|
||||
|
||||
with (
|
||||
patch("app.routers.messages.require_connected", return_value=mc),
|
||||
patch(
|
||||
"app.repository.ContactRepository.get_by_key_or_prefix",
|
||||
new=AsyncMock(
|
||||
side_effect=AmbiguousPublicKeyPrefixError(
|
||||
"abc123",
|
||||
[
|
||||
"abc1230000000000000000000000000000000000000000000000000000000000",
|
||||
"abc123ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
],
|
||||
)
|
||||
),
|
||||
),
|
||||
):
|
||||
with pytest.raises(HTTPException) as exc_info:
|
||||
await send_direct_message(
|
||||
SendDirectMessageRequest(destination="abc123", text="Hello")
|
||||
)
|
||||
|
||||
assert exc_info.value.status_code == 409
|
||||
assert "ambiguous" in exc_info.value.detail.lower()
|
||||
|
||||
|
||||
class TestOutgoingChannelBotTrigger:
|
||||
"""Test that sending a channel message triggers bots with is_outgoing=True."""
|
||||
|
||||
Reference in New Issue
Block a user