xync-client 0.0.141__py3-none-any.whl → 0.0.156.dev18__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. xync_client/Abc/AdLoader.py +5 -0
  2. xync_client/Abc/Agent.py +354 -8
  3. xync_client/Abc/Ex.py +432 -25
  4. xync_client/Abc/HasAbotUid.py +10 -0
  5. xync_client/Abc/InAgent.py +0 -11
  6. xync_client/Abc/PmAgent.py +34 -26
  7. xync_client/Abc/xtype.py +57 -3
  8. xync_client/Bybit/InAgent.py +233 -409
  9. xync_client/Bybit/agent.py +844 -777
  10. xync_client/Bybit/etype/__init__.py +0 -0
  11. xync_client/Bybit/etype/ad.py +54 -86
  12. xync_client/Bybit/etype/cred.py +29 -9
  13. xync_client/Bybit/etype/order.py +75 -103
  14. xync_client/Bybit/ex.py +35 -48
  15. xync_client/Gmail/__init__.py +119 -98
  16. xync_client/Htx/agent.py +213 -40
  17. xync_client/Htx/etype/ad.py +40 -16
  18. xync_client/Htx/etype/order.py +194 -0
  19. xync_client/Htx/ex.py +17 -19
  20. xync_client/Mexc/agent.py +268 -0
  21. xync_client/Mexc/api.py +1255 -0
  22. xync_client/Mexc/etype/ad.py +52 -1
  23. xync_client/Mexc/etype/order.py +354 -0
  24. xync_client/Mexc/ex.py +34 -22
  25. xync_client/Okx/1.py +14 -0
  26. xync_client/Okx/agent.py +39 -0
  27. xync_client/Okx/ex.py +8 -8
  28. xync_client/Pms/Payeer/agent.py +396 -0
  29. xync_client/Pms/Payeer/login.py +1 -59
  30. xync_client/Pms/Payeer/trade.py +58 -0
  31. xync_client/Pms/Volet/__init__.py +82 -63
  32. xync_client/Pms/Volet/api.py +5 -4
  33. xync_client/loader.py +2 -0
  34. xync_client/pm_unifier.py +1 -1
  35. {xync_client-0.0.141.dist-info → xync_client-0.0.156.dev18.dist-info}/METADATA +5 -1
  36. {xync_client-0.0.141.dist-info → xync_client-0.0.156.dev18.dist-info}/RECORD +38 -29
  37. xync_client/Pms/Payeer/__init__.py +0 -253
  38. xync_client/Pms/Payeer/api.py +0 -25
  39. {xync_client-0.0.141.dist-info → xync_client-0.0.156.dev18.dist-info}/WHEEL +0 -0
  40. {xync_client-0.0.141.dist-info → xync_client-0.0.156.dev18.dist-info}/top_level.txt +0 -0
