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/
|
.ruff_cache/
|
||||||
.coverage
|
.coverage
|
||||||
htmlcov/
|
htmlcov/
|
||||||
|
demo.run.py
|
||||||
|
|
||||||
# Build & distribution
|
# Build & distribution
|
||||||
dist/
|
dist/
|
||||||
|
|||||||
@@ -58,6 +58,9 @@ class FragmentClient:
|
|||||||
if word_count not in (12, 18, 24):
|
if word_count not in (12, 18, 24):
|
||||||
raise ConfigurationError(ConfigurationError.INVALID_MNEMONIC.format(count=word_count))
|
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):
|
if isinstance(cookies, str):
|
||||||
try:
|
try:
|
||||||
cookies = json.loads(cookies)
|
cookies = json.loads(cookies)
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ class ConfigurationError(ClientError):
|
|||||||
MISSING_VARS = "Missing required parameter(s): {keys}."
|
MISSING_VARS = "Missing required parameter(s): {keys}."
|
||||||
UNSUPPORTED_VERSION = "Unsupported wallet_version '{version}'. Must be one of: {supported}."
|
UNSUPPORTED_VERSION = "Unsupported wallet_version '{version}'. Must be one of: {supported}."
|
||||||
INVALID_MNEMONIC = "Invalid mnemonic: got {count} words, expected 12, 18, or 24."
|
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_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_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."
|
INVALID_TON_AMOUNT = "Amount must be an integer between 1 and 1 000 000 000 TON."
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
|
import asyncio
|
||||||
import base64
|
import base64
|
||||||
from typing import TYPE_CHECKING, Any
|
from typing import TYPE_CHECKING, Any
|
||||||
|
|
||||||
from tonutils.clients import TonapiClient
|
from tonutils.clients import TonapiClient
|
||||||
|
from tonutils.exceptions import ProviderResponseError
|
||||||
from tonutils.types import NetworkGlobalID
|
from tonutils.types import NetworkGlobalID
|
||||||
|
|
||||||
from pyfragment.types import MIN_TON_BALANCE, WALLET_CLASSES, TransactionError, WalletError
|
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:
|
try:
|
||||||
payload = clean_decode(message["payload"])
|
payload = clean_decode(message["payload"])
|
||||||
|
|
||||||
|
for attempt in range(2):
|
||||||
|
try:
|
||||||
result = await wallet.transfer(
|
result = await wallet.transfer(
|
||||||
destination=message["address"],
|
destination=message["address"],
|
||||||
amount=int(message["amount"]), # nanotons, not TON
|
amount=int(message["amount"]), # nanotons, not TON
|
||||||
body=payload,
|
body=payload,
|
||||||
)
|
)
|
||||||
return result.normalized_hash
|
return result.normalized_hash
|
||||||
|
except ProviderResponseError as exc:
|
||||||
|
if exc.code == 429 and attempt == 0:
|
||||||
|
await asyncio.sleep(1)
|
||||||
|
continue
|
||||||
|
raise
|
||||||
except (WalletError, TransactionError):
|
except (WalletError, TransactionError):
|
||||||
raise
|
raise
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
|
|||||||
+3
-3
@@ -27,13 +27,13 @@ classifiers = [
|
|||||||
]
|
]
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"httpx==0.28.1",
|
"httpx==0.28.1",
|
||||||
"tonutils[pytoniq]==2.0.0",
|
"tonutils[pytoniq]==2.0.4",
|
||||||
]
|
]
|
||||||
|
|
||||||
[project.optional-dependencies]
|
[project.optional-dependencies]
|
||||||
dev = [
|
dev = [
|
||||||
"pytest>=9.0",
|
"pytest==9.0.2",
|
||||||
"pytest-asyncio>=1.0",
|
"pytest-asyncio==1.3.0",
|
||||||
"ruff",
|
"ruff",
|
||||||
"black",
|
"black",
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ from pyfragment import FragmentClient
|
|||||||
from pyfragment.types import ConfigurationError, CookieError
|
from pyfragment.types import ConfigurationError, CookieError
|
||||||
|
|
||||||
VALID_SEED = "abandon " * 23 + "about"
|
VALID_SEED = "abandon " * 23 + "about"
|
||||||
VALID_API_KEY = "test_api_key"
|
VALID_API_KEY = "A" * 68
|
||||||
VALID_COOKIES = {
|
VALID_COOKIES = {
|
||||||
"stel_ssid": "x",
|
"stel_ssid": "x",
|
||||||
"stel_dt": "x",
|
"stel_dt": "x",
|
||||||
@@ -92,3 +92,8 @@ def test_valid_mnemonic_lengths() -> None:
|
|||||||
seed = " ".join(["abandon"] * (length - 1) + ["about"])
|
seed = " ".join(["abandon"] * (length - 1) + ["about"])
|
||||||
client = FragmentClient(seed=seed, api_key=VALID_API_KEY, cookies=VALID_COOKIES)
|
client = FragmentClient(seed=seed, api_key=VALID_API_KEY, cookies=VALID_COOKIES)
|
||||||
assert len(client.seed.split()) == length
|
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