Add experimental encryption support
This commit is contained in:
parent
36adfa124d
commit
f076764fff
10 changed files with 339 additions and 18 deletions
116
Cargo.lock
generated
116
Cargo.lock
generated
|
@ -2,6 +2,42 @@
|
|||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "aead"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b613b8e1e3cf911a086f53f03bf286f52fd7a7258e4fa606f0ef220d39d8877"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aes"
|
||||
version = "0.7.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9e8b47f52ea9bae42228d07ec09eb676433d7c4ed1ebdf0f1d1c29ed446f1ab8"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"cipher",
|
||||
"cpufeatures",
|
||||
"opaque-debug",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aes-gcm-siv"
|
||||
version = "0.10.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "589c637f0e68c877bbd59a4599bbe849cac8e5f3e4b5a3ebae8f528cd218dcdc"
|
||||
dependencies = [
|
||||
"aead",
|
||||
"aes",
|
||||
"cipher",
|
||||
"ctr",
|
||||
"polyval",
|
||||
"subtle",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.1.0"
|
||||
|
@ -78,6 +114,15 @@ version = "1.0.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "cipher"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7ee52072ec15386f770805afd189a01c8841be8696bed250fa2f13c4c0d6dfb7"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "console_error_panic_hook"
|
||||
version = "0.1.7"
|
||||
|
@ -107,6 +152,15 @@ dependencies = [
|
|||
"typenum",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ctr"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "049bb91fb4aaf0e3c7efa6cd5ef877dbbbd15b39dad06d9948de4ec8a75761ea"
|
||||
dependencies = [
|
||||
"cipher",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "digest"
|
||||
version = "0.9.0"
|
||||
|
@ -273,6 +327,18 @@ dependencies = [
|
|||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hex"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
|
||||
|
||||
[[package]]
|
||||
name = "hex-literal"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7ebdb29d2ea9ed0083cd8cece49bbd968021bd99b0849edb4a9a7ee0fdf6a4e0"
|
||||
|
||||
[[package]]
|
||||
name = "http"
|
||||
version = "0.2.8"
|
||||
|
@ -471,6 +537,12 @@ dependencies = [
|
|||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "obfstr"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7b2b2cbbfd8defa51ff24450a61d73b3ff3e158484ddd274a883e886e6fbaa78"
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.13.0"
|
||||
|
@ -521,6 +593,18 @@ version = "0.1.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
||||
|
||||
[[package]]
|
||||
name = "polyval"
|
||||
version = "0.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8419d2b623c7c0896ff2d5d96e2cb4ede590fed28fcc34934f4c33c036e620a1"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"cpufeatures",
|
||||
"opaque-debug",
|
||||
"universal-hash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ppv-lite86"
|
||||
version = "0.2.16"
|
||||
|
@ -686,6 +770,12 @@ dependencies = [
|
|||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "subtle"
|
||||
version = "2.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.98"
|
||||
|
@ -912,6 +1002,16 @@ dependencies = [
|
|||
"tinyvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "universal-hash"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9f214e8f697e925001e66ec2c6e37a4ef93f0f78c2eed7814394e10c62025b05"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
"subtle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "url"
|
||||
version = "2.2.2"
|
||||
|
@ -926,9 +1026,11 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "usdpl-back"
|
||||
version = "0.5.3"
|
||||
version = "0.6.0"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"hex",
|
||||
"obfstr",
|
||||
"tokio",
|
||||
"usdpl-core",
|
||||
"warp",
|
||||
|
@ -936,9 +1038,11 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "usdpl-core"
|
||||
version = "0.5.0"
|
||||
version = "0.6.0"
|
||||
dependencies = [
|
||||
"aes-gcm-siv",
|
||||
"base64",
|
||||
"hex-literal",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -946,7 +1050,9 @@ name = "usdpl-front"
|
|||
version = "0.5.0"
|
||||
dependencies = [
|
||||
"console_error_panic_hook",
|
||||
"hex",
|
||||
"js-sys",
|
||||
"obfstr",
|
||||
"usdpl-core",
|
||||
"wasm-bindgen",
|
||||
"wasm-bindgen-futures",
|
||||
|
@ -1193,3 +1299,9 @@ name = "windows_x86_64_msvc"
|
|||
version = "0.36.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680"
|
||||
|
||||
[[package]]
|
||||
name = "zeroize"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4756f7db3f7b5574938c3eb1c117038b8e07f95ee6718c0efad4ac21508f1efd"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "usdpl-back"
|
||||
version = "0.5.3"
|
||||
version = "0.6.0"
|
||||
edition = "2021"
|
||||
license = "GPL-3.0-only"
|
||||
repository = "https://github.com/NGnius/usdpl-rs"
|
||||
|
@ -12,11 +12,16 @@ default = ["blocking"]
|
|||
decky = ["usdpl-core/decky"]
|
||||
crankshaft = ["usdpl-core/crankshaft"]
|
||||
blocking = ["tokio"] # synchronous API for async functionality, using tokio
|
||||
encrypt = ["usdpl-core/encrypt", "obfstr", "hex"]
|
||||
|
||||
[dependencies]
|
||||
usdpl-core = { version = "0.5.0", path = "../usdpl-core" }
|
||||
usdpl-core = { version = "0.6.0", path = "../usdpl-core"}
|
||||
|
||||
# HTTP web framework
|
||||
warp = { version = "0.3" }
|
||||
bytes = { version = "1.1" }
|
||||
tokio = { version = "1.19", features = ["rt", "rt-multi-thread"], optional = true }
|
||||
|
||||
# encryption helpers
|
||||
obfstr = { version = "0.3", optional = true }
|
||||
hex = { version = "0.4", optional = true }
|
||||
|
|
|
@ -11,10 +11,15 @@ use super::Callable;
|
|||
|
||||
type WrappedCallable = Arc<Mutex<Box<dyn Callable>>>; // thread-safe, cloneable Callable
|
||||
|
||||
#[cfg(feature = "encrypt")]
|
||||
const NONCE: [u8; socket::NONCE_SIZE] = [0u8; socket::NONCE_SIZE];
|
||||
|
||||
/// Back-end instance for interacting with the front-end
|
||||
pub struct Instance {
|
||||
calls: HashMap<String, WrappedCallable>,
|
||||
port: u16,
|
||||
#[cfg(feature = "encrypt")]
|
||||
encryption_key: Vec<u8>,
|
||||
}
|
||||
|
||||
impl Instance {
|
||||
|
@ -24,6 +29,8 @@ impl Instance {
|
|||
Instance {
|
||||
calls: HashMap::new(),
|
||||
port: port_usdpl,
|
||||
#[cfg(feature = "encrypt")]
|
||||
encryption_key: hex::decode(obfstr::obfstr!(env!("USDPL_ENCRYPTION_KEY"))).unwrap(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -100,6 +107,7 @@ impl Instance {
|
|||
async fn serve_internal(&self) -> Result<(), ()> {
|
||||
let handlers = self.calls.clone();
|
||||
//self.calls = HashMap::new();
|
||||
#[cfg(not(feature = "encrypt"))]
|
||||
let calls = warp::post()
|
||||
.and(warp::path!("usdpl" / "call"))
|
||||
.and(warp::body::content_length_limit(
|
||||
|
@ -136,6 +144,47 @@ impl Instance {
|
|||
)
|
||||
})
|
||||
.map(|reply| warp::reply::with_header(reply, "Access-Control-Allow-Origin", "*"));
|
||||
#[cfg(feature = "encrypt")]
|
||||
let key = self.encryption_key.clone();
|
||||
#[cfg(feature = "encrypt")]
|
||||
let calls = warp::post()
|
||||
.and(warp::path!("usdpl" / "call"))
|
||||
.and(warp::body::content_length_limit(
|
||||
(socket::PACKET_BUFFER_SIZE * 2) as _,
|
||||
))
|
||||
.and(warp::body::bytes())
|
||||
.map(move |data: bytes::Bytes| {
|
||||
let (packet, _) = match socket::Packet::load_encrypted(&data, &key, &NONCE) {
|
||||
Ok(x) => x,
|
||||
Err(_) => {
|
||||
return warp::reply::with_status(
|
||||
warp::http::Response::builder()
|
||||
.body("Failed to load packet".to_string()),
|
||||
warp::http::StatusCode::from_u16(400).unwrap(),
|
||||
)
|
||||
}
|
||||
};
|
||||
let mut buffer = Vec::with_capacity(socket::PACKET_BUFFER_SIZE);
|
||||
buffer.extend(&[0u8; socket::PACKET_BUFFER_SIZE]);
|
||||
let response = Self::handle_call(packet, &handlers);
|
||||
let len = match response.dump_encrypted(&mut buffer, &key, &NONCE) {
|
||||
Ok(x) => x,
|
||||
Err(_) => {
|
||||
return warp::reply::with_status(
|
||||
warp::http::Response::builder()
|
||||
.body("Failed to dump response packet".to_string()),
|
||||
warp::http::StatusCode::from_u16(500).unwrap(),
|
||||
)
|
||||
}
|
||||
};
|
||||
buffer.truncate(len);
|
||||
let string: String = String::from_utf8(buffer).unwrap().into();
|
||||
warp::reply::with_status(
|
||||
warp::http::Response::builder().body(string),
|
||||
warp::http::StatusCode::from_u16(200).unwrap(),
|
||||
)
|
||||
})
|
||||
.map(|reply| warp::reply::with_header(reply, "Access-Control-Allow-Origin", "*"));
|
||||
#[cfg(debug_assertions)]
|
||||
warp::serve(calls).run(([0, 0, 0, 0], self.port)).await;
|
||||
#[cfg(not(debug_assertions))]
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "usdpl-core"
|
||||
version = "0.5.0"
|
||||
version = "0.6.0"
|
||||
edition = "2021"
|
||||
license = "GPL-3.0-only"
|
||||
repository = "https://github.com/NGnius/usdpl-rs"
|
||||
|
@ -11,6 +11,11 @@ description = "Universal Steam Deck Plugin Library core"
|
|||
default = []
|
||||
decky = []
|
||||
crankshaft = []
|
||||
encrypt = ["aes-gcm-siv"]
|
||||
|
||||
[dependencies]
|
||||
base64 = "0.13"
|
||||
aes-gcm-siv = { version = "0.10", optional = true, default-features = false, features = ["alloc", "aes"] }
|
||||
|
||||
[dev-dependencies]
|
||||
hex-literal = "0.3.4"
|
||||
|
|
|
@ -2,6 +2,12 @@ use base64::{decode_config_slice, encode_config_slice, Config};
|
|||
|
||||
const B64_CONF: Config = Config::new(base64::CharacterSet::Standard, true);
|
||||
|
||||
#[cfg(feature = "encrypt")]
|
||||
const ASSOCIATED_DATA: &[u8] = b"usdpl-core-data";
|
||||
|
||||
#[cfg(feature = "encrypt")]
|
||||
use aes_gcm_siv::aead::{AeadInPlace, NewAead};
|
||||
|
||||
/// Errors from Loadable::load
|
||||
#[derive(Debug)]
|
||||
pub enum LoadError {
|
||||
|
@ -9,6 +15,9 @@ pub enum LoadError {
|
|||
TooSmallBuffer,
|
||||
/// Unexpected/corrupted data encountered
|
||||
InvalidData,
|
||||
/// Encrypted data cannot be decrypted
|
||||
#[cfg(feature = "encrypt")]
|
||||
DecryptionError,
|
||||
/// Unimplemented
|
||||
#[cfg(debug_assertions)]
|
||||
Todo,
|
||||
|
@ -19,6 +28,8 @@ impl std::fmt::Display for LoadError {
|
|||
match self {
|
||||
Self::TooSmallBuffer => write!(f, "LoadError: TooSmallBuffer"),
|
||||
Self::InvalidData => write!(f, "LoadError: InvalidData"),
|
||||
#[cfg(feature = "encrypt")]
|
||||
Self::DecryptionError => write!(f, "LoadError: DecryptionError"),
|
||||
#[cfg(debug_assertions)]
|
||||
Self::Todo => write!(f, "LoadError: TODO!"),
|
||||
}
|
||||
|
@ -38,6 +49,21 @@ pub trait Loadable: Sized {
|
|||
.map_err(|_| LoadError::InvalidData)?;
|
||||
Self::load(&buffer2[..len])
|
||||
}
|
||||
|
||||
/// Load data from an encrypted base64-encoded buffer
|
||||
#[cfg(feature = "encrypt")]
|
||||
fn load_encrypted(buffer: &[u8], key: &[u8], nonce: &[u8]) -> Result<(Self, usize), LoadError> {
|
||||
println!("encrypted buffer: {}", String::from_utf8(buffer.to_vec()).unwrap());
|
||||
let key = aes_gcm_siv::Key::from_slice(key);
|
||||
let cipher = aes_gcm_siv::Aes256GcmSiv::new(key);
|
||||
let nonce = aes_gcm_siv::Nonce::from_slice(nonce);
|
||||
let mut decoded_buf = base64::decode_config(buffer, B64_CONF)
|
||||
.map_err(|_| LoadError::InvalidData)?;
|
||||
println!("Decoded buf: {:?}", decoded_buf);
|
||||
cipher.decrypt_in_place(nonce, ASSOCIATED_DATA, &mut decoded_buf).map_err(|_| LoadError::DecryptionError)?;
|
||||
println!("Decrypted buf: {:?}", decoded_buf);
|
||||
Self::load(decoded_buf.as_slice())
|
||||
}
|
||||
}
|
||||
|
||||
/// Errors from Dumpable::dump
|
||||
|
@ -47,6 +73,9 @@ pub enum DumpError {
|
|||
TooSmallBuffer,
|
||||
/// Data cannot be dumped
|
||||
Unsupported,
|
||||
/// Data cannot be encrypted
|
||||
#[cfg(feature = "encrypt")]
|
||||
EncryptionError,
|
||||
/// Unimplemented
|
||||
#[cfg(debug_assertions)]
|
||||
Todo,
|
||||
|
@ -57,6 +86,8 @@ impl std::fmt::Display for DumpError {
|
|||
match self {
|
||||
Self::TooSmallBuffer => write!(f, "DumpError: TooSmallBuffer"),
|
||||
Self::Unsupported => write!(f, "DumpError: Unsupported"),
|
||||
#[cfg(feature = "encrypt")]
|
||||
Self::EncryptionError => write!(f, "DumpError: EncryptionError"),
|
||||
#[cfg(debug_assertions)]
|
||||
Self::Todo => write!(f, "DumpError: TODO!"),
|
||||
}
|
||||
|
@ -77,4 +108,23 @@ pub trait Dumpable {
|
|||
let len = encode_config_slice(&buffer2[..len], B64_CONF, buffer);
|
||||
Ok(len)
|
||||
}
|
||||
|
||||
/// Dump data as an encrypted base64-encoded buffer
|
||||
#[cfg(feature = "encrypt")]
|
||||
fn dump_encrypted(&self, buffer: &mut Vec<u8>, key: &[u8], nonce: &[u8]) -> Result<usize, DumpError> {
|
||||
let mut buffer2 = Vec::with_capacity(buffer.capacity());
|
||||
buffer2.extend_from_slice(buffer.as_slice());
|
||||
let size = self.dump(&mut buffer2)?;
|
||||
buffer2.truncate(size);
|
||||
println!("Buf: {:?}", buffer2);
|
||||
let key = aes_gcm_siv::Key::from_slice(key);
|
||||
let cipher = aes_gcm_siv::Aes256GcmSiv::new(key);
|
||||
let nonce = aes_gcm_siv::Nonce::from_slice(nonce);
|
||||
cipher.encrypt_in_place(nonce, ASSOCIATED_DATA, &mut buffer2).map_err(|_| DumpError::EncryptionError)?;
|
||||
println!("Encrypted slice: {:?}", &buffer2);
|
||||
let size = encode_config_slice(buffer2.as_slice(), B64_CONF, buffer);
|
||||
let string = String::from_utf8(buffer.as_slice()[..size].to_vec()).unwrap();
|
||||
println!("Encoded slice: {}", string);
|
||||
Ok(size)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,6 +11,8 @@ pub const HOST: Ipv4Addr = Ipv4Addr::new(127, 0, 0, 1);
|
|||
|
||||
/// Standard max packet size
|
||||
pub const PACKET_BUFFER_SIZE: usize = 1024;
|
||||
/// Encryption nonce size
|
||||
pub const NONCE_SIZE: usize = 12;
|
||||
|
||||
/// Address and port
|
||||
#[inline]
|
||||
|
@ -108,3 +110,38 @@ impl Dumpable for Packet {
|
|||
Ok(result)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[cfg(feature = "encrypt")]
|
||||
#[test]
|
||||
fn encryption_integration_test() {
|
||||
let key = hex_literal::hex!("59C4E408F27250B3147E7724511824F1D28ED7BEF43CF7103ACE747F77A2B265");
|
||||
let nonce = [0u8; NONCE_SIZE];
|
||||
let packet = Packet::Call(RemoteCall{
|
||||
id: 42,
|
||||
function: "test".into(),
|
||||
parameters: Vec::new(),
|
||||
});
|
||||
let mut buffer = Vec::with_capacity(PACKET_BUFFER_SIZE);
|
||||
buffer.extend_from_slice(&[0u8; PACKET_BUFFER_SIZE]);
|
||||
let len = packet.dump_encrypted(&mut buffer, &key, &nonce).unwrap();
|
||||
println!("buffer: {}", String::from_utf8(buffer.as_slice()[..len].to_vec()).unwrap());
|
||||
|
||||
let (packet_out, _len) = Packet::load_encrypted(&buffer.as_slice()[..len], &key, &nonce).unwrap();
|
||||
|
||||
if let Packet::Call(call_out) = packet_out {
|
||||
if let Packet::Call(call_in) = packet {
|
||||
assert_eq!(call_in.id, call_out.id, "Input and output packets do not match");
|
||||
assert_eq!(call_in.function, call_out.function, "Input and output packets do not match");
|
||||
assert_eq!(call_in.parameters.len(), call_out.parameters.len(), "Input and output packets do not match");
|
||||
} else {
|
||||
panic!("Packet in not a Call");
|
||||
}
|
||||
} else {
|
||||
panic!("Packet out not a Call!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,10 +12,11 @@ description = "Universal Steam Deck Plugin Library front-end designed for WASM"
|
|||
crate-type = ["cdylib", "rlib"]
|
||||
|
||||
[features]
|
||||
default = []
|
||||
default = ["encrypt"]
|
||||
decky = ["usdpl-core/decky"]
|
||||
crankshaft = ["usdpl-core/crankshaft"]
|
||||
debug = ["console_error_panic_hook"]
|
||||
encrypt = ["usdpl-core/encrypt", "obfstr", "hex"]
|
||||
|
||||
[dependencies]
|
||||
wasm-bindgen = "0.2"
|
||||
|
@ -44,7 +45,10 @@ web-sys = { version = "0.3", features = [
|
|||
]}
|
||||
js-sys = { version = "0.3" }
|
||||
|
||||
usdpl-core = { version = "0.5.0", path = "../usdpl-core" }
|
||||
obfstr = { version = "0.3", optional = true }
|
||||
hex = { version = "0.4", optional = true }
|
||||
|
||||
usdpl-core = { version = "0.6.0", path = "../usdpl-core" }
|
||||
|
||||
[dev-dependencies]
|
||||
wasm-bindgen-test = { version = "0.3.13" }
|
||||
|
|
|
@ -6,17 +6,17 @@ $0 [decky|crankshaft|<nothing>]"
|
|||
exit 0
|
||||
elif [ "$1" == "decky" ]; then
|
||||
echo "Building WASM module for decky framework"
|
||||
wasm-pack build --target web --features decky
|
||||
RUSTFLAGS="--cfg aes_compact" wasm-pack build --target web --features decky
|
||||
elif [ "$1" == "crankshaft" ]; then
|
||||
echo "WARNING: crankshaft support is unimplemented"
|
||||
wasm-pack build --target web --features crankshaft
|
||||
RUSTFLAGS="--cfg aes_compact" wasm-pack build --target web --features crankshaft
|
||||
else
|
||||
echo "Unsupported plugin framework \`$1\`"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
echo "WARNING: Building for any plugin framework, which may not work for every framework"
|
||||
wasm-pack build --target web
|
||||
RUSTFLAGS="--cfg aes_compact" wasm-pack build --target web
|
||||
fi
|
||||
|
||||
python3 ./scripts/generate_embedded_wasm.py
|
||||
|
|
|
@ -13,18 +13,22 @@ use web_sys::{Request, RequestInit, RequestMode, Response};
|
|||
use usdpl_core::serdes::{Dumpable, Loadable, Primitive};
|
||||
use usdpl_core::socket;
|
||||
|
||||
pub async fn send_js(packet: socket::Packet, port: u16) -> Result<Vec<Primitive>, JsValue> {
|
||||
const NONCE: [u8; socket::NONCE_SIZE]= [0u8; socket::NONCE_SIZE];
|
||||
|
||||
pub async fn send_js(
|
||||
packet: socket::Packet,
|
||||
port: u16,
|
||||
#[cfg(feature = "encrypt")]
|
||||
key: Vec<u8>,
|
||||
) -> Result<Vec<Primitive>, JsValue> {
|
||||
let mut opts = RequestInit::new();
|
||||
opts.method("POST");
|
||||
opts.mode(RequestMode::Cors);
|
||||
|
||||
let url = format!("http://{}:{}/usdpl/call", socket::HOST_STR, port);
|
||||
|
||||
let mut buffer = [0u8; socket::PACKET_BUFFER_SIZE];
|
||||
let len = packet
|
||||
.dump_base64(&mut buffer)
|
||||
.map_err(super::convert::str_to_js)?;
|
||||
let string: String = String::from_utf8_lossy(&buffer[..len]).into();
|
||||
let (buffer, len) = dump_to_buffer(packet, #[cfg(feature = "encrypt")] key.as_slice())?;
|
||||
let string: String = String::from_utf8_lossy(&buffer.as_slice()[..len]).into();
|
||||
opts.body(Some(&string.into()));
|
||||
|
||||
let request = Request::new_with_str_and_init(&url, &opts)?;
|
||||
|
@ -39,6 +43,7 @@ pub async fn send_js(packet: socket::Packet, port: u16) -> Result<Vec<Primitive>
|
|||
let text = JsFuture::from(resp.text()?).await?;
|
||||
let string: JsString = text.dyn_into()?;
|
||||
|
||||
#[cfg(not(feature = "encrypt"))]
|
||||
match socket::Packet::load_base64(string.as_string().unwrap().as_bytes())
|
||||
.map_err(super::convert::str_to_js)?
|
||||
.0
|
||||
|
@ -53,4 +58,40 @@ pub async fn send_js(packet: socket::Packet, port: u16) -> Result<Vec<Primitive>
|
|||
.into())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "encrypt")]
|
||||
match socket::Packet::load_encrypted(string.as_string().unwrap().as_bytes(), key.as_slice(), &NONCE)
|
||||
.map_err(super::convert::str_to_js)?
|
||||
.0
|
||||
{
|
||||
socket::Packet::CallResponse(resp) => Ok(resp.response),
|
||||
_ => {
|
||||
//imports::console_warn(&format!("USDPL warning: Got non-call-response message from {}", resp.url()));
|
||||
Err(format!(
|
||||
"Expected call response message from {}, got something else",
|
||||
resp.url()
|
||||
)
|
||||
.into())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "encrypt")]
|
||||
fn dump_to_buffer(packet: socket::Packet, key: &[u8]) -> Result<(Vec<u8>, usize), JsValue> {
|
||||
let mut buffer = Vec::with_capacity(socket::PACKET_BUFFER_SIZE);
|
||||
buffer.extend_from_slice(&[0u8; socket::PACKET_BUFFER_SIZE]);
|
||||
let len = packet
|
||||
.dump_encrypted(&mut buffer, key, &NONCE)
|
||||
.map_err(super::convert::str_to_js)?;
|
||||
Ok((buffer, len))
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "encrypt"))]
|
||||
fn dump_to_buffer(packet: socket::Packet) -> Result<(Vec<u8>, usize), JsValue> {
|
||||
let mut buffer = Vec::with_capacity(socket::PACKET_BUFFER_SIZE);
|
||||
buffer.extend_from_slice(&[0u8; socket::PACKET_BUFFER_SIZE]);
|
||||
let len = packet
|
||||
.dump_base64(buffer.as_mut_slice())
|
||||
.map_err(super::convert::str_to_js)?;
|
||||
Ok((buffer, len))
|
||||
}
|
||||
|
|
|
@ -16,19 +16,30 @@ use usdpl_core::{socket::Packet, RemoteCall};
|
|||
//const REMOTE_CALL_ID: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
|
||||
//const REMOTE_PORT: std::sync::atomic::AtomicU16 = std::sync::atomic::AtomicU16::new(31337);
|
||||
|
||||
static mut CTX: UsdplContext = UsdplContext { port: 31337, id: 1 };
|
||||
static mut CTX: UsdplContext = UsdplContext { port: 31337, id: 1, key: Vec::new() };
|
||||
|
||||
#[cfg(feature = "encrypt")]
|
||||
fn encryption_key() -> Vec<u8> {
|
||||
hex::decode(obfstr::obfstr!(env!("USDPL_ENCRYPTION_KEY"))).unwrap()
|
||||
}
|
||||
|
||||
//#[wasm_bindgen]
|
||||
#[derive(Debug)]
|
||||
struct UsdplContext {
|
||||
port: u16,
|
||||
id: u64,
|
||||
#[cfg(feature = "encrypt")]
|
||||
key: Vec<u8>,
|
||||
}
|
||||
|
||||
fn get_port() -> u16 {
|
||||
unsafe { CTX.port }
|
||||
}
|
||||
|
||||
fn get_key() -> Vec<u8> {
|
||||
unsafe { CTX.key.clone() }
|
||||
}
|
||||
|
||||
fn increment_id() -> u64 {
|
||||
let current_id = unsafe { CTX.id };
|
||||
unsafe {
|
||||
|
@ -49,7 +60,12 @@ pub fn init_usdpl(port: u16) {
|
|||
console_error_panic_hook::set_once();
|
||||
//REMOTE_PORT.store(port, std::sync::atomic::Ordering::SeqCst);
|
||||
unsafe {
|
||||
CTX = UsdplContext { port: port, id: 1 };
|
||||
CTX = UsdplContext {
|
||||
port: port,
|
||||
id: 1,
|
||||
#[cfg(feature = "encrypt")]
|
||||
key: encryption_key(),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -84,6 +100,8 @@ pub async fn call_backend(name: String, parameters: Vec<JsValue>) -> JsValue {
|
|||
parameters: params,
|
||||
}),
|
||||
port,
|
||||
#[cfg(feature = "encrypt")]
|
||||
get_key()
|
||||
)
|
||||
.await;
|
||||
let results = match results {
|
||||
|
|
Loading…
Reference in a new issue