1use std::collections::HashMap;
32use std::fs;
33use std::io::{self, Read, Write};
34use std::net::TcpStream;
35use std::path::Path;
36use std::time::Duration;
37
38use layer_mtproto::transport::{AbridgedTransport, Transport};
39use layer_mtproto::{EncryptedSession, Session, authentication as auth};
40use layer_tl_types::{Cursor, Deserializable, RemoteCall};
41
42pub use error::Error;
43pub use sign_in_error::{SignInError, PasswordToken};
44pub use login::LoginToken;
45
46const DC_ADDRESSES: &[(i32, &str)] = &[
49 (1, "149.154.175.53:443"),
50 (2, "149.154.167.51:443"),
51 (3, "149.154.175.100:443"),
52 (4, "149.154.167.91:443"),
53 (5, "91.108.56.130:443"),
54];
55
56const ID_RPC_RESULT: u32 = 0xf35c6d01;
59const ID_RPC_ERROR: u32 = 0x2144ca19;
60const ID_MSG_CONTAINER: u32 = 0x73f1f8dc;
61const ID_GZIP_PACKED: u32 = 0x3072cfa1;
62const ID_PONG: u32 = 0x347773c5;
63const ID_MSGS_ACK: u32 = 0x62d6b459;
64const ID_BAD_SERVER_SALT: u32 = 0xedab447b;
65const ID_NEW_SESSION: u32 = 0x9ec20908;
66const ID_BAD_MSG_NOTIFY: u32 = 0xa7eff811;
67
68mod error {
71 use std::io;
72
73 #[derive(Debug)]
74 pub enum Error {
75 Io(io::Error),
76 Auth(layer_mtproto::authentication::Error),
77 Decrypt(layer_mtproto::encrypted::DecryptError),
78 Tl(layer_tl_types::deserialize::Error),
79 Rpc { code: i32, message: String },
81 Proto(&'static str),
82 }
83
84 impl std::fmt::Display for Error {
85 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
86 match self {
87 Self::Io(e) => write!(f, "IO: {e}"),
88 Self::Auth(e) => write!(f, "DH: {e}"),
89 Self::Decrypt(e) => write!(f, "Decrypt: {e}"),
90 Self::Tl(e) => write!(f, "TL: {e}"),
91 Self::Rpc { code, message } => write!(f, "RPC {code}: {message}"),
92 Self::Proto(s) => write!(f, "Protocol: {s}"),
93 }
94 }
95 }
96 impl std::error::Error for Error {}
97
98 impl From<io::Error> for Error { fn from(e: io::Error) -> Self { Self::Io(e) } }
99 impl From<layer_mtproto::authentication::Error> for Error { fn from(e: layer_mtproto::authentication::Error) -> Self { Self::Auth(e) } }
100 impl From<layer_mtproto::encrypted::DecryptError> for Error { fn from(e: layer_mtproto::encrypted::DecryptError) -> Self { Self::Decrypt(e) } }
101 impl From<layer_tl_types::deserialize::Error> for Error { fn from(e: layer_tl_types::deserialize::Error) -> Self { Self::Tl(e) } }
102}
103
104mod sign_in_error {
107 use super::Error;
108
109 pub struct PasswordToken {
111 pub(crate) password: layer_tl_types::types::account::Password,
112 }
113
114 impl PasswordToken {
115 pub fn hint(&self) -> Option<&str> {
117 self.password.hint.as_deref()
118 }
119 }
120
121 #[derive(Debug)]
125 pub enum SignInError {
126 SignUpRequired,
128 PasswordRequired(PasswordToken),
130 InvalidCode,
132 Other(Error),
134 }
135
136 impl std::fmt::Display for SignInError {
137 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
138 match self {
139 Self::SignUpRequired => write!(f, "sign up required — use official app"),
140 Self::PasswordRequired(_) => write!(f, "2FA password required"),
141 Self::InvalidCode => write!(f, "invalid or expired code"),
142 Self::Other(e) => write!(f, "{e}"),
143 }
144 }
145 }
146 impl std::error::Error for SignInError {}
147 impl From<Error> for SignInError { fn from(e: Error) -> Self { Self::Other(e) } }
148
149 impl std::fmt::Debug for PasswordToken {
150 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
151 write!(f, "PasswordToken {{ hint: {:?} }}", self.hint())
152 }
153 }
154}
155
156mod login {
159 pub struct LoginToken {
162 pub(crate) phone: String,
163 pub(crate) phone_code_hash: String,
164 }
165}
166
167mod two_factor_auth {
170 use hmac::Hmac;
171 use num_bigint::{BigInt, Sign};
172 use num_traits::ops::euclid::Euclid;
173 use sha2::{Digest, Sha256, Sha512};
174
175 fn sha256(parts: &[&[u8]]) -> [u8; 32] {
176 let mut h = Sha256::new();
177 for p in parts { h.update(p); }
178 h.finalize().into()
179 }
180
181 fn sh(data: &[u8], salt: &[u8]) -> [u8; 32] {
182 sha256(&[salt, data, salt])
183 }
184
185 fn ph1(password: &[u8], salt1: &[u8], salt2: &[u8]) -> [u8; 32] {
186 sh(&sh(password, salt1), salt2)
187 }
188
189 fn ph2(password: &[u8], salt1: &[u8], salt2: &[u8]) -> [u8; 32] {
190 let hash1 = ph1(password, salt1, salt2);
191 let mut dk = [0u8; 64];
192 pbkdf2::pbkdf2::<Hmac<Sha512>>(&hash1, salt1, 100_000, &mut dk).unwrap();
193 sh(&dk, salt2)
194 }
195
196 fn pad256(data: &[u8]) -> [u8; 256] {
197 let mut out = [0u8; 256];
198 let start = 256usize.saturating_sub(data.len());
199 out[start..].copy_from_slice(&data[data.len().saturating_sub(256)..]);
200 out
201 }
202
203 fn xor32(a: &[u8; 32], b: &[u8; 32]) -> [u8; 32] {
204 let mut out = [0u8; 32];
205 for i in 0..32 { out[i] = a[i] ^ b[i]; }
206 out
207 }
208
209 pub fn calculate_2fa(
212 salt1: &[u8],
213 salt2: &[u8],
214 p: &[u8],
215 g: i32,
216 g_b: &[u8],
217 a: &[u8],
218 password: impl AsRef<[u8]>,
219 ) -> ([u8; 32], [u8; 256]) {
220 let big_p = BigInt::from_bytes_be(Sign::Plus, p);
221 let g_b = pad256(g_b);
222 let a = pad256(a);
223 let g_hash = pad256(&[g as u8]);
224
225 let big_g_b = BigInt::from_bytes_be(Sign::Plus, &g_b);
226 let big_g = BigInt::from(g as u32);
227 let big_a = BigInt::from_bytes_be(Sign::Plus, &a);
228
229 let k = sha256(&[p, &g_hash]);
231 let big_k = BigInt::from_bytes_be(Sign::Plus, &k);
232
233 let g_a = big_g.modpow(&big_a, &big_p);
235 let g_a = pad256(&g_a.to_bytes_be().1);
236
237 let u = sha256(&[&g_a, &g_b]);
239 let big_u = BigInt::from_bytes_be(Sign::Plus, &u);
240
241 let x = ph2(password.as_ref(), salt1, salt2);
243 let big_x = BigInt::from_bytes_be(Sign::Plus, &x);
244
245 let big_v = big_g.modpow(&big_x, &big_p);
247 let big_kv = (big_k * big_v) % &big_p;
248
249 let big_t = (big_g_b - big_kv).rem_euclid(&big_p);
251
252 let exp = big_a + big_u * big_x;
254 let big_sa = big_t.modpow(&exp, &big_p);
255
256 let k_a = sha256(&[&pad256(&big_sa.to_bytes_be().1)]);
258
259 let h_p = sha256(&[p]);
261 let h_g = sha256(&[&g_hash]);
262 let p_xg = xor32(&h_p, &h_g);
263 let m1 = sha256(&[&p_xg, &sha256(&[salt1]), &sha256(&[salt2]), &g_a, &g_b, &k_a]);
264
265 (m1, g_a)
266 }
267}
268
269#[derive(Clone)]
272struct DcOption {
273 addr: String,
274 auth_key: Option<[u8; 256]>,
275}
276
277struct PersistedSession { home_dc_id: i32, dcs: Vec<PersistedDc> }
280struct PersistedDc { dc_id: i32, auth_key: Option<[u8;256]>, first_salt: i64, time_offset: i32, addr: String }
281
282impl PersistedSession {
283 fn save(&self, path: &Path) -> io::Result<()> {
284 let mut b = Vec::new();
285 b.extend_from_slice(&self.home_dc_id.to_le_bytes());
286 b.push(self.dcs.len() as u8);
287 for d in &self.dcs {
288 b.extend_from_slice(&d.dc_id.to_le_bytes());
289 if let Some(k) = &d.auth_key { b.push(1); b.extend_from_slice(k); } else { b.push(0); }
290 b.extend_from_slice(&d.first_salt.to_le_bytes());
291 b.extend_from_slice(&d.time_offset.to_le_bytes());
292 let ab = d.addr.as_bytes(); b.push(ab.len() as u8); b.extend_from_slice(ab);
293 }
294 fs::write(path, b)
295 }
296
297 fn load(path: &Path) -> io::Result<Self> {
298 let buf = fs::read(path)?;
299 let mut p = 0usize;
300 macro_rules! r { ($n:expr) => {{ if p+$n > buf.len() { return Err(io::Error::new(io::ErrorKind::InvalidData,"truncated")); } let s=&buf[p..p+$n]; p+=$n; s }}; }
301 let home_dc_id = i32::from_le_bytes(r!(4).try_into().unwrap());
302 let dc_count = r!(1)[0] as usize;
303 let mut dcs = Vec::with_capacity(dc_count);
304 for _ in 0..dc_count {
305 let dc_id = i32::from_le_bytes(r!(4).try_into().unwrap());
306 let has_key = r!(1)[0];
307 let auth_key = if has_key==1 { let mut k=[0u8;256]; k.copy_from_slice(r!(256)); Some(k) } else { None };
308 let first_salt = i64::from_le_bytes(r!(8).try_into().unwrap());
309 let time_offset = i32::from_le_bytes(r!(4).try_into().unwrap());
310 let al = r!(1)[0] as usize;
311 let addr = String::from_utf8_lossy(r!(al)).into_owned();
312 dcs.push(PersistedDc { dc_id, auth_key, first_salt, time_offset, addr });
313 }
314 Ok(Self { home_dc_id, dcs })
315 }
316}
317
318struct Tcp(TcpStream);
321impl Tcp {
322 fn connect(addr: &str) -> io::Result<Self> {
323 let s = TcpStream::connect(addr)?;
324 s.set_read_timeout(Some(Duration::from_secs(90)))?;
325 s.set_write_timeout(Some(Duration::from_secs(10)))?;
326 Ok(Self(s))
327 }
328}
329impl Transport for Tcp {
330 type Error = io::Error;
331 fn send(&mut self, data: &[u8]) -> io::Result<()> { self.0.write_all(data) }
332 fn recv(&mut self) -> io::Result<Vec<u8>> {
333 let mut f=[0u8;1]; self.0.read_exact(&mut f)?;
334 let words = if f[0]<0x7f { f[0] as usize }
335 else { let mut b=[0u8;3]; self.0.read_exact(&mut b)?; b[0] as usize|(b[1] as usize)<<8|(b[2] as usize)<<16 };
336 let mut buf=vec![0u8;words*4]; self.0.read_exact(&mut buf)?; Ok(buf)
337 }
338}
339
340struct Connection { transport: AbridgedTransport<Tcp>, enc: EncryptedSession }
343
344impl Connection {
345 fn connect_raw(addr: &str) -> Result<Self, Error> {
347 let tcp = Tcp::connect(addr)?;
348 let mut tr = AbridgedTransport::new(tcp);
349 let mut plain = Session::new();
350
351 let (req1, s1) = auth::step1()?;
352 tr.send_message(&plain.pack(&req1).to_plaintext_bytes())?;
353 let res_pq: layer_tl_types::enums::ResPq = recv_plain(&mut tr)?;
354
355 let (req2, s2) = auth::step2(s1, res_pq)?;
356 tr.send_message(&plain.pack(&req2).to_plaintext_bytes())?;
357 let dh: layer_tl_types::enums::ServerDhParams = recv_plain(&mut tr)?;
358
359 let (req3, s3) = auth::step3(s2, dh)?;
360 tr.send_message(&plain.pack(&req3).to_plaintext_bytes())?;
361 let ans: layer_tl_types::enums::SetClientDhParamsAnswer = recv_plain(&mut tr)?;
362
363 let done = auth::finish(s3, ans)?;
364 Ok(Self { transport: tr, enc: EncryptedSession::new(done.auth_key, done.first_salt, done.time_offset) })
365 }
366
367 fn connect_with_key(addr: &str, auth_key: [u8;256], first_salt: i64, time_offset: i32) -> Result<Self, Error> {
370 let tcp = Tcp::connect(addr)?;
371 Ok(Self { transport: AbridgedTransport::new(tcp), enc: EncryptedSession::new(auth_key, first_salt, time_offset) })
372 }
373
374 fn auth_key_bytes(&self) -> [u8;256] { self.enc.auth_key_bytes() }
375 fn first_salt(&self) -> i64 { self.enc.salt }
376 fn time_offset(&self) -> i32 { self.enc.time_offset }
377
378 fn rpc_call<R: RemoteCall>(&mut self, req: &R) -> Result<Vec<u8>, Error> {
379 let wire = self.enc.pack(req);
380 self.transport.send_message(&wire)?;
381 self.recv_rpc()
382 }
383
384 fn recv_rpc(&mut self) -> Result<Vec<u8>, Error> {
385 loop {
386 let mut raw = match self.transport.recv_message() {
387 Ok(r) => r,
388 Err(e) if e.kind()==io::ErrorKind::WouldBlock || e.kind()==io::ErrorKind::TimedOut => continue,
389 Err(e) if e.kind()==io::ErrorKind::UnexpectedEof
390 || e.kind()==io::ErrorKind::ConnectionReset
391 || e.kind()==io::ErrorKind::ConnectionAborted => {
392 return Err(Error::Proto("server closed the connection"));
393 }
394 Err(e) => return Err(e.into()),
395 };
396 let msg = self.enc.unpack(&mut raw)?;
397 if msg.salt != 0 { self.enc.salt = msg.salt; }
398 match unwrap_envelope(msg.body)? {
399 Some(p) => return Ok(p),
400 None => continue,
401 }
402 }
403 }
404}
405
406pub struct Client {
409 conn: Connection,
410 home_dc_id: i32,
411 dc_options: HashMap<i32, DcOption>,
412 api_id: i32,
413 api_hash: String,
414}
415
416impl Client {
417 pub fn connect(dc_addr: &str, api_id: i32, api_hash: &str) -> Result<Self, Error> {
424 eprintln!("[layer] Connecting to {dc_addr} …");
425 let conn = Connection::connect_raw(dc_addr)?;
426 eprintln!("[layer] DH complete ✓");
427 let mut client = Self {
428 conn, home_dc_id: 2,
429 dc_options: bootstrap_dc_options(),
430 api_id, api_hash: api_hash.to_string(),
431 };
432 client.init_and_get_config()?;
433 Ok(client)
434 }
435
436 pub fn load_or_connect(session_path: impl AsRef<Path>, api_id: i32, api_hash: &str) -> Result<Self, Error> {
441 let path = session_path.as_ref();
442 if path.exists() {
443 match PersistedSession::load(path) {
444 Ok(s) => {
445 if let Some(dc) = s.dcs.iter().find(|d| d.dc_id == s.home_dc_id) {
446 if let Some(key) = dc.auth_key {
447 eprintln!("[layer] Loading session (DC{}) …", s.home_dc_id);
448 let conn = Connection::connect_with_key(&dc.addr, key, dc.first_salt, dc.time_offset)?;
449 let mut dc_options = bootstrap_dc_options();
450 for d in &s.dcs {
451 dc_options.insert(d.dc_id, DcOption { addr: d.addr.clone(), auth_key: d.auth_key });
452 }
453 let mut client = Self { conn, home_dc_id: s.home_dc_id, dc_options, api_id, api_hash: api_hash.to_string() };
454 client.init_and_get_config()?;
455 eprintln!("[layer] Session restored ✓");
456 return Ok(client);
457 }
458 }
459 eprintln!("[layer] Session incomplete — connecting fresh …");
460 }
461 Err(e) => eprintln!("[layer] Session load failed ({e}) — connecting fresh …"),
462 }
463 }
464 Self::connect("149.154.167.51:443", api_id, api_hash)
465 }
466
467 pub fn save_session(&self, path: impl AsRef<Path>) -> Result<(), Error> {
471 let dcs = self.dc_options.iter().map(|(&dc_id, opt)| PersistedDc {
472 dc_id,
473 auth_key: opt.auth_key,
474 first_salt: if dc_id==self.home_dc_id { self.conn.first_salt() } else { 0 },
475 time_offset: if dc_id==self.home_dc_id { self.conn.time_offset() } else { 0 },
476 addr: opt.addr.clone(),
477 }).collect();
478 PersistedSession { home_dc_id: self.home_dc_id, dcs }.save(path.as_ref())?;
479 eprintln!("[layer] Session saved ✓");
480 Ok(())
481 }
482
483 pub fn is_authorized(&mut self) -> Result<bool, Error> {
488 match self.conn.rpc_call(&layer_tl_types::functions::updates::GetState {}) {
489 Ok(_) => Ok(true),
490 Err(Error::Rpc { code: 401, .. }) => Ok(false),
491 Err(e) => Err(e),
492 }
493 }
494
495 pub fn request_login_code(&mut self, phone: &str) -> Result<LoginToken, Error> {
498 use layer_tl_types::enums::auth::SentCode;
499 let req = self.make_send_code_req(phone);
500 let body = match self.conn.rpc_call(&req) {
501 Ok(b) => b,
502 Err(Error::Rpc { code: 303, message }) => {
503 let dc = parse_migrate_dc(&message)
504 .ok_or_else(|| Error::Rpc { code: 303, message: message.clone() })?;
505 eprintln!("[layer] PHONE_MIGRATE_{dc} — reconnecting …");
506 self.migrate_to(dc)?;
507 self.conn.rpc_call(&req)?
508 }
509 Err(e) => return Err(e),
510 };
511 let mut cur = Cursor::from_slice(&body);
512 let (hash, kind) = match layer_tl_types::enums::auth::SentCode::deserialize(&mut cur)? {
513 SentCode::SentCode(c) => (c.phone_code_hash, sent_code_type_name(&c.r#type)),
514 SentCode::Success(_) => return Err(Error::Proto("unexpected SentCode::Success")),
515 SentCode::PaymentRequired(_) => return Err(Error::Proto("payment required")),
516 };
517 eprintln!("[layer] Code sent via {kind}");
518 Ok(LoginToken { phone: phone.to_string(), phone_code_hash: hash })
519 }
520
521 pub fn sign_in(&mut self, token: &LoginToken, code: &str) -> Result<String, SignInError> {
529 let req = layer_tl_types::functions::auth::SignIn {
530 phone_number: token.phone.clone(),
531 phone_code_hash: token.phone_code_hash.clone(),
532 phone_code: Some(code.trim().to_string()),
533 email_verification: None,
534 };
535
536 let body = match self.conn.rpc_call(&req) {
537 Ok(b) => b,
538 Err(Error::Rpc { code: 303, message }) => {
540 let dc = parse_migrate_dc(&message)
541 .ok_or_else(|| Error::Rpc { code: 303, message: message.clone() })?;
542 eprintln!("[layer] USER_MIGRATE_{dc} — reconnecting …");
543 self.migrate_to(dc).map_err(SignInError::Other)?;
544 self.conn.rpc_call(&req).map_err(SignInError::Other)?
545 }
546 Err(Error::Rpc { message, .. }) if message.contains("SESSION_PASSWORD_NEEDED") => {
548 let pw_token = self.get_password_info().map_err(SignInError::Other)?;
549 return Err(SignInError::PasswordRequired(pw_token));
550 }
551 Err(Error::Rpc { message, .. }) if message.starts_with("PHONE_CODE") => {
553 return Err(SignInError::InvalidCode);
554 }
555 Err(e) => return Err(SignInError::Other(e)),
556 };
557
558 let mut cur = Cursor::from_slice(&body);
559 match layer_tl_types::enums::auth::Authorization::deserialize(&mut cur).map_err(|e| SignInError::Other(e.into()))? {
560 layer_tl_types::enums::auth::Authorization::Authorization(a) => {
561 let name = extract_user_name(&a.user);
562 eprintln!("[layer] Signed in ✓ Welcome, {name}!");
563 Ok(name)
564 }
565 layer_tl_types::enums::auth::Authorization::SignUpRequired(_) =>
566 Err(SignInError::SignUpRequired),
567 }
568 }
569
570 pub fn check_password(&mut self, password_token: PasswordToken, password: impl AsRef<[u8]>) -> Result<String, Error> {
575 let pw = password_token.password;
576 let algo = pw.current_algo.ok_or(Error::Proto("no current_algo in Password"))?;
577
578 let (salt1, salt2, p, g) = extract_password_params(&algo)?;
579
580 let g_b = pw.srp_b.ok_or(Error::Proto("no srp_b in Password"))?;
581 let a = pw.secure_random; let srp_id = pw.srp_id.ok_or(Error::Proto("no srp_id in Password"))?;
583
584 let (m1, g_a) = two_factor_auth::calculate_2fa(salt1, salt2, p, g, &g_b, &a, password.as_ref());
585
586 let req = layer_tl_types::functions::auth::CheckPassword {
587 password: layer_tl_types::enums::InputCheckPasswordSrp::InputCheckPasswordSrp(
588 layer_tl_types::types::InputCheckPasswordSrp {
589 srp_id,
590 a: g_a.to_vec(),
591 m1: m1.to_vec(),
592 },
593 ),
594 };
595
596 let body = self.conn.rpc_call(&req)?;
597 let mut cur = Cursor::from_slice(&body);
598 match layer_tl_types::enums::auth::Authorization::deserialize(&mut cur)? {
599 layer_tl_types::enums::auth::Authorization::Authorization(a) => {
600 let name = extract_user_name(&a.user);
601 eprintln!("[layer] 2FA ✓ Welcome, {name}!");
602 Ok(name)
603 }
604 layer_tl_types::enums::auth::Authorization::SignUpRequired(_) =>
605 Err(Error::Proto("unexpected SignUpRequired after 2FA")),
606 }
607 }
608
609 pub fn send_message(&mut self, peer: &str, text: &str) -> Result<(), Error> {
613 let input_peer = match peer {
614 "me" | "self" => layer_tl_types::enums::InputPeer::PeerSelf,
615 _ => return Err(Error::Proto("only \"me\" supported — resolve peer first")),
616 };
617 let req = layer_tl_types::functions::messages::SendMessage {
618 no_webpage: false, silent: false, background: false, clear_draft: false,
619 noforwards: false, update_stickersets_order: false, invert_media: false,
620 allow_paid_floodskip: false, peer: input_peer, reply_to: None,
621 message: text.to_string(), random_id: random_i64(),
622 reply_markup: None, entities: None, schedule_date: None,
623 schedule_repeat_period: None, send_as: None, quick_reply_shortcut: None,
624 effect: None, allow_paid_stars: None, suggested_post: None,
625 };
626 eprintln!("[layer] Sending message to {peer} …");
627 self.conn.rpc_call(&req)?;
628 eprintln!("[layer] Message sent ✓");
629 Ok(())
630 }
631
632 pub fn invoke<R: RemoteCall>(&mut self, req: &R) -> Result<R::Return, Error> {
636 let body = self.conn.rpc_call(req)?;
637 let mut cur = Cursor::from_slice(&body);
638 Ok(R::Return::deserialize(&mut cur)?)
639 }
640
641 fn init_and_get_config(&mut self) -> Result<(), Error> {
648 use layer_tl_types::functions::{InvokeWithLayer, InitConnection, help::GetConfig};
649 let req = InvokeWithLayer {
650 layer: layer_tl_types::LAYER,
651 query: InitConnection {
652 api_id: self.api_id,
653 device_model: "Linux".to_string(),
654 system_version: "1.0".to_string(),
655 app_version: "0.1.0".to_string(),
656 system_lang_code: "en".to_string(),
657 lang_pack: "".to_string(),
658 lang_code: "en".to_string(),
659 proxy: None,
660 params: None,
661 query: GetConfig {},
662 },
663 };
664 let wire = self.conn.enc.pack_serializable(&req);
665 self.conn.transport.send_message(&wire)?;
666 let body = self.conn.recv_rpc()?;
667 let mut cur = Cursor::from_slice(&body);
668 if let Ok(layer_tl_types::enums::Config::Config(cfg)) =
669 layer_tl_types::enums::Config::deserialize(&mut cur)
670 {
671 self.update_dc_options(&cfg.dc_options);
672 eprintln!("[layer] initConnection ✓ ({} DCs known)", self.dc_options.len());
673 } else {
674 eprintln!("[layer] initConnection ✓");
675 }
676 Ok(())
677 }
678
679 fn update_dc_options(&mut self, options: &[layer_tl_types::enums::DcOption]) {
683 for opt in options {
684 let layer_tl_types::enums::DcOption::DcOption(o) = opt;
685 if o.media_only || o.cdn || o.tcpo_only || o.ipv6 { continue; }
686 let addr = format!("{}:{}", o.ip_address, o.port);
687 self.dc_options.entry(o.id)
688 .or_insert_with(|| DcOption { addr: addr.clone(), auth_key: None })
689 .addr = addr.clone();
690 }
691 }
692
693 fn migrate_to(&mut self, new_dc_id: i32) -> Result<(), Error> {
696 let addr = self.dc_options.get(&new_dc_id)
697 .map(|o| o.addr.clone())
698 .or_else(|| DC_ADDRESSES.iter().find(|(id,_)| *id==new_dc_id).map(|(_,a)| a.to_string()))
699 .unwrap_or_else(|| "149.154.167.51:443".to_string());
700
701 eprintln!("[layer] Migrating to DC{new_dc_id} ({addr}) …");
702
703 let saved_key = self.dc_options.get(&new_dc_id).and_then(|o| o.auth_key);
704 let conn = if let Some(key) = saved_key {
705 Connection::connect_with_key(&addr, key, 0, 0)?
706 } else {
707 Connection::connect_raw(&addr)?
708 };
709
710 let new_key = conn.auth_key_bytes();
712 self.dc_options.entry(new_dc_id)
713 .or_insert_with(|| DcOption { addr: addr.clone(), auth_key: None })
714 .auth_key = Some(new_key);
715
716 self.conn = conn;
717 self.home_dc_id = new_dc_id;
718 self.init_and_get_config()?;
719 eprintln!("[layer] Now on DC{new_dc_id} ✓");
720 Ok(())
721 }
722
723 fn get_password_info(&mut self) -> Result<PasswordToken, Error> {
726 let body = self.conn.rpc_call(&layer_tl_types::functions::account::GetPassword {})?;
727 let mut cur = Cursor::from_slice(&body);
728 let pw: layer_tl_types::types::account::Password =
729 match layer_tl_types::enums::account::Password::deserialize(&mut cur)? {
730 layer_tl_types::enums::account::Password::Password(p) => p,
731 };
732 Ok(PasswordToken { password: pw })
733 }
734
735 fn make_send_code_req(&self, phone: &str) -> layer_tl_types::functions::auth::SendCode {
736 layer_tl_types::functions::auth::SendCode {
737 phone_number: phone.to_string(),
738 api_id: self.api_id,
739 api_hash: self.api_hash.clone(),
740 settings: layer_tl_types::enums::CodeSettings::CodeSettings(
741 layer_tl_types::types::CodeSettings {
742 allow_flashcall: false, current_number: false, allow_app_hash: false,
743 allow_missed_call: false, allow_firebase: false, unknown_number: false,
744 logout_tokens: None, token: None, app_sandbox: None,
745 },
746 ),
747 }
748 }
749}
750
751fn unwrap_envelope(body: Vec<u8>) -> Result<Option<Vec<u8>>, Error> {
754 if body.len() < 4 { return Err(Error::Proto("body < 4 bytes")); }
755 let cid = u32::from_le_bytes(body[..4].try_into().unwrap());
756 match cid {
757 ID_RPC_RESULT => {
758 if body.len() < 12 { return Err(Error::Proto("rpc_result too short")); }
759 unwrap_envelope(body[12..].to_vec())
760 }
761 ID_RPC_ERROR => {
762 if body.len() < 8 { return Err(Error::Proto("rpc_error too short")); }
763 let code = i32::from_le_bytes(body[4..8].try_into().unwrap());
764 let message = tl_read_string(&body[8..])?;
765 Err(Error::Rpc { code, message })
766 }
767 ID_MSG_CONTAINER => {
768 if body.len() < 8 { return Err(Error::Proto("container too short")); }
769 let count = u32::from_le_bytes(body[4..8].try_into().unwrap()) as usize;
770 let mut pos = 8usize;
771 let mut found: Option<Vec<u8>> = None;
772 for _ in 0..count {
773 if pos+16 > body.len() { break; }
774 let inner_len = u32::from_le_bytes(body[pos+12..pos+16].try_into().unwrap()) as usize;
775 pos += 16;
776 if pos+inner_len > body.len() { break; }
777 let inner = body[pos..pos+inner_len].to_vec();
778 pos += inner_len;
779 if let Some(p) = unwrap_envelope(inner)? { found = Some(p); }
780 }
781 Ok(found)
782 }
783 ID_GZIP_PACKED => {
784 let bytes = tl_read_bytes(&body[4..])?;
785 unwrap_envelope(gz_inflate(&bytes)?)
786 }
787 ID_PONG | ID_MSGS_ACK | ID_NEW_SESSION | ID_BAD_SERVER_SALT | ID_BAD_MSG_NOTIFY => Ok(None),
788 _ => Ok(Some(body)),
789 }
790}
791
792fn recv_plain<T: Deserializable>(tr: &mut AbridgedTransport<Tcp>) -> Result<T, Error> {
795 let raw = tr.recv_message()?;
796 if raw.len() < 20 { return Err(Error::Proto("plaintext frame too short")); }
797 if u64::from_le_bytes(raw[..8].try_into().unwrap()) != 0 {
798 return Err(Error::Proto("expected auth_key_id=0 in plaintext frame"));
799 }
800 let body_len = u32::from_le_bytes(raw[16..20].try_into().unwrap()) as usize;
801 let mut cur = Cursor::from_slice(&raw[20..20+body_len]);
802 Ok(T::deserialize(&mut cur)?)
803}
804
805fn bootstrap_dc_options() -> HashMap<i32, DcOption> {
808 DC_ADDRESSES.iter().map(|(id,addr)| (*id, DcOption { addr: addr.to_string(), auth_key: None })).collect()
809}
810
811fn parse_migrate_dc(msg: &str) -> Option<i32> {
813 msg.rsplit('_').next()?.parse().ok()
814}
815
816fn extract_password_params(algo: &layer_tl_types::enums::PasswordKdfAlgo)
817 -> Result<(&[u8], &[u8], &[u8], i32), Error>
818{
819 match algo {
820 layer_tl_types::enums::PasswordKdfAlgo::Sha256Sha256Pbkdf2Hmacsha512iter100000Sha256ModPow(a) => {
821 Ok((&a.salt1, &a.salt2, &a.p, a.g))
822 }
823 _ => Err(Error::Proto("unsupported password KDF algorithm")),
824 }
825}
826
827fn random_i64() -> i64 {
828 let mut b = [0u8;8]; getrandom::getrandom(&mut b).expect("getrandom"); i64::from_le_bytes(b)
829}
830
831fn tl_read_bytes(data: &[u8]) -> Result<Vec<u8>, Error> {
832 if data.is_empty() { return Ok(vec![]); }
833 let (len, start) = if data[0]<254 { (data[0] as usize, 1) }
834 else if data.len()>=4 { (data[1] as usize|(data[2] as usize)<<8|(data[3] as usize)<<16, 4) }
835 else { return Err(Error::Proto("TL bytes header truncated")); };
836 if data.len()<start+len { return Err(Error::Proto("TL bytes body truncated")); }
837 Ok(data[start..start+len].to_vec())
838}
839
840fn tl_read_string(data: &[u8]) -> Result<String, Error> {
841 tl_read_bytes(data).map(|b| String::from_utf8_lossy(&b).into_owned())
842}
843
844fn gz_inflate(data: &[u8]) -> Result<Vec<u8>, Error> {
845 use std::io::Read;
846 let mut out = Vec::new();
847 if flate2::read::GzDecoder::new(data).read_to_end(&mut out).is_ok() && !out.is_empty() { return Ok(out); }
848 out.clear();
849 flate2::read::ZlibDecoder::new(data).read_to_end(&mut out).map_err(|_| Error::Proto("gzip failed"))?;
850 Ok(out)
851}
852
853fn extract_user_name(user: &layer_tl_types::enums::User) -> String {
854 match user {
855 layer_tl_types::enums::User::User(u) =>
856 format!("{} {}", u.first_name.as_deref().unwrap_or(""), u.last_name.as_deref().unwrap_or("")).trim().to_string(),
857 layer_tl_types::enums::User::Empty(_) => "(unknown)".into(),
858 }
859}
860
861fn sent_code_type_name(t: &layer_tl_types::enums::auth::SentCodeType) -> &'static str {
862 use layer_tl_types::enums::auth::SentCodeType::*;
863 match t {
864 App(_) => "Telegram app", Sms(_) => "SMS", Call(_) => "phone call",
865 FlashCall(_) => "flash call", MissedCall(_) => "missed call",
866 FragmentSms(_) => "Fragment SMS", FirebaseSms(_) => "Firebase SMS",
867 EmailCode(_) => "email code", SetUpEmailRequired(_) => "email setup required",
868 SmsWord(_) => "SMS word", SmsPhrase(_) => "SMS phrase",
869 }
870}