tlgr-cli 2.0.1__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.
- tlgr/__init__.py +3 -0
- tlgr/__main__.py +6 -0
- tlgr/actions/__init__.py +45 -0
- tlgr/actions/forward.py +74 -0
- tlgr/actions/reply.py +32 -0
- tlgr/cli/__init__.py +259 -0
- tlgr/cli/confirm.py +55 -0
- tlgr/cli/errors.py +84 -0
- tlgr/cli/gen.py +690 -0
- tlgr/cli/globals.py +273 -0
- tlgr/cli/introspect.py +170 -0
- tlgr/cli/params.py +189 -0
- tlgr/cli/render.py +418 -0
- tlgr/core/__init__.py +0 -0
- tlgr/core/accounts.py +384 -0
- tlgr/core/config.py +358 -0
- tlgr/core/custom_tl.py +170 -0
- tlgr/core/errors.py +687 -0
- tlgr/core/eventtypes.py +1170 -0
- tlgr/core/identity.py +127 -0
- tlgr/core/launchd.py +122 -0
- tlgr/core/logging.py +194 -0
- tlgr/core/media.py +134 -0
- tlgr/core/output.py +251 -0
- tlgr/core/pagination.py +227 -0
- tlgr/core/paths.py +360 -0
- tlgr/core/peers.py +427 -0
- tlgr/core/process.py +138 -0
- tlgr/core/signing.py +38 -0
- tlgr/core/systemd.py +96 -0
- tlgr/core/telethon_compat.py +295 -0
- tlgr/core/text.py +211 -0
- tlgr/core/timefmt.py +199 -0
- tlgr/core/tl.py +98 -0
- tlgr/daemon/__init__.py +0 -0
- tlgr/daemon/app.py +869 -0
- tlgr/daemon/dispatch.py +446 -0
- tlgr/daemon/events.py +723 -0
- tlgr/daemon/files.py +431 -0
- tlgr/daemon/idle.py +119 -0
- tlgr/daemon/jobs.py +68 -0
- tlgr/daemon/main.py +161 -0
- tlgr/daemon/peercred.py +75 -0
- tlgr/daemon/policy.py +113 -0
- tlgr/daemon/preauth.py +366 -0
- tlgr/daemon/ratelimit.py +391 -0
- tlgr/daemon/server.py +24 -0
- tlgr/daemon/session.py +648 -0
- tlgr/daemon/sessions.py +274 -0
- tlgr/daemon/singleton.py +114 -0
- tlgr/daemon/stream.py +193 -0
- tlgr/daemon/transfers.py +219 -0
- tlgr/daemon/webhook.py +390 -0
- tlgr/data/catalog_index.json +1 -0
- tlgr/data/parity_waivers.toml +90 -0
- tlgr/filters/__init__.py +42 -0
- tlgr/filters/compose.py +121 -0
- tlgr/filters/content.py +85 -0
- tlgr/filters/context.py +114 -0
- tlgr/filters/message.py +161 -0
- tlgr/filters/temporal.py +87 -0
- tlgr/filters/user.py +36 -0
- tlgr/gateway/__init__.py +1 -0
- tlgr/gateway/config.py +161 -0
- tlgr/gateway/engine.py +215 -0
- tlgr/gateway/event.py +22 -0
- tlgr/jobs/__init__.py +0 -0
- tlgr/jobs/base.py +81 -0
- tlgr/jobs/client.py +37 -0
- tlgr/models/__init__.py +1220 -0
- tlgr/models/admin.py +744 -0
- tlgr/models/auth.py +510 -0
- tlgr/models/base.py +81 -0
- tlgr/models/bot.py +576 -0
- tlgr/models/business.py +265 -0
- tlgr/models/call.py +586 -0
- tlgr/models/config.py +101 -0
- tlgr/models/contact.py +481 -0
- tlgr/models/daemon.py +336 -0
- tlgr/models/dialog.py +626 -0
- tlgr/models/envelope.py +68 -0
- tlgr/models/error.py +30 -0
- tlgr/models/event.py +79 -0
- tlgr/models/export.py +66 -0
- tlgr/models/gift.py +275 -0
- tlgr/models/inline.py +84 -0
- tlgr/models/location.py +115 -0
- tlgr/models/media.py +507 -0
- tlgr/models/message.py +584 -0
- tlgr/models/net.py +232 -0
- tlgr/models/notify.py +105 -0
- tlgr/models/page.py +32 -0
- tlgr/models/payment.py +172 -0
- tlgr/models/peer.py +400 -0
- tlgr/models/poll.py +119 -0
- tlgr/models/premium.py +161 -0
- tlgr/models/privacy.py +93 -0
- tlgr/models/profile.py +217 -0
- tlgr/models/reaction.py +160 -0
- tlgr/models/resolve.py +175 -0
- tlgr/models/settings.py +103 -0
- tlgr/models/stars.py +101 -0
- tlgr/models/sticker.py +243 -0
- tlgr/models/story.py +467 -0
- tlgr/models/sync.py +105 -0
- tlgr/models/todo.py +36 -0
- tlgr/models/webapp.py +89 -0
- tlgr/ops/__init__.py +63 -0
- tlgr/ops/_admin.py +313 -0
- tlgr/ops/_auth.py +599 -0
- tlgr/ops/_bots.py +586 -0
- tlgr/ops/_calls.py +535 -0
- tlgr/ops/_common.py +160 -0
- tlgr/ops/_layer.py +46 -0
- tlgr/ops/_media.py +592 -0
- tlgr/ops/_params.py +212 -0
- tlgr/ops/_rights.py +402 -0
- tlgr/ops/_send.py +593 -0
- tlgr/ops/_serialize.py +667 -0
- tlgr/ops/_settings.py +306 -0
- tlgr/ops/_spec.py +167 -0
- tlgr/ops/_story.py +743 -0
- tlgr/ops/account.py +2604 -0
- tlgr/ops/agent.py +937 -0
- tlgr/ops/auth.py +1282 -0
- tlgr/ops/bot.py +4880 -0
- tlgr/ops/business.py +1520 -0
- tlgr/ops/call.py +1610 -0
- tlgr/ops/chat.py +4025 -0
- tlgr/ops/chat_admin.py +929 -0
- tlgr/ops/chat_extra.py +1061 -0
- tlgr/ops/chat_invite.py +716 -0
- tlgr/ops/chat_manage.py +1691 -0
- tlgr/ops/chat_member.py +1357 -0
- tlgr/ops/chat_stats.py +902 -0
- tlgr/ops/chat_topic.py +905 -0
- tlgr/ops/conference.py +791 -0
- tlgr/ops/config.py +1698 -0
- tlgr/ops/contact.py +2330 -0
- tlgr/ops/daemon.py +1397 -0
- tlgr/ops/draft.py +299 -0
- tlgr/ops/emoji.py +343 -0
- tlgr/ops/events.py +1327 -0
- tlgr/ops/export.py +596 -0
- tlgr/ops/folder.py +1322 -0
- tlgr/ops/gif.py +522 -0
- tlgr/ops/gift.py +1546 -0
- tlgr/ops/giveaway.py +541 -0
- tlgr/ops/inline.py +773 -0
- tlgr/ops/job.py +799 -0
- tlgr/ops/location.py +917 -0
- tlgr/ops/media.py +4495 -0
- tlgr/ops/message.py +3769 -0
- tlgr/ops/net.py +536 -0
- tlgr/ops/notify.py +840 -0
- tlgr/ops/passport.py +464 -0
- tlgr/ops/payment.py +907 -0
- tlgr/ops/poll.py +1078 -0
- tlgr/ops/premium.py +488 -0
- tlgr/ops/privacy.py +794 -0
- tlgr/ops/profile.py +1481 -0
- tlgr/ops/proxy.py +750 -0
- tlgr/ops/reaction.py +1475 -0
- tlgr/ops/resolve.py +1140 -0
- tlgr/ops/search.py +521 -0
- tlgr/ops/settings.py +1066 -0
- tlgr/ops/stars.py +594 -0
- tlgr/ops/sticker.py +1602 -0
- tlgr/ops/story.py +3216 -0
- tlgr/ops/sync.py +788 -0
- tlgr/ops/todo.py +514 -0
- tlgr/ops/user.py +1406 -0
- tlgr/ops/vc.py +2351 -0
- tlgr/ops/webapp.py +717 -0
- tlgr/ops/webhook.py +418 -0
- tlgr/parity.py +386 -0
- tlgr/processors/__init__.py +125 -0
- tlgr/processors/regex.py +26 -0
- tlgr/processors/text.py +56 -0
- tlgr/registry.py +519 -0
- tlgr/schema.py +173 -0
- tlgr/transport/__init__.py +30 -0
- tlgr/transport/autostart.py +293 -0
- tlgr/transport/client.py +805 -0
- tlgr/transport/ndjson.py +44 -0
- tlgr/version.py +31 -0
- tlgr_cli-2.0.1.dist-info/METADATA +957 -0
- tlgr_cli-2.0.1.dist-info/RECORD +192 -0
- tlgr_cli-2.0.1.dist-info/WHEEL +5 -0
- tlgr_cli-2.0.1.dist-info/entry_points.txt +2 -0
- tlgr_cli-2.0.1.dist-info/licenses/LICENSE +21 -0
- tlgr_cli-2.0.1.dist-info/top_level.txt +1 -0
tlgr/models/auth.py
ADDED
|
@@ -0,0 +1,510 @@
|
|
|
1
|
+
"""The shapes the auth, account, session, password and passport groups emit.
|
|
2
|
+
|
|
3
|
+
Three of them deserve a note, because their fields are the whole point.
|
|
4
|
+
|
|
5
|
+
* `SentCode` is a *resumable* login. Telegram's `auth.sendCode` answers with a
|
|
6
|
+
`phone_code_hash` that the next call needs, and a code *type* that decides
|
|
7
|
+
what the human should be looking at (another Telegram session, an SMS, a
|
|
8
|
+
Fragment page, an email). v1 kept both in memory and therefore had to hold
|
|
9
|
+
one process open across a human reading their phone; here they are a
|
|
10
|
+
response, so `auth send-code` and `auth verify-code` are two commands.
|
|
11
|
+
* `PasswordState` is the read side of 2-step verification and it deliberately
|
|
12
|
+
carries **no** SRP material. `srp_B`, `secure_random` and the KDF salts are
|
|
13
|
+
live cryptographic parameters; printing them buys nothing and leaks the
|
|
14
|
+
shape of the exchange, so they stop at the operation boundary.
|
|
15
|
+
* `Session` is one row of the Devices list. `deny_deadline` and
|
|
16
|
+
`sensitive_actions_eligible_at` are derived here rather than left to the
|
|
17
|
+
reader: "unconfirmed" is only actionable while the auto-confirm window is
|
|
18
|
+
open, and `SESSION_TOO_FRESH_X` is a 24-hour rule nobody can guess from
|
|
19
|
+
`date_created` alone.
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
from __future__ import annotations
|
|
23
|
+
|
|
24
|
+
from tlgr.models.base import Model
|
|
25
|
+
from tlgr.models.message import MessageEntity
|
|
26
|
+
|
|
27
|
+
__all__ = [
|
|
28
|
+
"AccountDeletion",
|
|
29
|
+
"AccountRecord",
|
|
30
|
+
"AccountState",
|
|
31
|
+
"AccountTtl",
|
|
32
|
+
"AutologinUrl",
|
|
33
|
+
"DeviceLock",
|
|
34
|
+
"LoginCodes",
|
|
35
|
+
"LoginEmail",
|
|
36
|
+
"LoginResult",
|
|
37
|
+
"Passkey",
|
|
38
|
+
"PassportDeletion",
|
|
39
|
+
"PassportForm",
|
|
40
|
+
"PassportRequirement",
|
|
41
|
+
"PassportValue",
|
|
42
|
+
"PassportVerification",
|
|
43
|
+
"PasswordReset",
|
|
44
|
+
"PasswordState",
|
|
45
|
+
"PhoneChange",
|
|
46
|
+
"QrLogin",
|
|
47
|
+
"RecoveryEmail",
|
|
48
|
+
"SentCode",
|
|
49
|
+
"Session",
|
|
50
|
+
"SessionChange",
|
|
51
|
+
"SessionTermination",
|
|
52
|
+
"SmsJobs",
|
|
53
|
+
"Suggestion",
|
|
54
|
+
"SupportInfo",
|
|
55
|
+
"TempPassword",
|
|
56
|
+
"Terms",
|
|
57
|
+
"WebSession",
|
|
58
|
+
"WebSessionRevocation",
|
|
59
|
+
]
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
# ---------------------------------------------------------------------------
|
|
63
|
+
# Logging in
|
|
64
|
+
# ---------------------------------------------------------------------------
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
class SentCode(Model):
|
|
68
|
+
"""What `auth.sendCode` (and the two phone-change flows) answered.
|
|
69
|
+
|
|
70
|
+
`type` is reported verbatim — `app`, `sms`, `sms_word`, `sms_phrase`,
|
|
71
|
+
`call`, `flash_call`, `missed_call`, `fragment`, `email`,
|
|
72
|
+
`setup_email_required` — because each one asks the human to look
|
|
73
|
+
somewhere different, and "we sent you a code" is not enough instruction
|
|
74
|
+
for any of them.
|
|
75
|
+
"""
|
|
76
|
+
|
|
77
|
+
phone: str = ""
|
|
78
|
+
code_hash: str = ""
|
|
79
|
+
type: str = ""
|
|
80
|
+
length: int | None = None
|
|
81
|
+
next_type: str | None = None
|
|
82
|
+
timeout: int | None = None
|
|
83
|
+
#: `sentCodeTypeFragmentSms.url` — the page the code is waiting on.
|
|
84
|
+
fragment_url: str | None = None
|
|
85
|
+
email_pattern: str | None = None
|
|
86
|
+
#: The first characters of a word/phrase SMS, so the human can tell which
|
|
87
|
+
#: message is the login one.
|
|
88
|
+
beginning: str | None = None
|
|
89
|
+
google_signin_allowed: bool = False
|
|
90
|
+
apple_signin_allowed: bool = False
|
|
91
|
+
reset_available_period: int | None = None
|
|
92
|
+
reset_pending_date: str | None = None
|
|
93
|
+
#: A `auth.sentCodeSuccess`: a stored future auth token matched and there
|
|
94
|
+
#: is no code to type at all.
|
|
95
|
+
already: bool = False
|
|
96
|
+
account: str = ""
|
|
97
|
+
cancelled: bool = False
|
|
98
|
+
changed: bool = False
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
class LoginResult(Model):
|
|
102
|
+
"""The terminal state of a login attempt.
|
|
103
|
+
|
|
104
|
+
`status` is one of `authorized`, `password_required`, `signup_required`.
|
|
105
|
+
The last two are *not* failures of the command, they are the next step,
|
|
106
|
+
which is why they carry the hint and the recovery pattern an agent needs
|
|
107
|
+
to take it.
|
|
108
|
+
"""
|
|
109
|
+
|
|
110
|
+
status: str = ""
|
|
111
|
+
user_id: int | None = None
|
|
112
|
+
username: str | None = None
|
|
113
|
+
alias: str = ""
|
|
114
|
+
#: `auth.authorization.setup_password_required`: Telegram will log this
|
|
115
|
+
#: session out after `otherwise_relogin_days` unless a cloud password is
|
|
116
|
+
#: set, which is a loud thing to be quiet about.
|
|
117
|
+
setup_password_required: bool = False
|
|
118
|
+
otherwise_relogin_days: int | None = None
|
|
119
|
+
hint: str | None = None
|
|
120
|
+
has_recovery: bool = False
|
|
121
|
+
email_pattern: str | None = None
|
|
122
|
+
tos_id: str | None = None
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
class QrLogin(Model):
|
|
126
|
+
"""One frame of a QR login: the token to show, and what happened to it."""
|
|
127
|
+
|
|
128
|
+
url: str = ""
|
|
129
|
+
token: str = ""
|
|
130
|
+
expires: str | None = None
|
|
131
|
+
status: str = ""
|
|
132
|
+
user_id: int | None = None
|
|
133
|
+
alias: str = ""
|
|
134
|
+
ascii: str | None = None
|
|
135
|
+
png: str | None = None
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
class LoginEmail(Model):
|
|
139
|
+
"""The login email the server demands during a pending login."""
|
|
140
|
+
|
|
141
|
+
email_pattern: str | None = None
|
|
142
|
+
verified: bool = False
|
|
143
|
+
sent_code: bool = False
|
|
144
|
+
reset_pending_date: str | None = None
|
|
145
|
+
length: int | None = None
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
class LoginCodes(Model):
|
|
149
|
+
"""Login codes Telegram delivered into the 777000 service chat."""
|
|
150
|
+
|
|
151
|
+
codes: list[str] = []
|
|
152
|
+
messages: list[str] = []
|
|
153
|
+
invalidated: list[str] = []
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
class Terms(Model):
|
|
157
|
+
"""A Terms-of-Service document and what was done about it."""
|
|
158
|
+
|
|
159
|
+
id: str | None = None
|
|
160
|
+
text: str = ""
|
|
161
|
+
entities: list[MessageEntity] = []
|
|
162
|
+
min_age_confirm: int | None = None
|
|
163
|
+
popup: bool = False
|
|
164
|
+
expires: str | None = None
|
|
165
|
+
update_available: bool = False
|
|
166
|
+
accepted: bool = False
|
|
167
|
+
declined: bool = False
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
class AccountDeletion(Model):
|
|
171
|
+
"""`account.deleteAccount`, whether it happened or started a countdown."""
|
|
172
|
+
|
|
173
|
+
deleted: bool = False
|
|
174
|
+
status: str = ""
|
|
175
|
+
wait_seconds: int | None = None
|
|
176
|
+
until: str | None = None
|
|
177
|
+
confirm_hint: str | None = None
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
# ---------------------------------------------------------------------------
|
|
181
|
+
# The local account record
|
|
182
|
+
# ---------------------------------------------------------------------------
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
class AccountRecord(Model, omit_defaults=False):
|
|
186
|
+
"""One row of `account list`.
|
|
187
|
+
|
|
188
|
+
`alias` and `name` are both here on purpose: v1 printed the alias under
|
|
189
|
+
the key `alias` and the display name under `name`, and §12.4 says a
|
|
190
|
+
documented key does not move. `omit_defaults=False` for the same reason:
|
|
191
|
+
`active: false` is an answer, and dropping it would make every row of a
|
|
192
|
+
table look ragged.
|
|
193
|
+
"""
|
|
194
|
+
|
|
195
|
+
alias: str = ""
|
|
196
|
+
name: str = ""
|
|
197
|
+
user_id: int | None = None
|
|
198
|
+
username: str | None = None
|
|
199
|
+
phone: str | None = None
|
|
200
|
+
active: bool = False
|
|
201
|
+
connected: bool = False
|
|
202
|
+
state: str = "unknown"
|
|
203
|
+
kind: str = "user"
|
|
204
|
+
created_at: str | None = None
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
class AccountState(Model):
|
|
208
|
+
"""`account info` / `account check` / `account switch` / `account rename`.
|
|
209
|
+
|
|
210
|
+
One struct for the whole local-record surface: the commands differ in
|
|
211
|
+
which subset they fill, and a reader that learns the field names once can
|
|
212
|
+
read all of them.
|
|
213
|
+
"""
|
|
214
|
+
|
|
215
|
+
alias: str = ""
|
|
216
|
+
account: str = ""
|
|
217
|
+
ok: bool = False
|
|
218
|
+
already: bool = False
|
|
219
|
+
removed: bool = False
|
|
220
|
+
server_logout: bool = False
|
|
221
|
+
logged_out: bool = False
|
|
222
|
+
future_auth_token_stored: bool = False
|
|
223
|
+
imported: bool = False
|
|
224
|
+
authorized: bool = False
|
|
225
|
+
old: str | None = None
|
|
226
|
+
new: str | None = None
|
|
227
|
+
user_id: int | None = None
|
|
228
|
+
username: str | None = None
|
|
229
|
+
first_name: str | None = None
|
|
230
|
+
phone: str | None = None
|
|
231
|
+
dc_id: int | None = None
|
|
232
|
+
premium: bool = False
|
|
233
|
+
kind: str = "user"
|
|
234
|
+
test_dc: bool = False
|
|
235
|
+
session_path: str | None = None
|
|
236
|
+
created_at: str | None = None
|
|
237
|
+
#: `account check` only.
|
|
238
|
+
state: str = ""
|
|
239
|
+
error: str | None = None
|
|
240
|
+
frozen_since: str | None = None
|
|
241
|
+
frozen_until: str | None = None
|
|
242
|
+
appeal_url: str | None = None
|
|
243
|
+
hint: str | None = None
|
|
244
|
+
#: `account sync` only.
|
|
245
|
+
dialogs: int | None = None
|
|
246
|
+
users: int | None = None
|
|
247
|
+
chats: int | None = None
|
|
248
|
+
pts: int | None = None
|
|
249
|
+
#: `account export` only.
|
|
250
|
+
format: str | None = None
|
|
251
|
+
path: str | None = None
|
|
252
|
+
session: str | None = None
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
class AccountTtl(Model):
|
|
256
|
+
"""The self-destruct timer, in days."""
|
|
257
|
+
|
|
258
|
+
days: int = 0
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
class DeviceLock(Model):
|
|
262
|
+
locked_for: int = 0
|
|
263
|
+
|
|
264
|
+
|
|
265
|
+
# ---------------------------------------------------------------------------
|
|
266
|
+
# Sessions (the Devices list)
|
|
267
|
+
# ---------------------------------------------------------------------------
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
class Session(Model):
|
|
271
|
+
"""One authorization — a device logged into this account."""
|
|
272
|
+
|
|
273
|
+
hash: str = ""
|
|
274
|
+
current: bool = False
|
|
275
|
+
official_app: bool = False
|
|
276
|
+
unconfirmed: bool = False
|
|
277
|
+
password_pending: bool = False
|
|
278
|
+
app_name: str = ""
|
|
279
|
+
app_version: str = ""
|
|
280
|
+
api_id: int | None = None
|
|
281
|
+
device_model: str = ""
|
|
282
|
+
platform: str = ""
|
|
283
|
+
system_version: str = ""
|
|
284
|
+
ip: str = ""
|
|
285
|
+
country: str = ""
|
|
286
|
+
region: str = ""
|
|
287
|
+
date_created: str | None = None
|
|
288
|
+
date_active: str | None = None
|
|
289
|
+
call_requests_disabled: bool = False
|
|
290
|
+
encrypted_requests_disabled: bool = False
|
|
291
|
+
#: `date_created + authorization_autoconfirm_period`: how long a cron
|
|
292
|
+
#: security check still has to deny an unrecognised login.
|
|
293
|
+
deny_deadline: str | None = None
|
|
294
|
+
#: `date_created + 24 h`. What `SESSION_TOO_FRESH_X` is counting down to.
|
|
295
|
+
sensitive_actions_eligible_at: str | None = None
|
|
296
|
+
#: Account-wide, repeated on every row so one `--json` read answers it.
|
|
297
|
+
ttl_days: int | None = None
|
|
298
|
+
#: A business bot connected to the account, which official clients show
|
|
299
|
+
#: in the same list.
|
|
300
|
+
bot: bool = False
|
|
301
|
+
bot_username: str | None = None
|
|
302
|
+
|
|
303
|
+
|
|
304
|
+
class SessionChange(Model):
|
|
305
|
+
hash: str = ""
|
|
306
|
+
confirmed: bool = False
|
|
307
|
+
already: bool = False
|
|
308
|
+
call_requests_disabled: bool | None = None
|
|
309
|
+
encrypted_requests_disabled: bool | None = None
|
|
310
|
+
authorization_ttl_days: int | None = None
|
|
311
|
+
#: `account session accept-qr` — the authorization that was just created.
|
|
312
|
+
device_model: str | None = None
|
|
313
|
+
app_name: str | None = None
|
|
314
|
+
ip: str | None = None
|
|
315
|
+
country: str | None = None
|
|
316
|
+
|
|
317
|
+
|
|
318
|
+
class SessionTermination(Model):
|
|
319
|
+
terminated: int = 0
|
|
320
|
+
hashes: list[str] = []
|
|
321
|
+
advice: str | None = None
|
|
322
|
+
|
|
323
|
+
|
|
324
|
+
class WebSession(Model):
|
|
325
|
+
"""A website or bot logged in through Telegram Login."""
|
|
326
|
+
|
|
327
|
+
hash: str = ""
|
|
328
|
+
bot: int | None = None
|
|
329
|
+
bot_username: str | None = None
|
|
330
|
+
domain: str = ""
|
|
331
|
+
browser: str = ""
|
|
332
|
+
platform: str = ""
|
|
333
|
+
ip: str = ""
|
|
334
|
+
region: str = ""
|
|
335
|
+
date_created: str | None = None
|
|
336
|
+
date_active: str | None = None
|
|
337
|
+
|
|
338
|
+
|
|
339
|
+
class WebSessionRevocation(Model):
|
|
340
|
+
revoked: int = 0
|
|
341
|
+
hashes: list[str] = []
|
|
342
|
+
blocked: list[int] = []
|
|
343
|
+
|
|
344
|
+
|
|
345
|
+
class Passkey(Model):
|
|
346
|
+
id: str = ""
|
|
347
|
+
name: str = ""
|
|
348
|
+
date: str | None = None
|
|
349
|
+
date_unix: int | None = None
|
|
350
|
+
last_usage_date: str | None = None
|
|
351
|
+
software_emoji_id: int | None = None
|
|
352
|
+
deleted: bool = False
|
|
353
|
+
|
|
354
|
+
|
|
355
|
+
# ---------------------------------------------------------------------------
|
|
356
|
+
# The cloud password
|
|
357
|
+
# ---------------------------------------------------------------------------
|
|
358
|
+
|
|
359
|
+
|
|
360
|
+
class PasswordState(Model):
|
|
361
|
+
"""2-step verification, as much of it as is safe to print.
|
|
362
|
+
|
|
363
|
+
Deliberately missing: `srp_B`, `srp_id`, `secure_random` and the KDF
|
|
364
|
+
salts. They are live parameters of an in-flight exchange, not status.
|
|
365
|
+
"""
|
|
366
|
+
|
|
367
|
+
has_password: bool = False
|
|
368
|
+
has_recovery: bool = False
|
|
369
|
+
has_secure_values: bool = False
|
|
370
|
+
hint: str | None = None
|
|
371
|
+
email_unconfirmed_pattern: str | None = None
|
|
372
|
+
login_email_pattern: str | None = None
|
|
373
|
+
pending_reset_date: str | None = None
|
|
374
|
+
#: Only with the password supplied: `account.getPasswordSettings`.
|
|
375
|
+
recovery_email: str | None = None
|
|
376
|
+
#: Only with `--verify`: did the supplied password check out.
|
|
377
|
+
password_ok: bool | None = None
|
|
378
|
+
#: `PASSWORD_TOO_FRESH_X` counts down to this.
|
|
379
|
+
sensitive_actions_eligible_at: str | None = None
|
|
380
|
+
changed: bool = False
|
|
381
|
+
|
|
382
|
+
|
|
383
|
+
class RecoveryEmail(Model):
|
|
384
|
+
kind: str = "recovery"
|
|
385
|
+
email_pattern: str | None = None
|
|
386
|
+
confirmed: bool = False
|
|
387
|
+
sent_code_length: int | None = None
|
|
388
|
+
cancelled: bool = False
|
|
389
|
+
resent: bool = False
|
|
390
|
+
|
|
391
|
+
|
|
392
|
+
class PasswordReset(Model):
|
|
393
|
+
"""`account.resetPassword` — the 7-day path for a password nobody has."""
|
|
394
|
+
|
|
395
|
+
status: str = ""
|
|
396
|
+
until_date: str | None = None
|
|
397
|
+
retry_date: str | None = None
|
|
398
|
+
cancelled: bool = False
|
|
399
|
+
|
|
400
|
+
|
|
401
|
+
class TempPassword(Model):
|
|
402
|
+
tmp_password: str = ""
|
|
403
|
+
valid_until: str | None = None
|
|
404
|
+
|
|
405
|
+
|
|
406
|
+
class PhoneChange(Model):
|
|
407
|
+
phone: str = ""
|
|
408
|
+
code_hash: str = ""
|
|
409
|
+
type: str = ""
|
|
410
|
+
timeout: int | None = None
|
|
411
|
+
changed: bool = False
|
|
412
|
+
confirmed: bool = False
|
|
413
|
+
cancelled: bool = False
|
|
414
|
+
resent: bool = False
|
|
415
|
+
|
|
416
|
+
|
|
417
|
+
class AutologinUrl(Model):
|
|
418
|
+
url: str = ""
|
|
419
|
+
domain_allowed: bool = False
|
|
420
|
+
|
|
421
|
+
|
|
422
|
+
class Suggestion(Model):
|
|
423
|
+
"""A server-side nudge (`SETUP_PASSKEY`, `VALIDATE_PASSWORD`, a PSA)."""
|
|
424
|
+
|
|
425
|
+
suggestion: str = ""
|
|
426
|
+
dismissible: bool = True
|
|
427
|
+
dismissed: bool = False
|
|
428
|
+
promo_peer: int | None = None
|
|
429
|
+
psa_type: str | None = None
|
|
430
|
+
hidden: bool = False
|
|
431
|
+
|
|
432
|
+
|
|
433
|
+
class SupportInfo(Model):
|
|
434
|
+
support_user: int | None = None
|
|
435
|
+
support_name: str | None = None
|
|
436
|
+
support_phone: str | None = None
|
|
437
|
+
faq_url: str | None = None
|
|
438
|
+
privacy_url: str | None = None
|
|
439
|
+
features_url: str | None = None
|
|
440
|
+
invite_text: str | None = None
|
|
441
|
+
my_link: str | None = None
|
|
442
|
+
note: str | None = None
|
|
443
|
+
author: str | None = None
|
|
444
|
+
date: str | None = None
|
|
445
|
+
date_unix: int | None = None
|
|
446
|
+
|
|
447
|
+
|
|
448
|
+
class SmsJobs(Model):
|
|
449
|
+
"""The Peer-to-Peer Login Program, control side only."""
|
|
450
|
+
|
|
451
|
+
eligible: bool = False
|
|
452
|
+
joined: bool = False
|
|
453
|
+
allow_international: bool = False
|
|
454
|
+
recent_sent: int | None = None
|
|
455
|
+
recent_since: str | None = None
|
|
456
|
+
recent_remains: int | None = None
|
|
457
|
+
terms_url: str | None = None
|
|
458
|
+
|
|
459
|
+
|
|
460
|
+
# ---------------------------------------------------------------------------
|
|
461
|
+
# Passport
|
|
462
|
+
# ---------------------------------------------------------------------------
|
|
463
|
+
|
|
464
|
+
|
|
465
|
+
class PassportValue(Model):
|
|
466
|
+
"""One stored Passport document, as metadata.
|
|
467
|
+
|
|
468
|
+
`plain_data` is the only field that can ever be filled without the
|
|
469
|
+
Passport crypto stack: phone and email secure values are stored in the
|
|
470
|
+
clear, every other type is encrypted under a secret derived from the
|
|
471
|
+
cloud password.
|
|
472
|
+
"""
|
|
473
|
+
|
|
474
|
+
type: str = ""
|
|
475
|
+
hash: str = ""
|
|
476
|
+
has_files: bool = False
|
|
477
|
+
has_translation: bool = False
|
|
478
|
+
plain_data: str | None = None
|
|
479
|
+
|
|
480
|
+
|
|
481
|
+
class PassportRequirement(Model):
|
|
482
|
+
type: str = ""
|
|
483
|
+
native_names: bool = False
|
|
484
|
+
selfie_required: bool = False
|
|
485
|
+
translation_required: bool = False
|
|
486
|
+
|
|
487
|
+
|
|
488
|
+
class PassportForm(Model):
|
|
489
|
+
"""What a service is asking for, and what of it we already hold."""
|
|
490
|
+
|
|
491
|
+
bot: int | None = None
|
|
492
|
+
required_types: list[PassportRequirement] = []
|
|
493
|
+
privacy_policy_url: str | None = None
|
|
494
|
+
values: list[PassportValue] = []
|
|
495
|
+
errors: list[str] = []
|
|
496
|
+
country_language: str | None = None
|
|
497
|
+
|
|
498
|
+
|
|
499
|
+
class PassportVerification(Model):
|
|
500
|
+
target: str = ""
|
|
501
|
+
sent: bool = False
|
|
502
|
+
verified: bool = False
|
|
503
|
+
code_length: int | None = None
|
|
504
|
+
#: Telegram will not accept the code without the hash that came with it,
|
|
505
|
+
#: and the second call is a different process.
|
|
506
|
+
code_hash: str | None = None
|
|
507
|
+
|
|
508
|
+
|
|
509
|
+
class PassportDeletion(Model):
|
|
510
|
+
deleted: list[str] = []
|
tlgr/models/base.py
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"""Shared msgspec configuration for every wire shape tlgr emits or accepts.
|
|
2
|
+
|
|
3
|
+
`models/` is the only place a wire shape is defined, and it imports nothing
|
|
4
|
+
else from tlgr — not even the error types — so that `import tlgr.models` works
|
|
5
|
+
without Telethon, without click and without a config file. The import lint in
|
|
6
|
+
`tests/test_layering.py` keeps it that way.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
from typing import Any, TypeVar, Union
|
|
12
|
+
|
|
13
|
+
import msgspec
|
|
14
|
+
|
|
15
|
+
__all__ = ["UNSET", "Model", "Request", "Unset", "decode", "encode", "to_builtins"]
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class Model(
|
|
19
|
+
msgspec.Struct,
|
|
20
|
+
kw_only=True,
|
|
21
|
+
omit_defaults=True,
|
|
22
|
+
forbid_unknown_fields=False,
|
|
23
|
+
):
|
|
24
|
+
"""A response/domain model.
|
|
25
|
+
|
|
26
|
+
Unknown fields are tolerated on decode: an older client talking to a newer
|
|
27
|
+
daemon must keep working, and dropping a field it does not understand is
|
|
28
|
+
the only forward-compatible answer.
|
|
29
|
+
|
|
30
|
+
`omit_defaults=True` keeps the JSON small and — more importantly — makes
|
|
31
|
+
"absent" meaningful: a field that is missing was not applicable or not
|
|
32
|
+
requested, a field that is `null` is known to be empty.
|
|
33
|
+
"""
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class Request(
|
|
37
|
+
msgspec.Struct,
|
|
38
|
+
kw_only=True,
|
|
39
|
+
omit_defaults=True,
|
|
40
|
+
forbid_unknown_fields=True,
|
|
41
|
+
):
|
|
42
|
+
"""An operation request.
|
|
43
|
+
|
|
44
|
+
Unknown fields are a USAGE error, the opposite of `Model`: a newer CLI must
|
|
45
|
+
not silently lose a field against an older daemon. The version handshake
|
|
46
|
+
catches the mismatch first; this is the backstop.
|
|
47
|
+
"""
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
UNSET = msgspec.UNSET
|
|
51
|
+
"""Sentinel for "the caller did not supply this field at all".
|
|
52
|
+
|
|
53
|
+
Distinct from an explicit `null`, which means "clear it". That tri-state is
|
|
54
|
+
what makes one `edit` operation able to express leave-alone, set and clear
|
|
55
|
+
without three flags per field.
|
|
56
|
+
"""
|
|
57
|
+
|
|
58
|
+
_T = TypeVar("_T")
|
|
59
|
+
|
|
60
|
+
# PEP 695's `type Unset[T] = ...` needs 3.12 and we target 3.10.
|
|
61
|
+
Unset = Union[_T, msgspec.UnsetType]
|
|
62
|
+
"""`Unset[str]` is "a string, or nothing was supplied".
|
|
63
|
+
|
|
64
|
+
`Unset[str | None]` adds "explicitly cleared" — the `| None` is what makes a
|
|
65
|
+
clear expressible at all, because `Unset[str]` alone rejects a literal null.
|
|
66
|
+
"""
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def encode(value: Any) -> bytes:
|
|
70
|
+
"""Encode any model (or builtin) to compact UTF-8 JSON."""
|
|
71
|
+
return msgspec.json.encode(value)
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def decode(data: bytes | str, type: type[_T]) -> _T:
|
|
75
|
+
"""Decode JSON into *type*, raising `msgspec.ValidationError` on a mismatch."""
|
|
76
|
+
return msgspec.json.decode(data, type=type)
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def to_builtins(value: Any) -> Any:
|
|
80
|
+
"""Convert a model tree to plain dicts/lists, honouring `omit_defaults`."""
|
|
81
|
+
return msgspec.to_builtins(value)
|