chore: init, very barren
- guacutils
This commit is contained in:
commit
92925ab4d2
8 changed files with 251 additions and 0 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
/target
|
7
Cargo.lock
generated
Normal file
7
Cargo.lock
generated
Normal file
|
@ -0,0 +1,7 @@
|
|||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "cvm12-rs"
|
||||
version = "0.1.0"
|
6
Cargo.toml
Normal file
6
Cargo.toml
Normal file
|
@ -0,0 +1,6 @@
|
|||
[package]
|
||||
name = "cvm12-rs"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
46
README.md
Normal file
46
README.md
Normal file
|
@ -0,0 +1,46 @@
|
|||
# cvm1.2-rs
|
||||
|
||||
Stopgap part 4. Mostly made as a experiment, and maybe for production use?.
|
||||
|
||||
# Usage
|
||||
|
||||
There is none, at the moment. Once there is, there will be actual documentation here.
|
||||
|
||||
## Noodling for configuration
|
||||
|
||||
collabvm.toml
|
||||
```toml
|
||||
[collabvm]
|
||||
listen = "127.0.0.1:3000" # or /run/cvm.sock ? if warp supports uds i guess
|
||||
|
||||
# optional
|
||||
vm_directory = "vms"
|
||||
|
||||
# nested table. you can define it non-nested if you want
|
||||
mod_permissions = { xxx = true, xyz = false }
|
||||
|
||||
mod_password_hash = "argon2 hash"
|
||||
admin_password_hash = "argon2 hash"
|
||||
|
||||
# applied to vms by default unless they override
|
||||
default_motd = "hice powered vms"
|
||||
|
||||
ban_command = "sexy $user $ip"
|
||||
```
|
||||
|
||||
vms/vm1.toml
|
||||
```toml
|
||||
[vm]
|
||||
name = "Window XP have honse (VM 1)"
|
||||
|
||||
# cvm1.2-rs will automatically append parameters as needed
|
||||
command_line = "./vm1.lvm start"
|
||||
|
||||
motd = "YOU HAVE FUCKER GOOGLE FROM 999999999.. Banned!"
|
||||
```
|
||||
|
||||
# Building
|
||||
|
||||
`cargo b --release`
|
||||
|
||||
Unit tests can be run with `cargo test`, as is for most rust programs...
|
3
rustfmt.toml
Normal file
3
rustfmt.toml
Normal file
|
@ -0,0 +1,3 @@
|
|||
# sorry guys this isnt something im going to have an argument about
|
||||
# other than that this is fine
|
||||
hard_tabs = true
|
182
src/guac.rs
Normal file
182
src/guac.rs
Normal file
|
@ -0,0 +1,182 @@
|
|||
//! This guacutils impl was certified not mostly copilot generated
|
||||
//! also omits diagnostic information, we don't need diagnostics at all
|
||||
use std::fmt;
|
||||
|
||||
// type of a guac message
|
||||
pub type Elements = Vec<String>;
|
||||
|
||||
/// Errors during decoding
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum DecodeError {
|
||||
/// Invalid guacamole instruction format
|
||||
InvalidFormat,
|
||||
|
||||
/// Instruction is too long for the current decode policy.
|
||||
InstructionTooLong,
|
||||
|
||||
/// Element is too long for the current decode policy.
|
||||
ElementTooLong,
|
||||
|
||||
/// Invalid element size.
|
||||
ElementSizeInvalid,
|
||||
}
|
||||
|
||||
pub type DecodeResult<T> = std::result::Result<T, DecodeError>;
|
||||
|
||||
impl fmt::Display for DecodeError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Self::InvalidFormat => write!(f, "Invalid Guacamole instruction while decoding"),
|
||||
Self::InstructionTooLong => write!(f, "Instruction too long for current decode policy"),
|
||||
Self::ElementTooLong => write!(f, "Element too long for current decode policy"),
|
||||
Self::ElementSizeInvalid => write!(f, "Element size is invalid")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// this decode policy abstraction would in theory be useful,
|
||||
// but idk how to do this kind of thing in rust very well
|
||||
|
||||
pub struct StaticDecodePolicy<const INST_SIZE: usize, const ELEM_SIZE: usize>();
|
||||
|
||||
impl<const INST_SIZE: usize, const ELEM_SIZE: usize> StaticDecodePolicy<INST_SIZE, ELEM_SIZE> {
|
||||
fn max_instruction_size(&self) -> usize {
|
||||
INST_SIZE
|
||||
}
|
||||
|
||||
fn max_element_size(&self) -> usize {
|
||||
ELEM_SIZE
|
||||
}
|
||||
}
|
||||
|
||||
/// The default decode policy.
|
||||
pub type DefaultDecodePolicy = StaticDecodePolicy<12288, 4096>;
|
||||
|
||||
|
||||
/// Encodes elements into a Guacamole instruction
|
||||
pub fn encode_instruction(elements: &Elements) -> String {
|
||||
let mut str = String::new();
|
||||
|
||||
for elem in elements.iter() {
|
||||
str.push_str(&format!("{}.{},", elem.len(), elem));
|
||||
}
|
||||
|
||||
// hacky, but whatever
|
||||
str.pop();
|
||||
str.push(';');
|
||||
|
||||
str
|
||||
}
|
||||
|
||||
/// Decodes a Guacamole instruction to individual elements
|
||||
pub fn decode_instruction(element_string: &String) -> DecodeResult<Elements> {
|
||||
let policy = DefaultDecodePolicy {};
|
||||
|
||||
let mut vec: Elements = Vec::new();
|
||||
let mut current_position: usize = 0;
|
||||
|
||||
// Instruction is too long. Don't even bother
|
||||
if policy.max_instruction_size() < element_string.len() {
|
||||
return Err(DecodeError::InstructionTooLong);
|
||||
}
|
||||
|
||||
let chars = element_string.chars().collect::<Vec<_>>();
|
||||
|
||||
loop {
|
||||
let mut element_size: usize = 0;
|
||||
|
||||
// Scan the integer value in by hand. This is mostly because
|
||||
// I'm stupid, and the Rust integer parsing routines (seemingly)
|
||||
// require a substring (or a slice, but if you can generate a slice bound,
|
||||
// you can also just scan the value in by hand.....)
|
||||
//
|
||||
// We bound this anyways so it's fine(TM)
|
||||
loop {
|
||||
let c = chars[current_position];
|
||||
|
||||
if c >= '0' && c <= '9' {
|
||||
element_size = element_size * 10 + (c as usize) - ('0' as usize);
|
||||
} else {
|
||||
if c == '.' {
|
||||
break;
|
||||
}
|
||||
|
||||
return Err(DecodeError::InvalidFormat);
|
||||
}
|
||||
current_position += 1;
|
||||
}
|
||||
|
||||
// eat the '.'; our integer scanning ensures
|
||||
// we only get here in that case
|
||||
current_position += 1;
|
||||
|
||||
if element_size >= policy.max_element_size() {
|
||||
return Err(DecodeError::ElementTooLong);
|
||||
}
|
||||
|
||||
if element_size >= element_string.len() {
|
||||
return Err(DecodeError::ElementSizeInvalid);
|
||||
}
|
||||
|
||||
let element = chars
|
||||
.iter()
|
||||
.skip(current_position)
|
||||
.take(element_size)
|
||||
.collect::<String>();
|
||||
|
||||
current_position += element_size;
|
||||
|
||||
vec.push(element);
|
||||
|
||||
// make sure seperator is proper
|
||||
match chars[current_position] {
|
||||
',' => {}
|
||||
';' => break,
|
||||
_ => return Err(DecodeError::InvalidFormat),
|
||||
}
|
||||
|
||||
// eat the ','
|
||||
current_position += 1;
|
||||
}
|
||||
|
||||
Ok(vec)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn decode_basic() {
|
||||
let test = String::from("7.connect,3.vm1;");
|
||||
let res = decode_instruction(&test);
|
||||
|
||||
assert!(res.is_ok());
|
||||
assert_eq!(res.unwrap(), vec!["connect", "vm1"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decode_errors() {
|
||||
let test = String::from("700.connect,3.vm1;");
|
||||
let res = decode_instruction(&test);
|
||||
|
||||
eprintln!("Error for: {}", res.clone().unwrap_err());
|
||||
|
||||
assert!(res.is_err())
|
||||
}
|
||||
|
||||
// generally just test that the codec even works
|
||||
// (we can decode a instruction we created)
|
||||
#[test]
|
||||
fn general_codec_works() {
|
||||
let vec = vec![String::from("connect"), String::from("vm1")];
|
||||
let test = encode_instruction(&vec);
|
||||
|
||||
assert_eq!(test, "7.connect,3.vm1;");
|
||||
|
||||
let res = decode_instruction(&test);
|
||||
|
||||
assert!(res.is_ok());
|
||||
assert_eq!(res.unwrap(), vec);
|
||||
}
|
||||
}
|
1
src/lib.rs
Normal file
1
src/lib.rs
Normal file
|
@ -0,0 +1 @@
|
|||
pub mod guac;
|
5
src/main.rs
Normal file
5
src/main.rs
Normal file
|
@ -0,0 +1,5 @@
|
|||
use cvm12_rs::guac;
|
||||
|
||||
fn main() {
|
||||
println!("Hello, world!");
|
||||
}
|
Loading…
Reference in a new issue