Generated
+67
@@ -81,6 +81,12 @@ version = "1.8.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b588b76d00fde79687d7646a9b5bdf3cc0f655e0bbd080335a95d7e96f3587da"
|
||||
|
||||
[[package]]
|
||||
name = "block-buffer"
|
||||
version = "0.10.4"
|
||||
@@ -226,6 +232,7 @@ dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tokio",
|
||||
"tower-http",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -349,6 +356,12 @@ dependencies = [
|
||||
"pin-project-lite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "http-range-header"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9171a2ea8a68358193d15dd5d70c1c10a2afc3e7e4c5bc92bc9f025cebd7359c"
|
||||
|
||||
[[package]]
|
||||
name = "httparse"
|
||||
version = "1.10.1"
|
||||
@@ -432,6 +445,16 @@ version = "0.3.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
|
||||
|
||||
[[package]]
|
||||
name = "mime_guess"
|
||||
version = "2.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e"
|
||||
dependencies = [
|
||||
"mime",
|
||||
"unicase",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mio"
|
||||
version = "1.2.2"
|
||||
@@ -820,6 +843,19 @@ dependencies = [
|
||||
"tungstenite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-util"
|
||||
version = "0.7.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "494815d09bf52b5548659851081238f0ca39ff638363907596da739561c62c52"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
"pin-project-lite",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tower"
|
||||
version = "0.5.3"
|
||||
@@ -836,6 +872,31 @@ dependencies = [
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tower-http"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b11f75e912b0c2be01b63d8cf8057b8c3f97cf34abb3d431a3a4c8675498e233"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"bytes",
|
||||
"futures-core",
|
||||
"futures-util",
|
||||
"http",
|
||||
"http-body",
|
||||
"http-body-util",
|
||||
"http-range-header",
|
||||
"httpdate",
|
||||
"mime",
|
||||
"mime_guess",
|
||||
"percent-encoding",
|
||||
"pin-project-lite",
|
||||
"tokio",
|
||||
"tokio-util",
|
||||
"tower-layer",
|
||||
"tower-service",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tower-layer"
|
||||
version = "0.3.3"
|
||||
@@ -890,6 +951,12 @@ version = "1.20.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20"
|
||||
|
||||
[[package]]
|
||||
name = "unicase"
|
||||
version = "2.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dbc4bc3a9f746d862c45cb89d705aa10f187bb96c76001afab07a0d35ce60142"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.24"
|
||||
|
||||
@@ -12,3 +12,4 @@ tokio = { version = "1.53.1", features = ["rt", "rt-multi-thread", "macros", "sy
|
||||
ed25519-dalek = { version = "2", features = ["rand_core"] }
|
||||
rand = "0.8"
|
||||
bs58 = "0.5.1"
|
||||
tower-http = { version = "0.7.0", features = ["fs", "cors"] }
|
||||
|
||||
+16
-3
@@ -2,7 +2,7 @@ use std::{collections::HashSet, path::PathBuf};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::protocol::ServerMeta;
|
||||
use crate::types::{Channel, ChannelKind, ServerMeta};
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct Config {
|
||||
@@ -18,13 +18,26 @@ impl Config {
|
||||
meta: ServerMeta {
|
||||
name: "New Server".to_string(),
|
||||
description: String::new(),
|
||||
|
||||
channels: vec![Channel {
|
||||
id: "text-channels".to_string(),
|
||||
name: "Text Channels".to_string(),
|
||||
|
||||
data: ChannelKind::Category {
|
||||
channels: vec![Channel {
|
||||
id: "general".to_string(),
|
||||
name: "General".to_string(),
|
||||
data: ChannelKind::Text,
|
||||
}],
|
||||
},
|
||||
}],
|
||||
},
|
||||
|
||||
port: 3415,
|
||||
|
||||
public_hostname: "localhost:3000".to_string(),
|
||||
public_hostname: "localhost:3415".to_string(),
|
||||
|
||||
hostnames: HashSet::from_iter(["localhost:3000".to_string()]),
|
||||
hostnames: HashSet::from_iter(["localhost:3415".to_string()]),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+13
-1
@@ -2,6 +2,7 @@ pub mod config;
|
||||
pub mod protocol;
|
||||
pub mod server;
|
||||
pub mod signature;
|
||||
pub mod types;
|
||||
|
||||
use std::{
|
||||
net::{IpAddr, Ipv4Addr, SocketAddr},
|
||||
@@ -14,6 +15,10 @@ use axum::{
|
||||
response::Response,
|
||||
routing::{any, get},
|
||||
};
|
||||
use tower_http::{
|
||||
cors::{Any, CorsLayer},
|
||||
services::ServeFile,
|
||||
};
|
||||
|
||||
use crate::server::Server;
|
||||
|
||||
@@ -21,10 +26,17 @@ use crate::server::Server;
|
||||
async fn main() -> anyhow::Result<()> {
|
||||
let server = Server::new().await?;
|
||||
|
||||
let cors = CorsLayer::new()
|
||||
.allow_origin(Any)
|
||||
.allow_methods(Any)
|
||||
.allow_headers(Any);
|
||||
|
||||
let app = Router::new()
|
||||
.route("/meta", get(meta))
|
||||
.route("/", any(ws_handler))
|
||||
.with_state(server.clone());
|
||||
.route_service("/icon", ServeFile::new("./icon.png"))
|
||||
.with_state(server.clone())
|
||||
.layer(cors);
|
||||
|
||||
let listener = tokio::net::TcpListener::bind(SocketAddr::new(
|
||||
IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)),
|
||||
|
||||
@@ -37,9 +37,9 @@ impl UserConnections {
|
||||
));
|
||||
};
|
||||
|
||||
let server_timestamp = SystemTime::now().duration_since(UNIX_EPOCH)?.as_secs();
|
||||
let server_timestamp = SystemTime::now().duration_since(UNIX_EPOCH)?.as_millis() as u64;
|
||||
|
||||
if server_timestamp - timestamp > 2 {
|
||||
if server_timestamp.saturating_sub(timestamp) > 2000 {
|
||||
send_socket(
|
||||
&mut socket,
|
||||
&ClientMethod::Error {
|
||||
@@ -53,7 +53,8 @@ impl UserConnections {
|
||||
return Err(anyhow::anyhow!("Client tampstamp wasn't correct"));
|
||||
}
|
||||
|
||||
if !server.config.hostnames.contains(&hostname) {
|
||||
if hostname != server.config.public_hostname || !server.config.hostnames.contains(&hostname)
|
||||
{
|
||||
send_socket(
|
||||
&mut socket,
|
||||
&ClientMethod::Error {
|
||||
@@ -100,10 +101,9 @@ impl UserConnections {
|
||||
&mut socket,
|
||||
&ClientMethod::Initialized {
|
||||
public_key: crate::signature::to_string(&server.key.verifying_key()),
|
||||
signature: server
|
||||
.key
|
||||
.sign(format!("{timestamp}@{hostname}@{public_key_string}").as_bytes())
|
||||
.to_string(),
|
||||
signature: crate::signature::to_string_sig(&server.key.sign(
|
||||
format!("{server_timestamp}@{hostname}@{public_key_string}").as_bytes(),
|
||||
)),
|
||||
|
||||
timestamp: server_timestamp,
|
||||
hostname,
|
||||
|
||||
+2
-9
@@ -4,17 +4,10 @@ use axum::extract::ws::{Message, Utf8Bytes, WebSocket};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tokio::sync::Mutex;
|
||||
|
||||
use crate::types::ClientMeta;
|
||||
|
||||
pub mod initialize;
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct ClientMeta {}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct ServerMeta {
|
||||
pub name: String,
|
||||
pub description: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[serde(tag = "method")]
|
||||
pub enum ClientMethod {
|
||||
|
||||
+14
-8
@@ -12,7 +12,8 @@ use tokio::sync::Mutex;
|
||||
|
||||
use crate::{
|
||||
config::Config,
|
||||
protocol::{ClientMeta, ClientMethod, read_loop, send_socket},
|
||||
protocol::{ClientMethod, read_loop, send_socket},
|
||||
types::ClientMeta,
|
||||
};
|
||||
|
||||
pub struct UserConnections {
|
||||
@@ -49,7 +50,7 @@ impl Server {
|
||||
|
||||
let mut clients_meta = s.clients.lock().await;
|
||||
|
||||
let client_meta =
|
||||
let clients =
|
||||
clients_meta
|
||||
.entry(public_key)
|
||||
.or_insert_with(|| UserConnections {
|
||||
@@ -59,18 +60,23 @@ impl Server {
|
||||
connections: HashMap::new(),
|
||||
});
|
||||
|
||||
client_meta.connections.insert(
|
||||
client_meta
|
||||
.counter
|
||||
.fetch_add(1, std::sync::atomic::Ordering::Relaxed),
|
||||
client.clone(),
|
||||
);
|
||||
let conid = clients
|
||||
.counter
|
||||
.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
|
||||
|
||||
clients.connections.insert(conid, client.clone());
|
||||
|
||||
if let Err(e) = read_loop(&client).await {
|
||||
eprintln!("Failed to handle client: {e}");
|
||||
} else {
|
||||
println!("Client connection closed")
|
||||
}
|
||||
|
||||
clients.connections.remove(&conid);
|
||||
|
||||
if clients.connections.len() == 0 {
|
||||
clients_meta.remove(&public_key);
|
||||
}
|
||||
}
|
||||
|
||||
Err(e) => {
|
||||
|
||||
+5
-1
@@ -24,6 +24,10 @@ pub fn to_string(key: &VerifyingKey) -> String {
|
||||
bs58::encode(key.to_bytes()).into_string()
|
||||
}
|
||||
|
||||
pub fn to_string_sig(signature: &Signature) -> String {
|
||||
bs58::encode(signature.to_bytes()).into_string()
|
||||
}
|
||||
|
||||
pub fn from_string(key: &str) -> anyhow::Result<VerifyingKey> {
|
||||
Ok(VerifyingKey::from_bytes(
|
||||
&bs58::decode(key)
|
||||
@@ -38,6 +42,6 @@ pub fn from_string_sig(signature: &str) -> anyhow::Result<Signature> {
|
||||
&bs58::decode(signature)
|
||||
.into_vec()?
|
||||
.try_into()
|
||||
.map_err(|_| anyhow::anyhow!("Invalid public key"))?,
|
||||
.map_err(|_| anyhow::anyhow!("Invalid signature"))?,
|
||||
))
|
||||
}
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct ClientMeta {}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct ServerMeta {
|
||||
pub name: String,
|
||||
pub description: String,
|
||||
pub channels: Vec<Channel>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[serde(tag = "kind")]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub enum ChannelKind {
|
||||
Text,
|
||||
Category { channels: Vec<Channel> },
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Channel {
|
||||
pub id: String,
|
||||
pub name: String,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub data: ChannelKind,
|
||||
}
|
||||
Reference in New Issue
Block a user