mirror of
https://github.com/bohd4nx/FragmentAPI.git
synced 2026-07-25 06:14:29 +00:00
228fbfcd1c
- Moved account-related functions and classes from `pyfragment.domains.tonapi.account` to `pyfragment.services.tonapi.account`. - Moved transaction-related functions and classes from `pyfragment.domains.tonapi.transaction` to `pyfragment.services.tonapi.transaction`. - Updated imports across the codebase to reflect the new structure. - Removed unused `tonapi` module files and cleaned up related code. - Introduced `ApiProvider` enum to manage API provider types. - Added validation functions for cookies and wallet versions in a new `validation.py` module.
133 lines
4.1 KiB
Python
133 lines
4.1 KiB
Python
"""Decode Fragment BOC payloads so comments become text and structured messages stay raw."""
|
|
|
|
import base64
|
|
import re
|
|
from unittest.mock import patch
|
|
|
|
import pytest
|
|
from ton_core import Cell
|
|
|
|
from pyfragment import ParseError
|
|
from pyfragment.services.tonapi.transaction import clean_decode
|
|
|
|
PAYLOAD_CASES = [
|
|
pytest.param(
|
|
"te6ccgEBAgEALwABTgAAAAAxMDAwMDAwIFRlbGVncmFtIFN0YXJzIAoKUmVmI1RQb01wegEABkM3ZQ",
|
|
True,
|
|
id="stars",
|
|
),
|
|
pytest.param(
|
|
"te6ccgEBAgEANAABTgAAAABUZWxlZ3JhbSBQcmVtaXVtIGZvciAxIHllYXIgCgpSZWYjcgEAEE9OQnM2cmNt",
|
|
True,
|
|
id="premium",
|
|
),
|
|
pytest.param(
|
|
"te6ccgEBAgEAMAABTgAAAABUZWxlZ3JhbSBhY2NvdW50IHRvcCB1cCAKClJlZiNrMXpDRQEACFkxd3g",
|
|
True,
|
|
id="topup",
|
|
),
|
|
pytest.param(
|
|
"te6ccgEBAgEAfgABqA-KfqVP885dhccidjC3GwgBCkiH8LM_zUu0afyGCTWJwX1mDjdlf2rMa9UoQlD4UHUAF1jLlcMomlo5RJTwl8jnDDdfdhc7EgQQWPqFQ9IjyLPCAwEASgAAAAA1MCBUZWxlZ3JhbSBTdGFycyAKClJlZiNtOUpoWndBcFE",
|
|
False,
|
|
id="real_stars_50",
|
|
),
|
|
pytest.param(
|
|
"te6ccgEBAgEANgABTgAAAABUZWxlZ3JhbSBQcmVtaXVtIGZvciAzIG1vbnRocyAKClJlZgEAFCMzcFdKdGJkYnU",
|
|
False,
|
|
id="real_premium_3m",
|
|
),
|
|
pytest.param(
|
|
"te6ccgEBAwEAhgABqg-KfqWibdDaYaJCPUWWgvAIAQpIh_CzP81LtGn8hgk1icF9Zg43ZX9qzGvVKEJQ-FB1ABdYy5XDKJpaOUSU8JfI5ww3X3YXOxIEEFj6hUPSI8izwgMBAU4AAAAAMTAwMDAwIFRlbGVncmFtIFN0YXJzIAoKUmVmIzBoZ0RmNEYCAAQ5VA",
|
|
False,
|
|
id="real_stars_100k",
|
|
),
|
|
]
|
|
|
|
|
|
# Decode valid payload tests
|
|
|
|
|
|
@pytest.mark.parametrize(("payload", "strict_ref"), PAYLOAD_CASES)
|
|
def test_decode_payload(payload: str, strict_ref: bool) -> None:
|
|
result = clean_decode(payload)
|
|
if isinstance(result, str):
|
|
assert "Telegram" in result
|
|
if strict_ref:
|
|
assert re.search(r"Ref#[A-Za-z0-9]+", result), f"no Ref# in {result!r}"
|
|
assert all(ord(c) < 128 for c in result), f"non-ASCII chars in {result!r}"
|
|
else:
|
|
assert isinstance(result, Cell)
|
|
|
|
|
|
# Edge case tests
|
|
|
|
|
|
def test_empty_payload_returns_empty_string() -> None:
|
|
assert clean_decode("") == ""
|
|
|
|
|
|
def test_invalid_payload_raises_parse_error() -> None:
|
|
with pytest.raises(ParseError):
|
|
clean_decode("!!!not-valid-base64!!!")
|
|
|
|
|
|
def test_decode_payload_accepts_base64url_alphabet() -> None:
|
|
class _FakeSlice:
|
|
def load_uint(self, _: int) -> int:
|
|
return 0
|
|
|
|
def load_snake_string(self) -> str:
|
|
return "Telegram Stars Ref#abc"
|
|
|
|
class _FakeCell:
|
|
def begin_parse(self) -> _FakeSlice:
|
|
return _FakeSlice()
|
|
|
|
raw = b"\xfb\xef\xff\x00"
|
|
payload = base64.urlsafe_b64encode(raw).decode().rstrip("=")
|
|
|
|
with patch("pyfragment.services.tonapi.transaction.Cell.one_from_boc", return_value=_FakeCell()) as mocked:
|
|
result = clean_decode(payload)
|
|
|
|
mocked.assert_called_once_with(raw)
|
|
assert result == "Telegram Stars Ref#abc"
|
|
|
|
|
|
def test_clean_decode_returns_text_comment_when_utf8() -> None:
|
|
class _FakeSlice:
|
|
def load_uint(self, _: int) -> int:
|
|
return 0
|
|
|
|
def load_snake_string(self) -> str:
|
|
return "Telegram Premium Ref#abc"
|
|
|
|
class _FakeCell:
|
|
def begin_parse(self) -> _FakeSlice:
|
|
return _FakeSlice()
|
|
|
|
payload = base64.urlsafe_b64encode(b"\x00\x01").decode().rstrip("=")
|
|
with patch("pyfragment.services.tonapi.transaction.Cell.one_from_boc", return_value=_FakeCell()):
|
|
parsed = clean_decode(payload)
|
|
|
|
assert parsed == "Telegram Premium Ref#abc"
|
|
|
|
|
|
def test_clean_decode_returns_cell_for_binary_payload() -> None:
|
|
class _FakeSlice:
|
|
def load_uint(self, _: int) -> int:
|
|
return 0
|
|
|
|
def load_snake_string(self) -> str:
|
|
raise UnicodeDecodeError("utf-8", b"\xff", 0, 1, "invalid start byte")
|
|
|
|
class _FakeCell:
|
|
def begin_parse(self) -> _FakeSlice:
|
|
return _FakeSlice()
|
|
|
|
payload = base64.urlsafe_b64encode(b"\x00\x01").decode().rstrip("=")
|
|
fake_cell: object = _FakeCell()
|
|
with patch("pyfragment.services.tonapi.transaction.Cell.one_from_boc", return_value=fake_cell):
|
|
parsed = clean_decode(payload)
|
|
|
|
assert parsed is fake_cell
|