Skip to content

Commit

Permalink
dev: use clock in minimal connection cookie implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
da2ce7 committed Sep 12, 2022
1 parent c123da0 commit 23b241b
Show file tree
Hide file tree
Showing 9 changed files with 330 additions and 49 deletions.
18 changes: 18 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,21 @@ pub mod static_time {
pub static ref TIME_AT_APP_START: SystemTime = SystemTime::now();
}
}

pub mod static_keys {
pub mod static_seeds {
use rand::rngs::ThreadRng;
use rand::Rng;

pub type SeedSize = [u8; 32];

lazy_static! {
pub static ref INSTANCE_SEED: SeedSize = Rng::gen(&mut ThreadRng::default());
}

#[cfg(test)]
lazy_static! {
pub static ref ZEROED_TEST_SEED: SeedSize = [0u8; 32];
}
}
}
5 changes: 5 additions & 0 deletions src/protocol/clock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,10 @@ pub trait StoppedTime: Time {
fn local_reset();
}

#[derive(Debug)]
pub struct Clock<const T: usize>;

#[derive(Debug)]
pub enum ClockType {
WorkingClock,
StoppedClock,
Expand Down Expand Up @@ -153,18 +155,21 @@ impl StoppedTime for StoppedClock {

#[cfg(test)]
mod tests {
use std::any::TypeId;
use std::thread;

use super::*;

#[test]
fn the_stopped_time_and_default_time_should_be_the_same_when_testing() {
// We are testing, so we should default to the fixed time.
assert_eq!(TypeId::of::<StoppedClock>(), TypeId::of::<DefaultClock>());
assert_eq!(StoppedClock::now(), DefaultClock::now())
}

#[test]
fn the_stopped_time_and_working_time_should_be_different() {
assert_ne!(TypeId::of::<StoppedClock>(), TypeId::of::<WorkingClock>());
assert_ne!(StoppedClock::now(), WorkingClock::now())
}

Expand Down
84 changes: 84 additions & 0 deletions src/protocol/crypto.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
pub mod keys {

pub mod seeds {
use crate::static_keys::static_seeds::{SeedSize, INSTANCE_SEED};

pub trait Seed {
type Seed: Sized + Default + AsMut<[u8]>;
fn seed() -> &'static Self::Seed;
}

pub struct InstanceSeed;
pub struct DefaultSeed;

impl Seed for InstanceSeed {
type Seed = SeedSize;
fn seed() -> &'static Self::Seed {
&*INSTANCE_SEED
}
}

impl Seed for DefaultSeed {
type Seed = SeedSize;
fn seed() -> &'static Self::Seed {
&*self::detail::DEFAULT_SEED
}
}

pub fn initialize_default_seed() {
lazy_static::initialize(&self::detail::DEFAULT_SEED);
}

mod detail {

#[cfg(not(test))]
pub use INSTANCE_SEED as DEFAULT_SEED;

pub use crate::static_keys::static_seeds::INSTANCE_SEED;
#[cfg(test)]
pub use crate::static_keys::static_seeds::ZEROED_TEST_SEED as DEFAULT_SEED;

#[cfg(test)]
mod tests {
use std::convert::TryInto;

use crate::static_keys::static_seeds::{INSTANCE_SEED, ZEROED_TEST_SEED};

#[test]
fn it_should_have_a_zero_test_seed() {
assert_eq!(*ZEROED_TEST_SEED, [0u8; 32])
}

#[test]
fn it_should_have_a_large_random_seed() {
assert!(u128::from_ne_bytes((*INSTANCE_SEED)[..16].try_into().unwrap()) > u64::MAX as u128);
assert!(u128::from_ne_bytes((*INSTANCE_SEED)[16..].try_into().unwrap()) > u64::MAX as u128);
}
}
}

#[cfg(test)]
mod tests {
use super::*;

pub struct ZeroedTestSeed;

impl Seed for ZeroedTestSeed {
type Seed = SeedSize;
fn seed() -> &'static Self::Seed {
&*crate::static_keys::static_seeds::ZEROED_TEST_SEED
}
}

#[test]
fn the_default_seed_and_the_zeroed_seed_should_be_the_same_when_testing() {
assert_eq!(DefaultSeed::seed(), ZeroedTestSeed::seed())
}

#[test]
fn the_default_seed_and_the_instance_seed_should_be_different_when_testing() {
assert_ne!(DefaultSeed::seed(), InstanceSeed::seed())
}
}
}
}
1 change: 1 addition & 0 deletions src/protocol/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
pub mod clock;
pub mod common;
pub mod crypto;
pub mod utils;
46 changes: 1 addition & 45 deletions src/protocol/utils.rs
Original file line number Diff line number Diff line change
@@ -1,48 +1,4 @@
use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};
use std::net::SocketAddr;
use std::ops::Mul;
use std::time::Duration;

use aquatic_udp_protocol::ConnectionId;

use super::clock::{DefaultClock, SinceUnixEpoch, Time};
use crate::udp::ServerError;

pub fn make_connection_cookie(lifetime: &Duration, remote_address: &SocketAddr) -> ConnectionId {
let period = DefaultClock::now_add_periods(&lifetime, &lifetime);

let mut hasher = DefaultHasher::new();

remote_address.hash(&mut hasher);
period.hash(&mut hasher);

let connection_id_cookie = i64::from_le_bytes(hasher.finish().to_le_bytes());

ConnectionId(connection_id_cookie)
}

pub fn check_connection_cookie(
lifetime: &Duration,
remote_address: &SocketAddr,
connection_id: &ConnectionId,
) -> Result<(), ServerError> {
for n in 0..=1 {
let period = DefaultClock::now_add_periods(&lifetime.mul(n), &lifetime);

let mut hasher = DefaultHasher::new();

remote_address.hash(&mut hasher);
period.hash(&mut hasher);

let connection_id_cookie = i64::from_le_bytes(hasher.finish().to_le_bytes());

if (*connection_id).0 == connection_id_cookie {
return Ok(());
}
}
Err(ServerError::InvalidConnectionId)
}
use super::clock::SinceUnixEpoch;

pub fn ser_unix_time_value<S: serde::Serializer>(unix_time_value: &SinceUnixEpoch, ser: S) -> Result<S::Ok, S::Error> {
ser.serialize_u64(unix_time_value.as_millis() as u64)
Expand Down
Loading

0 comments on commit 23b241b

Please sign in to comment.