xync-client 0.0.114__py3-none-any.whl → 0.0.155__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 (39) hide show
  1. xync_client/Abc/AdLoader.py +299 -0
  2. xync_client/Abc/Agent.py +94 -10
  3. xync_client/Abc/Ex.py +27 -22
  4. xync_client/Abc/HasAbotUid.py +10 -0
  5. xync_client/Abc/InAgent.py +0 -11
  6. xync_client/Abc/PmAgent.py +42 -35
  7. xync_client/Abc/xtype.py +24 -2
  8. xync_client/Binance/ex.py +2 -2
  9. xync_client/BingX/ex.py +2 -2
  10. xync_client/BitGet/ex.py +2 -2
  11. xync_client/Bybit/InAgent.py +229 -114
  12. xync_client/Bybit/agent.py +584 -572
  13. xync_client/Bybit/etype/ad.py +11 -56
  14. xync_client/Bybit/etype/cred.py +29 -9
  15. xync_client/Bybit/etype/order.py +55 -62
  16. xync_client/Bybit/ex.py +17 -4
  17. xync_client/Gate/ex.py +2 -2
  18. xync_client/Gmail/__init__.py +119 -98
  19. xync_client/Htx/agent.py +162 -31
  20. xync_client/Htx/etype/ad.py +18 -11
  21. xync_client/Htx/ex.py +9 -11
  22. xync_client/KuCoin/ex.py +2 -2
  23. xync_client/Mexc/agent.py +85 -0
  24. xync_client/Mexc/api.py +636 -0
  25. xync_client/Mexc/etype/order.py +639 -0
  26. xync_client/Mexc/ex.py +12 -10
  27. xync_client/Okx/ex.py +2 -2
  28. xync_client/Pms/Payeer/__init__.py +147 -43
  29. xync_client/Pms/Payeer/login.py +29 -2
  30. xync_client/Pms/Volet/__init__.py +148 -94
  31. xync_client/Pms/Volet/api.py +17 -13
  32. xync_client/TgWallet/ex.py +2 -2
  33. xync_client/details.py +44 -0
  34. xync_client/loader.py +2 -1
  35. xync_client/pm_unifier.py +1 -1
  36. {xync_client-0.0.114.dist-info → xync_client-0.0.155.dist-info}/METADATA +6 -1
  37. {xync_client-0.0.114.dist-info → xync_client-0.0.155.dist-info}/RECORD +39 -33
  38. {xync_client-0.0.114.dist-info → xync_client-0.0.155.dist-info}/WHEEL +0 -0
  39. {xync_client-0.0.114.dist-info → xync_client-0.0.155.dist-info}/top_level.txt +0 -0
xync_client/Okx/ex.py CHANGED
@@ -1,7 +1,7 @@
1
1
  from asyncio import run
2
2
 
3
3
  from pyro_client.client.file import FileClient
4
- from pyro_client.loader import TOKEN
4
+ from pyro_client.loader import NET_TOKEN
5
5
  from x_model import init_db
6
6
 
7
7
  from xync_client.Abc.Exception import NoPairOnEx
@@ -102,7 +102,7 @@ class ExClient(BaseExClient):
102
102
  async def main():
103
103
  _ = await init_db(TORM)
104
104
  bg = await models.Ex.get(name="Okx")
105
- cl = ExClient(bg, FileClient(TOKEN))
105
+ cl = ExClient(bg, FileClient(NET_TOKEN))
106
106
  await cl.ads("USDT", "EUR", True)
107
107
  # curs = await cl.curs()
108
108
  # coins = await cl.coins()
@@ -1,22 +1,65 @@
1
1
  import logging
2
2
  from asyncio import run
3
+ from base64 import b64encode
3
4
  from datetime import datetime
4
5
  from decimal import Decimal
5
6
  from enum import StrEnum
7
+ from hashlib import sha256
8
+ from json import dumps
6
9
  from math import ceil
10
+ from os import urandom
7
11
  from time import sleep
12
+ from urllib.parse import urlencode
8
13
 
14
+ from PGram import Bot
9
15
  from asyncpg.pgproto.pgproto import timedelta
