utils.rs 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. use std::{str::FromStr as _, time::Duration};
  2. use url::Url;
  3. use utils::{binary::checksum, serialize::Serialize as _};
  4. use crate::{API_DEFAULT_PORT, message::Message};
  5. #[derive(Debug)]
  6. pub enum UrlError {
  7. ParseError(url::ParseError),
  8. DomainBasePortError,
  9. }
  10. pub fn fix_url(url: &str) -> Result<String, UrlError> {
  11. let mut url: String = url.to_string();
  12. if !url.starts_with("http://") && !url.starts_with("https://") {
  13. url = format!("http://{}", url);
  14. }
  15. let mut url = Url::from_str(&url).map_err(|x| UrlError::ParseError(x))?;
  16. if url.port().is_none() {
  17. url.set_port(Some(API_DEFAULT_PORT)).map_err(|_| UrlError::DomainBasePortError)?;
  18. }
  19. let mut url = url.to_string();
  20. if !url.ends_with('/') {
  21. url.push('/');
  22. }
  23. Ok(url)
  24. }
  25. #[derive(Debug)]
  26. pub enum ConnectionError {
  27. UrlError(UrlError),
  28. ReqwestError(reqwest::Error),
  29. StatusCodeError(u16),
  30. }
  31. pub fn tx_message(host: &str, password: &str, timeout_sec: u64, mut message: Message) -> Result<(), ConnectionError> {
  32. message.sanitize();
  33. let url = fix_url(host)
  34. .map_err(|x| ConnectionError::UrlError(x))?;
  35. let mut bytes = message.serialize_checked();
  36. utils::aes::encrypt_cbc(&mut bytes, &password);
  37. bytes.push(checksum(&bytes));
  38. let str = utils::binary::bin2hex(bytes);
  39. let resp = reqwest::blocking::Client::new()
  40. .post(url)
  41. .body(str)
  42. .timeout(Duration::from_secs(timeout_sec))
  43. .send()
  44. .map_err(|e| ConnectionError::ReqwestError(e))?;
  45. if resp.status().is_success() {
  46. Ok(())
  47. } else {
  48. Err(ConnectionError::StatusCodeError(resp.status().as_u16()))
  49. }
  50. }
  51. pub fn rx_messages(host: &str, password: &str, timeout_sec: u64) -> Result<Vec<Message>, ConnectionError> {
  52. let url = fix_url(host)
  53. .map_err(|x| ConnectionError::UrlError(x))?;
  54. let resp = reqwest::blocking::Client::new()
  55. .get(url)
  56. .timeout(Duration::from_secs(timeout_sec))
  57. .send()
  58. .map_err(|x| ConnectionError::ReqwestError(x))?;
  59. if resp.status() != reqwest::StatusCode::OK {
  60. return Err(ConnectionError::StatusCodeError(resp.status().as_u16()));
  61. }
  62. let bytes = resp.bytes()
  63. .map_err(|e| ConnectionError::ReqwestError(e))?;
  64. let contents = String::from_utf8_lossy(&bytes);
  65. let mut messages = vec![];
  66. for message_ser_hex in contents.split(",") {
  67. let Some(mut message_ser_bin) = utils::binary::hex2bin(message_ser_hex) else {
  68. continue;
  69. };
  70. if message_ser_bin.len() < 2 {
  71. continue;
  72. }
  73. // Checksum before decryption
  74. if checksum(&message_ser_bin[..message_ser_bin.len()-1]) != message_ser_bin[message_ser_bin.len()-1] {
  75. continue;
  76. }
  77. // Remove checksum
  78. message_ser_bin.pop();
  79. if utils::aes::decrypt_cbc(&mut message_ser_bin, &password).is_err() {
  80. continue;
  81. }
  82. let Ok(mut message) = Message::deserialize_checked(message_ser_bin) else {
  83. continue;
  84. };
  85. if message.is_valid() {
  86. message.sanitize();
  87. messages.push(message);
  88. }
  89. }
  90. Ok(messages)
  91. }
  92. #[test]
  93. fn test_tx_rx() {
  94. let host = "http://localhost:13337/";
  95. let password = "null";
  96. let message = Message::new("Alice", "Hello", "root");
  97. tx_message(host, password, 5, message.clone()).expect("Failed to send message");
  98. let messages = rx_messages(host, password, 5).expect("Failed to receive messages");
  99. assert_eq!(messages.len(), 1);
  100. assert_eq!(messages[0].sender, message.sender);
  101. assert_eq!(messages[0].content, message.content);
  102. }