mirror of
https://github.com/vibe-existing/pyfragment.git
synced 2026-07-25 06:54:31 +00:00
feat: add API key validation and corresponding error handling; update tests for validation
This commit is contained in:
@@ -31,6 +31,7 @@ Thumbs.db
|
||||
.ruff_cache/
|
||||
.coverage
|
||||
htmlcov/
|
||||
demo.run.py
|
||||
|
||||
# Build & distribution
|
||||
dist/
|
||||
|
||||
@@ -58,6 +58,9 @@ class FragmentClient:
|
||||
if word_count not in (12, 18, 24):
|
||||
raise ConfigurationError(ConfigurationError.INVALID_MNEMONIC.format(count=word_count))
|
||||
|
||||
if len(api_key.strip()) < 68:
|
||||
raise ConfigurationError(ConfigurationError.INVALID_API_KEY.format(length=len(api_key.strip())))
|
||||
|
||||
if isinstance(cookies, str):
|
||||
try:
|
||||
cookies = json.loads(cookies)
|
||||
|
||||
@@ -12,6 +12,7 @@ class ConfigurationError(ClientError):
|
||||
MISSING_VARS = "Missing required parameter(s): {keys}."
|
||||
UNSUPPORTED_VERSION = "Unsupported wallet_version '{version}'. Must be one of: {supported}."
|
||||
INVALID_MNEMONIC = "Invalid mnemonic: got {count} words, expected 12, 18, or 24."
|
||||
INVALID_API_KEY = "Invalid Tonapi key: got {length} characters, expected at least 68. Get one at https://tonconsole.com."
|
||||
INVALID_MONTHS = "Invalid duration. Choose 3, 6, or 12 months."
|
||||
INVALID_STARS_AMOUNT = "Amount must be an integer between 50 and 1 000 000 stars."
|
||||
INVALID_TON_AMOUNT = "Amount must be an integer between 1 and 1 000 000 000 TON."
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import asyncio
|
||||
import base64
|
||||
from typing import TYPE_CHECKING, Any
|
||||
|
||||
from tonutils.clients import TonapiClient
|
||||
from tonutils.exceptions import ProviderResponseError
|
||||
from tonutils.types import NetworkGlobalID
|
||||
|
||||
from pyfragment.types import MIN_TON_BALANCE, WALLET_CLASSES, TransactionError, WalletError
|
||||
@@ -57,12 +59,19 @@ async def process_transaction(client: "FragmentClient", transaction_data: dict)
|
||||
try:
|
||||
payload = clean_decode(message["payload"])
|
||||
|
||||
result = await wallet.transfer(
|
||||
destination=message["address"],
|
||||
amount=int(message["amount"]), # nanotons, not TON
|
||||
body=payload,
|
||||
)
|
||||
return result.normalized_hash
|
||||
for attempt in range(2):
|
||||
try:
|
||||
result = await wallet.transfer(
|
||||
destination=message["address"],
|
||||
amount=int(message["amount"]), # nanotons, not TON
|
||||
body=payload,
|
||||
)
|
||||
return result.normalized_hash
|
||||
except ProviderResponseError as exc:
|
||||
if exc.code == 429 and attempt == 0:
|
||||
await asyncio.sleep(1)
|
||||
continue
|
||||
raise
|
||||
except (WalletError, TransactionError):
|
||||
raise
|
||||
except Exception as exc:
|
||||
|
||||
+3
-3
@@ -27,13 +27,13 @@ classifiers = [
|
||||
]
|
||||
dependencies = [
|
||||
"httpx==0.28.1",
|
||||
"tonutils[pytoniq]==2.0.0",
|
||||
"tonutils[pytoniq]==2.0.4",
|
||||
]
|
||||
|
||||
[project.optional-dependencies]
|
||||
dev = [
|
||||
"pytest>=9.0",
|
||||
"pytest-asyncio>=1.0",
|
||||
"pytest==9.0.2",
|
||||
"pytest-asyncio==1.3.0",
|
||||
"ruff",
|
||||
"black",
|
||||
]
|
||||
|
||||
@@ -8,7 +8,7 @@ from pyfragment import FragmentClient
|
||||
from pyfragment.types import ConfigurationError, CookieError
|
||||
|
||||
VALID_SEED = "abandon " * 23 + "about"
|
||||
VALID_API_KEY = "test_api_key"
|
||||
VALID_API_KEY = "A" * 68
|
||||
VALID_COOKIES = {
|
||||
"stel_ssid": "x",
|
||||
"stel_dt": "x",
|
||||
@@ -92,3 +92,8 @@ def test_valid_mnemonic_lengths() -> None:
|
||||
seed = " ".join(["abandon"] * (length - 1) + ["about"])
|
||||
client = FragmentClient(seed=seed, api_key=VALID_API_KEY, cookies=VALID_COOKIES)
|
||||
assert len(client.seed.split()) == length
|
||||
|
||||
|
||||
def test_short_api_key_raises() -> None:
|
||||
with pytest.raises(ConfigurationError):
|
||||
FragmentClient(seed=VALID_SEED, api_key="A" * 42, cookies=VALID_COOKIES)
|
||||
|
||||
Reference in New Issue
Block a user