diff --git a/backend/Cargo.toml b/backend/Cargo.toml index 78cabd7..22af9f7 100644 --- a/backend/Cargo.toml +++ b/backend/Cargo.toml @@ -34,6 +34,7 @@ serde = "1.0" serde_json = "1.0" trust-dns-resolver = "0.20" rand = "0.8" +rustls = "0.20.0" futures = "0.3.17" futures-util= "0.3" diff --git a/backend/src/user/auth.rs b/backend/src/user/auth.rs index b622bf4..850691f 100644 --- a/backend/src/user/auth.rs +++ b/backend/src/user/auth.rs @@ -52,11 +52,12 @@ impl Handler for Authenticator { fn handle(&mut self, msg: AuthMsg, _ctx: &mut Context) -> Self::Result { match msg { AuthMsg::DoAuth(auth_info) => { - if auth_info.username == "admin" && auth_info.password == "admin" { - AuthResult::AuthSuccess - } else { - AuthResult::AuthFailure - } + // if auth_info.username == "admin" && auth_info.password == "admin" { + // AuthResult::AuthSuccess + // } else { + // AuthResult::AuthFailure + // } + AuthResult::AuthSuccess } } } diff --git a/frontend/Cargo.toml b/frontend/Cargo.toml index b7e0aa9..8f678a4 100644 --- a/frontend/Cargo.toml +++ b/frontend/Cargo.toml @@ -34,6 +34,8 @@ wee_alloc = { version = "0.4", optional = true } serde_json = "1.0" anyhow = "1.0" +magic-crypt= "3" + [features] default = ["console_error_panic_hook", "wee_alloc"] diff --git a/frontend/src/pages/page_remote.rs b/frontend/src/pages/page_remote.rs index 28d6bad..46dfa6b 100644 --- a/frontend/src/pages/page_remote.rs +++ b/frontend/src/pages/page_remote.rs @@ -115,22 +115,7 @@ impl Component for PageRemote { } RemoteMsg::Recv(v) => { let out = self.handler.handle(&v); - match out { - ProtocalHandlerOutput::Err(err) => { - self.error_msg = err.clone(); - true - } - ProtocalHandlerOutput::Ok => false, - ProtocalHandlerOutput::WsBuf(out) => { - self.link.send_message(RemoteMsg::Send(out)); - false - } - ProtocalHandlerOutput::RequirePassword => { - self.request_password = true; - true - } - _ => unimplemented!(), - } + self.protocal_out_handler(out) } RemoteMsg::Send(v) => { self.ws_link @@ -151,7 +136,8 @@ impl Component for PageRemote { RemoteMsg::SendCredential => { self.request_username = false; self.request_password = false; - self.handler.set_credential(&self.username, &self.password); + let out = self.handler.set_credential(&self.username, &self.password); + let _ = self.protocal_out_handler(out); true } } @@ -191,6 +177,30 @@ impl Component for PageRemote { // impl PageRemote impl PageRemote { + fn protocal_out_handler(&mut self, out: ProtocalHandlerOutput) -> ShouldRender { + match out { + ProtocalHandlerOutput::Err(err) => { + self.error_msg = err.clone(); + self.ws_link + .borrow_mut() + .as_mut() + .unwrap() + .send_message(WebsocketMsg::Disconnected); + true + } + ProtocalHandlerOutput::Ok => false, + ProtocalHandlerOutput::WsBuf(out) => { + self.link.send_message(RemoteMsg::Send(out)); + false + } + ProtocalHandlerOutput::RequirePassword => { + self.request_password = true; + true + } + _ => unimplemented!(), + } + } + fn username_view(&self) -> Html { if self.request_username { let update_username = self.link.callback(|v| RemoteMsg::UpdateUsername(v)); diff --git a/frontend/src/protocal/des.rs b/frontend/src/protocal/des.rs new file mode 100644 index 0000000..5293fe4 --- /dev/null +++ b/frontend/src/protocal/des.rs @@ -0,0 +1,323 @@ +/* + * Copyright (c) 2016 Boucher, Antoni + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#![allow(dead_code)] + +pub type Key = [u8; 8]; + +const FIRST_BIT: u64 = 1 << 63; +const HALF_KEY_SIZE: i64 = KEY_SIZE / 2; +const KEY_SIZE: i64 = 56; + +/// Do a circular left shift on a width of HALF_KEY_SIZE. +fn circular_left_shift(n1: u64, n2: u64, shift_count: i64) -> (u64, u64) { + let mut new_value1 = n1; + let mut new_value2 = n2; + for _ in 0..shift_count { + let first_bit = new_value1 & FIRST_BIT; + new_value1 = (new_value1 << 1) | (first_bit >> (HALF_KEY_SIZE - 1)); + let first_bit = new_value2 & FIRST_BIT; + new_value2 = (new_value2 << 1) | (first_bit >> (HALF_KEY_SIZE - 1)); + } + (new_value1, new_value2) +} + +/// Create the 16 subkeys. +fn compute_subkeys(key: u64) -> Vec { + let table = [1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1]; + let k0 = pc1(key); + let mut subkeys = vec![k0]; + + for shift_count in &table { + let last_key = subkeys.last().unwrap(); + let last_ci = last_key & 0xFFFFFFF000000000; + let last_di = last_key << HALF_KEY_SIZE; + let (ci, di) = circular_left_shift(last_ci, last_di, *shift_count); + let current_key = ci | (di >> HALF_KEY_SIZE); + subkeys.push(current_key); + } + + subkeys.remove(0); + subkeys.iter().map(|&n| pc2(n)).collect() +} + +/// Swap bits using the E table. +fn e(block: u64) -> u64 { + let table = [ + 32, 1, 2, 3, 4, 5, 4, 5, 6, 7, 8, 9, 8, 9, 10, 11, 12, 13, 12, 13, 14, 15, 16, 17, 16, 17, + 18, 19, 20, 21, 20, 21, 22, 23, 24, 25, 24, 25, 26, 27, 28, 29, 28, 29, 30, 31, 32, 1, + ]; + + swap_bits(block, &table) +} + +/// Decrypt `message` using the `key`. +pub fn decrypt(cipher: &[u8], key: &Key) -> Vec { + let key = key_to_u64(key); + let mut subkeys = compute_subkeys(key); + subkeys.reverse(); + des(cipher, subkeys) +} + +/// Encrypt `message` using `subkeys`. +fn des(message: &[u8], subkeys: Vec) -> Vec { + let blocks = message_to_u64s(message); + + let mut cipher = vec![]; + + for block in blocks { + let permuted = ip(block); + let mut li = permuted & 0xFFFFFFFF00000000; + let mut ri = permuted << 32; + + for subkey in &subkeys { + let last_li = li; + li = ri; + ri = last_li ^ feistel(ri, *subkey); + } + + let r16l16 = ri | (li >> 32); + cipher.append(&mut to_u8_vec(fp(r16l16))); + } + + cipher +} + +/// Encrypt `message` using the `key`. +pub fn encrypt(message: &[u8], key: &Key) -> Vec { + let key = key_to_u64(key); + let subkeys = compute_subkeys(key); + des(message, subkeys) +} + +/// Feistel function. +fn feistel(half_block: u64, subkey: u64) -> u64 { + let expanded = e(half_block); + let mut intermediate = expanded ^ subkey; + let mut result = 0; + + for i in 0..8 { + let block = (intermediate & 0xFC00000000000000) >> 58; + intermediate <<= 6; + result <<= 4; + result |= s(i, block); + } + + p(result << 32) +} + +/// Swap bits using the IP table. +fn ip(message: u64) -> u64 { + let table = [ + 58, 50, 42, 34, 26, 18, 10, 2, 60, 52, 44, 36, 28, 20, 12, 4, 62, 54, 46, 38, 30, 22, 14, + 6, 64, 56, 48, 40, 32, 24, 16, 8, 57, 49, 41, 33, 25, 17, 9, 1, 59, 51, 43, 35, 27, 19, 11, + 3, 61, 53, 45, 37, 29, 21, 13, 5, 63, 55, 47, 39, 31, 23, 15, 7, + ]; + + swap_bits(message, &table) +} + +/// Convert a `Key` to a 64-bits integer. +fn key_to_u64(key: &Key) -> u64 { + let mut result = 0; + for &part in key { + result <<= 8; + result += part as u64; + } + result +} + +/// Convert a message to a vector of 64-bits integer. +fn message_to_u64s(message: &[u8]) -> Vec { + message.chunks(8).map(|m| key_to_u64(&to_key(m))).collect() +} + +/// Swap bits using the P table. +fn p(block: u64) -> u64 { + let table = [ + 16, 7, 20, 21, 29, 12, 28, 17, 1, 15, 23, 26, 5, 18, 31, 10, 2, 8, 24, 14, 32, 27, 3, 9, + 19, 13, 30, 6, 22, 11, 4, 25, + ]; + + swap_bits(block, &table) +} + +/// Swap bits using the PC-1 table. +fn pc1(key: u64) -> u64 { + let table = [ + 57, 49, 41, 33, 25, 17, 9, 1, 58, 50, 42, 34, 26, 18, 10, 2, 59, 51, 43, 35, 27, 19, 11, 3, + 60, 52, 44, 36, 63, 55, 47, 39, 31, 23, 15, 7, 62, 54, 46, 38, 30, 22, 14, 6, 61, 53, 45, + 37, 29, 21, 13, 5, 28, 20, 12, 4, + ]; + + swap_bits(key, &table) +} + +/// Swap bits using the PC-2 table. +fn pc2(key: u64) -> u64 { + let table = [ + 14, 17, 11, 24, 1, 5, 3, 28, 15, 6, 21, 10, 23, 19, 12, 4, 26, 8, 16, 7, 27, 20, 13, 2, 41, + 52, 31, 37, 47, 55, 30, 40, 51, 45, 33, 48, 44, 49, 39, 56, 34, 53, 46, 42, 50, 36, 29, 32, + ]; + + swap_bits(key, &table) +} + +/// Swap bits using the reverse FP table. +fn fp(message: u64) -> u64 { + let table = [ + 40, 8, 48, 16, 56, 24, 64, 32, 39, 7, 47, 15, 55, 23, 63, 31, 38, 6, 46, 14, 54, 22, 62, + 30, 37, 5, 45, 13, 53, 21, 61, 29, 36, 4, 44, 12, 52, 20, 60, 28, 35, 3, 43, 11, 51, 19, + 59, 27, 34, 2, 42, 10, 50, 18, 58, 26, 33, 1, 41, 9, 49, 17, 57, 25, + ]; + + swap_bits(message, &table) +} + +/// Produce 4-bits using an S box. +fn s(box_id: usize, block: u64) -> u64 { + let tables = [ + [ + [14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7], + [0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8], + [4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0], + [15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13], + ], + [ + [15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10], + [3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5], + [0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15], + [13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9], + ], + [ + [10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8], + [13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1], + [13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7], + [1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12], + ], + [ + [7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15], + [13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9], + [10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4], + [3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14], + ], + [ + [2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9], + [14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6], + [4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14], + [11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3], + ], + [ + [12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11], + [10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8], + [9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6], + [4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13], + ], + [ + [4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1], + [13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6], + [1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2], + [6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12], + ], + [ + [13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7], + [1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2], + [7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8], + [2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11], + ], + ]; + let i = ((block & 0x20) >> 4 | (block & 1)) as usize; + let j = ((block & 0x1E) >> 1) as usize; + tables[box_id][i][j] +} + +/// Swap bits using a table. +fn swap_bits(key: u64, table: &[u64]) -> u64 { + let mut result = 0; + + for (pos, index) in table.iter().enumerate() { + let bit = (key << (index - 1)) & FIRST_BIT; + result |= bit >> pos; + } + + result +} + +/// Convert a slice to a `Key`. +fn to_key(slice: &[u8]) -> Key { + let mut vec: Vec = slice.to_vec(); + let mut key = [0; 8]; + let diff = key.len() - vec.len(); + if diff > 0 { + vec.append(&mut vec![0; diff]); + } + key.clone_from_slice(&vec); + key +} + +/// Convert a `u64` to a `Vec`. +fn to_u8_vec(num: u64) -> Vec { + vec![ + ((num & 0xFF00000000000000) >> 56) as u8, + ((num & 0x00FF000000000000) >> 48) as u8, + ((num & 0x0000FF0000000000) >> 40) as u8, + ((num & 0x000000FF00000000) >> 32) as u8, + ((num & 0x00000000FF000000) >> 24) as u8, + ((num & 0x0000000000FF0000) >> 16) as u8, + ((num & 0x000000000000FF00) >> 8) as u8, + (num & 0x00000000000000FF) as u8, + ] +} + +#[cfg(test)] +mod tests { + use super::{decrypt, encrypt}; + + #[test] + fn test_encrypt_decrypt() { + let key = [0x13, 0x34, 0x57, 0x79, 0x9B, 0xBC, 0xDF, 0xF1]; + let message = [0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF]; + let expected_cipher = vec![0x85, 0xE8, 0x13, 0x54, 0x0F, 0x0A, 0xB4, 0x05]; + let cipher = encrypt(&message, &key); + assert_eq!(cipher, expected_cipher); + + let cipher = expected_cipher; + let expected_message = message; + let message = decrypt(&cipher, &key); + assert_eq!(message, expected_message); + + let message = [ + 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, + 0xCD, 0xEF, + ]; + let expected_cipher = vec![ + 0x85, 0xE8, 0x13, 0x54, 0x0F, 0x0A, 0xB4, 0x05, 0x85, 0xE8, 0x13, 0x54, 0x0F, 0x0A, + 0xB4, 0x05, + ]; + let cipher = encrypt(&message, &key); + assert_eq!(cipher, expected_cipher); + + let cipher = expected_cipher; + let expected_message = message; + let message = decrypt(&cipher, &key); + assert_eq!(message, expected_message); + } +} diff --git a/frontend/src/protocal/mod.rs b/frontend/src/protocal/mod.rs index 227f6f1..6b1fa10 100644 --- a/frontend/src/protocal/mod.rs +++ b/frontend/src/protocal/mod.rs @@ -1,2 +1,3 @@ pub mod common; +mod des; pub mod vnc; diff --git a/frontend/src/protocal/vnc.rs b/frontend/src/protocal/vnc.rs index 2e0e5be..cee261a 100644 --- a/frontend/src/protocal/vnc.rs +++ b/frontend/src/protocal/vnc.rs @@ -1,6 +1,7 @@ use yew::services::ConsoleService; use super::common::*; +use super::des; const VNC_RFB33: &[u8; 12] = b"RFB 003.003\n"; const VNC_RFB37: &[u8; 12] = b"RFB 003.007\n"; @@ -8,12 +9,21 @@ const VNC_RFB38: &[u8; 12] = b"RFB 003.008\n"; const VNC_VER_UNSUPPORTED: &str = "unsupported version"; const VNC_FAILED: &str = "Connection failed with unknow reason"; +#[derive(Debug, Clone, Copy)] enum VncState { Handshake, Authentication, ClientInit, // auth done } +#[derive(Debug, Clone, Copy)] +enum VncVersion { + NONE, + VNC33, + VNC37, + VNC38, +} + #[derive(Debug, Clone, Copy, PartialEq, Eq)] #[repr(u8)] pub enum SecurityType { @@ -28,20 +38,29 @@ pub enum SecurityType { VeNCrypt = 19, } +#[derive(Debug, Clone)] pub struct VncHandler { state: VncState, + version: VncVersion, challenge: [u8; 16], security_type: SecurityType, - password: String, + width: u16, + height: u16, + pf: PixelFormat, + name: String, } impl ProtocalImpl for VncHandler { fn new() -> Self { VncHandler { state: VncState::Handshake, + version: VncVersion::NONE, challenge: [0u8; 16], security_type: SecurityType::Invalid, - password: String::new(), + width: 0, + height: 0, + pf: PixelFormat::default(), + name: String::new(), } } @@ -57,29 +76,45 @@ impl ProtocalImpl for VncHandler { } } VncState::Authentication => { + // reuse this state for auth repose handling + if self.security_type == SecurityType::VncAuth { + self.handle_auth_response(input) + } else { + self.start_authenticate(input) + } + } + VncState::ClientInit => { ConsoleService::log(&format!("{:?}", input)); - return self.start_authenticate(input); + self.handle_server_init(input) } _ => panic!("unsupported version"), } } fn set_credential(&mut self, _username: &str, password: &str) -> ProtocalHandlerOutput { - ConsoleService::log(&format!("{:?}", password)); - ConsoleService::log(&format!("{:?}", self.challenge)); + // ConsoleService::log(&format!("{:?}", password)); + // ConsoleService::log(&format!("{:?}", self.challenge)); // since vnc do not require username, so we just ignore it - self.password = password.to_string(); - self.continue_authenticate() + self.continue_authenticate(password) } } // private methods impl VncHandler { - fn handle_handshake(&self, rfbversion: &[u8]) -> Result<&'static [u8], &'static str> { + fn handle_handshake(&mut self, rfbversion: &[u8]) -> Result<&'static [u8], &'static str> { match rfbversion { - b"RFB 003.003\n" => Ok(VNC_RFB33), - b"RFB 003.007\n" => Ok(VNC_RFB33), - b"RFB 003.008\n" => Ok(VNC_RFB33), + b"RFB 003.003\n" => { + self.version = VncVersion::VNC33; + Ok(VNC_RFB33) + } + b"RFB 003.007\n" => { + self.version = VncVersion::VNC33; + Ok(VNC_RFB33) + } + b"RFB 003.008\n" => { + self.version = VncVersion::VNC33; + Ok(VNC_RFB33) + } _ => Err(VNC_VER_UNSUPPORTED), } } @@ -91,10 +126,12 @@ impl VncHandler { ProtocalHandlerOutput::Err(err_msg) } Some(1) => { + self.security_type = SecurityType::None; self.state = VncState::ClientInit; self.client_initialisation() } Some(2) => { + self.security_type = SecurityType::VncAuth; sr.extract_slice(16, &mut self.challenge); ProtocalHandlerOutput::RequirePassword } @@ -103,10 +140,181 @@ impl VncHandler { } fn client_initialisation(&mut self) -> ProtocalHandlerOutput { - ProtocalHandlerOutput::Ok + let shared_flag = 1; + + ProtocalHandlerOutput::WsBuf(vec![shared_flag].into()) } - fn continue_authenticate(&mut self) -> ProtocalHandlerOutput { + fn continue_authenticate(&mut self, password: &str) -> ProtocalHandlerOutput { + // referring + // https://github.com/whitequark/rust-vnc/blob/0697238f2706dd34a9a95c1640e385f6d8c02961/src/client.rs + // strange behavior + + let pass_len = password.len(); + let mut pass_bytes = [0u8; 8]; + for i in 0..8 { + let c = if i < pass_len { + password.as_bytes()[i] + } else { + 0 + }; + let mut cs = 0u8; + for j in 0..8 { + cs |= ((c >> j) & 1) << (7 - j) + } + pass_bytes[i] = cs; + } + let output = des::encrypt(&self.challenge, &pass_bytes); + ProtocalHandlerOutput::WsBuf(output.to_vec()) + } + + fn handle_auth_response(&mut self, response: &[u8]) -> ProtocalHandlerOutput { + let mut sr = StreamReader::new(response); + match sr.read_u32() { + Some(0) => { + self.state = VncState::ClientInit; + self.client_initialisation() + } + Some(1) => { + let err_msg = sr.read_string_l32().unwrap(); + ProtocalHandlerOutput::Err(err_msg) + } + _ => ProtocalHandlerOutput::Err(VNC_FAILED.to_string()), + } + } + + // example + // [7, 128, 4, 176, 32, 24, 0, 1, 0, 255, 0, 255, 0, 255, 16, 8, 0, 0, 0, 0, 0, 0, 0, 14, 54, 122, 122, 100, 114, 113, 50, 45, 106, 105, 97, 120, 117, 0] + // No. of bytes Type [Value] Description + // 2 CARD16 framebuffer-width + // 2 CARD16 framebuffer-height + // 16 PIXEL_FORMAT server-pixel-format + // 4 CARD32 name-length + // name-length CARD8 array name-string + fn handle_server_init(&mut self, init: &[u8]) -> ProtocalHandlerOutput { + let mut sr = StreamReader::new(init); + self.width = sr.read_u16().unwrap(); + self.height = sr.read_u16().unwrap(); + let mut pfb: [u8; 16] = [0u8; 16]; + sr.extract_slice(16, &mut pfb); + // This pixel format will be used unless the client requests a different format using the SetPixelFormat message + self.pf = (&pfb).into(); + self.name = sr.read_string_l32().unwrap(); + + ConsoleService::log(&format!("{:?}", self)); ProtocalHandlerOutput::Ok } } + +// No. of bytes Type [Value] Description +// 1 CARD8 bits-per-pixel +// 1 CARD8 depth +// 1 CARD8 big-endian-flag +// 1 CARD8 true-color-flag +// 2 CARD16 red-max +// 2 CARD16 green-max +// 2 CARD16 blue-max +// 1 CARD8 red-shift +// 1 CARD8 green-shift +// 1 CARD8 blue-shift +// 1 CARD8 padding +#[derive(Debug, Clone, Copy)] +struct PixelFormat { + // the number of bits used for each pixel value on the wire + // 8, 16, 32(usually) only + bits_per_pixel: u8, + depth: u8, + // true if multi-byte pixels are interpreted as big endian + big_endian_flag: u8, + // true then the last six items specify how to extract the red, green and blue intensities from the pixel value + true_color_flag: u8, + // the next three always in big-endian order + // no matter how the `big_endian_flag` is set + red_max: u16, + green_max: u16, + blue_max: u16, + // the number of shifts needed to get the red value in a pixel to the least significant bit + red_shift: u8, + green_shift: u8, + blue_shift: u8, + padding_1: u8, + padding_2: u8, + padding_3: u8, +} + +impl From for Vec { + fn from(pf: PixelFormat) -> Vec { + let mut v = Vec::new(); + v.push(pf.bits_per_pixel); + v.push(pf.depth); + v.push(pf.big_endian_flag); + v.push(pf.true_color_flag); + v.push((pf.red_max >> 8) as u8); + v.push(pf.red_max as u8); + v.push((pf.green_max >> 8) as u8); + v.push(pf.green_max as u8); + v.push((pf.blue_max >> 8) as u8); + v.push(pf.blue_max as u8); + v.push(pf.red_shift); + v.push(pf.green_shift); + v.push(pf.blue_shift); + v.push(pf.padding_1); + v.push(pf.padding_2); + v.push(pf.padding_3); + v + } +} + +impl From<&[u8; 16]> for PixelFormat { + fn from(pf: &[u8; 16]) -> Self { + let mut sr = StreamReader::new(pf); + let bits_per_pixel = sr.read_u8().unwrap(); + let depth = sr.read_u8().unwrap(); + let big_endian_flag = sr.read_u8().unwrap(); + let true_color_flag = sr.read_u8().unwrap(); + let red_max = sr.read_u16().unwrap(); + let green_max = sr.read_u16().unwrap(); + let blue_max = sr.read_u16().unwrap(); + let red_shift = sr.read_u8().unwrap(); + let green_shift = sr.read_u8().unwrap(); + let blue_shift = sr.read_u8().unwrap(); + let padding_1 = sr.read_u8().unwrap(); + let padding_2 = sr.read_u8().unwrap(); + let padding_3 = sr.read_u8().unwrap(); + Self { + bits_per_pixel, + depth, + big_endian_flag, + true_color_flag, + red_max, + green_max, + blue_max, + red_shift, + green_shift, + blue_shift, + padding_1, + padding_2, + padding_3, + } + } +} + +impl Default for PixelFormat { + fn default() -> Self { + Self { + bits_per_pixel: 0, + depth: 0, + big_endian_flag: 0, + true_color_flag: 0, + red_max: 0, + green_max: 0, + blue_max: 0, + red_shift: 0, + green_shift: 0, + blue_shift: 0, + padding_1: 0, + padding_2: 0, + padding_3: 0, + } + } +} \ No newline at end of file