16
+ from cryptography.hazmat.primitives import padding
17
+ from cryptography.hazmat.primitives.ciphers import Cipher
18
+ from cryptography.hazmat.primitives.ciphers.algorithms import AES
19
+ from cryptography.hazmat.primitives.ciphers.modes import CBC
10
20
  from payeer_api import PayeerAPI
11
- from playwright.async_api import async_playwright, Playwright, Error
21
+ from playwright.async_api import async_playwright, Playwright, Error, Browser
22
+
23
+ # noinspection PyProtectedMember
12
24
  from playwright._impl._errors import TimeoutError
25
+ from tortoise.timezone import now
26
+ from xync_bot import XyncBot
27
+ from xync_schema.models import TopUp, TopUpAble, PmAgent, Transfer
13
28
 
14
- from xync_client.loader import TORM
29
+ from xync_client.loader import TORM, PAY_TOKEN
15
30
 
16
31
  from xync_client.Abc.PmAgent import PmAgentClient
17
32
  from xync_client.Pms.Payeer.login import login
18
33
 
19
34
 
35
+ def encrypt_data(data: dict, md5digest: bytes):
36
+ # Convert data to JSON string (equivalent to json_encode)
37
+ bdata = dumps(data).encode()
38
+
39
+ # Generate random IV (16 bytes for AES)
40
+ iv = urandom(16)
41
+
42
+ # Pad or truncate key to 32 bytes
43
+ if len(md5digest) < 32:
44
+ md5digest = md5digest.ljust(32, b"\0") # Pad with null bytes
45
+ elif len(md5digest) > 32:
46
+ md5digest = md5digest[:32] # Truncate to 32 bytes
47
+
48
+ # Apply PKCS7 padding
49
+ padder = padding.PKCS7(128).padder() # 128 bits = 16 bytes block size
50
+ padded_data = padder.update(bdata)
51
+ padded_data += padder.finalize()
52
+
53
+ # Create cipher
54
+ cipher = Cipher(AES(md5digest), CBC(iv))
55
+ encryptor = cipher.encryptor()
56
+
57
+ # Encrypt
58
+ ciphertext = encryptor.update(padded_data) + encryptor.finalize()
59
+
60
+ return iv + ciphertext
61
+
62
+
20
63
  class Client(PmAgentClient):
21
64
  class Pages(StrEnum):
22
65
  _base = "https://payeer.com/en/"
@@ -26,40 +69,94 @@ class Client(PmAgentClient):
26
69
  norm: str = "payeer"
27
70
  pages: type(StrEnum) = Pages
28
71
  api: PayeerAPI
72
+ with_userbot: bool = False
29
73
 
30
- async def start(self, pw: Playwright, headed: bool = False) -> "PmAgentClient":
31
- await super().start(pw, headed)
74
+ def __init__(self, agent: PmAgent, browser: Browser, abot: XyncBot):
75
+ super().__init__(agent, browser, abot)
32
76
  if api_id := self.agent.auth.get("api_id"):
33
77
  self.api = PayeerAPI(self.agent.auth["email"], api_id, self.agent.auth["api_sec"])
34
- return self
35
78
 
36
79
  async def _login(self):
37
80
  await login(self.agent)
38
81
  for cookie in self.agent.state["cookies"]:
39
82
  await self.page.context.add_cookies([cookie])
