Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

identity: created initial did:web server #123

Merged
merged 2 commits into from
Aug 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 57 additions & 0 deletions Cargo.lock

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

7 changes: 7 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
[workspace]
resolver = "2"
members = [
"apps/identity_server",
"apps/legacy_web/backend",
"apps/legacy_web/frontend",
"apps/networked_physics_demo/client",
Expand Down Expand Up @@ -29,6 +30,7 @@ rust-version = "1.78.0"

[workspace.dependencies]
async-compat = "0.2.4"
axum = "0.7.5"
base64 = "0.21.7"
bevy = { version = "0.13", features = ["serialize"] }
bevy-inspector-egui = "0.23.4"
Expand All @@ -47,15 +49,19 @@ bevy_web_asset = { git = "https://github.com/Schmarni-Dev/bevy_web_asset", rev =
bytes = "1.5.0"
clap = { version = "4.4.11", features = ["derive"] }
color-eyre = "0.6"
did-simple.path = "crates/did-simple"
egui = "0.26"
egui-picking = { path = "crates/egui-picking" }
eyre = "0.6"
futures = "0.3.30"
hex-literal = "0.4.1"
jose-jwk = { version = "0.1.2", default-features = false }
lightyear = "0.12"
openxr = "0.18"
picking-xr = { path = "crates/picking-xr" }
pin-project = "1"
rand = "0.8.5"
rand_chacha = "0.3.1"
rand_xoshiro = "0.6.0"
random-number = "0.1.8"
replicate-client.path = "crates/replicate/client"
Expand All @@ -69,6 +75,7 @@ thiserror = "1.0.56"
tokio = { version = "1.35.1", default-features = false }
tokio-serde = "0.9"
tokio-util = { version = "0.7.10", default-features = true }
tower-http = "0.5.2"
tracing = "0.1.40"
tracing-subscriber = "0.3.18"
url = "2.5.0"
Expand Down
28 changes: 28 additions & 0 deletions apps/identity_server/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
[package]
name = "identity_server"
version.workspace = true
license.workspace = true
repository.workspace = true
edition.workspace = true
rust-version.workspace = true
description = "Self-custodial identity using did:web"
publish = false

[dependencies]
axum.workspace = true
clap.workspace = true
color-eyre.workspace = true
did-simple.workspace = true
jose-jwk = { workspace = true, default-features = false }
rand.workspace = true
serde.workspace = true
serde_json.workspace = true
tokio = { workspace = true, features = ["full"] }
tower-http = { workspace = true, features = ["trace"] }
tracing-subscriber = { workspace = true, features = ["env-filter"] }
tracing.workspace = true
uuid = { workspace = true, features = ["std", "v4", "serde"] }

[dev-dependencies]
base64.workspace = true
hex-literal.workspace = true
21 changes: 21 additions & 0 deletions apps/identity_server/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
mod uuid;
pub mod v1;

use axum::routing::get;
use tower_http::trace::TraceLayer;

/// Main router of API
pub fn router() -> axum::Router<()> {
let v1_router = crate::v1::RouterConfig {
..Default::default()
}
.build();
axum::Router::new()
.route("/", get(root))
.nest("/api/v1", v1_router)
.layer(TraceLayer::new_for_http())
}

async fn root() -> &'static str {
"uwu hewwo this api is under constwuction"
}
33 changes: 33 additions & 0 deletions apps/identity_server/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
use std::net::{Ipv6Addr, SocketAddr};

use clap::Parser as _;
use tracing::info;
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt, EnvFilter};

#[derive(clap::Parser, Debug)]
struct Cli {
#[clap(default_value = "0")]
port: u16,
}

#[tokio::main]
async fn main() -> color_eyre::Result<()> {
color_eyre::install()?;
tracing_subscriber::registry()
.with(EnvFilter::try_from_default_env().unwrap_or("info".into()))
.with(tracing_subscriber::fmt::layer())
.init();

let cli = Cli::parse();

let listener = tokio::net::TcpListener::bind(SocketAddr::new(
Ipv6Addr::UNSPECIFIED.into(),
cli.port,
))
.await
.unwrap();
info!("listening on {}", listener.local_addr().unwrap());
axum::serve(listener, identity_server::router())
.await
.map_err(|e| e.into())
}
104 changes: 104 additions & 0 deletions apps/identity_server/src/uuid.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
//! Mockable UUID generation.

use ::uuid::Uuid;
use std::sync::atomic::{AtomicUsize, Ordering};

/// Handles generation of UUIDs. This is used instead of the uuid crate directly,
/// to better support deterministic UUID creation in tests.
#[derive(Debug)]
pub struct UuidProvider {
#[cfg(not(test))]
provider: ThreadLocalRng,
#[cfg(test)]
provider: Box<dyn UuidProviderT>,
}

impl UuidProvider {
#[allow(dead_code)]
pub fn new_thread_local() -> Self {
Self {
#[cfg(test)]
provider: Box::new(ThreadLocalRng),
#[cfg(not(test))]
provider: ThreadLocalRng,
}
}

/// Allows controlling the sequence of generated UUIDs. Only available in
/// `cfg(test)`.
#[allow(dead_code)]
#[cfg(test)]
pub fn new_from_sequence(uuids: Vec<Uuid>) -> Self {
Self {
provider: Box::new(TestSequence::new(uuids)),
}
}

#[inline]
pub fn next_v4(&self) -> Uuid {
self.provider.next_v4()
}
}

impl Default for UuidProvider {
fn default() -> Self {
Self::new_thread_local()
}
}

trait UuidProviderT: std::fmt::Debug + Send + Sync + 'static {
fn next_v4(&self) -> Uuid;
}

#[derive(Debug)]
struct ThreadLocalRng;
impl UuidProviderT for ThreadLocalRng {
fn next_v4(&self) -> Uuid {
Uuid::new_v4()
}
}

/// Provides UUIDs from a known sequence. Useful for tests.
#[derive(Debug)]
struct TestSequence {
uuids: Vec<Uuid>,
pos: AtomicUsize,
}
impl TestSequence {
/// # Panics
/// Panics if len of vec is 0
#[allow(dead_code)]
fn new(uuids: Vec<Uuid>) -> Self {
assert!(!uuids.is_empty());
Self {
uuids,
pos: AtomicUsize::new(0),
}
}
}

impl UuidProviderT for TestSequence {
fn next_v4(&self) -> Uuid {
let curr_pos = self.pos.fetch_add(1, Ordering::SeqCst) % self.uuids.len();
self.uuids[curr_pos]
}
}

fn _assert_bounds(p: UuidProvider) {
fn helper(_p: impl std::fmt::Debug + Send + Sync + 'static) {}
helper(p)
}

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

#[test]
fn test_sequence_order() {
let uuids: Vec<Uuid> = (0..4).map(|_| Uuid::new_v4()).collect();
let sequence = TestSequence::new(uuids.clone());
for uuid in uuids {
assert_eq!(uuid, sequence.next_v4());
}
}
}
Loading
Loading