--- /dev/null
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 4
+
+[[package]]
+name = "aho-corasick"
+version = "1.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "memchr"
+version = "2.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79"
+
+[[package]]
+name = "regex"
+version = "1.12.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-automata",
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-automata"
+version = "0.4.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-syntax"
+version = "0.8.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a"
+
+[[package]]
+name = "ws"
+version = "0.1.0"
+dependencies = [
+ "regex",
+]
--- /dev/null
+[package]
+name = "ws"
+version = "0.1.0"
+edition = "2024"
+description = "web-sync project"
+repository = "https://tangled.org/autumn.bsky.gay/ws"
+
+[dependencies]
+regex = "1.12.3"
--- /dev/null
+use regex::Regex;
+use std::{env, net::TcpListener, process::exit, thread};
+
+mod routes;
+mod server;
+
+struct ServerConfig {
+ port: u16,
+ ip: String,
+}
+
+fn args_handler(conf: &mut ServerConfig, args: Vec<String>) {
+ if args.iter().any(|i| i == "--help") {
+ println!(
+ r"
+ --help: print this help message
+ --ip: set the IP address to bind the server to
+ --port: set the port for the server
+ --token: token used to authenticate"
+ );
+ exit(0);
+ }
+
+ for item in args {
+ if item.contains("--ip=") {
+ conf.ip = item.replace("--ip=", "");
+ let checker = Regex::new(r"^((25[0-5]|(2[0-4]|1\d|[1-9]|)\d)\.?\b){4}$").unwrap(); // Grabbed from https://stackoverflow.com/questions/5284147/validating-ipv4-addresses-with-regexp
+ if !checker.is_match(&conf.ip) {
+ println!("IP provided is not within acceptable range!");
+ exit(-1);
+ }
+ } else if item.contains("--port=") {
+ conf.port = item
+ .replace("--port=", "")
+ .parse::<u16>()
+ .unwrap_or_else(|e| {
+ println!("Port provided must be within 16-bit range! => {e}");
+ exit(-1);
+ });
+ } else if item.contains("--token=") {
+ unsafe {
+ env::set_var("token", item.replace("--token=", ""));
+ }
+ }
+ }
+}
+
+fn main() {
+ println!("{}", routes::home().1);
+
+ let mut conf = ServerConfig {
+ port: 7878,
+ ip: String::from("127.0.0.1"),
+ };
+
+ args_handler(&mut conf, env::args().collect());
+
+ println!("Started server on {}:{}", conf.ip, conf.port);
+
+ let listener = TcpListener::bind(format!("{}:{}", conf.ip, conf.port)).unwrap();
+
+ for stream in listener.incoming() {
+ let stream = stream.unwrap();
+
+ thread::spawn(|| {
+ server::server::handle_connection(stream);
+ });
+ }
+}
--- /dev/null
+use crate::server::server::get_authorization;
+
+pub fn home() -> (String, String) {
+ (
+ String::from("200 OK"),
+ format!("{} {}", env!("CARGO_PKG_NAME"), env!("CARGO_PKG_VERSION")),
+ )
+}
+
+pub fn auth(headers: &Vec<String>) -> (String, String) {
+ if !get_authorization(headers) {
+ (
+ String::from("403 FORBIDDEN"),
+ String::from("You are not authorized to view this endpoint"),
+ )
+ } else {
+ (
+ String::from("200 OK"),
+ String::from("Successfully authenticated!"),
+ )
+ }
+}
--- /dev/null
+pub mod server {
+
+ use crate::routes;
+ use std::{
+ env,
+ io::{BufReader, prelude::*},
+ net::TcpStream,
+ };
+
+ pub fn get_authorization(headers: &Vec<String>) -> bool {
+ match env::var("token") {
+ Ok(x) => {
+ for header in headers {
+ if header.contains("Authorization: Basic ") {
+ return header.replace("Authorization: Basic ", "") == x;
+ }
+ }
+ }
+ Err(_) => return false,
+ }
+
+ false
+ }
+
+ pub fn handle_connection(mut stream: TcpStream) {
+ let buf_reader = BufReader::new(&stream);
+ let request_data: Vec<_> = buf_reader
+ .lines()
+ .map(|result| result.unwrap())
+ .take_while(|line| !line.is_empty())
+ .collect();
+
+ println!("{request_data:#?}");
+
+ let request_line = &request_data[0];
+
+ let (status, response) = router(&request_data, &request_line);
+ let status_line = format!("HTTP/1.1 {}", status);
+ let length = response.len();
+
+ let response = format!("{status_line}\r\nContent-Length: {length}\r\n\r\n{response}");
+
+ stream.write_all(response.as_bytes()).unwrap();
+ }
+
+ fn router(headers: &Vec<String>, request_line: &String) -> (String, String) {
+ match request_line.as_str() {
+ "GET / HTTP/1.1" => routes::home(),
+ "GET /auth HTTP/1.1" => routes::auth(headers),
+ _ => (
+ String::from("404 NOT FOUND"),
+ String::from("The provided endpoint was not found"),
+ ),
+ }
+ }
+}