cleanup code, reponse object
This commit is contained in:
parent
58b0df5757
commit
cca5e24cc9
76
Cargo.lock
generated
76
Cargo.lock
generated
@ -635,6 +635,7 @@ dependencies = [
|
||||
"ffprobe",
|
||||
"file-rotate",
|
||||
"jsonrpc-http-server",
|
||||
"jsonwebtoken",
|
||||
"lettre",
|
||||
"log",
|
||||
"notify",
|
||||
@ -709,7 +710,7 @@ dependencies = [
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
"pin-project",
|
||||
"spin",
|
||||
"spin 0.9.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1202,6 +1203,20 @@ dependencies = [
|
||||
"unicase",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jsonwebtoken"
|
||||
version = "8.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cc9051c17f81bae79440afa041b3a278e1de71bfb96d32454b477fd4703ccb6f"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"pem",
|
||||
"ring",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"simple_asn1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "kernel32-sys"
|
||||
version = "0.2.2"
|
||||
@ -1462,6 +1477,17 @@ dependencies = [
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-bigint"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-integer"
|
||||
version = "0.1.45"
|
||||
@ -1638,6 +1664,15 @@ version = "1.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0c520e05135d6e763148b6426a837e239041653ba7becd2e538c076c738025fc"
|
||||
|
||||
[[package]]
|
||||
name = "pem"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e9a3b09a20e374558580a4914d3b7d89bd61b954a5a5e1dcbea98753addb1947"
|
||||
dependencies = [
|
||||
"base64",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "percent-encoding"
|
||||
version = "2.1.0"
|
||||
@ -1837,6 +1872,21 @@ dependencies = [
|
||||
"winreg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ring"
|
||||
version = "0.16.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
"once_cell",
|
||||
"spin 0.5.2",
|
||||
"untrusted",
|
||||
"web-sys",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc_version"
|
||||
version = "0.4.0"
|
||||
@ -1998,6 +2048,18 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "simple_asn1"
|
||||
version = "0.6.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "adc4e5204eb1910f40f9cfa375f6f05b68c3abac4b6fd879c8ff5e7ae8a0a085"
|
||||
dependencies = [
|
||||
"num-bigint",
|
||||
"num-traits",
|
||||
"thiserror",
|
||||
"time 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "simplelog"
|
||||
version = "0.12.0"
|
||||
@ -2032,6 +2094,12 @@ dependencies = [
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "spin"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
|
||||
|
||||
[[package]]
|
||||
name = "spin"
|
||||
version = "0.9.3"
|
||||
@ -2424,6 +2492,12 @@ version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e"
|
||||
|
||||
[[package]]
|
||||
name = "untrusted"
|
||||
version = "0.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a"
|
||||
|
||||
[[package]]
|
||||
name = "url"
|
||||
version = "2.2.2"
|
||||
|
@ -18,6 +18,7 @@ faccess = "0.2"
|
||||
ffprobe = "0.3"
|
||||
file-rotate = { git = "https://github.com/Ploppz/file-rotate.git", branch = "timestamp-parse-fix" }
|
||||
jsonrpc-http-server = "18.0"
|
||||
jsonwebtoken = "8"
|
||||
lettre = "0.10.0-rc.6"
|
||||
log = "0.4"
|
||||
notify = "4.0"
|
||||
@ -30,8 +31,11 @@ serde_json = "1.0"
|
||||
serde_yaml = "0.8"
|
||||
shlex = "1.1"
|
||||
simplelog = { version = "^0.12", features = ["paris"] }
|
||||
|
||||
sqlx = { version = "0.5", features = [ "chrono", "runtime-actix-native-tls", "sqlite" ] }
|
||||
sqlx = { version = "0.5", features = [
|
||||
"chrono",
|
||||
"runtime-actix-native-tls",
|
||||
"sqlite"
|
||||
] }
|
||||
time = { version = "0.3", features = ["formatting", "macros"] }
|
||||
walkdir = "2"
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
use std::path::Path;
|
||||
|
||||
use faccess::PathExt;
|
||||
use rand::{distributions::Alphanumeric, Rng};
|
||||
use simplelog::*;
|
||||
use sqlx::{migrate::MigrateDatabase, sqlite::SqliteQueryResult, Pool, Sqlite, SqlitePool};
|
||||
|
||||
@ -20,7 +21,7 @@ pub fn db_path() -> Result<String, Box<dyn std::error::Error>> {
|
||||
}
|
||||
|
||||
async fn cretea_schema() -> Result<SqliteQueryResult, sqlx::Error> {
|
||||
let pool = db_connection().await?;
|
||||
let conn = db_connection().await?;
|
||||
let query = "PRAGMA foreign_keys = ON;
|
||||
CREATE TABLE IF NOT EXISTS groups
|
||||
(
|
||||
@ -35,6 +36,7 @@ async fn cretea_schema() -> Result<SqliteQueryResult, sqlx::Error> {
|
||||
preview_url TEXT NOT NULL,
|
||||
settings_path TEXT NOT NULL,
|
||||
extra_extensions TEXT NOT NULL,
|
||||
secret TEXT NOT NULL,
|
||||
UNIQUE(channel_name)
|
||||
);
|
||||
CREATE TABLE IF NOT EXISTS user
|
||||
@ -48,8 +50,8 @@ async fn cretea_schema() -> Result<SqliteQueryResult, sqlx::Error> {
|
||||
FOREIGN KEY (group_id) REFERENCES groups (id) ON UPDATE SET NULL ON DELETE SET NULL,
|
||||
UNIQUE(email, username)
|
||||
);";
|
||||
let result = sqlx::query(query).execute(&pool).await;
|
||||
pool.close().await;
|
||||
let result = sqlx::query(query).execute(&conn).await;
|
||||
conn.close().await;
|
||||
|
||||
result
|
||||
}
|
||||
@ -64,14 +66,19 @@ pub async fn db_init() -> Result<&'static str, Box<dyn std::error::Error>> {
|
||||
Err(e) => panic!("{e}"),
|
||||
}
|
||||
}
|
||||
let secret: String = rand::thread_rng()
|
||||
.sample_iter(&Alphanumeric)
|
||||
.take(80)
|
||||
.map(char::from)
|
||||
.collect();
|
||||
|
||||
let instances = db_connection().await?;
|
||||
|
||||
let query = "INSERT INTO groups(name) VALUES('admin'), ('user');
|
||||
INSERT INTO settings(channel_name, preview_url, settings_path, extra_extensions)
|
||||
INSERT INTO settings(channel_name, preview_url, settings_path, extra_extensions, secret)
|
||||
VALUES('Channel 1', 'http://localhost/live/preview.m3u8',
|
||||
'/etc/ffplayout/ffplayout.yml', '.jpg,.jpeg,.png');";
|
||||
sqlx::query(query).execute(&instances).await?;
|
||||
|
||||
'/etc/ffplayout/ffplayout.yml', '.jpg,.jpeg,.png', $1);";
|
||||
sqlx::query(query).bind(secret).execute(&instances).await?;
|
||||
instances.close().await;
|
||||
|
||||
Ok("Database initialized!")
|
||||
@ -79,20 +86,19 @@ pub async fn db_init() -> Result<&'static str, Box<dyn std::error::Error>> {
|
||||
|
||||
pub async fn db_connection() -> Result<Pool<Sqlite>, sqlx::Error> {
|
||||
let db_path = db_path().unwrap();
|
||||
let conn = SqlitePool::connect(&db_path).await?;
|
||||
|
||||
let pool = SqlitePool::connect(&db_path).await?;
|
||||
|
||||
Ok(pool)
|
||||
Ok(conn)
|
||||
}
|
||||
|
||||
pub async fn add_user(
|
||||
instances: &SqlitePool,
|
||||
mail: &str,
|
||||
user: &str,
|
||||
pass: &str,
|
||||
salt: &str,
|
||||
group: &i64,
|
||||
) -> Result<SqliteQueryResult, sqlx::Error> {
|
||||
let conn = db_connection().await?;
|
||||
let query =
|
||||
"INSERT INTO user (email, username, password, salt, group_id) VALUES($1, $2, $3, $4, $5)";
|
||||
let result = sqlx::query(query)
|
||||
@ -101,32 +107,18 @@ pub async fn add_user(
|
||||
.bind(pass)
|
||||
.bind(salt)
|
||||
.bind(group)
|
||||
.execute(instances)
|
||||
.execute(&conn)
|
||||
.await?;
|
||||
conn.close().await;
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
pub async fn get_users(
|
||||
instances: &SqlitePool,
|
||||
index: Option<i64>,
|
||||
) -> Result<Vec<User>, sqlx::Error> {
|
||||
let query = match index {
|
||||
Some(i) => format!("SELECT id, email, username FROM user WHERE id = {i}"),
|
||||
None => "SELECT id, email, username FROM user".to_string(),
|
||||
};
|
||||
|
||||
let result: Vec<User> = sqlx::query_as(&query).fetch_all(instances).await?;
|
||||
instances.close().await;
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
pub async fn get_login(user: &str) -> Result<Vec<User>, sqlx::Error> {
|
||||
let pool = db_connection().await?;
|
||||
let query = "SELECT id, username, password, salt FROM user WHERE username = $1";
|
||||
let result: Vec<User> = sqlx::query_as(query).bind(user).fetch_all(&pool).await?;
|
||||
pool.close().await;
|
||||
pub async fn get_login(user: &str) -> Result<User, sqlx::Error> {
|
||||
let conn = db_connection().await?;
|
||||
let query = "SELECT id, email, username, password, salt FROM user WHERE username = $1";
|
||||
let result: User = sqlx::query_as(query).bind(user).fetch_one(&conn).await?;
|
||||
conn.close().await;
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
|
@ -2,23 +2,30 @@ use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize, sqlx::FromRow)]
|
||||
pub struct User {
|
||||
#[sqlx(default)]
|
||||
pub id: Option<i64>,
|
||||
#[sqlx(default)]
|
||||
pub email: Option<String>,
|
||||
pub username: String,
|
||||
#[sqlx(default)]
|
||||
#[serde(skip_serializing)]
|
||||
pub password: String,
|
||||
#[sqlx(default)]
|
||||
#[serde(skip_serializing)]
|
||||
pub salt: Option<String>,
|
||||
#[sqlx(default)]
|
||||
#[serde(skip_serializing)]
|
||||
pub group_id: Option<i64>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
#[derive(Debug, Deserialize, Serialize, sqlx::FromRow)]
|
||||
pub struct Settings {
|
||||
pub id: i64,
|
||||
pub channel_name: String,
|
||||
pub preview_url: String,
|
||||
pub settings_path: String,
|
||||
pub extra_extensions: String,
|
||||
#[sqlx(default)]
|
||||
#[serde(skip_serializing)]
|
||||
pub secret: String,
|
||||
}
|
||||
|
@ -1,81 +1,59 @@
|
||||
use crate::api::{
|
||||
handles::{db_connection, get_login, get_users},
|
||||
models::User,
|
||||
};
|
||||
use actix_web::{get, post, web, Responder};
|
||||
use argon2::{password_hash::PasswordHash, Argon2, PasswordVerifier};
|
||||
use serde::Serialize;
|
||||
use simplelog::*;
|
||||
|
||||
use crate::api::{handles::get_login, models::User};
|
||||
|
||||
#[get("/hello/{name}")]
|
||||
async fn greet(name: web::Path<String>) -> impl Responder {
|
||||
format!("Hello {name}!")
|
||||
}
|
||||
|
||||
// /// curl -X POST -H "Content-Type: application/json" -d '{"username": "USER", "password": "abc123", "email":"user@example.org" }' http://127.0.0.1:8080/api/user/
|
||||
// #[post("/api/user/")]
|
||||
// pub async fn user(user: web::Json<User>) -> impl Responder {
|
||||
// let params = Sha512Params::new(10_000).expect("RandomError!");
|
||||
// let hashed_password = sha512_simple(&user.password, ¶ms).expect("Should not fail");
|
||||
|
||||
// // // Verifying a stored password
|
||||
// // assert!(sha512_check("Not so secure password", &hashed_password).is_ok());
|
||||
|
||||
// if let Ok(pool) = db_connection().await {
|
||||
// if let Err(e) = add_user(
|
||||
// &pool,
|
||||
// &user.email.clone().unwrap(),
|
||||
// &user.username,
|
||||
// &hashed_password,
|
||||
// &user.group_id.unwrap(),
|
||||
// )
|
||||
// .await
|
||||
// {
|
||||
// pool.close().await;
|
||||
// return e.to_string();
|
||||
// };
|
||||
|
||||
// pool.close().await;
|
||||
// }
|
||||
|
||||
// format!("User {} added", user.username)
|
||||
// }
|
||||
|
||||
/// curl -X GET http://127.0.0.1:8080/api/user/1
|
||||
#[get("/api/user/{id}")]
|
||||
pub async fn get_user(id: web::Path<i64>) -> impl Responder {
|
||||
if let Ok(pool) = db_connection().await {
|
||||
match get_users(&pool, Some(*id)).await {
|
||||
Ok(r) => {
|
||||
return web::Json(r);
|
||||
}
|
||||
Err(_) => {
|
||||
return web::Json(vec![]);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
web::Json(vec![])
|
||||
#[derive(Serialize)]
|
||||
struct ResponseObj<T> {
|
||||
message: String,
|
||||
status: i32,
|
||||
data: Option<T>,
|
||||
}
|
||||
|
||||
/// curl -X POST -H "Content-Type: application/json" -d '{"username": "USER", "password": "abc123" }' http://127.0.0.1:8080/auth/login/
|
||||
#[post("/auth/login/")]
|
||||
pub async fn login(credentials: web::Json<User>) -> impl Responder {
|
||||
if let Ok(u) = get_login(&credentials.username).await {
|
||||
if u.is_empty() {
|
||||
return "User not found";
|
||||
}
|
||||
let pass = u[0].password.clone();
|
||||
match get_login(&credentials.username).await {
|
||||
Ok(mut user) => {
|
||||
let pass = user.password.clone();
|
||||
user.password = "".into();
|
||||
user.salt = None;
|
||||
|
||||
if let Ok(hash) = PasswordHash::new(&pass) {
|
||||
let hash = PasswordHash::new(&pass).unwrap();
|
||||
if Argon2::default()
|
||||
.verify_password(credentials.password.as_bytes(), &hash)
|
||||
.is_ok()
|
||||
{
|
||||
info!("user {} login", credentials.username);
|
||||
return "login correct!";
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
error!("Login {} failed!", credentials.username);
|
||||
"Login failed!"
|
||||
web::Json(ResponseObj {
|
||||
message: "login correct!".into(),
|
||||
status: 200,
|
||||
data: Some(user),
|
||||
})
|
||||
} else {
|
||||
error!("Wrong password for {}!", credentials.username);
|
||||
web::Json(ResponseObj {
|
||||
message: "Wrong password!".into(),
|
||||
status: 401,
|
||||
data: None,
|
||||
})
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
error!("Login {} failed! {e}", credentials.username);
|
||||
return web::Json(ResponseObj {
|
||||
message: format!("Login {} failed!", credentials.username),
|
||||
status: 404,
|
||||
data: None,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ use simplelog::*;
|
||||
|
||||
use crate::api::{
|
||||
args_parse::Args,
|
||||
handles::{add_user, db_connection, db_init},
|
||||
handles::{add_user, db_init},
|
||||
};
|
||||
|
||||
pub async fn run_args(args: Args) -> Result<(), i32> {
|
||||
@ -42,33 +42,22 @@ pub async fn run_args(args: Args) -> Result<(), i32> {
|
||||
}
|
||||
};
|
||||
|
||||
match db_connection().await {
|
||||
Ok(pool) => {
|
||||
if let Err(e) = add_user(
|
||||
&pool,
|
||||
&args.email.unwrap(),
|
||||
&username,
|
||||
&password_hash.to_string(),
|
||||
&salt.to_string(),
|
||||
&1,
|
||||
)
|
||||
.await
|
||||
{
|
||||
pool.close().await;
|
||||
error!("{e}");
|
||||
return Err(1);
|
||||
};
|
||||
if let Err(e) = add_user(
|
||||
&args.email.unwrap(),
|
||||
&username,
|
||||
&password_hash.to_string(),
|
||||
&salt.to_string(),
|
||||
&1,
|
||||
)
|
||||
.await
|
||||
{
|
||||
error!("{e}");
|
||||
return Err(1);
|
||||
};
|
||||
|
||||
pool.close().await;
|
||||
info!("Create admin user \"{username}\" done...");
|
||||
info!("Create admin user \"{username}\" done...");
|
||||
|
||||
return Err(0);
|
||||
}
|
||||
Err(e) => {
|
||||
error!("Add admin user failed! Did you init the database?");
|
||||
panic!("{e}")
|
||||
}
|
||||
}
|
||||
return Err(0);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
@ -5,11 +5,7 @@ use clap::Parser;
|
||||
use simplelog::*;
|
||||
|
||||
use ffplayout_engine::{
|
||||
api::{
|
||||
args_parse::Args,
|
||||
routes::{get_user, login},
|
||||
utils::run_args,
|
||||
},
|
||||
api::{args_parse::Args, routes::login, utils::run_args},
|
||||
utils::{init_logging, GlobalConfig},
|
||||
};
|
||||
|
||||
@ -35,7 +31,7 @@ async fn main() -> std::io::Result<()> {
|
||||
let port = ip_port[1].parse::<u16>().unwrap();
|
||||
info!("running ffplayout API, listen on {conn}");
|
||||
|
||||
HttpServer::new(|| App::new().service(get_user).service(login))
|
||||
HttpServer::new(|| App::new().service(login))
|
||||
.bind((addr, port))?
|
||||
.run()
|
||||
.await
|
||||
|
Loading…
Reference in New Issue
Block a user