1#![allow(dead_code)]
2use base64::Engine;
3use base64::engine::general_purpose::STANDARD as BASE64;
4use openssl::pkey::{PKey, Private, Public};
5use openssl::rsa::{Padding, Rsa};
6use crate::Result;
7use rand::distr::Alphanumeric;
8use rand::Rng;
9use crate::errors::Errors;
10
11#[derive(Debug, Clone)]
12pub struct EncryptionState {
13 private_key: Rsa<Private>,
14 public_key: Rsa<Public>,
15 private_signing_key: Rsa<Private>,
16 public_signing_key: Rsa<Public>,
17}
18impl EncryptionState {
19 pub fn new(private_encryption_key: Rsa<Private>, public_encryption_key: Rsa<Public>, private_signing_key: Rsa<Private>, public_signing_key: Rsa<Public>) -> Self {
20 Self {
21 private_key: private_encryption_key,
22 public_key: public_encryption_key,
23 private_signing_key,
24 public_signing_key
25 }
26 }
27 pub fn decrypt(&self, key: String) -> Result<Vec<u8>> {
28 let encrypted_data = BASE64.decode(key).map_err(|e| Errors::Base64Error(e))?;
29 let mut result = vec![0; encrypted_data.len()];
30 let decrypted_len = self.private_key.private_decrypt(&*encrypted_data, &mut *result, Padding::PKCS1_OAEP).map_err(|e| Errors::EncryptionError(e))?;
31 result.truncate(decrypted_len);
32 Ok(result)
33 }
34 pub fn encrypt(&self, data: Vec<u8>) -> Result<Vec<u8>> {
35 let mut result = vec![0; self.private_key.size() as usize];
36 let encrypted_len = self.private_key.private_encrypt(&*data, &mut *result, Padding::PKCS1_OAEP).map_err(|e| Errors::EncryptionError(e))?;
37 result.truncate(encrypted_len);
38 Ok(result)
39 }
40 #[cfg(feature = "experimental")]
41 pub fn sign(&self, data: Vec<u8>) -> Result<String> {
42 let key = PKey::from_rsa(self.private_key.clone())?;
43 let mut signer = openssl::sign::Signer::new(openssl::hash::MessageDigest::sha256(), &key)?;
44 signer.update(&*data)?;
45 Ok(BASE64.encode(signer.sign_to_vec()?))
46 }
47}
48#[derive(Clone, Debug)]
49pub struct State {
50 pub(crate) base_url: String,
51 pub device_id: String,
52 pub client_key: Option<String>,
53}
54impl State {
55 pub fn build_url(&self, path: impl ToString) -> String {
56 let path = path.to_string();
57 let base = if self.base_url.ends_with('/') {
58 self.base_url.clone()
59 } else {
60 self.base_url.clone() + "/"
61 };
62 base + path.trim_start_matches("/")
63 }
64 pub(crate) fn expect_client_key(&self) -> Result<String> {
65 self.client_key.clone().ok_or(Errors::NotAuthenticated)
66 }
67 pub(crate) fn get_device_id(&self) -> String {self.device_id.clone()}
68}
69impl State {
70 pub fn new(base_url: String, device_id: String, client_key: Option<String>) -> Self {
71 let base_url = if base_url.starts_with("http://") || base_url.starts_with("https://") {
72 base_url
73 } else {
74 "https://".to_string() + &base_url
75 };
76 Self {
77 base_url,
78 device_id,
79 client_key,
80 }
81 }
82}
83impl Default for State {
84 fn default() -> Self {
85 Self {
86 base_url: "https://api.stashcat.com/".into(),
87 device_id: rand::rng().sample_iter(&Alphanumeric).take(32).map(char::from).collect(),
88 client_key: None,
89 }
90 }
91}