refactor: re-organize workspace (#101)

- Remove Tauri client.

  It was useful when initially prototyping the Web Component, but now
  it’s more of a maintenance burden. It’s notably not convenient to
  check in CI. Since we now have another native alternative that does
  not require any GPU (`ironrdp-client`), it’s probably a good time to
  part ways.

- Move wasm package into the workspace.

- Move Rust crates into a `crates` subfolder.

- Introduce `xtask` crate for free-form automation.
This commit is contained in:
Benoît Cortier
2023-03-29 19:09:15 -04:00
committed by GitHub
parent 4ad13df499
commit 710a51f24a
378 changed files with 1424 additions and 1814 deletions
+2
View File
@@ -0,0 +1,2 @@
[alias]
xtask = "run --package xtask --"
+7 -6
View File
@@ -28,7 +28,7 @@ jobs:
if ($LastExitCode -eq 1) {
throw "Bad formatting, please run 'cargo +stable fmt --all'"
}
lints:
name: Lints
runs-on: ubuntu-20.04
@@ -47,7 +47,8 @@ jobs:
key: ${{ runner.os }}-lints-${{ hashFiles('Cargo.lock') }}
- name: Check clippy
run: cargo clippy --workspace -- -D warnings
# FIXME: run: cargo clippy --workspace -- -D warnings
run: cargo clippy -- -D warnings
wasm:
name: WASM target
@@ -63,15 +64,14 @@ jobs:
path: |
~/.cargo/registry/
~/.cargo/git/
./ffi/wasm/target/
./target/
key: ${{ runner.os }}-wasm-${{ hashFiles('ffi/wasm/Cargo.lock') }}
- name: Prepare runner
run: sudo apt install wabt
- name: Check
shell: pwsh
run: ./ffi/wasm/check.ps1
run: cargo xtask check wasm
tests:
name: Tests [${{ matrix.os }}]
@@ -100,7 +100,8 @@ jobs:
key: ${{ runner.os }}-tests-${{ hashFiles('Cargo.lock') }}
- name: Test [${{ matrix.os }}]
run: cargo test --workspace
# FIXME: run: cargo test --workspace
run: cargo test
fuzz:
name: Fuzzing
+6
View File
@@ -1,6 +1,12 @@
# Build artifacts
/target
# Log files
*.log
# Coverage
/docs
# Editor/IDE files
*~
/tags
Generated
+322 -164
View File
File diff suppressed because it is too large Load Diff
+40 -12
View File
@@ -1,15 +1,43 @@
[package]
name = "ironrdp"
version = "0.5.0"
edition = "2021"
readme = "README.md"
license = "MIT/Apache-2.0"
homepage = "https://github.com/Devolutions/IronRDP"
repository = "https://github.com/Devolutions/IronRDP"
authors = ["Devolutions Inc. <infos@devolutions.net>"]
description = "A Rust implementation of the Microsoft Remote Desktop Protocol (RDP)"
keywords = ["rdp", "remote", "desktop", "protocol"]
[workspace]
members = [
"ironrdp",
"ironrdp-core",
"ironrdp-graphics",
"ironrdp-input",
"ironrdp-session",
"ironrdp-session-async",
"ironrdp-tls",
"ironrdp-rdcleanpath",
"ironrdp-renderer",
"ironrdp-client",
"ironrdp-client-glutin",
"ironrdp-replay-client",
"crates/*",
"xtask",
]
default-members = [
"crates/pdu",
"crates/session",
"crates/graphics",
"crates/input",
"crates/session-async",
"crates/client",
]
[profile.production]
inherits = "release"
lto = true
[profile.production-wasm]
inherits = "release"
opt-level = "s"
lto = true
[features]
default = []
[dependencies]
ironrdp-pdu = { path = "crates/pdu" }
ironrdp-session = { path = "crates/session" }
ironrdp-graphics = { path = "crates/graphics" }
ironrdp-input = { path = "crates/input" }
+37 -20
View File
@@ -1,25 +1,10 @@
# IronRDP
A Rust implementation of the Microsoft Remote Desktop Protocol, with a focus on security.
A collection of Rust crates providing an implementation of the Microsoft Remote Desktop Protocol, with a focus on security.
## Architecture (Work In Progress…)
## Demonstration
- `ironrdp`: meta crate re-exporting important crates
- `ironrdp-core`: core, RDP protocol packets encoding and decoding.
- `ironrdp-graphics`: image processing primitives and algorithms (ZGFX, DWT…).
- `ironrdp-input`: helpers to build FastPathInput packets.
- `ironrdp-session`: abstract state machine on top of `ironrdp-graphics`.
- `ironrdp-session-async`: `Future`s built on top of `ironrdp-session`.
- `ironrdp-tls`: TLS boilerplate common with most IronRDP clients.
- `ironrdp-devolutions-gateway`: Devolutions Gateway extensions.
- `ironrdp-renderer`: `glutin` primitives for OpenGL rendering.
- `ironrdp-client`: Portable RDP client without GPU acceleration using softbuffer and winit for windowing.
- `ironrdp-client-glutin`: GPU-accelerated RDP client using glutin.
- `ironrdp-replay-client`: utility tool to replay RDP graphics pipeline for debugging purposes.
- `iron-remote-gui`: core frontend ui used by both, iron-svelte-client and iron-tauri-client.
- `iron-svelte-client`: web-based frontend using `Svelte` and `Material` frameworks).
- `iron-tauri-client`: a native client built with Tauri. Frontend is using the `iron-web-client`/`iron-svelte-client` component.
- `ffi/wasm`: WebAssembly high-level bindings targeting web browsers.
https://user-images.githubusercontent.com/3809077/202049929-76f42471-aeb0-41da-9118-0dc6ea491bd2.mp4
## Video Codec Support
@@ -50,7 +35,39 @@ Alternatively, you may change a few group policies using `gpedit.msc`:
5. Reboot.
## Demonstration
## Architecture (Work In Progress…)
https://user-images.githubusercontent.com/3809077/202049929-76f42471-aeb0-41da-9118-0dc6ea491bd2.mp4
- `ironrdp` (root package): meta crate re-exporting important crates,
- `ironrdp-pdu` (`crates/pdu`): PDU encoding and decoding (no I/O, trivial to fuzz),
- `ironrdp-graphics` (`crates/graphics`): image processing primitives (no I/O, trivial to fuzz),
- `ironrdp-session` (`crates/session`): state machine to drive a complete VNC session (no I/O, not _too_ hard to fuzz),
- `ironrdp-input` (`crates/input`): utilities to manage and build input packets (no I/O),
- `ironrdp-session-async` (`crates/session-async`): provides `Future`s wrapping the session state machine conveniently,
- `ironrdp-tls` (`crates/tls`): TLS boilerplate common with most IronRDP clients,
- `ironrdp-rdcleanpath` (`crates/rdcleanpath`): RDCleanPath PDU structure used by IronRDP web client and Devolutions Gateway,
- `ironrdp-client` (`crates/client`): Portable RDP client without GPU acceleration using softbuffer and winit for windowing,
- `ironrdp-web` (`crates/web`): WebAssembly high-level bindings targeting web browsers,
- `ironrdp-glutin-renderer` (`crates/glutin-renderer`): `glutin` primitives for OpenGL rendering,
- `ironrdp-client-glutin` (`crates/client-glutin`): GPU-accelerated RDP client using glutin,
- `ironrdp-replay-client` (`crates/replay-client`): utility tool to replay RDP graphics pipeline for debugging purposes,
- `ironrdp-pdu-generators` (`crates/pdu-generators`): `proptest` generators for `ironrdp-pdu` types,
- `ironrdp-session-generators` (`crates/session-generators`): `proptest` generators for `ironrdp-session` types,
- `iron-remote-gui` (`web-client/iron-remote-gui`): core frontend UI used by `iron-svelte-client` as a Web Component,
- `iron-svelte-client` (`web-client/iron-svelte-client`): web-based frontend using `Svelte` and `Material` frameworks,
- and finally, `ironrdp-fuzz` (`fuzz`): fuzz targets for core crates.
## General design
- Avoid I/O wherever possible
- Dependency injection when runtime information is necessary in core crates (no system call such as `gethostname`)
- Keep non-portable code out of core crates
- Make crate `no_std`-compatible wherever possible
- Facilitate fuzzing
- In libraries, provide concrete error types either hand-crafted or using `thiserror` crate
- In binaries, use the convenient catch-all error type `anyhow::Error`
- Free-form automation a-la `make` following [`cargo xtask`](https://github.com/matklad/cargo-xtask) specification
## Continuous integration
We use GitHub action and our workflows simply run `cargo xtask`.
The expectation is that, if `cargo xtask ci` passes locally, the CI will be green as well.
@@ -1,5 +1,5 @@
[package]
name = "ironrdp-gui-client"
name = "ironrdp-client-glutin"
version = "0.4.2"
edition = "2021"
readme = "README.md"
@@ -11,13 +11,14 @@ keywords = ["rdp", "client", "remote", "desktop", "protocol", "gfx", "rfx"]
[features]
default = ["rustls"]
rustls = ["dep:tokio-rustls", "ironrdp/rustls"]
native-tls = ["dep:async-native-tls", "ironrdp/native-tls"]
rustls = ["dep:tokio-rustls", "ironrdp-session/rustls"]
native-tls = ["dep:async-native-tls", "ironrdp-session/native-tls"]
[dependencies]
# Protocol
ironrdp = { path = "../ironrdp" }
# Protocols
ironrdp = { path = "../.." }
ironrdp-session = { path = "../session" }
sspi = { version = "0.8", features = ["network_client"] }
# CLI
@@ -43,4 +44,4 @@ chrono = "0.4.23"
# GUI
glutin = "0.29"
ironrdp-renderer = { path = "../ironrdp-renderer"}
ironrdp-glutin-renderer = { path = "../glutin-renderer"}
@@ -26,11 +26,11 @@ enum SecurityProtocol {
}
impl SecurityProtocol {
fn parse(security_protocol: SecurityProtocol) -> ironrdp::core::SecurityProtocol {
fn parse(security_protocol: SecurityProtocol) -> ironrdp::pdu::SecurityProtocol {
match security_protocol {
SecurityProtocol::Ssl => ironrdp::core::SecurityProtocol::SSL,
SecurityProtocol::Hybrid => ironrdp::core::SecurityProtocol::HYBRID,
SecurityProtocol::HybridEx => ironrdp::core::SecurityProtocol::HYBRID_EX,
SecurityProtocol::Ssl => ironrdp::pdu::SecurityProtocol::SSL,
SecurityProtocol::Hybrid => ironrdp::pdu::SecurityProtocol::HYBRID,
SecurityProtocol::HybridEx => ironrdp::pdu::SecurityProtocol::HYBRID_EX,
}
}
}
@@ -47,15 +47,15 @@ enum KeyboardType {
}
impl KeyboardType {
fn parse(keyboard_type: KeyboardType) -> ironrdp::gcc::KeyboardType {
fn parse(keyboard_type: KeyboardType) -> ironrdp::pdu::gcc::KeyboardType {
match keyboard_type {
KeyboardType::IbmEnhanced => ironrdp::gcc::KeyboardType::IbmEnhanced,
KeyboardType::IbmPcAt => ironrdp::gcc::KeyboardType::IbmPcAt,
KeyboardType::IbmPcXt => ironrdp::gcc::KeyboardType::IbmPcXt,
KeyboardType::OlivettiIco => ironrdp::gcc::KeyboardType::OlivettiIco,
KeyboardType::Nokia1050 => ironrdp::gcc::KeyboardType::Nokia1050,
KeyboardType::Nokia9140 => ironrdp::gcc::KeyboardType::Nokia9140,
KeyboardType::Japanese => ironrdp::gcc::KeyboardType::Japanese,
KeyboardType::IbmEnhanced => ironrdp::pdu::gcc::KeyboardType::IbmEnhanced,
KeyboardType::IbmPcAt => ironrdp::pdu::gcc::KeyboardType::IbmPcAt,
KeyboardType::IbmPcXt => ironrdp::pdu::gcc::KeyboardType::IbmPcXt,
KeyboardType::OlivettiIco => ironrdp::pdu::gcc::KeyboardType::OlivettiIco,
KeyboardType::Nokia1050 => ironrdp::pdu::gcc::KeyboardType::Nokia1050,
KeyboardType::Nokia9140 => ironrdp::pdu::gcc::KeyboardType::Nokia9140,
KeyboardType::Japanese => ironrdp::pdu::gcc::KeyboardType::Japanese,
}
}
}
@@ -6,9 +6,9 @@ use std::sync::{self, Arc};
use glutin::dpi::PhysicalPosition;
use glutin::event::{Event, WindowEvent};
use glutin::event_loop::ControlFlow;
use ironrdp::dvc::gfx::ServerPdu;
use ironrdp::pdu::dvc::gfx::ServerPdu;
use ironrdp::session::{ErasedWriter, GfxHandler};
use ironrdp_renderer::renderer::Renderer;
use ironrdp_glutin_renderer::renderer::Renderer;
use tokio::sync::Mutex;
use self::input::{handle_input_events, translate_input_event};
@@ -28,7 +28,7 @@ impl MessagePassingGfxHandler {
}
impl GfxHandler for MessagePassingGfxHandler {
fn on_message(&self, message: ServerPdu) -> Result<Option<ironrdp::dvc::gfx::ClientPdu>, RdpError> {
fn on_message(&self, message: ServerPdu) -> Result<Option<ironrdp::pdu::dvc::gfx::ClientPdu>, RdpError> {
self.channel.send(message).map_err(|e| RdpError::Send(e.to_string()))?;
Ok(None)
}
@@ -4,10 +4,10 @@ use std::sync::Arc;
use futures_util::AsyncWriteExt;
use glutin::dpi::PhysicalPosition;
use glutin::event::{ElementState, Event, WindowEvent};
use ironrdp::core::input::fast_path::{FastPathInput, FastPathInputEvent, KeyboardFlags};
use ironrdp::core::input::mouse::PointerFlags;
use ironrdp::core::input::MousePdu;
use ironrdp::core::PduParsing;
use ironrdp::pdu::input::fast_path::{FastPathInput, FastPathInputEvent, KeyboardFlags};
use ironrdp::pdu::input::mouse::PointerFlags;
use ironrdp::pdu::input::MousePdu;
use ironrdp::pdu::PduParsing;
use ironrdp::session::ErasedWriter;
use tokio::sync::Mutex;
@@ -9,8 +9,8 @@ use std::{io, process};
use futures_util::io::AsyncWriteExt as _;
use gui::MessagePassingGfxHandler;
use ironrdp::dvc::gfx::ServerPdu;
use ironrdp::graphics::image_processing::PixelFormat;
use ironrdp::pdu::dvc::gfx::ServerPdu;
use ironrdp::session::connection_sequence::{process_connection_sequence, UpgradedStream};
use ironrdp::session::image::DecodedImage;
use ironrdp::session::{ActiveStageOutput, ActiveStageProcessor, ErasedWriter, RdpError};
@@ -11,15 +11,16 @@ keywords = ["rdp", "client", "remote", "desktop", "protocol", "gfx", "rfx"]
[features]
default = ["rustls"]
rustls = ["dep:tokio-rustls", "ironrdp/rustls"]
native-tls = ["dep:async-native-tls", "ironrdp/native-tls"]
rustls = ["dep:tokio-rustls", "ironrdp-session/rustls"]
native-tls = ["dep:async-native-tls", "ironrdp-session/native-tls"]
[dependencies]
# Protocol
ironrdp = { path = "../ironrdp" }
ironrdp-input = { path = "../ironrdp-input" }
sspi = { version = "0.8.0", features = ["network_client"] } # TODO: enable dns_resolver at some point
# Protocols
ironrdp = { path = "../.." }
ironrdp-input = { path = "../input" }
ironrdp-session = { path = "../session" }
sspi = { version = "0.8", features = ["network_client"] } # TODO: enable dns_resolver at some point
# GUI
softbuffer = "0.2.0"
@@ -30,16 +31,18 @@ clap = { version = "4.0", features = ["derive", "cargo"] }
exitcode = "1.1.2"
inquire = "0.5.3"
# logging
# Logging
log = "0.4"
fern = "0.6"
tracing-subscriber = { version = "0.3.16", features = ["env-filter"] }
tracing = "0.1.37"
# SSL
x509-parser = "0.14"
async-native-tls = { version = "0.4", default-features = false, features = [ "runtime-tokio" ], optional = true }
tokio-rustls = { version = "0.23", features = ["dangerous_configuration"], optional = true }
# async, futures
# Async, futures
tokio = { version = "1", features = ["full"]}
tokio-util = { version = "0.7.4", features = ["compat"] }
futures-util = "0.3"
@@ -49,5 +52,3 @@ chrono = "0.4.23"
whoami = "1.2.3"
anyhow = "1.0.68"
smallvec = "1.10.0"
tracing-subscriber = { version = "0.3.16", features = ["env-filter"] }
tracing = "0.1.37"
@@ -26,11 +26,11 @@ enum SecurityProtocol {
}
impl SecurityProtocol {
fn parse(security_protocol: SecurityProtocol) -> ironrdp::core::SecurityProtocol {
fn parse(security_protocol: SecurityProtocol) -> ironrdp::pdu::SecurityProtocol {
match security_protocol {
SecurityProtocol::Ssl => ironrdp::core::SecurityProtocol::SSL,
SecurityProtocol::Hybrid => ironrdp::core::SecurityProtocol::HYBRID,
SecurityProtocol::HybridEx => ironrdp::core::SecurityProtocol::HYBRID_EX,
SecurityProtocol::Ssl => ironrdp::pdu::SecurityProtocol::SSL,
SecurityProtocol::Hybrid => ironrdp::pdu::SecurityProtocol::HYBRID,
SecurityProtocol::HybridEx => ironrdp::pdu::SecurityProtocol::HYBRID_EX,
}
}
}
@@ -47,15 +47,15 @@ enum KeyboardType {
}
impl KeyboardType {
fn parse(keyboard_type: KeyboardType) -> ironrdp::gcc::KeyboardType {
fn parse(keyboard_type: KeyboardType) -> ironrdp::pdu::gcc::KeyboardType {
match keyboard_type {
KeyboardType::IbmEnhanced => ironrdp::gcc::KeyboardType::IbmEnhanced,
KeyboardType::IbmPcAt => ironrdp::gcc::KeyboardType::IbmPcAt,
KeyboardType::IbmPcXt => ironrdp::gcc::KeyboardType::IbmPcXt,
KeyboardType::OlivettiIco => ironrdp::gcc::KeyboardType::OlivettiIco,
KeyboardType::Nokia1050 => ironrdp::gcc::KeyboardType::Nokia1050,
KeyboardType::Nokia9140 => ironrdp::gcc::KeyboardType::Nokia9140,
KeyboardType::Japanese => ironrdp::gcc::KeyboardType::Japanese,
KeyboardType::IbmEnhanced => ironrdp::pdu::gcc::KeyboardType::IbmEnhanced,
KeyboardType::IbmPcAt => ironrdp::pdu::gcc::KeyboardType::IbmPcAt,
KeyboardType::IbmPcXt => ironrdp::pdu::gcc::KeyboardType::IbmPcXt,
KeyboardType::OlivettiIco => ironrdp::pdu::gcc::KeyboardType::OlivettiIco,
KeyboardType::Nokia1050 => ironrdp::pdu::gcc::KeyboardType::Nokia1050,
KeyboardType::Nokia9140 => ironrdp::pdu::gcc::KeyboardType::Nokia9140,
KeyboardType::Japanese => ironrdp::pdu::gcc::KeyboardType::Japanese,
}
}
}
@@ -261,7 +261,7 @@ impl GuiContext {
fn send_fast_path_events(
input_event_sender: &mpsc::UnboundedSender<RdpInputEvent>,
input_events: smallvec::SmallVec<[ironrdp::core::input::fast_path::FastPathInputEvent; 2]>,
input_events: smallvec::SmallVec<[ironrdp::pdu::input::fast_path::FastPathInputEvent; 2]>,
) {
if !input_events.is_empty() {
let _ = input_event_sender.send(RdpInputEvent::FastPath(input_events));
@@ -1,15 +1,11 @@
#[macro_use]
extern crate log;
use std::fs::OpenOptions;
use anyhow::Context as _;
use ironrdp_client::config::Config;
use ironrdp_client::gui::GuiContext;
use ironrdp_client::rdp::{RdpClient, RdpInputEvent};
use tokio::runtime;
use tracing_subscriber::prelude::__tracing_subscriber_SubscriberExt;
use tracing_subscriber::EnvFilter;
fn main() -> anyhow::Result<()> {
let mut config = Config::parse_args().context("CLI arguments parsing")?;
@@ -63,6 +59,11 @@ fn setup_logging(log_file: &str) -> Result<(), fern::InitError> {
// sspi-rs logging
if let Ok(path) = std::env::var("SSPI_LOG_FILE") {
use std::fs::OpenOptions;
use tracing_subscriber::prelude::*;
use tracing_subscriber::EnvFilter;
let file = match OpenOptions::new().read(true).append(true).open(path) {
Ok(file) => file,
Err(e) => {
@@ -1,6 +1,6 @@
use futures_util::io::AsyncWriteExt as _;
use ironrdp::core::input::fast_path::FastPathInputEvent;
use ironrdp::graphics::image_processing::PixelFormat;
use ironrdp::pdu::input::fast_path::FastPathInputEvent;
use ironrdp::session::connection_sequence::{process_connection_sequence, Address};
use ironrdp::session::image::DecodedImage;
use ironrdp::session::{ActiveStageOutput, ActiveStageProcessor, RdpError};
@@ -143,8 +143,8 @@ async fn run_impl(
return Ok(RdpControlFlow::ReconnectWithNewSize { width, height })
},
RdpInputEvent::FastPath(events) => {
use ironrdp::core::input::fast_path::FastPathInput;
use ironrdp::core::PduParsing as _;
use ironrdp::pdu::input::fast_path::FastPathInput;
use ironrdp::pdu::PduParsing as _;
trace!("Inputs: {events:?}");
@@ -159,7 +159,7 @@ async fn run_impl(
writer.write_all(&frame).await?;
}
RdpInputEvent::Close => {
// TODO: should we send a connection close to server?
// TODO: https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/27915739-8f77-487e-9927-55008af7fd68
break 'outer;
}
}

Some files were not shown because too many files have changed in this diff Show More