Some decentralize

This commit is contained in:
BitHeaven 2024-03-22 14:09:27 +05:00
parent 54c82537b7
commit a6ab0d0945
5 changed files with 187 additions and 91 deletions

11
TODO
View File

@ -1,4 +1,13 @@
Auth using tokens Auth using tokens
Auth using uniq id on device Auth using uniq id on device
Auth using QR code Auth using QR code
Auth using SMS or popup Auth using msg or popup
Auth using email
##### API v0
# Auth link (device check url with this session and get data)
/auth?session=<UNIQUE>
# Get auth data
/auth_finish?session=<UNIQUE>

36
src/api.rs Normal file
View File

@ -0,0 +1,36 @@
mod v0;
use {
hyper::{
StatusCode,
Request,
header::HeaderValue,
body::{
Incoming,
},
},
serde_json::{
Value as Json,
json,
},
skytable::pool::ConnectionMgrTcp,
bb8::Pool,
std::sync::Arc,
};
type Res<T, E> = std::result::Result<T, E>;
type Result<T> = std::result::Result<T, Box<dyn std::error::Error + Send + Sync>>;
type DBPool = Arc<Pool<ConnectionMgrTcp>>;
pub async fn endpoint(req: Request<Incoming>, pool: DBPool) -> (String, StatusCode, HeaderValue) {
let uri: &str = req.uri().path().as_ref();
let res: Json = match &uri[4..uri.len()] {
"/test" => json!({"error": false, "msg": "test"}),
x if x.starts_with("/v0/") => v0::api(req, pool.clone()).await,
_ => json!({"error": true, "msg": "No endpoint"})
};
let restype: HeaderValue = "application/json".parse().unwrap();
(res.to_string(), StatusCode::IM_A_TEAPOT, restype)
}

42
src/api/v0.rs Normal file
View File

@ -0,0 +1,42 @@
use {
hyper::{
Request,
body::{
Incoming,
},
},
serde_json::{
Value as Json,
json,
},
skytable::pool::ConnectionMgrTcp,
bb8::Pool,
std::sync::Arc,
crate::double_split,
};
type Res<T, E> = std::result::Result<T, E>;
type Result<T> = std::result::Result<T, Box<dyn std::error::Error + Send + Sync>>;
type DBPool = Arc<Pool<ConnectionMgrTcp>>;
pub async fn api(req: Request<Incoming>, pool: DBPool) -> Json {
let uri: &str = req.uri().path().as_ref();
match &uri[7..uri.len()] {
"/test" => json!({"error": false, "msg": "test endpoint v0"}),
"/auth" => auth(req, pool.clone()).await,
"/auth_get" => auth_get(req, pool.clone()).await,
_ => json!({"error": true, "msg": "No endpoint"})
}
}
async fn auth(req: Request<Incoming>, pool: DBPool) -> Json {
json!({"error": false, "msg": "test auth endpoint v0"})
}
async fn auth_get(req: Request<Incoming>, pool: DBPool) -> Json {
let query = req.uri().query().or(Some("")).unwrap();
let query = double_split(query.to_string(), "&", "=");
println!("{:?}", query);
json!({"error": false, "msg": "test auth_get endpoint v0"})
}

64
src/html.rs Normal file
View File

@ -0,0 +1,64 @@
pub const HEADER_HTML: &str = r#"
<!DOCTYPE html>
<html>
<head></head>
<body>
<header>
<a href="/">index</a>
<a href="/login">login</a>
<a href="/register">register</a>
<hr>
</header>
<main>
"#;
pub const FOOTER_HTML: &str = r#"
</main>
<footer>
<hr>
Render time: RENDER_TIMEns. Made by BitHeaven.
</footer>
</body>
</html>
"#;
pub const INDEX_HTML: &str = "<h1>main</h1>";
pub const LOGIN_HTML: &str = r#"
<h1>login</h1>
<form method="POST">
<input name="login" type="text" placeholder="login / email" required>
<br>
<input name="password" type="password" placeholder="password" required>
<br>
<br>
<button type="submit">login</button>
</form>
"#;
pub const REG_HTML: &str = r#"
<h1>register</h1>
<form method="POST">
<input name="login" type="text" placeholder="login" required>
<br>
<input name="email" type="email" placeholder="email (opt)">
<br>
<input name="password" type="password" placeholder="password" required>
<br>
<input name="password2" type="password" placeholder="password again" required>
<br>
<br>
<button type="submit">register</button>
</form>
"#;
pub const RECOVER_HTML: &str = "<h1>recover</h1>";
pub const NF_HTML: &str = "<h1>404</h1>think about it.";
pub const CSS3: &str = r#"<style>
:root { color-scheme: dark; }
body { margin: auto; max-width: 768px; }
footer { text-align: right; }
</style>"#;

