Skip to main content

schul_cloud_api/requests/
chats.rs

1use crate::errors::Errors;
2use crate::request_types::about::RSAPublicKey;
3use crate::request_types::{chats, AuthOnlyRequest};
4use crate::requests::about::get_other_user_info;
5use crate::requests::post_request;
6use crate::state::State;
7use crate::types::chats::channels::Channel;
8use crate::types::chats::conversations::Conversation;
9use crate::types::chats::messages::{File, Message, PossibleSender};
10use crate::types::user::others::User;
11use crate::Result;
12use base64::Engine;
13use openssl::rsa::Padding;
14use openssl::symm::{decrypt, Cipher};
15use std::fmt::{Display, Formatter};
16
17pub async fn get_channels(state: &State, company_id: impl ToString) -> Result<Vec<Channel>> {
18    Ok(post_request::<chats::ChannelsResponse>(state,
19                                               "/channels/subscripted",
20                                               chats::ChannelRequest::new(state, company_id.to_string())?)
21        .await?.channels)
22}
23pub async fn get_conversations(state: &State, limit: usize, offset: usize, archive: usize, sorting: Vec<String>) -> Result<Vec<Conversation>> {
24    Ok(post_request::<chats::ConversationResponse>(state,
25                                               "/message/conversations",
26                                               chats::ConversationsRequest::new(state, limit, offset, archive, sorting)?)
27        .await?.conversations)
28}
29
30pub async fn get_messages(state: &State, id: String, chat_type: ChatType, limit: usize, offset: usize, key: Option<Vec<u8>>) -> Result<Vec<Message>> {
31    let mut messages = post_request::<chats::MessageResponse>(state,
32                                                          "/message/content",
33                                                          chats::MessageRequest::new(state, id, chat_type.to_string(), limit, offset)?)
34        .await?.messages;
35    let _ = messages.iter_mut().map(|m| m.original_text = m.text.clone()).collect::<Vec<()>>();
36    let Some(key) = key else {
37        return Ok(messages);
38    };
39    for message in &mut messages {
40        if message.encrypted != Some(true) || message.text.is_none() || message.text == Some("".to_string()) {
41            continue;
42        }
43        let encrypted = hex::decode(message.text.clone().unwrap()).map_err(|e| Errors::HexError(e))?;
44        let iv_ = match &message.iv {
45            Some(iv) => Some(hex::decode(iv).map_err(|e| Errors::HexError(e))?),
46            None => None,
47        };
48        let iv = match &iv_ {
49            Some(iv) => Some(&**iv),
50            None => None
51        };
52        let decrypted = decrypt(Cipher::aes_256_cbc(), &*key, iv, &*encrypted)
53            .map_err(|e| Errors::EncryptionError(e))?;
54        let text = String::from_utf8(decrypted).map_err(|e| Errors::StringDecodeError(e))?;
55        message.text = Some(text);
56    }
57    Ok(messages)
58}
59pub async fn download_file(state: &State, key: Option<Vec<u8>>, file: File) -> Result<Vec<u8>> {
60    let raw_data = reqwest::Client::new()
61        .post(state.build_url("/file/download"))
62        .query(&chats::FileDownloadQuery { id: file.id })
63        .form(&AuthOnlyRequest::new(state)?)
64        .send().await
65        .map_err(|e| Errors::RequestError(e))?
66        .bytes().await
67        .map_err(|e| Errors::RequestError(e))?
68        .to_vec();
69    if !file.encrypted || key.is_none() {
70        return Ok(raw_data);
71    }
72    let iv_ = match file.e2e_iv {
73        Some(iv) => Some(hex::decode(iv).map_err(|e| Errors::HexError(e))?),
74        None => None
75    };
76    let iv = match &iv_ {
77        Some(iv) => Some(&**iv),
78        None => None,
79    };
80    decrypt(Cipher::aes_256_cbc(), key.unwrap().as_ref(), iv, &*raw_data)
81        .map_err(|e| Errors::EncryptionError(e))
82}
83#[cfg(feature = "experimental")]
84pub async fn verify_signature(state: &State, message: &Message) -> Result<bool> {
85    if message.verification.is_none() {
86        return Ok(true);
87    }
88    let sender_id = match &message.sender {
89        PossibleSender::MessageSender(s) => s.id.clone().unwrap(),
90        PossibleSender::String(_s) => return Err(Errors::OtherErrors("Can't verify hash of unknown sender.".to_string()))
91    };
92    let target = hex::decode(message.verification.clone().unwrap())?;
93    let user_info: User = get_other_user_info(state, sender_id).await?;
94    let rsa_key = RSAPublicKey::from_str(&*user_info.public_signing_key)?.to_key()?;
95    let key = openssl::pkey::PKey::from_rsa(rsa_key.clone())?;
96    let data = message.text.clone().unwrap().into_bytes();
97    if message.encrypted == Some(true) {
98        hex::decode(message.original_text.clone().unwrap())?
99    } else {
100        message.original_text.clone().unwrap().into_bytes()
101    };
102    let target_hash = base64::engine::general_purpose::STANDARD.decode(message.hash.clone().unwrap())?;
103    let generated_hash = openssl::hash::hash(openssl::hash::MessageDigest::sha256(), &*data)?.to_vec();
104    println!("{}", generated_hash == target_hash);
105    let mut buff = vec![0; rsa_key.size() as usize];
106    let buff_len = rsa_key.public_decrypt(&*generated_hash, &mut buff, Padding::NONE)?;
107    buff.truncate(buff_len);
108    println!("{}", buff == target);
109    println!("{:?}", buff);
110    println!("{buff_len}");
111
112    let mut verifier = openssl::sign::Verifier::new(openssl::hash::MessageDigest::sha256(), &key)?;
113    verifier.update(&*data)?;
114    let res = verifier.verify(&*target).map_err(Errors::from);
115    res
116}
117pub enum ChatType {
118    Channel,
119    Conversation,
120}
121impl Display for ChatType {
122    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
123        write!(f, "{}", match self {
124            ChatType::Channel => "channel",
125            ChatType::Conversation => "conversation",
126        })
127    }
128}