sticker-convert 2.14.0.0__py3-none-any.whl → 2.15.0.0__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.
- sticker_convert/auth/__init__.py +0 -0
- sticker_convert/auth/auth_base.py +19 -0
- sticker_convert/{utils/auth/get_discord_auth.py → auth/auth_discord.py} +40 -13
- sticker_convert/{utils/auth/get_kakao_auth_android_login.py → auth/auth_kakao_android_login.py} +80 -84
- sticker_convert/{utils/auth/get_kakao_auth_desktop_login.py → auth/auth_kakao_desktop_login.py} +69 -28
- sticker_convert/{utils/auth/get_kakao_auth_desktop_memdump.py → auth/auth_kakao_desktop_memdump.py} +31 -24
- sticker_convert/{utils/auth/get_line_auth.py → auth/auth_line.py} +21 -6
- sticker_convert/{utils/auth/get_signal_auth.py → auth/auth_signal.py} +18 -20
- sticker_convert/auth/auth_telethon.py +151 -0
- sticker_convert/{utils/auth/get_viber_auth.py → auth/auth_viber.py} +19 -11
- sticker_convert/{utils/auth → auth}/telegram_api.py +4 -13
- sticker_convert/cli.py +44 -70
- sticker_convert/downloaders/download_line.py +2 -2
- sticker_convert/downloaders/download_telegram.py +1 -1
- sticker_convert/gui.py +15 -100
- sticker_convert/gui_components/frames/comp_frame.py +12 -4
- sticker_convert/gui_components/frames/config_frame.py +14 -6
- sticker_convert/gui_components/frames/control_frame.py +1 -1
- sticker_convert/gui_components/frames/cred_frame.py +6 -8
- sticker_convert/gui_components/windows/advanced_compression_window.py +3 -4
- sticker_convert/gui_components/windows/base_window.py +7 -2
- sticker_convert/gui_components/windows/discord_get_auth_window.py +3 -7
- sticker_convert/gui_components/windows/kakao_get_auth_window.py +79 -51
- sticker_convert/gui_components/windows/line_get_auth_window.py +5 -14
- sticker_convert/gui_components/windows/signal_get_auth_window.py +4 -12
- sticker_convert/gui_components/windows/viber_get_auth_window.py +8 -11
- sticker_convert/job.py +16 -32
- sticker_convert/uploaders/upload_telegram.py +1 -1
- sticker_convert/utils/callback.py +238 -6
- sticker_convert/version.py +1 -1
- {sticker_convert-2.14.0.0.dist-info → sticker_convert-2.15.0.0.dist-info}/METADATA +5 -5
- {sticker_convert-2.14.0.0.dist-info → sticker_convert-2.15.0.0.dist-info}/RECORD +36 -34
- sticker_convert/utils/auth/telethon_setup.py +0 -97
- {sticker_convert-2.14.0.0.dist-info → sticker_convert-2.15.0.0.dist-info}/WHEEL +0 -0
- {sticker_convert-2.14.0.0.dist-info → sticker_convert-2.15.0.0.dist-info}/entry_points.txt +0 -0
- {sticker_convert-2.14.0.0.dist-info → sticker_convert-2.15.0.0.dist-info}/licenses/LICENSE +0 -0
- {sticker_convert-2.14.0.0.dist-info → sticker_convert-2.15.0.0.dist-info}/top_level.txt +0 -0
File without changes
|
@@ -0,0 +1,19 @@
|
|
1
|
+
#!/usr/bin/env python3
|
2
|
+
from typing import Optional
|
3
|
+
|
4
|
+
from sticker_convert.job_option import CredOption
|
5
|
+
from sticker_convert.utils.callback import CallbackCli, CallbackProtocol
|
6
|
+
|
7
|
+
|
8
|
+
class AuthBase:
|
9
|
+
def __init__(
|
10
|
+
self,
|
11
|
+
opt_cred: CredOption,
|
12
|
+
cb: Optional[CallbackProtocol] = None,
|
13
|
+
) -> None:
|
14
|
+
self.opt_cred = opt_cred
|
15
|
+
self.cb: CallbackProtocol
|
16
|
+
if cb is None:
|
17
|
+
self.cb = CallbackCli()
|
18
|
+
else:
|
19
|
+
self.cb = cb
|
@@ -4,23 +4,27 @@ import os
|
|
4
4
|
import platform
|
5
5
|
import shutil
|
6
6
|
import time
|
7
|
-
from
|
7
|
+
from pathlib import Path
|
8
|
+
from typing import Any, Optional, Tuple
|
8
9
|
from urllib.parse import urlparse
|
9
10
|
|
11
|
+
from sticker_convert.auth.auth_base import AuthBase
|
10
12
|
from sticker_convert.definitions import CONFIG_DIR
|
11
13
|
from sticker_convert.utils.chrome_remotedebug import CRD
|
12
|
-
from sticker_convert.utils.process import killall
|
14
|
+
from sticker_convert.utils.process import find_pid_by_name, killall
|
13
15
|
|
16
|
+
OK_MSG = "Got token successfully:\ntoken={token}"
|
17
|
+
FAIL_MSG = "Failed to get token"
|
14
18
|
|
15
|
-
|
16
|
-
|
19
|
+
|
20
|
+
class AuthDiscord(AuthBase):
|
21
|
+
def __init__(self, *args: Any, **kwargs: Any) -> None:
|
22
|
+
super().__init__(*args, **kwargs)
|
17
23
|
chromedriver_download_dir = CONFIG_DIR / "bin"
|
18
24
|
os.makedirs(chromedriver_download_dir, exist_ok=True)
|
19
25
|
|
20
26
|
self.chromedriver_download_dir = chromedriver_download_dir
|
21
27
|
|
22
|
-
self.cb_msg = cb_msg
|
23
|
-
|
24
28
|
def get_discord_bin_path(self) -> Optional[str]:
|
25
29
|
discord_bin: Optional[str]
|
26
30
|
if platform.system() == "Windows":
|
@@ -42,6 +46,8 @@ class GetDiscordAuth:
|
|
42
46
|
for discord_dir, discord_bin in discord_win_dirs:
|
43
47
|
app_dir: Optional[str] = None
|
44
48
|
chrome_path: Optional[str] = None
|
49
|
+
if os.path.isdir(discord_dir) is False:
|
50
|
+
continue
|
45
51
|
for i in [j for j in os.listdir(discord_dir) if j.startswith("app-")]:
|
46
52
|
app_dir = os.path.join(discord_dir, i)
|
47
53
|
chrome_path = os.path.join(app_dir, discord_bin)
|
@@ -67,6 +73,9 @@ class GetDiscordAuth:
|
|
67
73
|
return None
|
68
74
|
|
69
75
|
def get_cred(self) -> Tuple[Optional[str], str]:
|
76
|
+
msg = "Getting Discord authorization token..."
|
77
|
+
self.cb.put(("msg_dynamic", (msg,), None))
|
78
|
+
|
70
79
|
using_discord_app = False
|
71
80
|
chrome_path = self.get_discord_bin_path()
|
72
81
|
if chrome_path is not None:
|
@@ -74,14 +83,26 @@ class GetDiscordAuth:
|
|
74
83
|
else:
|
75
84
|
chrome_path = CRD.get_chromium_path()
|
76
85
|
if chrome_path is None:
|
86
|
+
self.cb.put(("msg_dynamic", (None,), None))
|
77
87
|
return (
|
78
88
|
None,
|
79
89
|
"Please install Discord Desktop or Chrome/Chromium and try again",
|
80
90
|
)
|
81
91
|
|
82
92
|
token = None
|
83
|
-
|
84
|
-
|
93
|
+
|
94
|
+
if find_pid_by_name(Path(chrome_path).name):
|
95
|
+
response = self.cb.put(
|
96
|
+
(
|
97
|
+
"ask_bool",
|
98
|
+
(f"All {Path(chrome_path).name} will be closed. Continue?",),
|
99
|
+
None,
|
100
|
+
)
|
101
|
+
)
|
102
|
+
if response is True:
|
103
|
+
killall(Path(chrome_path).name.lower())
|
104
|
+
else:
|
105
|
+
return None, FAIL_MSG
|
85
106
|
|
86
107
|
crd = CRD(chrome_path)
|
87
108
|
while True:
|
@@ -98,9 +119,14 @@ class GetDiscordAuth:
|
|
98
119
|
|
99
120
|
while True:
|
100
121
|
try:
|
101
|
-
|
102
|
-
|
103
|
-
|
122
|
+
if using_discord_app:
|
123
|
+
r = crd.exec_js(
|
124
|
+
"(webpackChunkdiscord_app.push([[''],{},e=>{m=[];for(let c in e.c)m.push(e.c[c])}]),m).find(m=>m?.exports?.default?.getToken!==void 0).exports.default.getToken();"
|
125
|
+
)
|
126
|
+
else:
|
127
|
+
r = crd.exec_js(
|
128
|
+
"const iframe=document.createElement('iframe');JSON.parse(document.body.appendChild(iframe).contentWindow.localStorage.token);"
|
129
|
+
)
|
104
130
|
except RuntimeError:
|
105
131
|
break
|
106
132
|
if (
|
@@ -112,7 +138,8 @@ class GetDiscordAuth:
|
|
112
138
|
time.sleep(1)
|
113
139
|
crd.close()
|
114
140
|
|
141
|
+
self.cb.put(("msg_dynamic", (None,), None))
|
115
142
|
if token is None:
|
116
|
-
return None,
|
143
|
+
return None, FAIL_MSG
|
117
144
|
|
118
|
-
return token,
|
145
|
+
return token, OK_MSG.format(token=token)
|
sticker_convert/{utils/auth/get_kakao_auth_android_login.py → auth/auth_kakao_android_login.py}
RENAMED
@@ -2,31 +2,24 @@
|
|
2
2
|
import json
|
3
3
|
import secrets
|
4
4
|
import uuid
|
5
|
-
from typing import Any,
|
5
|
+
from typing import Any, Dict, Optional, Tuple
|
6
6
|
from urllib.parse import parse_qs, urlparse
|
7
7
|
|
8
8
|
import requests
|
9
9
|
from bs4 import BeautifulSoup
|
10
10
|
|
11
|
-
from sticker_convert.
|
11
|
+
from sticker_convert.auth.auth_base import AuthBase
|
12
12
|
|
13
|
+
OK_MSG = "Got auth_token successfully:\n{auth_token=}\n"
|
13
14
|
|
14
|
-
class GetKakaoAuthAndroidLogin:
|
15
|
-
def __init__(
|
16
|
-
self,
|
17
|
-
opt_cred: CredOption,
|
18
|
-
cb_msg: Callable[..., None] = print,
|
19
|
-
cb_msg_block: Callable[..., Any] = input,
|
20
|
-
cb_ask_str: Callable[..., str] = input,
|
21
|
-
) -> None:
|
22
|
-
self.username = opt_cred.kakao_username
|
23
|
-
self.password = opt_cred.kakao_password
|
24
|
-
self.country_code = opt_cred.kakao_country_code
|
25
|
-
self.phone_number = opt_cred.kakao_phone_number
|
26
15
|
|
27
|
-
|
28
|
-
|
29
|
-
|
16
|
+
class AuthKakaoAndroidLogin(AuthBase):
|
17
|
+
def __init__(self, *args: Any, **kwargs: Any) -> None:
|
18
|
+
super().__init__(*args, **kwargs)
|
19
|
+
self.username = self.opt_cred.kakao_username
|
20
|
+
self.password = self.opt_cred.kakao_password
|
21
|
+
self.country_code = self.opt_cred.kakao_country_code
|
22
|
+
self.phone_number = self.opt_cred.kakao_phone_number
|
30
23
|
|
31
24
|
self.device_uuid = secrets.token_hex(32)
|
32
25
|
self.device_ssaid = secrets.token_hex(20)
|
@@ -67,8 +60,9 @@ class GetKakaoAuthAndroidLogin:
|
|
67
60
|
return a.get("href").split("/")[-1]
|
68
61
|
return "25.2.1"
|
69
62
|
|
70
|
-
def login(self) -> bool:
|
71
|
-
|
63
|
+
def login(self) -> Tuple[bool, str]:
|
64
|
+
msg = "Getting Kakao authorization token by Android login: Logging in"
|
65
|
+
self.cb.put(("msg_dynamic", (msg,), None))
|
72
66
|
|
73
67
|
json_data = {
|
74
68
|
"id": self.username,
|
@@ -83,29 +77,29 @@ class GetKakaoAuthAndroidLogin:
|
|
83
77
|
|
84
78
|
response_json = json.loads(response.text)
|
85
79
|
|
80
|
+
self.cb.put(("msg_dynamic", (None,), None))
|
86
81
|
if response_json["status"] != 0:
|
87
|
-
|
88
|
-
return False
|
82
|
+
return False, f"Failed at login: {response.text}"
|
89
83
|
|
90
84
|
self.headers["Ss"] = response.headers["Set-SS"]
|
91
85
|
self.country_dicts = response_json["viewData"]["countries"]["all"]
|
92
86
|
|
93
|
-
return True
|
87
|
+
return True, ""
|
94
88
|
|
95
|
-
def get_country_iso(self) -> bool:
|
89
|
+
def get_country_iso(self) -> Tuple[bool, str]:
|
96
90
|
self.country_iso = None
|
97
91
|
for country_dict in self.country_dicts:
|
98
92
|
if country_dict["code"] == self.country_code:
|
99
93
|
self.country_iso = country_dict["iso"]
|
100
94
|
|
101
95
|
if not self.country_iso:
|
102
|
-
|
103
|
-
return False
|
96
|
+
return False, "Invalid country code"
|
104
97
|
|
105
|
-
return True
|
98
|
+
return True, ""
|
106
99
|
|
107
|
-
def enter_phone(self) -> bool:
|
108
|
-
|
100
|
+
def enter_phone(self) -> Tuple[bool, str]:
|
101
|
+
msg = "Getting Kakao authorization token by Android login: Submitting phone number"
|
102
|
+
self.cb.put(("msg_dynamic", (msg,), None))
|
109
103
|
|
110
104
|
json_data: Dict[str, Any] = {
|
111
105
|
"countryCode": self.country_code,
|
@@ -123,9 +117,9 @@ class GetKakaoAuthAndroidLogin:
|
|
123
117
|
|
124
118
|
response_json = json.loads(response.text)
|
125
119
|
|
120
|
+
self.cb.put(("msg_dynamic", (None,), None))
|
126
121
|
if response_json["status"] != 0:
|
127
|
-
|
128
|
-
return False
|
122
|
+
return False, f"Failed at entering phone number: {response.text}"
|
129
123
|
|
130
124
|
self.verify_method = response_json["view"]
|
131
125
|
|
@@ -135,12 +129,9 @@ class GetKakaoAuthAndroidLogin:
|
|
135
129
|
dest_number = response_json["viewData"]["moNumber"]
|
136
130
|
msg = response_json["viewData"]["moMessage"]
|
137
131
|
return self.verify_send_sms(dest_number, msg)
|
138
|
-
|
139
|
-
return False
|
140
|
-
|
141
|
-
def verify_send_sms(self, dest_number: str, msg: str) -> bool:
|
142
|
-
self.cb_msg("Verification by sending SMS")
|
132
|
+
return False, f"Unknown verification method: {response.text}"
|
143
133
|
|
134
|
+
def verify_send_sms(self, dest_number: str, verify_msg: str) -> Tuple[bool, str]:
|
144
135
|
response = requests.post(
|
145
136
|
"https://katalk.kakao.com/android/account2/mo-sent", headers=self.headers
|
146
137
|
)
|
@@ -148,15 +139,20 @@ class GetKakaoAuthAndroidLogin:
|
|
148
139
|
response_json = json.loads(response.text)
|
149
140
|
|
150
141
|
if response_json["status"] != 0:
|
151
|
-
|
152
|
-
return False
|
142
|
+
return False, f"Failed at confirm sending SMS: {response.text}"
|
153
143
|
|
154
144
|
prompt = f"Send this SMS message to number {dest_number} then press enter:"
|
155
|
-
self.
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
145
|
+
self.cb.put(
|
146
|
+
(
|
147
|
+
"ask_str",
|
148
|
+
None,
|
149
|
+
{
|
150
|
+
"msg": prompt,
|
151
|
+
"initialvalue": verify_msg,
|
152
|
+
"cli_show_initialvalue": False,
|
153
|
+
},
|
154
|
+
)
|
155
|
+
)
|
160
156
|
|
161
157
|
response = requests.post(
|
162
158
|
"https://katalk.kakao.com/android/account2/mo-confirm", headers=self.headers
|
@@ -165,21 +161,18 @@ class GetKakaoAuthAndroidLogin:
|
|
165
161
|
response_json = json.loads(response.text)
|
166
162
|
|
167
163
|
if response_json["status"] != 0:
|
168
|
-
|
169
|
-
return False
|
164
|
+
return False, f"Failed at verifying SMS sent: {response.text}"
|
170
165
|
|
171
166
|
if response_json.get("reason") or "error" in response_json.get("message", ""):
|
172
|
-
|
173
|
-
return False
|
167
|
+
return False, f"Failed at verifying SMS sent: {response.text}"
|
174
168
|
|
175
169
|
self.confirm_url = response_json.get("viewData", {}).get("url")
|
176
170
|
|
177
|
-
return True
|
178
|
-
|
179
|
-
def verify_receive_sms(self) -> bool:
|
180
|
-
self.cb_msg("Verification by receiving SMS")
|
171
|
+
return True, ""
|
181
172
|
|
182
|
-
|
173
|
+
def verify_receive_sms(self) -> Tuple[bool, str]:
|
174
|
+
msg = "Enter passcode received from SMS:"
|
175
|
+
passcode = self.cb.put(("ask_str", (msg,), None))
|
183
176
|
|
184
177
|
json_data = {
|
185
178
|
"passcode": passcode,
|
@@ -193,16 +186,19 @@ class GetKakaoAuthAndroidLogin:
|
|
193
186
|
|
194
187
|
response_json = json.loads(response.text)
|
195
188
|
|
189
|
+
self.cb.put(("msg_dynamic", (None,), None))
|
196
190
|
if response_json["status"] != 0:
|
197
|
-
|
198
|
-
return False
|
191
|
+
return False, f"Failed at verifying passcode: {response.text}"
|
199
192
|
|
200
193
|
self.confirm_url = response_json.get("viewData", {}).get("url")
|
201
194
|
|
202
|
-
return True
|
195
|
+
return True, ""
|
203
196
|
|
204
|
-
def confirm_device_change(self) -> bool:
|
205
|
-
|
197
|
+
def confirm_device_change(self) -> Tuple[bool, str]:
|
198
|
+
msg = (
|
199
|
+
"Getting Kakao authorization token by Android login: Confirm device change"
|
200
|
+
)
|
201
|
+
self.cb.put(("msg_dynamic", (msg,), None))
|
206
202
|
|
207
203
|
confirm_url_parsed = urlparse(self.confirm_url) # type: ignore
|
208
204
|
confirm_url_qs = parse_qs(confirm_url_parsed.query) # type: ignore
|
@@ -238,14 +234,15 @@ class GetKakaoAuthAndroidLogin:
|
|
238
234
|
|
239
235
|
response_json = json.loads(response.text)
|
240
236
|
|
237
|
+
self.cb.put(("msg_dynamic", (None,), None))
|
241
238
|
if response_json["status"] != 0:
|
242
|
-
|
243
|
-
return False
|
239
|
+
return False, f"Failed at confirm device change: {response.text}"
|
244
240
|
|
245
|
-
return True
|
241
|
+
return True, ""
|
246
242
|
|
247
|
-
def passcode_callback(self) -> bool:
|
248
|
-
|
243
|
+
def passcode_callback(self) -> Tuple[bool, str]:
|
244
|
+
msg = "Getting Kakao authorization token by Android login: Passcode callback"
|
245
|
+
self.cb.put(("msg_dynamic", (msg,), None))
|
249
246
|
|
250
247
|
response = requests.get(
|
251
248
|
"https://katalk.kakao.com/android/account2/passcode/callback",
|
@@ -254,14 +251,15 @@ class GetKakaoAuthAndroidLogin:
|
|
254
251
|
|
255
252
|
response_json = json.loads(response.text)
|
256
253
|
|
254
|
+
self.cb.put(("msg_dynamic", (None,), None))
|
257
255
|
if response_json["status"] != 0:
|
258
|
-
|
259
|
-
return False
|
256
|
+
return False, f"Failed at passcode callback: {response.text}"
|
260
257
|
|
261
|
-
return True
|
258
|
+
return True, ""
|
262
259
|
|
263
|
-
def skip_restoration(self) -> bool:
|
264
|
-
|
260
|
+
def skip_restoration(self) -> Tuple[bool, str]:
|
261
|
+
msg = "Getting Kakao authorization token by Android login: Skip restoration"
|
262
|
+
self.cb.put(("msg_dynamic", (msg,), None))
|
265
263
|
|
266
264
|
response = requests.post(
|
267
265
|
"https://katalk.kakao.com/android/account2/skip-restoration",
|
@@ -270,19 +268,19 @@ class GetKakaoAuthAndroidLogin:
|
|
270
268
|
response_json = json.loads(response.text)
|
271
269
|
|
272
270
|
if response_json["status"] != 0:
|
273
|
-
|
274
|
-
return False
|
271
|
+
return False, f"Failed at skip restoration: {response.text}"
|
275
272
|
|
276
273
|
self.nickname = response_json.get("viewData", {}).get("nickname")
|
277
274
|
|
275
|
+
self.cb.put(("msg_dynamic", (None,), None))
|
278
276
|
if self.nickname is None:
|
279
|
-
|
280
|
-
return False
|
277
|
+
return False, f"Failed at passcode callback: {response.text}"
|
281
278
|
|
282
|
-
return True
|
279
|
+
return True, ""
|
283
280
|
|
284
|
-
def get_profile(self) -> bool:
|
285
|
-
|
281
|
+
def get_profile(self) -> Tuple[bool, str]:
|
282
|
+
msg = "Getting Kakao authorization token by Android login: Get profile"
|
283
|
+
self.cb.put(("msg_dynamic", (msg,), None))
|
286
284
|
|
287
285
|
json_data = {
|
288
286
|
"nickname": self.nickname,
|
@@ -298,18 +296,16 @@ class GetKakaoAuthAndroidLogin:
|
|
298
296
|
|
299
297
|
response_json = json.loads(response.text)
|
300
298
|
|
299
|
+
self.cb.put(("msg_dynamic", (None,), None))
|
301
300
|
if response_json["status"] != 0:
|
302
|
-
|
303
|
-
return False
|
301
|
+
return False, f"Failed at get profile: {response.text}"
|
304
302
|
|
305
303
|
self.access_token = response_json["signupData"]["oauth2Token"]["accessToken"]
|
306
304
|
|
307
|
-
return True
|
308
|
-
|
309
|
-
def get_cred(self) -> Optional[str]:
|
310
|
-
self.cb_msg("Get authorization token")
|
305
|
+
return True, ""
|
311
306
|
|
312
|
-
|
307
|
+
def get_cred(self) -> Tuple[Optional[str], str]:
|
308
|
+
auth_token = None
|
313
309
|
|
314
310
|
steps = (
|
315
311
|
self.login,
|
@@ -322,9 +318,9 @@ class GetKakaoAuthAndroidLogin:
|
|
322
318
|
)
|
323
319
|
|
324
320
|
for step in steps:
|
325
|
-
success = step()
|
321
|
+
success, msg = step()
|
326
322
|
if not success:
|
327
|
-
return None
|
323
|
+
return None, msg
|
328
324
|
|
329
|
-
|
330
|
-
return
|
325
|
+
auth_token = self.access_token + "-" + self.device_uuid
|
326
|
+
return auth_token, OK_MSG.format(auth_token=auth_token)
|
sticker_convert/{utils/auth/get_kakao_auth_desktop_login.py → auth/auth_kakao_desktop_login.py}
RENAMED
@@ -4,40 +4,36 @@ import hashlib
|
|
4
4
|
import json
|
5
5
|
import os
|
6
6
|
import platform
|
7
|
+
import re
|
7
8
|
import shutil
|
8
9
|
import socket
|
9
10
|
import subprocess
|
10
11
|
import time
|
11
12
|
import uuid
|
12
|
-
from typing import Any,
|
13
|
+
from typing import Any, Optional, Tuple
|
13
14
|
|
14
15
|
import requests
|
16
|
+
from bs4 import BeautifulSoup
|
15
17
|
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
|
16
18
|
|
17
|
-
from sticker_convert.
|
19
|
+
from sticker_convert.auth.auth_base import AuthBase
|
18
20
|
|
21
|
+
OK_MSG = "Login successful, auth_token: {auth_token}"
|
19
22
|
|
20
|
-
class GetKakaoAuthDesktopLogin:
|
21
|
-
def __init__(
|
22
|
-
self,
|
23
|
-
opt_cred: CredOption,
|
24
|
-
cb_msg: Callable[..., None] = print,
|
25
|
-
cb_msg_block: Callable[..., Any] = input,
|
26
|
-
cb_ask_str: Callable[..., str] = input,
|
27
|
-
) -> None:
|
28
|
-
self.opt_cred = opt_cred
|
29
|
-
self.username = opt_cred.kakao_username
|
30
|
-
self.password = opt_cred.kakao_password
|
31
23
|
|
32
|
-
|
33
|
-
|
34
|
-
|
24
|
+
class AuthKakaoDesktopLogin(AuthBase):
|
25
|
+
def __init__(self, *args: Any, **kwargs: Any) -> None:
|
26
|
+
super().__init__(*args, **kwargs)
|
27
|
+
self.username = self.opt_cred.kakao_username
|
28
|
+
self.password = self.opt_cred.kakao_password
|
35
29
|
|
36
30
|
if platform.system() == "Darwin":
|
37
31
|
self.plat = "mac"
|
38
32
|
user_agent_os = "Mc"
|
39
33
|
self.os_version = platform.mac_ver()[0]
|
40
|
-
version =
|
34
|
+
version = self.macos_get_ver()
|
35
|
+
if version is None:
|
36
|
+
version = "25.2.0"
|
41
37
|
else:
|
42
38
|
self.plat = "win32"
|
43
39
|
user_agent_os = "Wd"
|
@@ -45,7 +41,9 @@ class GetKakaoAuthDesktopLogin:
|
|
45
41
|
self.os_version = platform.uname().version
|
46
42
|
else:
|
47
43
|
self.os_version = "10.0"
|
48
|
-
version =
|
44
|
+
version = self.windows_get_ver()
|
45
|
+
if version is None:
|
46
|
+
version = "25.8.2"
|
49
47
|
|
50
48
|
user_agent = f"KT/{version} {user_agent_os}/{self.os_version} en"
|
51
49
|
self.headers = {
|
@@ -59,6 +57,8 @@ class GetKakaoAuthDesktopLogin:
|
|
59
57
|
}
|
60
58
|
|
61
59
|
self.device_name = socket.gethostname()
|
60
|
+
if platform.system() != "Darwin":
|
61
|
+
self.device_name = self.device_name.upper()
|
62
62
|
self.device_uuid = self.get_device_uuid()
|
63
63
|
|
64
64
|
hash = hashlib.sha512(
|
@@ -74,6 +74,31 @@ class GetKakaoAuthDesktopLogin:
|
|
74
74
|
def pkcs7_pad(self, m: str) -> str:
|
75
75
|
return m + chr(16 - len(m) % 16) * (16 - len(m) % 16)
|
76
76
|
|
77
|
+
def windows_get_ver(self) -> Optional[str]:
|
78
|
+
r = requests.get(
|
79
|
+
"https://api.github.com/repos/microsoft/winget-pkgs/contents/manifests/k/Kakao/KakaoTalk"
|
80
|
+
)
|
81
|
+
rjson = json.loads(r.text)
|
82
|
+
if len(rjson) == 0:
|
83
|
+
return None
|
84
|
+
ver = rjson[-1]["name"]
|
85
|
+
return ".".join(ver.split(".")[:3])
|
86
|
+
|
87
|
+
def macos_get_ver(self) -> Optional[str]:
|
88
|
+
country = "us"
|
89
|
+
app_name = "kakaotalk-messenger"
|
90
|
+
app_id = "362057947"
|
91
|
+
|
92
|
+
url = f"https://apps.apple.com/{country}/app/{app_name}/id{app_id}"
|
93
|
+
|
94
|
+
r = requests.get(url)
|
95
|
+
soup = BeautifulSoup(r.text, "html.parser")
|
96
|
+
version_tag = soup.find("p", {"class": re.compile(".*latest__version")})
|
97
|
+
version_str = None
|
98
|
+
if version_tag is not None:
|
99
|
+
version_str = version_tag.text.replace("Version ", "")
|
100
|
+
return version_str
|
101
|
+
|
77
102
|
def windows_get_pragma(self, use_wine: bool = False) -> Optional[str]:
|
78
103
|
sys_uuid = None
|
79
104
|
hdd_model = None
|
@@ -248,28 +273,44 @@ class GetKakaoAuthDesktopLogin:
|
|
248
273
|
return json.loads(response.text)
|
249
274
|
|
250
275
|
def get_cred(self) -> Tuple[Optional[str], str]:
|
251
|
-
|
276
|
+
msg = "Getting Kakao authorization token by desktop login..."
|
277
|
+
self.cb.put(("msg_dynamic", (msg,), None))
|
252
278
|
rjson = self.login()
|
253
279
|
access_token = rjson.get("access_token")
|
254
280
|
if access_token is not None:
|
255
281
|
auth_token = access_token + "-" + self.device_uuid
|
256
|
-
return auth_token,
|
282
|
+
return auth_token, OK_MSG.format(auth_token=auth_token)
|
257
283
|
|
258
284
|
rjson = self.generate_passcode()
|
259
285
|
if rjson.get("status") != 0:
|
260
286
|
return None, f"Failed to generate passcode: {rjson}"
|
261
287
|
passcode = rjson["passcode"]
|
262
288
|
|
263
|
-
|
264
|
-
|
265
|
-
while
|
266
|
-
self.cb_ask_str(f"Please enter passcode within 1 minute: {passcode}")
|
289
|
+
fail_reason = None
|
290
|
+
self.cb.put(("msg_dynamic", (None,), None))
|
291
|
+
while True:
|
267
292
|
rjson = self.register_device()
|
268
293
|
if rjson["status"] == 0:
|
269
|
-
register_success = True
|
270
294
|
break
|
271
|
-
|
272
|
-
|
295
|
+
elif rjson["status"] == -110:
|
296
|
+
fail_reason = "Timeout"
|
297
|
+
break
|
298
|
+
elif rjson["status"] != -100:
|
299
|
+
fail_reason = str(rjson)
|
300
|
+
break
|
301
|
+
time_remaining = rjson.get("remainingSeconds")
|
302
|
+
next_req_time = rjson.get("nextRequestIntervalInSeconds")
|
303
|
+
if time_remaining is None or next_req_time is None:
|
304
|
+
fail_reason = str(rjson)
|
305
|
+
msg = f"Please enter passcode in Kakao app on mobile device within {time_remaining} seconds: {passcode}"
|
306
|
+
msg_dynamic_window_exist = self.cb.put(("msg_dynamic", (msg,), None))
|
307
|
+
if msg_dynamic_window_exist is False:
|
308
|
+
fail_reason = "Cancelled"
|
309
|
+
break
|
310
|
+
time.sleep(next_req_time)
|
311
|
+
self.cb.put(("msg_dynamic", (None,), None))
|
312
|
+
if fail_reason is not None:
|
313
|
+
return None, f"Failed to register device: {fail_reason}"
|
273
314
|
|
274
315
|
rjson = self.login()
|
275
316
|
if rjson.get("status") == -101:
|
@@ -279,4 +320,4 @@ class GetKakaoAuthDesktopLogin:
|
|
279
320
|
return None, f"Failed to login after registering device: {rjson}"
|
280
321
|
|
281
322
|
auth_token = access_token + "-" + self.device_uuid
|
282
|
-
return auth_token,
|
323
|
+
return auth_token, OK_MSG.format(auth_token=auth_token)
|