40
- await self.page.goto(self.pages.SEND)
83
+ await self.page.goto(self.pages.SEND, wait_until="commit")
84
+
85
+ @staticmethod
86
+ def form_redirect(topup: TopUp) -> tuple[str, dict | None]:
87
+ m_shop = str(topup.topupable.auth["id"])
88
+ m_orderid = str(topup.id)
89
+ m_amount = "{0:.2f}".format(topup.amount * 0.01)
90
+ m_curr = topup.cur.ticker
91
+ m_desc = b64encode(b"XyncPay top up").decode()
92
+ m_key = topup.topupable.auth["sec"]
93
+ data = [m_shop, m_orderid, m_amount, m_curr, m_desc]
94
+
95
+ # # additional
96
+ # m_params = {
97
+ # 'success_url': 'https://xync.net/topup?success=1',
98
+ # 'fail_url': 'https://xync.net/topup?success=0',
99
+ # 'status_url': 'https://xync.net/topup',
100
+ # 'reference': {'var1': '1'},
101
+ # }
102
+ #
103
+ # key = md5(m_orderid.to_bytes()).digest()
104
+ #
105
+ # base64url_encode(encrypt_data(params, key))
106
+ #
107
+ # data.append(m_params)
108
+ # # additional
109
+
110
+ data.append(m_key)
111
+
112
+ sign = sha256(":".join(data).encode()).hexdigest().upper()
113
+
114
+ params = {
115
+ "m_shop": m_shop,
116
+ "m_orderid": m_orderid,
117
+ "m_amount": m_amount,
118
+ "m_curr": m_curr,
119
+ "m_desc": m_desc,
120
+ "m_sign": sign,
121
+ # 'm_params': m_params,
122
+ # 'm_cipher_method': 'AES-256-CBC-IV',
123
+ "form[ps]": "2609",
124
+ "form[curr[2609]]": m_curr,
125
+ }
126
+ url = "https://payeer.com/merchant/?" + urlencode(params)
127
+ return url, None
128
+
129
+ def get_topup(self, tid: str) -> dict:
130
+ hi = self.api.get_history_info(tid)
131
+ ti = self.api.shop_order_info(hi["params"]["SHOP_ID"], hi["params"]["ORDER_ID"])["info"]
132
+ return ti["status"] == "execute" and {
133
+ "pmid": ti["id"],
134
+ "from_acc": hi["params"]["ACCOUNT_NUMBER"],
135
+ "oid": hi["params"]["ORDER_ID"],
136
+ "amount": int(float(ti["sumOut"]) * 100),
137
+ "ts": datetime.strptime(ti["dateCreate"], "%d.%m.%Y %H:%M:%S") - timedelta(hours=3),
138
+ }
41
139
 
42
- async def send(self, dest: str, amount: int, cur: str) -> tuple[int, bytes, int] | int:
43
- self.last_active = datetime.now()
140
+ async def send(self, t: Transfer) -> tuple[str, bytes] | float:
141
+ dest, cur = t.order.cred.detail, t.order.cred.pmcur.cur.ticker
142
+ amount = round(t.order.amount * 10**-t.order.cred.pmcur.cur.scale, t.order.cred.pmcur.cur.scale)
143
+ self.last_active = now()
44
144
  page = self.page
45
145
  if not page.url.startswith(self.pages.SEND):
46
146
  try:
47
- await page.goto(self.pages.SEND)
147
+ await page.goto(self.pages.SEND, wait_until="commit")
48
148
  except (TimeoutError, Error):
49
149
  await login(self.agent)
50
150
  for cookie in self.agent.state["cookies"]:
51
151
  await page.context.add_cookies([cookie])
52
152
  sleep(0.5)
53
- await page.goto("https://payeer.com/en/account/send/")
54
- fiat_accounts = await page.locator(
55
- f".balance-item.balance-item--green.balance-item--{cur.lower()}"
56
- ).all_text_contents()
57
- has_amount = float(fiat_accounts[0].replace(",", "").strip())
58
- if float(amount) <= has_amount:
153
+ await page.goto("https://payeer.com/en/account/send/", wait_until="commit")
154
+ has_amount = float(self.api.get_balance()[cur]["DOSTUPNO"])
155
+ if amount <= has_amount:
59
156
  sleep(0.1)
60
157
  await page.locator('input[name="param_ACCOUNT_NUMBER"]').fill(dest)
61
158
  await page.locator("select[name=curr_receive]").select_option(value=cur)
62
- sleep(0.9)
159
+ sleep(0.8)
63
160
  await page.locator('input[name="sum_receive"]').fill(str(amount))
64
161
  sleep(0.1)
65
162
  # await page.locator("div.n-form--title").first.click()
@@ -67,7 +164,7 @@ class Client(PmAgentClient):
67
164
  await page.click(".btn.n-form--btn.n-form--btn-mod")
68
165
  sleep(0.5)
69
166
  await page.click(".btn.n-form--btn.n-form--btn-mod")
70
- sleep(1.2)
167
+ sleep(1.1)
71
168
  if await page.locator(".input4").count():
