diff --git a/cloud/leptos/Cargo.toml b/cloud/leptos/Cargo.toml index 1d6c957..daa9bfa 100644 --- a/cloud/leptos/Cargo.toml +++ b/cloud/leptos/Cargo.toml @@ -24,15 +24,15 @@ http = "1" [features] hydrate = ["leptos/hydrate", "leptos_meta/hydrate", "leptos_router/hydrate"] ssr = [ - "dep:axum", - "dep:tokio", - "dep:tower", - "dep:tower-http", - "dep:leptos_axum", - "leptos/ssr", - "leptos_meta/ssr", - "leptos_router/ssr", - "dep:tracing", + "dep:axum", + "dep:tokio", + "dep:tower", + "dep:tower-http", + "dep:leptos_axum", + "leptos/ssr", + "leptos_meta/ssr", + "leptos_router/ssr", + "dep:tracing", ] # Defines a size-optimized profile for the WASM bundle in release mode @@ -41,7 +41,7 @@ ssr = [ # The name used by wasm-bindgen/cargo-leptos for the JS/WASM bundle. Defaults to the crate name output-name = "leptos" -# The site root folder is where cargo-leptos generate all output. WARNING: all content of this folder will be erased on a rebuild. Use it in your server setup. +# The site root folder is where cargo-leptos generate all output. site-root = "target/site" # The site-root relative folder where all compiled output (JS, WASM and CSS) is written diff --git a/packages/providers/core/lib/README.md b/packages/providers/core/lib/README.md index 0b5edc6..4f3850c 100644 --- a/packages/providers/core/lib/README.md +++ b/packages/providers/core/lib/README.md @@ -39,7 +39,6 @@ Majors only. e.g. 0x01, 0x02, 0x03 16-bit ones' complement of the header and payload. The checksum is initially set to 0 for checksum calculation. -1. Decode payload as bytes 1. Generate a header version, opcode, 0x0 (nil checksum), payload length 1. Group by 16 bit words 1. Pad 0's to complete words @@ -57,5 +56,3 @@ The checksum is initially set to 0 for checksum calculation. 1. Wrap overflows 1. Add checksum 1. All 1's, else error - -TODO: double check diff --git a/packages/providers/core/lib/src/errors.rs b/packages/providers/core/lib/src/errors.rs index c2a7193..81da321 100644 --- a/packages/providers/core/lib/src/errors.rs +++ b/packages/providers/core/lib/src/errors.rs @@ -6,7 +6,6 @@ pub enum ServerError { Read, NoMessages, SocketError, - // TODO: not error? WouldBlock, } diff --git a/packages/providers/core/lib/src/handler.rs b/packages/providers/core/lib/src/handler.rs index 5905ec3..5226f06 100644 --- a/packages/providers/core/lib/src/handler.rs +++ b/packages/providers/core/lib/src/handler.rs @@ -30,24 +30,6 @@ impl Handler { // "Actions" are also processed in their own green thread to allow for actions of varying // durations to be processed concurrently without blocking queue I/O. pub async fn handle(self: Arc) -> Result { - // TODO: think about whether or not we need to authenticate/authorize - // new clients in any way. It will probably go here. - // Had a thought today that the root problem is how to share a secret with both - // the client app and the nv unix system. I thought about setting at compile/build time for - // both but I feel like its essentially the same as saving to FS just w/ obfuscation. - // We need a dynamic way to auth a client with server, that the server is actually the - // inteded app. Maybe look into code signing for inspo? - // ....... - // Lots more thinking today. Another idea... - // We leave most of the auth to the providers. e.g. locally setting AWS creds in env vars - // and conforming to AWS idea of identity on their machines. - // Another potential to maybe harden is to write some secret token at startup or build time - // that is consumed by the server and client once. This means only the first claim of the - // container will have access for the rest of the duration of the container? - // Also, we could ignore all the above and have some other agent/server that is - // completely separate and private. This would essentially be stepping into the role of the providers - // to some degree. For example, hashicorpt vault is secret management server that auths and comms with clients. - let (req_tx, req_rx) = mpsc::channel(16); let (res_tx, res_rx) = mpsc::channel(16); let cancel_token = CancellationToken::new(); @@ -171,7 +153,7 @@ impl Handler { match result { Err(ServerError::WouldBlock) => { - // TODO: test that this is required + // Re-queue received message if blocking let _ = action_out_recover.send(message).await; continue; } @@ -237,7 +219,10 @@ impl Handler { res: Result, ) -> Result<(), ServerError> { let message = res.unwrap_or("nout".as_bytes().into()); - let serialized = self.serializer.serialize(message); + let serialized = self + .serializer + .serialize(message) + .map_err(|_| ServerError::Write)?; match stream.try_write(&serialized) { Ok(_) => Ok(()), diff --git a/packages/providers/core/lib/src/protocol.rs b/packages/providers/core/lib/src/protocol.rs index ac7605b..68bc77f 100644 --- a/packages/providers/core/lib/src/protocol.rs +++ b/packages/providers/core/lib/src/protocol.rs @@ -33,7 +33,6 @@ impl Opcode { fn from_byte(byte: u8) -> Result { log::debug!("Converting opcode byte {} to opcode", byte); - // TODO: has to be a better way, also see similar conversions to improve in LSP, lexer and parser match byte { 0x1 => Ok(Opcode::Initialize), 0x2 => Ok(Opcode::Destroy), @@ -85,24 +84,23 @@ impl Header { fn from_message(message: MessageSlice) -> Result { let version = *message.first().ok_or(ProtocolError::InvalidHeader)?; log::debug!("Header from message, version:{:?}", version); + let opcode = *message.get(1).ok_or(ProtocolError::InvalidHeader)?; log::debug!("Header from message, opcode:{:?}", opcode); + let checksum: [u8; 2] = message .get(2..=3) .ok_or(ProtocolError::InvalidHeader)? .try_into() .or(Err(ProtocolError::InvalidHeader))?; log::debug!("Header from message, checksum:{:?}", checksum); + let payload_length: [u8; 4] = message .get(4..=7) .ok_or(ProtocolError::InvalidHeader)? .try_into() .or(Err(ProtocolError::InvalidHeader))?; log::debug!("Header from message, payload_length:{:?}", payload_length); - log::debug!( - "Header from message, payload_length AS BE BYTES:{:?}", - u32::from_be_bytes(payload_length) - ); Ok(Header { version, @@ -114,23 +112,66 @@ impl Header { } impl MessageSerializer { - pub fn serialize(&self, payload: Payload) -> Message { + pub fn serialize(&self, payload: Payload) -> Result { log::debug!("Serializing payload {:?}", payload); - let header = self.generate_header(&payload); + let header = MessageSerializer::generate_header(&payload)?; - header.iter().chain(payload.iter()).copied().collect() + Ok(header.iter().chain(payload.iter()).copied().collect()) } - fn generate_header(&self, payload: &Payload) -> Vec { - let header = Header { - version: 0x0, // TODO: get from git tags at compile time?? + fn generate_header(payload: &Payload) -> Result, ProtocolError> { + let mut header = Header { + version: 0x1, opcode: Opcode::GetValue, checksum: 0x0, - payload_length: payload.len() as u32, // TODO: try from + payload_length: payload + .len() + .try_into() + .map_err(|_| ProtocolError::InvalidPayload)?, }; - header.to_bytes() + let header_bytes = header.to_bytes(); + + header.checksum = MessageSerializer::generate_checksum(&header_bytes, payload)?; + + Ok(header.to_bytes()) + } + + fn generate_checksum(header_bytes: &[u8], payload: &Payload) -> Result { + let mut res: u16 = 0; + + let all_bytes: Vec = header_bytes.iter().chain(payload.iter()).copied().collect(); + + for chunk in all_bytes.chunks(2) { + let pad_count = 2 - chunk.len(); + + let mut padding = vec![0; pad_count]; + padding.fill(0); + + let word: Vec<_> = chunk.iter().chain(padding.iter()).copied().collect(); + let word: [u8; 2] = word + .get(0..=1) + .ok_or(ProtocolError::UngeneratableChecksum)? + .try_into() + .or(Err(ProtocolError::UngeneratableChecksum))?; + let word = u16::from_be_bytes(word); + + res = res.wrapping_add(word); + } + + Ok(res) + } + + fn verify_checksum(message: Message) -> Result<(), ProtocolError> { + let header = message.get(0..=7).ok_or(ProtocolError::CorruptChecksum)?; + let payload = message.get(8..); + + let checksum = header.get(1..=3); + + // TODO: you must perform error detection on checksum to complete + + Ok(()) } } @@ -141,6 +182,8 @@ pub enum ProtocolError { InvalidPayload, UnreadableStream, InvalidOpcode, + UngeneratableChecksum, + CorruptChecksum, } pub struct MessageDeserializer {} @@ -151,7 +194,6 @@ pub struct DeserializedMessage { } impl MessageDeserializer { - // TODO: use a struct to return instead of tuple pub fn deserialize(message: MessageSlice) -> Result { log::debug!("Deserialize on message called: {:?}", message); diff --git a/packages/providers/core/lib/src/server.rs b/packages/providers/core/lib/src/server.rs index 6c486ba..8980f81 100644 --- a/packages/providers/core/lib/src/server.rs +++ b/packages/providers/core/lib/src/server.rs @@ -111,7 +111,6 @@ mod tests { tokio::spawn(async move { let _ = server.start().await; }); - // TODO: no sleepy, receive signal that server is ready instead sleep(Duration::from_millis(100)).await; let client = Arc::new(Mutex::new(UnixStream::connect(path).await.unwrap())); @@ -137,11 +136,13 @@ mod tests { let header = res.header; let payload = res.payload; - assert_eq!(header.version, 0x0); + assert_eq!(header.version, 0x1); assert_eq!(header.opcode, Opcode::GetValue); assert_snapshot!(header.checksum); assert_eq!(header.payload_length, 4); assert_eq!(String::from_utf8(payload), Ok("nout".to_owned())); + + // TODO: verify checksum } Err(err) => { diff --git a/packages/providers/core/lib/src/snapshots/nv_provider_core__server__tests__server.snap b/packages/providers/core/lib/src/snapshots/nv_provider_core__server__tests__server.snap index 1849dd7..e67aef0 100644 --- a/packages/providers/core/lib/src/snapshots/nv_provider_core__server__tests__server.snap +++ b/packages/providers/core/lib/src/snapshots/nv_provider_core__server__tests__server.snap @@ -2,4 +2,4 @@ source: packages/providers/core/lib/src/server.rs expression: header.checksum --- -0 +58346 diff --git a/packages/providers/providers/env/lib/src/provider.rs b/packages/providers/providers/env/lib/src/provider.rs index ace7f3b..8be942d 100644 --- a/packages/providers/providers/env/lib/src/provider.rs +++ b/packages/providers/providers/env/lib/src/provider.rs @@ -21,7 +21,6 @@ impl Provider for EnvProvider { match error { env::VarError::NotPresent => ProviderError::NoValueForKey, - // TODO: do it properly _ => ProviderError::ExplodeyProvider, } });