8 changed files with 285 additions and 31 deletions
@ -1 +1,3 @@ |
|||
/target |
|||
*.db |
|||
*.lock |
|||
|
|||
@ -1,8 +1,21 @@ |
|||
[package] |
|||
name = "FreeID" |
|||
name = "free_id" |
|||
version = "0.1.0" |
|||
edition = "2021" |
|||
|
|||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html |
|||
|
|||
[dependencies] |
|||
#httparse = "1.7.0" |
|||
serde = "1.0.136" |
|||
serde_json = "1.0" |
|||
rusqlite = { version = "0.27.0", features = ["bundled"] } |
|||
rocket = "0.5.0-rc.1" |
|||
|
|||
[dependencies.uuid] |
|||
version = "1.0.0" |
|||
features = [ |
|||
"v4", # Lets you generate random UUIDs |
|||
"fast-rng", # Use a faster (but still sufficiently random) RNG |
|||
"macro-diagnostics", # Enable better diagnostics for compile-time UUIDs |
|||
] |
|||
|
|||
@ -0,0 +1,29 @@ |
|||
ARG BUILD_TAG=1.56.1 |
|||
ARG RUN_TAG=alpine |
|||
#$BUILD_TAG |
|||
|
|||
FROM rust:$BUILD_TAG as builder |
|||
|
|||
WORKDIR /usr/src/ |
|||
RUN USER=root cargo new --bin free_id |
|||
WORKDIR /usr/src/free_id |
|||
|
|||
# Compile dependencies |
|||
COPY Cargo.toml Cargo.lock ./ |
|||
RUN cargo build --locked --release |
|||
|
|||
# Remove bins to make sure we rebuild |
|||
# hadolint ignore=DL3059 |
|||
RUN rm ./target/release/deps/free_id* |
|||
|
|||
COPY src ./src |
|||
RUN cargo build --release |
|||
|
|||
FROM rust:$RUN_TAG |
|||
WORKDIR /app |
|||
COPY --from=builder /usr/src/free_id/target/release/free_id /usr/local/bin/ |
|||
|
|||
EXPOSE 8000 |
|||
ENV ROCKET_ADDRESS=0.0.0.0 |
|||
|
|||
CMD ["/usr/local/bin/free_id"] |
|||
@ -0,0 +1,5 @@ |
|||
mod user; |
|||
|
|||
pub use crate::api::user::{ |
|||
routes as user_routes |
|||
}; |
|||
@ -0,0 +1,58 @@ |
|||
use rocket::Route; |
|||
use serde::Deserialize; |
|||
use rusqlite::Connection; |
|||
use uuid::Uuid; |
|||
|
|||
#[derive(Debug, Deserialize)] |
|||
struct NewAccount { |
|||
firstname: String, |
|||
lastname: String |
|||
} |
|||
|
|||
pub fn routes() -> Vec<Route> { |
|||
routes![delete_user, add_user] |
|||
} |
|||
|
|||
#[delete("/user/<id>/delete")] |
|||
fn delete_user(id: &str) -> String { |
|||
format!("Preparing deletion for user {}", id) |
|||
} |
|||
|
|||
#[post("/user", format = "application/json", data = "<data>")] |
|||
fn add_user(data: &str) -> String { |
|||
|
|||
match serde_json::from_str(data) { |
|||
Ok(acc) => { |
|||
let account: NewAccount = acc; |
|||
println!("User {} {} prepared for creation", account.firstname, account.lastname); |
|||
|
|||
match Connection::open("freeid.db") { |
|||
Ok(connection) => { |
|||
let id = Uuid::new_v4().hyphenated().to_string(); |
|||
match connection.execute("INSERT INTO accounts (id, firstname, lastname) VALUES (:id, :firstname, :lastname)",
|
|||
&[(":id", &id), (":firstname", &account.firstname), (":lastname", &account.lastname)] |
|||
) { |
|||
Ok(updated) => { |
|||
println!("Account with ID {} created", id); |
|||
println!("{} accounts were updated", updated); |
|||
format!("Account with ID {} created", id) |
|||
}, |
|||
Err(err) => { |
|||
println!("update on accounts failed: {}", err); |
|||
format!("Error {}", err) |
|||
}, |
|||
} |
|||
} |
|||
Err(err) => { |
|||
println!("{}", err); |
|||
format!("Error {}", err) |
|||
} |
|||
} |
|||
|
|||
} |
|||
Err(err) => { |
|||
println!("{}", err); |
|||
format!("Error {}", err) |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,44 @@ |
|||
use rusqlite::{Connection, Result}; |
|||
|
|||
pub fn init_db() -> Result<()>{ |
|||
let conn = Connection::open("freeid.db")?; |
|||
println!("DB opened"); |
|||
//let conn = Connection::open_in_memory()?;
|
|||
conn.execute( |
|||
"CREATE TABLE IF NOT EXISTS accounts ( |
|||
id TEXT primary key, |
|||
firstname TEXT , |
|||
lastname TEXT
|
|||
)", |
|||
[] |
|||
)?; |
|||
|
|||
conn.execute( |
|||
"CREATE TABLE IF NOT EXISTS authtokens ( |
|||
id TEXT primary key, |
|||
accountID TEXT references accounts(id), |
|||
validFrom TEXT , |
|||
validUntil TEXT
|
|||
)", |
|||
[] |
|||
)?; |
|||
|
|||
println!("Created tables"); |
|||
|
|||
match conn.execute("INSERT INTO accounts (id, firstname, lastname) VALUES (:id, :firstname, :lastname)",
|
|||
&[(":id", "4711"), (":firstname", "Klaus"), (":lastname", "Mustermann")] //, &"Test", &"User"]
|
|||
) { |
|||
Ok(updated) => println!("{} accounts were updated", updated), |
|||
Err(err) => println!("update on accounts failed: {}", err), |
|||
} |
|||
|
|||
match conn.execute("INSERT INTO authtokens (id, accountID, validFrom, validUntil) VALUES (?1, ?2, ?3, ?4)",
|
|||
&[&"992756", &"4711", &"2022-04-25 14:30:00.000", &"2023-04-25 14:30:00.000"] |
|||
) { |
|||
Ok(updated) => println!("{} authtokens were updated", updated), |
|||
Err(err) => println!("update on authtokens failed: {}", err), |
|||
} |
|||
|
|||
Ok(()) |
|||
|
|||
} |
|||
@ -1,44 +1,137 @@ |
|||
use std::io::prelude::*; |
|||
use std::net::TcpListener; |
|||
use std::net::TcpStream; |
|||
#[macro_use] |
|||
extern crate rocket; |
|||
|
|||
fn main() { |
|||
let listener = TcpListener::bind("127.0.0.1:7878").unwrap(); |
|||
/* use rocket::response::Responder;
|
|||
use rocket::http::{ContentType, Header}; */ |
|||
|
|||
for stream in listener.incoming() { |
|||
let stream = stream.unwrap(); |
|||
use rusqlite::Connection; |
|||
|
|||
handle_connection(stream); |
|||
} |
|||
} |
|||
mod api; |
|||
mod db; |
|||
|
|||
fn getit(slice: &[u8]) -> String { |
|||
let value = format!("{}{}{}{}{}{}", slice[8]-48, slice[9]-48, slice[10]-48, slice[11]-48, slice[12]-48, slice[13]-48); |
|||
value |
|||
#[derive(Debug)] |
|||
struct AuthToken { |
|||
id: i32, |
|||
account_id: i32, |
|||
valid_from: String, |
|||
valid_until: String |
|||
} |
|||
|
|||
fn handle_connection(mut stream: TcpStream) { |
|||
let mut buffer = [0; 1024]; |
|||
/* #[derive(Debug, Deserialize)]
|
|||
struct Account { |
|||
id: i32, |
|||
firstname: String, |
|||
lastname: String |
|||
} */ |
|||
|
|||
/* #[derive(Debug)]
|
|||
struct EMail { |
|||
address: String, |
|||
description: String |
|||
} */ |
|||
|
|||
fn get_auth_token(token: &str) -> AuthToken { |
|||
let mut result: AuthToken = AuthToken { |
|||
id: 0, |
|||
account_id: 0, |
|||
valid_from: String::from(""), |
|||
valid_until: String::from("") |
|||
}; |
|||
|
|||
stream.read(&mut buffer).unwrap(); |
|||
let conn = Connection::open("freeid.db"); |
|||
|
|||
println!("Request: {}", String::from_utf8_lossy(&buffer[..])); |
|||
match conn { |
|||
Ok(connection) => { |
|||
let stmt = connection.prepare("SELECT id, accountID, validFrom, validUntil FROM authtokens WHERE id = :id"); |
|||
match stmt { |
|||
Ok(mut statement) => { |
|||
let auth_tokens = statement.query_map(&[(":id", token)], |row| { |
|||
Ok(AuthToken { |
|||
id: row.get(0)?, |
|||
account_id: row.get(1)?, |
|||
valid_from: row.get(2)?, |
|||
valid_until: row.get(3)? |
|||
}) |
|||
}); |
|||
match auth_tokens { |
|||
Ok(auth_tokens_iter) => { |
|||
for auth_token_res in auth_tokens_iter { |
|||
match auth_token_res { |
|||
Ok(auth_token) => { |
|||
result = auth_token; |
|||
} |
|||
Err(err) => { |
|||
println!("Error: {}", err); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
Err(err) => { |
|||
println!("Error: {}", err); |
|||
} |
|||
} |
|||
} |
|||
Err(err) => { |
|||
println!("Error: {}", err); |
|||
} |
|||
} |
|||
}
|
|||
Err(err) => { |
|||
println!("Error: {}", err); |
|||
} |
|||
} |
|||
|
|||
let get_id = b"GET /id/"; |
|||
let get_auth = b"GET /auth/"; |
|||
let mut response = ""; |
|||
result |
|||
} |
|||
|
|||
if buffer.starts_with(get_id) { |
|||
response = "HTTP/1.1 200 OK\r\n\r\n"; |
|||
//req_id = buffer[8 .. 13];
|
|||
println!("ID Requested: {}", getit(&buffer)); |
|||
fn remove_brackets(value: &str) -> &str { |
|||
if value.starts_with('[') && value.ends_with(']') { |
|||
let mut chars = value.chars(); |
|||
chars.next(); |
|||
chars.next_back(); |
|||
chars.as_str() |
|||
} |
|||
else if buffer.starts_with(get_auth) { |
|||
response = "HTTP/1.1 404 NOT FOUND\r\n\r\n"; |
|||
println!("Auth Requested"); |
|||
else { |
|||
value |
|||
} |
|||
} |
|||
|
|||
#[get("/")] |
|||
fn index() -> &'static str { |
|||
"Hello, world!" |
|||
} |
|||
|
|||
#[get("/id/<token>/options/<options>", rank = 1)] |
|||
fn id_options(token: &str, options: &str) -> String { |
|||
println!("Route: Id -> {}", token); |
|||
let auth_token = get_auth_token(token); |
|||
let options = remove_brackets(options); |
|||
format!("Auth Token {} for Account {} with options [{}]", auth_token.id, auth_token.account_id, options) |
|||
} |
|||
|
|||
#[get("/id/<token>", rank = 2)] |
|||
fn id(token: &str) -> String { |
|||
println!("Route: Id -> {}", token); |
|||
let auth_token = get_auth_token(token); |
|||
format!("Auth Token {} for Account {}", auth_token.id, auth_token.account_id) |
|||
} |
|||
|
|||
#[get("/health")] |
|||
fn health() -> String { |
|||
String::from("200 OK") |
|||
} |
|||
|
|||
stream.write(response.as_bytes()).unwrap(); |
|||
stream.flush().unwrap(); |
|||
} |
|||
#[launch] |
|||
fn rocket() -> _ { |
|||
match db::init_db() { |
|||
Ok(_) => { |
|||
println!("Database initiated"); |
|||
}, |
|||
Err(err) => { |
|||
println!("Error {}", err); |
|||
} |
|||
} |
|||
rocket::build(). |
|||
mount("/", routes![index, id, id_options, health]). |
|||
mount("/api", api::user_routes()) |
|||
} |
|||
|
|||
@ -0,0 +1,10 @@ |
|||
{ |
|||
"user": "12345", |
|||
"firstname": "Test", |
|||
"lastname": "User", |
|||
|
|||
"email": [ |
|||
{ "address": "test@test.com" }, |
|||
{ "address": "another@test.com" } |
|||
] |
|||
} |
|||
Loading…
Reference in new issue