Skip to content

Commit

Permalink
Merge pull request #255 from c410-f3r/misc
Browse files Browse the repository at this point in the history
Add the "no-masking" parameter
  • Loading branch information
c410-f3r authored Oct 29, 2024
2 parents b2a6d93 + c6247c5 commit cdf0afc
Show file tree
Hide file tree
Showing 46 changed files with 933 additions and 583 deletions.
10 changes: 10 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Contributing

Before submitting a PR, you should probably run `./scripts/internal-tests-all.sh` and/or `./scripts/intergration-tests.sh` to make sure everything is fine.

Integration tests interact with external programs like `podman` or require an internet connection, therefore, they usually aren't good candidates for offline development. On the other hand, internal tests are composed by unit tests, code formatting, `clippy` lints and fuzzing targets.

## Building

Taking aside common Rust tools that can be installed with `rustup` (https://rustup.rs/), at the current time it is only necessary to only have an C compiler to build the project. For example, you can use your favorite system package manager to install `gcc`.

42 changes: 19 additions & 23 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions wtx-docs/src/web-socket/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ The "permessage-deflate" extension is the only supported compression format and

To get the most performance possible, try compiling your program with `RUSTFLAGS='-C target-cpu=native'` to allow `zlib-rs` to use more efficient SIMD instructions.

## No masking

Although not officially endorsed, the `no-masking` parameter described at https://datatracker.ietf.org/doc/html/draft-damjanovic-websockets-nomasking-02 is supported to increase performance. If such a feature is not desirable, please make sure to check the handshake parameters to avoid accidental scenarios.

## Client Example

```rust,edition2021,no_run
Expand Down
1 change: 1 addition & 0 deletions wtx-fuzz/web_socket.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ libfuzzer_sys::fuzz_target!(|data: (OpCode, Vec<u8>)| {
Builder::new_current_thread().enable_all().build().unwrap().block_on(async move {
let Ok(mut ws) = WebSocketServerOwned::new(
(),
false,
Xorshift64::from(simple_seed()),
BytesStream::default(),
WebSocketBuffer::default(),
Expand Down
1 change: 1 addition & 0 deletions wtx-instances/generic-examples/client-api-framework.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ async fn main() -> wtx::Result<()> {
let web_socket = WebSocketClient::connect(
(),
[],
false,
Xorshift64::from(simple_seed()),
TcpStream::connect(uri.hostname_with_implied_port()).await?,
&uri,
Expand Down
1 change: 1 addition & 0 deletions wtx-instances/generic-examples/web-socket-client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ async fn main() -> wtx::Result<()> {
let mut ws = WebSocketClient::connect(
(),
[],
false,
Xorshift64::from(simple_seed()),
TcpStream::connect(uri.hostname_with_implied_port()).await?,
&uri.to_ref(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,16 @@
//! password BYTEA NOT NULL,
//! salt BYTEA NOT NULL
//! );
//! ALTER TABLE "user" ADD CONSTRAINT user__email__uq UNIQUE (email);
//!
//! CREATE TABLE session (
//! id BYTEA NOT NULL PRIMARY KEY,
//! user_id INT NOT NULL,
//! expires_at TIMESTAMPTZ NOT NULL
//! );
//!
//! ALTER TABLE session ADD CONSTRAINT session__user__fk FOREIGN KEY (user_id) REFERENCES "user" (id);
//! ```
use argon2::{Algorithm, Argon2, Block, Params, Version};
use rand_chacha::{rand_core::SeedableRng, ChaCha20Rng};
use tokio::net::TcpStream;
use wtx::{
Expand All @@ -29,21 +28,10 @@ use wtx::{
server_framework::{get, post, Router, ServerFrameworkBuilder, State, StateClean},
ReqResBuffer, ReqResData, SessionDecoder, SessionEnforcer, SessionTokio, StatusCode,
},
misc::argon2_pwd,
pool::{PostgresRM, SimplePoolTokio},
};

const ARGON2_OUTPUT_LEN: usize = 32;
const ARGON2_PARAMS: Params = {
let Ok(elem) = Params::new(
Params::DEFAULT_M_COST,
Params::DEFAULT_T_COST,
Params::DEFAULT_P_COST,
Some(ARGON2_OUTPUT_LEN),
) else {
panic!();
};
elem
};
type ConnAux = (Session, ChaCha20Rng);
type Pool = SimplePoolTokio<PostgresRM<wtx::Error, TcpStream>>;
type Session = SessionTokio<u32, wtx::Error, Pool>;
Expand Down Expand Up @@ -71,40 +59,29 @@ async fn main() -> wtx::Result<()> {
Ok(())
}

#[derive(Debug, serde::Deserialize)]
struct User<'req> {
email: &'req str,
password: &'req str,
}