72
169
  await page.locator(".input4").fill(self.agent.auth.get("master_key"))
73
170
  await page.click(".ok.button_green2")
@@ -77,42 +174,42 @@ class Client(PmAgentClient):
77
174
  except TimeoutError as _:
78
175
  logging.error("Repeat!")
79
176
  sleep(0.5)
80
- return await self.send(dest, amount, cur)
177
+ return await self.send(t)
81
178
  if await page.locator('.note_txt:has-text("successfully completed")').count():
82
179
  transaction = await page.locator(".note_txt").all_text_contents()
83
- trans_num = int(transaction[0].replace("Transaction #", "").split()[0])
84
- await page.goto("https://payeer.com/ru/account/history/")
180
+ trans_num = transaction[0].replace("Transaction #", "").split()[0]
181
+ await page.goto("https://payeer.com/ru/account/history/", wait_until="commit")
85
182
  await page.click(f".history-id-{trans_num} a.link")
86
183
  sleep(1)
87
184
  receipt = await page.query_selector(".ui-dialog.ui-corner-all")
88
- return trans_num, await receipt.screenshot(path=f"tmp/{dest}.png"), has_amount - amount
185
+ return trans_num, receipt and await receipt.screenshot(path=f"tmp/{trans_num}.png")
89
186
  else:
90
- await self.bot.send("Payeer хз", self.uid, photo=await self.page.screenshot())
187
+ await self.receive("Payeer хз", photo=await self.page.screenshot())
91
188
  return -1
92
189
  else:
