1use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
2use std::io::Read;
3use std::io::Write;
4
5use messages::Message;
6use Result;
7
8use rand::rngs::OsRng;
9use rand::RngCore;
10
11mod basic_blob;
12mod logon_blob;
13pub use self::basic_blob::BasicBlob;
14pub use self::logon_blob::LogonBlob;
15
16#[cfg(feature = "wasm")]
17use wasm_bindgen::prelude::*;
18
19#[cfg_attr(feature = "wasm", wasm_bindgen)]
20#[cfg_attr(feature = "ser", derive(Serialize, Deserialize))]
21#[derive(Debug, PartialEq, Eq, Clone)]
22pub struct SrdBlob {
23    blob_type: String,
24    data: Vec<u8>,
25}
26
27#[cfg(feature = "wasm")]
28#[wasm_bindgen]
29impl SrdBlob {
30    pub fn new_logon(username: &str, password: &str) -> SrdBlob {
31        let logon = LogonBlob::new(username, password);
32        let mut data = Vec::new();
33        logon.write_to(&mut data).unwrap();
34        SrdBlob {
35            blob_type: "Logon".to_string(),
36            data,
37        }
38    }
39}
40
41#[cfg_attr(feature = "wasm", wasm_bindgen)]
42impl SrdBlob {
43    pub fn new(blob_type: &str, data: &[u8]) -> SrdBlob {
44        SrdBlob {
45            blob_type: blob_type.to_string(),
46            data: Vec::from(data),
47        }
48    }
49
50    pub fn blob_type_copy(&self) -> String {
51        self.blob_type.clone()
52    }
53
54    pub fn data_copy(&self) -> Vec<u8> {
55        self.data.clone()
56    }
57}
58
59impl SrdBlob {
60    pub fn blob_type(&self) -> &str {
61        &self.blob_type
62    }
63
64    pub fn data(&self) -> &[u8] {
65        &self.data
66    }
67}
68
69impl Message for SrdBlob {
70    fn read_from<R: Read>(reader: &mut R) -> Result<Self>
71    where
72        Self: Sized,
73    {
74        let type_size = reader.read_u16::<LittleEndian>()?;
75        let type_padding = reader.read_u16::<LittleEndian>()?;
76        let data_size = reader.read_u16::<LittleEndian>()?;
77        let data_padding = reader.read_u16::<LittleEndian>()?;
78
79        let length = type_size - 1;
80        let mut string = vec![0u8; length as usize];
81        reader.read_exact(&mut string)?;
82        reader.read_u8()?; let mut padding = vec![0u8; type_padding as usize];
84        reader.read_exact(&mut padding)?;
85        let blob_type: String = string.iter().map(|c| *c as char).collect();
86
87        let mut data = vec![0u8; data_size as usize];
88        reader.read_exact(&mut data)?;
89        let mut padding = vec![0u8; data_padding as usize];
90        reader.read_exact(&mut padding)?;
91
92        Ok(SrdBlob { blob_type, data })
93    }
94
95    fn write_to<W: Write>(&self, writer: &mut W) -> Result<()> {
96        let type_size = self.blob_type.len() + 1;
97        let type_padding = 16 - (type_size + 8) % 16;
98        let data_size = self.data.len();
99        let data_padding = 16 - (data_size % 16);
100
101        writer.write_u16::<LittleEndian>(type_size as u16)?;
102        writer.write_u16::<LittleEndian>(type_padding as u16)?;
103        writer.write_u16::<LittleEndian>(data_size as u16)?;
104        writer.write_u16::<LittleEndian>(data_padding as u16)?;
105
106        writer.write_all(&self.blob_type.chars().map(|c| c as u8).collect::<Vec<u8>>())?;
107        writer.write_u8(0u8)?;
108
109        let mut padding = vec![0u8; type_padding];
110        OsRng.fill_bytes(&mut padding);
111        writer.write_all(&padding)?;
112
113        writer.write_all(&self.data)?;
114
115        let mut padding = vec![0u8; data_padding];
116        OsRng.fill_bytes(&mut padding);
117        writer.write_all(&padding)?;
118
119        Ok(())
120    }
121}
122
123pub trait Blob: Message {
124    fn blob_type() -> &'static str;
125}
126
127#[cfg(test)]
128mod test {
129    use blobs::SrdBlob;
130    use messages::Message;
131    use std;
132
133    #[test]
134    fn blob_encoding() {
135        let srd_blob = SrdBlob::new("Basic", &vec![0, 1, 2, 3]);
136
137        let mut buffer: Vec<u8> = Vec::new();
138        match srd_blob.write_to(&mut buffer) {
139            Ok(_) => (),
140            Err(_) => assert!(false),
141        };
142
143        let mut cursor = std::io::Cursor::new(buffer.as_slice());
144        match SrdBlob::read_from(&mut cursor) {
145            Ok(blob) => {
146                assert_eq!(blob, srd_blob);
147            }
148            Err(_) => assert!(false),
149        };
150    }
151}