#[inline]
async fn login(state: State<'_, ConnAux, (), ReqResBuffer>) -> wtx::Result<StatusCode> {
let (session, rng) = state.ca;
if session.content.lock().await.state().is_some() {
session.delete_session_cookie(&mut state.req.rrd).await?;
return Ok(StatusCode::Forbidden);
}
let user: User<'_> = serde_json::from_slice(state.req.rrd.body())?;
let user: UserLoginReq<'_> = serde_json::from_slice(state.req.rrd.body())?;
let mut executor_guard = session.store.get().await?;
let record = executor_guard
.fetch_with_stmt("SELECT id,password,salt FROM user WHERE email = $1", (user.email,))
.await?;
let id = record.decode::<_, u32>(0)?;
let password_db = record.decode::<_, &[u8]>(1)?;
let salt = record.decode::<_, &[u8]>(2)?;
let mut password_req = [0; ARGON2_OUTPUT_LEN];
Argon2::new(Algorithm::Argon2id, Version::V0x13, ARGON2_PARAMS).hash_password_into_with_memory(
user.password.as_bytes(),
salt,
&mut password_req,
&mut [Block::new(); ARGON2_PARAMS.block_count()],
)?;
let password_req = argon2_pwd(user.password.as_bytes(), salt)?;
state.req.rrd.clear();
if password_db != &password_req {
return Ok(StatusCode::Unauthorized);
}
drop(executor_guard);
session.set_session_cookie(id, rng, &mut state.req.rrd).await?;
serde_json::to_writer(&mut state.req.rrd.body, &UserLoginRes { id })?;
Ok(StatusCode::Ok)
}

Expand All @@ -113,3 +90,14 @@ async fn logout(state: StateClean<'_, ConnAux, (), ReqResBuffer>) -> wtx::Result
state.ca.0.delete_session_cookie(&mut state.req.rrd).await?;
Ok(StatusCode::Ok)
}

#[derive(Debug, serde::Deserialize)]
struct UserLoginReq<'req> {
email: &'req str,
password: &'req str,
}