@@ -1,253 +0,0 @@
1
- import logging
2
- from asyncio import run
3
- from base64 import b64encode
4
- from datetime import datetime
5
- from decimal import Decimal
6
- from enum import StrEnum
7
- from hashlib import sha256
8
- from json import dumps
9
- from math import ceil
10
- from os import urandom
11
- from time import sleep
12
- from urllib.parse import urlencode
13
-
14
- from asyncpg.pgproto.pgproto import timedelta
15
- from cryptography.hazmat.primitives import padding
16
- from cryptography.hazmat.primitives.ciphers import Cipher
17
- from cryptography.hazmat.primitives.ciphers.algorithms import AES
18
- from cryptography.hazmat.primitives.ciphers.modes import CBC
19
- from payeer_api import PayeerAPI
20
- from playwright.async_api import async_playwright, Playwright, Error
21
- from playwright._impl._errors import TimeoutError
22
- from xync_schema.models import TopUp, TopUpAble, PmAgent
23
-
24
- from xync_client.loader import TORM
25
-
26
- from xync_client.Abc.PmAgent import PmAgentClient
27
- from xync_client.Pms.Payeer.login import login
28
-
29
-
30
- def encrypt_data(data: dict, md5digest: bytes):
31
- # Convert data to JSON string (equivalent to json_encode)
32
- bdata = dumps(data).encode()
33
-
34
- # Generate random IV (16 bytes for AES)
35
- iv = urandom(16)
36
-
37
- # Pad or truncate key to 32 bytes
38
- if len(md5digest) < 32:
39
- md5digest = md5digest.ljust(32, b"\0") # Pad with null bytes
40
- elif len(md5digest) > 32:
41
- md5digest = md5digest[:32] # Truncate to 32 bytes
42
-
43
- # Apply PKCS7 padding
44
- padder = padding.PKCS7(128).padder() # 128 bits = 16 bytes block size
45
- padded_data = padder.update(bdata)
46
- padded_data += padder.finalize()
47
-
48
- # Create cipher
49
- cipher = Cipher(AES(md5digest), CBC(iv))
50
- encryptor = cipher.encryptor()
51
-
52
- # Encrypt
53
- ciphertext = encryptor.update(padded_data) + encryptor.finalize()
54
-
55
- return iv + ciphertext
56
-
57
-
58
- class Client(PmAgentClient):
59
- class Pages(StrEnum):
60
- _base = "https://payeer.com/en/"
61
- LOGIN = _base + "auth/"
62
- SEND = _base + "account/send/"
63
-
64
- norm: str = "payeer"
65
- pages: type(StrEnum) = Pages
66
- api: PayeerAPI
67
-
68
- def __init__(self, agent: PmAgent):
69
- super().__init__(agent)
70
- if api_id := self.agent.auth.get("api_id"):
71
- self.api = PayeerAPI(self.agent.auth["email"], api_id, self.agent.auth["api_sec"])
72
-
73
- async def _login(self):
74
- await login(self.agent)
75
- for cookie in self.agent.state["cookies"]:
76
- await self.page.context.add_cookies([cookie])
77
- await self.page.goto(self.pages.SEND)
78
-
79
- @staticmethod
80
- def form_redirect(topup: TopUp) -> tuple[str, dict | None]:
81
- m_shop = str(topup.topupable.auth["id"])
82
- m_orderid = str(topup.id)
83
- m_amount = "{0:.2f}".format(topup.amount * 0.01)
84
- m_curr = topup.cur.ticker
85
- m_desc = b64encode(b"XyncPay top up").decode()
86
- m_key = topup.topupable.auth["sec"]
87
- data = [m_shop, m_orderid, m_amount, m_curr, m_desc]
88
-
89
- # # additional
90
- # m_params = {
91
- # 'success_url': 'https://xync.net/topup?success=1',
92
- # 'fail_url': 'https://xync.net/topup?success=0',
93
- # 'status_url': 'https://xync.net/topup',
94
- # 'reference': {'var1': '1'},
95
- # }
96
- #
97
- # key = md5(m_orderid.to_bytes()).digest()
98
- #
99
- # base64url_encode(encrypt_data(params, key))
100
- #
101
- # data.append(m_params)
102
- # # additional
103
-
104
- data.append(m_key)
105
-
106
- sign = sha256(":".join(data).encode()).hexdigest().upper()
107
-
108
- params = {
109
- "m_shop": m_shop,
110
- "m_orderid": m_orderid,
111
- "m_amount": m_amount,
112
- "m_curr": m_curr,
113
- "m_desc": m_desc,
114
- "m_sign": sign,
115
- # 'm_params': m_params,
116
- # 'm_cipher_method': 'AES-256-CBC-IV',
117
- "form[ps]": "2609",
118
- "form[curr[2609]]": m_curr,
119
- }
120
- url = "https://payeer.com/merchant/?" + urlencode(params)
121
- return url, None
122
-
123
- def get_topup(self, tid: str) -> dict:
124
- hi = self.api.get_history_info(tid)
125
- ti = self.api.shop_order_info(hi["params"]["SHOP_ID"], hi["params"]["ORDER_ID"])["info"]
126
- return ti["status"] == "execute" and {
127
- "pmid": ti["id"],
128
- "from_acc": hi["params"]["ACCOUNT_NUMBER"],
129
- "oid": hi["params"]["ORDER_ID"],
130
- "amount": int(float(ti["sumOut"]) * 100),
131
- "ts": datetime.strptime(ti["dateCreate"], "%d.%m.%Y %H:%M:%S") - timedelta(hours=3),
132
- }
133
-
134
- async def send(self, dest: str, amount: int, cur: str) -> tuple[int, bytes, int] | int:
135
- self.last_active = datetime.now()
136
- page = self.page
137
- if not page.url.startswith(self.pages.SEND):
138
- try:
139
- await page.goto(self.pages.SEND)
140
- except (TimeoutError, Error):
141
- await login(self.agent)
142
- for cookie in self.agent.state["cookies"]:
143
- await page.context.add_cookies([cookie])
144
- sleep(0.5)
145
- await page.goto("https://payeer.com/en/account/send/")
146
- has_amount = float(self.api.get_balance()[cur]["DOSTUPNO"])
147
- if float(amount) <= has_amount:
148
- sleep(0.1)
149
- await page.locator('input[name="param_ACCOUNT_NUMBER"]').fill(dest)
150
- await page.locator("select[name=curr_receive]").select_option(value=cur)
151
- sleep(0.8)
152
- await page.locator('input[name="sum_receive"]').fill(str(amount))
153
- sleep(0.1)
154
- # await page.locator("div.n-form--title").first.click()
155
- # sleep(0.1)
156
- await page.click(".btn.n-form--btn.n-form--btn-mod")
157
- sleep(0.5)
158
- await page.click(".btn.n-form--btn.n-form--btn-mod")
159
- sleep(1.1)
160
- if await page.locator(".input4").count():
161
- await page.locator(".input4").fill(self.agent.auth.get("master_key"))
162
- await page.click(".ok.button_green2")
163
- sleep(1)
164
- try:
165
- await page.locator(".note_txt").wait_for(state="visible", timeout=6000)
166
- except TimeoutError as _:
167
- logging.error("Repeat!")
168
- sleep(0.5)
169
- return await self.send(dest, amount, cur)
170
- if await page.locator('.note_txt:has-text("successfully completed")').count():
171
- transaction = await page.locator(".note_txt").all_text_contents()
172
- trans_num = int(transaction[0].replace("Transaction #", "").split()[0])
173
- await page.goto("https://payeer.com/ru/account/history/")
174
- await page.click(f".history-id-{trans_num} a.link")
175
- sleep(1)
176
- receipt = await page.query_selector(".ui-dialog.ui-corner-all")
177
- return trans_num, await receipt.screenshot(path=f"tmp/{trans_num}.png"), int(has_amount - amount)
178
- else:
179
- await self.bot.send("Payeer хз", self.uid, photo=await self.page.screenshot())
180
- return -1
181
- else:
182
- await self.bot.send(
183
- f"Payeer no have {amount}, only {has_amount}{cur} to {dest}",
184
- self.uid,
185
- photo=await self.page.screenshot(),
186
- )
187
- return has_amount
188
-
189
- def check_in(
190
- self, amount: Decimal | int | float, cur: str, tme: datetime = None, tid: str | int = None
191
- ) -> tuple[Decimal | None, int | None]:
192
- history = self.api.history(type="incoming", append=tid, count=3)
193
- if tid:
194
- return (t := history.get(tid)) and Decimal(t["creditedAmount"])
195
- t = [
196
- h
197
- for h in history.values()
198
- if (
199
- amount <= Decimal(h["creditedAmount"]) <= ceil(amount)
200
- and h["creditedCurrency"] == cur
201
- and datetime.fromisoformat(h["date"]) > tme - timedelta(minutes=1)
202
- )
203
- ]
204
- if not (t := t and t[0]):
205
- return None, None
206
- return (
207
- amount <= (am := Decimal(t["creditedAmount"])) <= ceil(amount) and t["creditedCurrency"] == cur
208
- ) and am, t["id"]
209
-
210
- async def proof(self) -> bytes: ...
211
-
212
-
213
- async def main(uid: int):
214
- from x_model import init_db
215
-
216
- _ = await init_db(TORM, True)
217
- agent = await PmAgent.get_or_none(pm__norm="payeer", user__username_id=uid).prefetch_related(
218
- "user__username__session", "pm"
219
- )
220
- if not agent:
221
- raise Exception(f"No active user #{uid} with agent for volet!")
222
- pyr = agent.client()
223
- playwright: Playwright = await async_playwright().start()
224
- try:
225
- dest, amount, cur = "P79619335", 4, "RUB"
226
- ta = await TopUpAble.get(pm__norm="payeer")
227
- topup = await TopUp.create(amount=1001, cur_id=1, topupable=ta, user_id=1)
228
- await topup.fetch_related("cur")
229
- _url, _data = pyr.form_redirect(topup)
230
-
231
- await pyr.start(playwright, False)
232
-
233
- _res = await pyr.send(dest, amount, cur)
234
- _res = await pyr.send(dest, 3, cur)
235
-
236
- res = pyr.check_in(3, cur, datetime.now())
237
-
238
- if len(res) > 1 and isinstance(res[1], bytes):
239
- await pyr.bot.send(f"Transaction #{res[0]}", uid, photo=res[1])
240
- elif res[0] > 0:
241
- await pyr.bot.send(f"Sreen of transaction #{res[0]} failed", uid, photo=await pyr.page.screenshot())
242
- else:
243
- await pyr.bot.send(f"Sending {amount} {cur} to {dest} FAILED", uid, photo=await pyr.page.screenshot())
244
-
245
- except TimeoutError as te:
246
- await pyr.bot.send(repr(te), uid, photo=await pyr.page.screenshot())
247
- raise te
248
- # finally:
249
- # await pyr.stop()
250
-
251
-
252
- if __name__ == "__main__":
253
- run(main(193017646))
@@ -1,25 +0,0 @@
1
- from asyncio import run
2
- from playwright.async_api import Playwright, async_playwright
3
-
4
- from xync_client.loader import TORM
5
- from xync_client.Pms.Payeer import Client
6
-
7
-
8
- async def main():
9
- from x_model import init_db
10
-
11
- _ = await init_db(TORM, True)
12
- done = set()
13
- pyr = Client(193017646)
14
- pw: Playwright = await async_playwright().start()
15
- await pyr.start(pw, False)
16
- if r := pyr.check_in(3000, "RUB"):
17
- am, tid = r
18
- if tid not in done:
19
- done.add(tid)
20
-
21
- ...
22
-
23
-
24
- if __name__ == "__main__":
25
- run(main())