93
- await self.bot.send(
190
+ await self.receive(
94
191
  f"Payeer no have {amount}, only {has_amount}{cur} to {dest}",
95
- self.uid,
96
192
  photo=await self.page.screenshot(),
97
193
  )
98
194
  return has_amount
99
195
 
100
- def check_in(
101
- self, amount: Decimal | int | float, cur: str, tme: datetime = None, tid: str | int = None
196
+ async def check_in(
197
+ self, amount: Decimal | int | float, cur: str, dt: datetime = None, tid: str | int = None
102
198
  ) -> tuple[Decimal | None, int | None]:
103
- history = self.api.history(type="incoming", append=tid, count=3)
199
+ history = self.api.history(type="incoming", count=10)
104
200
  if tid:
105
201
  return (t := history.get(tid)) and Decimal(t["creditedAmount"])
106
- t = [
202
+ ts: list[dict] = [
107
203
  h
108
204
  for h in history.values()
109
205
  if (
110
206
  amount <= Decimal(h["creditedAmount"]) <= ceil(amount)
111
207
  and h["creditedCurrency"] == cur
112
- and datetime.fromisoformat(h["date"]) > tme - timedelta(minutes=1)
208
+ # todo: wrong tz
209
+ and datetime.fromisoformat(h["date"]) > dt - timedelta(minutes=3) # +180(tz)-5
113
210
  )
114
211
  ]
115
- if not (t := t and t[0]):
212
+ if not (t := ts and ts[0]):
116
213
  return None, None
117
214
  return (
118
215
  amount <= (am := Decimal(t["creditedAmount"])) <= ceil(amount) and t["creditedCurrency"] == cur
@@ -125,30 +222,37 @@ async def main(uid: int):
125
222
  from x_model import init_db
126
223
 
127
224
  _ = await init_db(TORM, True)
225
+ agent = await PmAgent.get_or_none(pm__norm="payeer", user__username_id=uid).prefetch_related(
226
+ "user__username__session", "pm"
227
+ )
228
+ if not agent:
229
+ raise Exception(f"No active user #{uid} with agent for volet!")
230
+ abot = Bot(PAY_TOKEN)
231
+ pyr = agent.client(abot)
128
232
  playwright: Playwright = await async_playwright().start()
129
- pyr = Client(uid)
130
233
  try:
131
- await pyr.start(playwright, True)
234
+ dest, amount, cur = "P79619335", 4, "RUB"
235
+ ta = await TopUpAble.get(pm__norm="payeer")
236
+ topup = await TopUp.create(amount=1001, cur_id=1, topupable=ta, user_id=1)
237
+ await topup.fetch_related("cur")
238
+ _url, _data = pyr.form_redirect(topup)
132
239
 
133
- dest, amount, cur = "P79619335", 2, "RUB"
240
+ await pyr.start(playwright, False)
134
241
 
135
- res = await pyr.send(dest, amount, cur)
136
- res = await pyr.send(dest, 3, cur)
137
- res = await pyr.send(dest, amount, cur)
138
- res = await pyr.send(dest, 3, cur)
139
- res = await pyr.send(dest, amount, cur)
242
+ _res = await pyr.send(dest, amount, cur)
243
+ _res = await pyr.send(dest, 3, cur)
140
244
 
141
- res = pyr.check_in(2, cur, datetime.now())
245
+ res = pyr.check_in(3, cur, datetime.now())
142
246
 
143
247
  if len(res) > 1 and isinstance(res[1], bytes):
144
- await pyr.bot.send(f"Transaction #{res[0]}", uid, photo=res[1])
248
+ await pyr.receive(f"Transaction #{res[0]}", photo=res[1])
145
249
  elif res[0] > 0:
146
- await pyr.bot.send(f"Sreen of transaction #{res[0]} failed", uid, photo=await pyr.page.screenshot())
250
+ await pyr.receive(f"Sreen of transaction #{res[0]} failed", photo=await pyr.page.screenshot())
147
251
  else:
148
- await pyr.bot.send(f"Sending {amount} {cur} to {dest} FAILED", uid, photo=await pyr.page.screenshot())
252
+ await pyr.receive(f"Sending {amount} {cur} to {dest} FAILED", photo=await pyr.page.screenshot())
149
253
 
150
254
  except TimeoutError as te:
151
- await pyr.bot.send(repr(te), uid, photo=await pyr.page.screenshot())
255
+ await pyr.receive(repr(te), photo=await pyr.page.screenshot())
152
256
  raise te
153
257
  # finally:
154
258
  # await pyr.stop()
@@ -8,7 +8,31 @@ import time
8
8
 
9
9
 
10
10
  async def login(agent: PmAgent):
11
- driver = uc.Chrome(no_sandbox=True, headless=False)
11
+ options = uc.ChromeOptions()
12
+ options.add_argument("--disable-blink-features=AutomationControlled")
13
+ options.add_argument("--no-sandbox")
14
+ options.add_argument("--disable-dev-shm-usage")
15
+ # options.add_argument("--headless=new") # for Chrome >= 109
16
+ options.add_argument("--disable-renderer-backgrounding")
17
+ options.add_argument("--disable-background-timer-throttling")
18
+ options.add_argument("--disable-backgrounding-occluded-windows")
19
+ options.add_argument("--disable-client-side-phishing-detection")
20
+ options.add_argument("--disable-crash-reporter")
21
+ options.add_argument("--disable-oopr-debug-crash-dump")
22
+ options.add_argument("--no-crash-upload")
23
+ options.add_argument("--disable-gpu")
24
+ options.add_argument("--disable-extensions")
25
+ options.add_argument("--disable-low-res-tiling")
26
+ options.add_argument("--log-level=3")
27
+ options.add_argument("--silent")
28
+ options.add_argument("--window-size=1920,1080")
29
+ options.add_argument("--user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36")
30
+
31
+ driver = uc.Chrome(
32
+ options=options,
33
+ headless=False,
34
+ browser_executable_path="/Applications/Google Chrome Beta.app/Contents/MacOS/Google Chrome Beta",
35
+ )
12
36
  wait = WebDriverWait(driver, timeout=10)
13
37
  try:
14
38
  driver.get("https://payeer.com/en/auth")
@@ -22,7 +46,10 @@ async def login(agent: PmAgent):
22
46
  login_button = wait.until(EC.element_to_be_clickable((By.CLASS_NAME, "login-form__login-btn.step1")))
23
47
  login_button.click()
24
48
  time.sleep(4)
25
- login_button.click()
49
+ try:
50
+ login_button.click()
51
+ except Exception:
52
+ pass
26
53
  time.sleep(1)
27
54
  if (v := driver.find_elements(By.CLASS_NAME, "form-input-top")) and v[0].text == "Введите проверочный код":
28
55
  code = input("Email code: ")