#[derive(Debug, serde::Serialize)]
struct UserLoginRes {
id: u32,
}
37 changes: 21 additions & 16 deletions wtx-instances/http2-examples/http2-server.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//! Serves requests using low-level HTTP/2 resources along side self-made certificates.
//! HTTP/2 server that uses optioned parameters.
extern crate tokio;
extern crate tokio_rustls;
Expand All @@ -8,8 +8,11 @@ extern crate wtx_instances;
use tokio::{io::WriteHalf, net::TcpStream};
use tokio_rustls::server::TlsStream;
use wtx::{
http::{Headers, OptionedServer, ReqResBuffer, Request, Response, StatusCode},
http2::{Http2Buffer, Http2Params, ServerStreamTokio, WebSocketOverStream},
http::{
AutoStream, ManualServerStreamTokio, OptionedServer, ReqResBuffer, Response, StatusCode,
StreamMode,
},
http2::{is_web_socket_handshake, Http2Buffer, Http2Params, WebSocketOverStream},
misc::{simple_seed, TokioRustlsAcceptor, Vector, Xorshift64},
web_socket::{Frame, OpCode},
};
Expand All @@ -31,6 +34,13 @@ async fn main() -> wtx::Result<()> {
|error| eprintln!("{error}"),
manual,
|| Ok((Vector::new(), ReqResBuffer::empty())),
|headers, method, protocol| {
Ok(if is_web_socket_handshake(headers, method, protocol) {
StreamMode::Manual
} else {
StreamMode::Auto
})
},
(
|| {
TokioRustlsAcceptor::without_client_auth()
Expand All @@ -44,31 +54,26 @@ async fn main() -> wtx::Result<()> {
.await
}

async fn auto(
_: (),
_: Vector<u8>,
mut req: Request<ReqResBuffer>,
) -> Result<Response<ReqResBuffer>, wtx::Error> {
req.rrd.clear();
Ok(req.into_response(StatusCode::Ok))
async fn auto(mut ha: AutoStream<(), Vector<u8>>) -> Result<Response<ReqResBuffer>, wtx::Error> {
ha.req.rrd.clear();
Ok(ha.req.into_response(StatusCode::Ok))
}

async fn manual(
_: (),
mut buffer: Vector<u8>,
_: Headers,
stream: ServerStreamTokio<Http2Buffer, WriteHalf<TlsStream<TcpStream>>, false>,
mut hm: ManualServerStreamTokio<(), Vector<u8>, Http2Buffer, WriteHalf<TlsStream<TcpStream>>>,
) -> Result<(), wtx::Error> {
let rng = Xorshift64::from(simple_seed());
let mut wos = WebSocketOverStream::new(&Headers::new(), rng, stream).await?;
hm.headers.clear();
let mut wos = WebSocketOverStream::new(&hm.headers, false, rng, hm.stream).await?;
loop {
let mut frame = wos.read_frame(&mut buffer).await?;
let mut frame = wos.read_frame(&mut hm.sa).await?;
match (frame.op_code(), frame.text_payload()) {
(_, Some(elem)) => println!("{elem}"),
(OpCode::Close, _) => break,
_ => {}
}
wos.write_frame(&mut Frame::new_fin(OpCode::Text, frame.payload_mut())).await?;
}
wos.close().await?;
Ok(())
}
4 changes: 2 additions & 2 deletions wtx-instances/http2-examples/http2-web-socket.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ extern crate wtx;
extern crate wtx_instances;

use core::mem;

use tokio::net::TcpListener;
use wtx::{
http::{Headers, ReqResBuffer},
Expand Down Expand Up @@ -47,7 +46,7 @@ async fn main() -> wtx::Result<()> {
return Ok(());
};
let mut buffer = Vector::new();
let mut wos = WebSocketOverStream::new(&Headers::new(), rng, &mut stream).await?;
let mut wos = WebSocketOverStream::new(&Headers::new(), false, rng, &mut stream).await?;
loop {
let mut frame = wos.read_frame(&mut buffer).await?;
match (frame.op_code(), frame.text_payload()) {
Expand All @@ -57,6 +56,7 @@ async fn main() -> wtx::Result<()> {
}
wos.write_frame(&mut Frame::new_fin(OpCode::Text, frame.payload_mut())).await?;
}
wos.close().await?;
stream.common().clear(false).await?;
Ok(())
}
3 changes: 3 additions & 0 deletions wtx-instances/src/bin/autobahn-client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ async fn main() -> wtx::Result<()> {
let mut ws = WebSocketClient::connect(
Flate2::default(),
[],
false,
Xorshift64::from(simple_seed()),
TcpStream::connect(host).await?,
&UriRef::new(&format!("http://{host}/runCase?case={case}&agent=wtx")),
Expand All @@ -40,6 +41,7 @@ async fn main() -> wtx::Result<()> {
WebSocketClient::connect(
(),
[],
false,
Xorshift64::from(simple_seed()),
TcpStream::connect(host).await?,
&UriRef::new(&format!("http://{host}/updateReports?agent=wtx")),
Expand All @@ -55,6 +57,7 @@ async fn get_case_count(host: &str, wsb: &mut WebSocketBuffer) -> wtx::Result<u3
let mut ws = WebSocketClient::connect(
(),
[],
false,
Xorshift64::from(simple_seed()),
TcpStream::connect(host).await?,
&UriRef::new(&format!("http://{host}/getCaseCount")),
Expand Down
Loading

0 comments on commit cdf0afc

Please sign in to comment.