View File

@ -1,10 +1,13 @@
mod types; mod types;
mod html;
mod api;
use { use {
std::{ std::{
sync::Arc, sync::Arc,
net::SocketAddr, net::SocketAddr,
collections::HashMap, collections::HashMap,
process::exit,
time::{ time::{
SystemTime, SystemTime,
UNIX_EPOCH, UNIX_EPOCH,
@ -79,8 +82,11 @@ use {
Pool, Pool,
}, },
crate::{ crate::{
types::users::Users, types::{
types::sites::Sites, users::Users,
sites::Sites,
},
html::*,
}, },
}; };
@ -101,75 +107,31 @@ const DB_PASS: &str = "rootpass12345678";
const TOKEN_LIFETIME: u32 = 300; const TOKEN_LIFETIME: u32 = 300;
const REFRESH_LIFETIME: u32 = 2_678_400; const REFRESH_LIFETIME: u32 = 2_678_400;
const HEADER_HTML: &str = r#"
<!DOCTYPE html>
<html>
<head></head>
<body>
<header>
<a href="/">index</a>
<a href="/login">login</a>
<a href="/register">register</a>
<hr>
</header>
<main>
"#;
const FOOTER_HTML: &str = r#"
</main>
<footer>
<hr>
Made by BitHeaven.
</footer>
</body>
</html>
"#;
const INDEX_HTML: &str = "<h1>main</h1>";
const LOGIN_HTML: &str = r#"
<h1>login</h1>
<form method="POST">
<input name="login" type="text" placeholder="login / email" required>
<br>
<input name="password" type="password" placeholder="password" required>
<br>
<br>
<button type="submit">login</button>
</form>
"#;
const REG_HTML: &str = r#"
<h1>register</h1>
<form method="POST">
<input name="login" type="text" placeholder="login" required>
<br>
<input name="email" type="email" placeholder="email (opt)">
<br>
<input name="password" type="password" placeholder="password" required>
<br>
<input name="password2" type="password" placeholder="password again" required>
<br>
<br>
<button type="submit">register</button>
</form>
"#;
const RECOVER_HTML: &str = "<h1>recover</h1>";
const NF_HTML: &str = "<h1>404</h1>think about it.";
const CSS3: &str = r#"<style>
:root { color-scheme: dark; }
body { margin: auto; max-width: 768px; }
footer { text-align: right; }
</style>"#;
#[tokio::main] #[tokio::main]
async fn main() -> Result<()> { async fn main() -> Result<()> {
println!("Starting.");
print!("Binding port...");
let addr = SocketAddr::from(([0, 0, 0, 0], PORT)); let addr = SocketAddr::from(([0, 0, 0, 0], PORT));
let listener = TcpListener::bind(addr).await?; let listener = TcpListener::bind(addr).await;
if listener.is_err() {
println!(" Error.");
exit(1);
}
let listener = listener?;
println!(" OK.");
print!("Connecting to DB...");
let pool = pool::get_async(DB_POOL, Config::new(DB_ADDR, DB_PORT, DB_USER, DB_PASS)).await;
let pool = Arc::new(pool.unwrap());
if pool.get().await.is_err() {
println!(" Error.");
exit(1);
}
println!(" OK.");
let pool = Arc::new(
pool::get_async(
DB_POOL,
Config::new(DB_ADDR, DB_PORT, DB_USER, DB_PASS)
).await.unwrap()
);
init_tables(pool.clone()).await?; init_tables(pool.clone()).await?;
println!("Server started on port: {}", PORT); println!("Server started on port: {}", PORT);
@ -197,6 +159,8 @@ async fn main() -> Result<()> {
} }
async fn handle_connection(req: Request<Incoming>, pool: DBPool, ip: String) -> FullBytes { async fn handle_connection(req: Request<Incoming>, pool: DBPool, ip: String) -> FullBytes {
let t = time_ns();
if ip == "1.1.1.1" { if ip == "1.1.1.1" {
} }
@ -217,7 +181,7 @@ async fn handle_connection(req: Request<Incoming>, pool: DBPool, ip: String) ->
match <str as AsRef<str>>::as_ref(req.uri().path()) { match <str as AsRef<str>>::as_ref(req.uri().path()) {
x if x.starts_with("/api/") => {} x if x.starts_with("/api/") => {}
_ => { _ => {
println!("{}", token); // println!("{}", token);
if token != "" && jwt_verify(pool.clone(), token) if token != "" && jwt_verify(pool.clone(), token)
.await?.claims.as_object().unwrap().len() == 0 .await?.claims.as_object().unwrap().len() == 0
@ -239,13 +203,14 @@ async fn handle_connection(req: Request<Incoming>, pool: DBPool, ip: String) ->
"/register" => uri_register(req, pool.clone(), &mut headers).await?, "/register" => uri_register(req, pool.clone(), &mut headers).await?,
"/recover" => uri_recover(), "/recover" => uri_recover(),
x if x.starts_with("/@") => uri_user(req, pool.clone()).await?, x if x.starts_with("/@") => uri_user(req, pool.clone()).await?,
x if x.starts_with("/api/") => uri_api(req), x if x.starts_with("/api/") => api::endpoint(req, pool.clone()).await,
_ => uri_404() _ => uri_404()
}; };
headers.insert(hyper::header::CONTENT_TYPE, restype); headers.insert(hyper::header::CONTENT_TYPE, restype);
parts.headers = headers; parts.headers = headers;
let body = body.replace("RENDER_TIME", &format!("{}", time_ns() - t));
Ok(Response::from_parts(parts, Full::new(Bytes::from(body)))) Ok(Response::from_parts(parts, Full::new(Bytes::from(body))))
} }
@ -338,26 +303,6 @@ fn uri_recover() -> (String, StatusCode, HeaderValue) {
(build_html(RECOVER_HTML), StatusCode::OK, restype) (build_html(RECOVER_HTML), StatusCode::OK, restype)
} }
fn uri_api(req: Request<Incoming>) -> (String, StatusCode, HeaderValue) {
let uri: &str = req.uri().path().as_ref();
let res: Json = match &uri[4..uri.len()] {
"/test" => json!({"error": false, "msg": "test"}),
x if x.starts_with("/v0/") => uri_api_v0(req),
_ => json!({"error": true, "msg": "No endpoint"})
};
let restype: HeaderValue = "application/json".parse().unwrap();
(res.to_string(), StatusCode::IM_A_TEAPOT, restype)
}
fn uri_api_v0(req: Request<Incoming>) -> Json {
let uri: &str = req.uri().path().as_ref();
match &uri[7..uri.len()] {
"/test" => json!({"error": false, "msg": "test endpoint v0"}),
_ => json!({"error": true, "msg": "No endpoint"})
}
}
async fn uri_user(req: Request<Incoming>, pool: DBPool) -> Res<(String, StatusCode, HeaderValue), SkyError> { async fn uri_user(req: Request<Incoming>, pool: DBPool) -> Res<(String, StatusCode, HeaderValue), SkyError> {
let uri: &str = req.uri().path().as_ref(); let uri: &str = req.uri().path().as_ref();
let login = &uri[2..uri.len()]; let login = &uri[2..uri.len()];
@ -610,9 +555,9 @@ fn time() -> u32 {
.as_secs() as u32 .as_secs() as u32
} }
/*fn time_ns() -> u128 { fn time_ns() -> u128 {
SystemTime::now() SystemTime::now()
.duration_since(UNIX_EPOCH) .duration_since(UNIX_EPOCH)
.unwrap() .unwrap()
.as_millis() as u128 .as_millis() as u128
}*/ }