1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
// Copyright 2020 - developers of the `grammers` project. // // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or // https://www.apache.org/licenses/LICENSE-2.0> or the MIT license // <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your // option. This file may not be copied, modified, or distributed // except according to those terms. use crate::errors::DeserializeError; use grammers_tl_types::{Cursor, Deserializable, Serializable}; /// An implementation of the [Mobile Transport Protocol] for plaintext /// (unencrypted) messages. /// /// The reason to separate the plaintext and encrypted implementations /// for serializing messages is that, even though they are similar, the /// benefits outweight some minor code reuse. /// /// This way, the encryption key for [`Mtp`] is mandatory so errors /// for trying to encrypt data without a key are completely eliminated. /// /// Also, the plaintext part of the protocol does not need to deal with /// the complexity of the full protocol once encrypted messages are used, /// so being able to keep a simpler implementation separate is a bonus. /// /// [Mobile Transport Protocol]: https://core.telegram.org/mtproto /// [`Mtp`]: struct.Mtp.html #[non_exhaustive] pub struct PlainMtp; impl PlainMtp { pub fn new() -> Self { Self } /// Wraps a request's data into a plain message (also known as /// [unencrypted messages]), and returns its serialized contents. /// /// Plain messages may be used for requests that don't require an /// authorization key to be present, such as those needed to generate /// the authorization key itself. /// /// [unencrypted messages]: https://core.telegram.org/mtproto/description#unencrypted-message pub fn serialize_plain_message(&mut self, body: &[u8]) -> Vec<u8> { let mut buf = Vec::with_capacity(body.len() + 8 + 8 + 4); 0i64.serialize(&mut buf); // Even though https://core.telegram.org/mtproto/samples-auth_key // seems to imply the `msg_id` has to follow some rules, there is // no need to generate a valid `msg_id`, it seems. Just use `0`. 0i64.serialize(&mut buf); (body.len() as u32).serialize(&mut buf); buf.extend(body); buf } /// Validates that the returned data is a correct plain message, and /// if it is, the method returns the inner contents of the message. /// /// [`serialize_plain_message`]: #method.serialize_plain_message pub fn deserialize_plain_message<'a>( &self, message: &'a [u8], ) -> Result<&'a [u8], DeserializeError> { crate::utils::check_message_buffer(message)?; let mut buf = Cursor::from_slice(message); let auth_key_id = i64::deserialize(&mut buf)?; if auth_key_id != 0 { return Err(DeserializeError::BadAuthKey { got: auth_key_id, expected: 0, }); } let msg_id = i64::deserialize(&mut buf)?; // We can't validate it's close to our system time because our sytem // time may be wrong at this point (it only matters once encrypted // communication begins). However, we can validate the following: // // > server message identifiers modulo 4 yield 1 if // > the message is a response to a client message // https://core.telegram.org/mtproto/description#message-identifier-msg-id if msg_id <= 0 || (msg_id % 4) != 1 { return Err(DeserializeError::BadMessageId { got: msg_id }); } let len = i32::deserialize(&mut buf)?; if len <= 0 { return Err(DeserializeError::NegativeMessageLength { got: len }); } if (20 + len) as usize > message.len() { return Err(DeserializeError::TooLongMessageLength { got: len as usize, max_length: message.len() - 20, }); } Ok(&message[20..20 + len as usize]) } }