Merge pull request #725 from jb-alvarado/master
get paths from global settings, remove trailing id
This commit is contained in:
commit
ae06fcbd20
106
Cargo.lock
generated
106
Cargo.lock
generated
@ -81,6 +81,31 @@ dependencies = [
|
||||
"zstd",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "actix-http-test"
|
||||
version = "3.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "061d27c2a6fea968fdaca0961ff429d23a4ec878c4f68f5d08626663ade69c80"
|
||||
dependencies = [
|
||||
"actix-codec",
|
||||
"actix-rt",
|
||||
"actix-server",
|
||||
"actix-service",
|
||||
"actix-tls",
|
||||
"actix-utils",
|
||||
"awc",
|
||||
"bytes",
|
||||
"futures-core",
|
||||
"http 0.2.12",
|
||||
"log",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_urlencoded",
|
||||
"slab",
|
||||
"socket2",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "actix-macros"
|
||||
version = "0.2.4"
|
||||
@ -150,6 +175,7 @@ version = "2.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "24eda4e2a6e042aa4e55ac438a2ae052d3b5da0ecf83d7411e1a368946925208"
|
||||
dependencies = [
|
||||
"actix-macros",
|
||||
"futures-core",
|
||||
"tokio",
|
||||
]
|
||||
@ -182,6 +208,48 @@ dependencies = [
|
||||
"pin-project-lite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "actix-test"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "439022b5a7b5dac10798465029a9566e8e0cca7a6014541ed277b695691fac5f"
|
||||
dependencies = [
|
||||
"actix-codec",
|
||||
"actix-http",
|
||||
"actix-http-test",
|
||||
"actix-rt",
|
||||
"actix-service",
|
||||
"actix-utils",
|
||||
"actix-web",
|
||||
"awc",
|
||||
"futures-core",
|
||||
"futures-util",
|
||||
"log",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_urlencoded",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "actix-tls"
|
||||
version = "3.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac453898d866cdbecdbc2334fe1738c747b4eba14a677261f2b768ba05329389"
|
||||
dependencies = [
|
||||
"actix-rt",
|
||||
"actix-service",
|
||||
"actix-utils",
|
||||
"futures-core",
|
||||
"http 0.2.12",
|
||||
"http 1.1.0",
|
||||
"impl-more",
|
||||
"pin-project-lite",
|
||||
"tokio",
|
||||
"tokio-util",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "actix-utils"
|
||||
version = "3.0.1"
|
||||
@ -524,6 +592,39 @@ version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0"
|
||||
|
||||
[[package]]
|
||||
name = "awc"
|
||||
version = "3.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "79049b2461279b886e46f1107efc347ebecc7b88d74d023dda010551a124967b"
|
||||
dependencies = [
|
||||
"actix-codec",
|
||||
"actix-http",
|
||||
"actix-rt",
|
||||
"actix-service",
|
||||
"actix-tls",
|
||||
"actix-utils",
|
||||
"base64 0.22.1",
|
||||
"bytes",
|
||||
"cfg-if",
|
||||
"cookie",
|
||||
"derive_more 0.99.18",
|
||||
"futures-core",
|
||||
"futures-util",
|
||||
"h2",
|
||||
"http 0.2.12",
|
||||
"itoa",
|
||||
"log",
|
||||
"mime",
|
||||
"percent-encoding",
|
||||
"pin-project-lite",
|
||||
"rand",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_urlencoded",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "backtrace"
|
||||
version = "0.3.73"
|
||||
@ -3441,6 +3542,11 @@ dependencies = [
|
||||
name = "tests"
|
||||
version = "0.24.0-beta2"
|
||||
dependencies = [
|
||||
"actix-rt",
|
||||
"actix-test",
|
||||
"actix-web",
|
||||
"actix-web-grants",
|
||||
"actix-web-httpauth",
|
||||
"chrono",
|
||||
"crossbeam-channel",
|
||||
"ffplayout",
|
||||
|
@ -160,26 +160,27 @@ struct ProgramItem {
|
||||
/// }
|
||||
/// ```
|
||||
#[post("/auth/login/")]
|
||||
pub async fn login(pool: web::Data<Pool<Sqlite>>, credentials: web::Json<User>) -> impl Responder {
|
||||
pub async fn login(
|
||||
pool: web::Data<Pool<Sqlite>>,
|
||||
credentials: web::Json<User>,
|
||||
) -> Result<impl Responder, ServiceError> {
|
||||
let username = credentials.username.clone();
|
||||
let password = credentials.password.clone();
|
||||
|
||||
match handles::select_login(&pool, &username).await {
|
||||
Ok(mut user) => {
|
||||
let role = handles::select_role(&pool, &user.role_id.unwrap_or_default())
|
||||
.await
|
||||
.unwrap_or(Role::Guest);
|
||||
let role = handles::select_role(&pool, &user.role_id.unwrap_or_default()).await?;
|
||||
|
||||
let pass = user.password.clone();
|
||||
let password_clone = password.clone();
|
||||
let pass_hash = user.password.clone();
|
||||
let cred_password = password.clone();
|
||||
|
||||
user.password = "".into();
|
||||
|
||||
let verified_password = web::block(move || {
|
||||
let hash = PasswordHash::new(&pass).unwrap();
|
||||
Argon2::default().verify_password(password_clone.as_bytes(), &hash)
|
||||
let hash = PasswordHash::new(&pass_hash)?;
|
||||
Argon2::default().verify_password(cred_password.as_bytes(), &hash)
|
||||
})
|
||||
.await;
|
||||
.await?;
|
||||
|
||||
if verified_password.is_ok() {
|
||||
let claims = Claims::new(
|
||||
@ -195,31 +196,31 @@ pub async fn login(pool: web::Data<Pool<Sqlite>>, credentials: web::Json<User>)
|
||||
|
||||
info!("user {} login, with role: {role}", username);
|
||||
|
||||
web::Json(UserObj {
|
||||
Ok(web::Json(UserObj {
|
||||
message: "login correct!".into(),
|
||||
user: Some(user),
|
||||
})
|
||||
.customize()
|
||||
.with_status(StatusCode::OK)
|
||||
.with_status(StatusCode::OK))
|
||||
} else {
|
||||
error!("Wrong password for {username}!");
|
||||
|
||||
web::Json(UserObj {
|
||||
Ok(web::Json(UserObj {
|
||||
message: "Wrong password!".into(),
|
||||
user: None,
|
||||
})
|
||||
.customize()
|
||||
.with_status(StatusCode::FORBIDDEN)
|
||||
.with_status(StatusCode::FORBIDDEN))
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
error!("Login {username} failed! {e}");
|
||||
web::Json(UserObj {
|
||||
Ok(web::Json(UserObj {
|
||||
message: format!("Login {username} failed!"),
|
||||
user: None,
|
||||
})
|
||||
.customize()
|
||||
.with_status(StatusCode::BAD_REQUEST)
|
||||
.with_status(StatusCode::BAD_REQUEST))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -54,7 +54,7 @@ pub async fn init_globales(conn: &Pool<Sqlite>) {
|
||||
}
|
||||
|
||||
// #[serde_as]
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
|
||||
pub struct User {
|
||||
#[serde(skip_deserializing)]
|
||||
pub id: i32,
|
||||
|
@ -1,5 +1,8 @@
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
use actix_web::{dev::ServiceRequest, Error, HttpMessage};
|
||||
use actix_web_grants::authorities::AttachAuthorities;
|
||||
use actix_web_httpauth::extractors::bearer::BearerAuth;
|
||||
use clap::Parser;
|
||||
use lazy_static::lazy_static;
|
||||
use sysinfo::{Disks, Networks, System};
|
||||
@ -11,6 +14,8 @@ pub mod player;
|
||||
pub mod sse;
|
||||
pub mod utils;
|
||||
|
||||
use api::auth;
|
||||
use db::models::UserMeta;
|
||||
use utils::advanced_config::AdvancedConfig;
|
||||
use utils::args_parse::Args;
|
||||
|
||||
@ -22,3 +27,21 @@ lazy_static! {
|
||||
Arc::new(Mutex::new(Networks::new_with_refreshed_list()));
|
||||
pub static ref SYS: Arc<Mutex<System>> = Arc::new(Mutex::new(System::new_all()));
|
||||
}
|
||||
|
||||
pub async fn validator(
|
||||
req: ServiceRequest,
|
||||
credentials: BearerAuth,
|
||||
) -> Result<ServiceRequest, (Error, ServiceRequest)> {
|
||||
// We just get permissions from JWT
|
||||
match auth::decode_jwt(credentials.token()).await {
|
||||
Ok(claims) => {
|
||||
req.attach(vec![claims.role]);
|
||||
|
||||
req.extensions_mut()
|
||||
.insert(UserMeta::new(claims.id, claims.channels));
|
||||
|
||||
Ok(req)
|
||||
}
|
||||
Err(e) => Err((e, req)),
|
||||
}
|
||||
}
|
||||
|
@ -9,11 +9,9 @@ use std::{
|
||||
};
|
||||
|
||||
use actix_files::Files;
|
||||
use actix_web::{
|
||||
dev::ServiceRequest, middleware::Logger, web, App, Error, HttpMessage, HttpServer,
|
||||
};
|
||||
use actix_web_grants::authorities::AttachAuthorities;
|
||||
use actix_web_httpauth::{extractors::bearer::BearerAuth, middleware::HttpAuthentication};
|
||||
use actix_web::{middleware::Logger, web, App, HttpServer};
|
||||
|
||||
use actix_web_httpauth::middleware::HttpAuthentication;
|
||||
|
||||
#[cfg(all(not(debug_assertions), feature = "embed_frontend"))]
|
||||
use actix_web_static_files::ResourceFiles;
|
||||
@ -22,11 +20,8 @@ use log::*;
|
||||
use path_clean::PathClean;
|
||||
|
||||
use ffplayout::{
|
||||
api::{auth, routes::*},
|
||||
db::{
|
||||
db_drop, db_pool, handles,
|
||||
models::{init_globales, UserMeta},
|
||||
},
|
||||
api::routes::*,
|
||||
db::{db_drop, db_pool, handles, models::init_globales},
|
||||
player::{
|
||||
controller::{ChannelController, ChannelManager},
|
||||
utils::{get_date, is_remote, json_validate::validate_playlist, JsonPlaylist},
|
||||
@ -38,7 +33,7 @@ use ffplayout::{
|
||||
logging::{init_logging, MailQueue},
|
||||
playlist::generate_playlist,
|
||||
},
|
||||
ARGS,
|
||||
validator, ARGS,
|
||||
};
|
||||
|
||||
#[cfg(any(debug_assertions, not(feature = "embed_frontend")))]
|
||||
@ -55,24 +50,6 @@ fn thread_counter() -> usize {
|
||||
(available_threads / 2).max(2)
|
||||
}
|
||||
|
||||
async fn validator(
|
||||
req: ServiceRequest,
|
||||
credentials: BearerAuth,
|
||||
) -> Result<ServiceRequest, (Error, ServiceRequest)> {
|
||||
// We just get permissions from JWT
|
||||
match auth::decode_jwt(credentials.token()).await {
|
||||
Ok(claims) => {
|
||||
req.attach(vec![claims.role]);
|
||||
|
||||
req.extensions_mut()
|
||||
.insert(UserMeta::new(claims.id, claims.channels));
|
||||
|
||||
Ok(req)
|
||||
}
|
||||
Err(e) => Err((e, req)),
|
||||
}
|
||||
}
|
||||
|
||||
#[actix_web::main]
|
||||
async fn main() -> std::io::Result<()> {
|
||||
let mail_queues = Arc::new(Mutex::new(vec![]));
|
||||
|
@ -67,15 +67,15 @@ pub async fn create_channel(
|
||||
channel.preview_url = preview_url(&channel.preview_url, channel.id);
|
||||
|
||||
if global.shared_storage {
|
||||
channel.hls_path = Path::new(&channel.hls_path)
|
||||
channel.hls_path = Path::new(&global.public_root)
|
||||
.join(channel.id.to_string())
|
||||
.to_string_lossy()
|
||||
.to_string();
|
||||
channel.playlist_path = Path::new(&channel.playlist_path)
|
||||
channel.playlist_path = Path::new(&global.playlist_root)
|
||||
.join(channel.id.to_string())
|
||||
.to_string_lossy()
|
||||
.to_string();
|
||||
channel.storage_path = Path::new(&channel.storage_path)
|
||||
channel.storage_path = Path::new(&global.storage_root)
|
||||
.join(channel.id.to_string())
|
||||
.to_string_lossy()
|
||||
.to_string();
|
||||
|
2
frontend
2
frontend
@ -1 +1 @@
|
||||
Subproject commit fd85411c773f86cd3cef02fdd8c3fd041d9af1a8
|
||||
Subproject commit 0b1e083ce5b1818589b899d2fe0cc04f4100df32
|
@ -10,6 +10,11 @@ publish = false
|
||||
[dev-dependencies]
|
||||
ffplayout= { path = "../ffplayout" }
|
||||
|
||||
actix-web = "4"
|
||||
actix-web-grants = "4"
|
||||
actix-web-httpauth = "0.8"
|
||||
actix-rt = "2.10"
|
||||
actix-test = "0.1"
|
||||
chrono = "0.4"
|
||||
crossbeam-channel = "0.5"
|
||||
ffprobe = "0.4"
|
||||
@ -29,6 +34,10 @@ tokio = { version = "1.29", features = ["full"] }
|
||||
toml_edit = {version ="0.22", features = ["serde"]}
|
||||
walkdir = "2"
|
||||
|
||||
[[test]]
|
||||
name = "api_routes"
|
||||
path = "src/api_routes.rs"
|
||||
|
||||
[[test]]
|
||||
name = "lib_utils"
|
||||
path = "src/lib_utils.rs"
|
||||
|
95
tests/src/api_routes.rs
Normal file
95
tests/src/api_routes.rs
Normal file
@ -0,0 +1,95 @@
|
||||
use actix_web::{get, web, App, Error, HttpResponse, Responder};
|
||||
// use actix_web_httpauth::extractors::bearer::BearerAuth;
|
||||
|
||||
use serde_json::json;
|
||||
use sqlx::{sqlite::SqlitePoolOptions, Pool, Sqlite};
|
||||
|
||||
use ffplayout::api::routes::login;
|
||||
use ffplayout::db::{
|
||||
handles,
|
||||
models::{init_globales, User},
|
||||
};
|
||||
use ffplayout::player::controller::ChannelManager;
|
||||
use ffplayout::utils::config::PlayoutConfig;
|
||||
// use ffplayout::validator;
|
||||
|
||||
async fn prepare_config() -> (PlayoutConfig, ChannelManager, Pool<Sqlite>) {
|
||||
let pool = SqlitePoolOptions::new()
|
||||
.connect("sqlite::memory:")
|
||||
.await
|
||||
.unwrap();
|
||||
handles::db_migrate(&pool).await.unwrap();
|
||||
|
||||
sqlx::query(
|
||||
r#"
|
||||
UPDATE global SET public_root = "assets/hls", logging_path = "assets/log", playlist_root = "assets/playlists", storage_root = "assets/storage";
|
||||
UPDATE channels SET hls_path = "assets/hls", playlist_path = "assets/playlists", storage_path = "assets/storage";
|
||||
"#,
|
||||
)
|
||||
.execute(&pool)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let user = User {
|
||||
id: 0,
|
||||
mail: Some("admin@mail.com".to_string()),
|
||||
username: "admin".to_string(),
|
||||
password: "admin".to_string(),
|
||||
role_id: Some(1),
|
||||
channel_ids: Some(vec![1]),
|
||||
token: None,
|
||||
};
|
||||
|
||||
handles::insert_user(&pool, user.clone()).await.unwrap();
|
||||
|
||||
let config = PlayoutConfig::new(&pool, 1).await;
|
||||
let channel = handles::select_channel(&pool, &1).await.unwrap();
|
||||
let manager = ChannelManager::new(Some(pool.clone()), channel, config.clone());
|
||||
|
||||
(config, manager, pool)
|
||||
}
|
||||
|
||||
#[get("/")]
|
||||
async fn get_handler() -> Result<impl Responder, Error> {
|
||||
Ok(HttpResponse::Ok())
|
||||
}
|
||||
|
||||
#[actix_rt::test]
|
||||
async fn test_get() {
|
||||
let srv = actix_test::start(|| App::new().service(get_handler));
|
||||
|
||||
let req = srv.get("/");
|
||||
let res = req.send().await.unwrap();
|
||||
|
||||
assert!(res.status().is_success());
|
||||
}
|
||||
|
||||
#[actix_rt::test]
|
||||
async fn test_login() {
|
||||
let (_, _, pool) = prepare_config().await;
|
||||
|
||||
init_globales(&pool).await;
|
||||
|
||||
let srv = actix_test::start(move || {
|
||||
let db_pool = web::Data::new(pool.clone());
|
||||
App::new().app_data(db_pool).service(login)
|
||||
});
|
||||
|
||||
let payload = json!({"username": "admin", "password": "admin"});
|
||||
|
||||
let res = srv.post("/auth/login/").send_json(&payload).await.unwrap();
|
||||
|
||||
assert!(res.status().is_success());
|
||||
|
||||
let payload = json!({"username": "admin", "password": "1234"});
|
||||
|
||||
let res = srv.post("/auth/login/").send_json(&payload).await.unwrap();
|
||||
|
||||
assert_eq!(res.status().as_u16(), 403);
|
||||
|
||||
let payload = json!({"username": "aaa", "password": "1234"});
|
||||
|
||||
let res = srv.post("/auth/login/").send_json(&payload).await.unwrap();
|
||||
|
||||
assert_eq!(res.status().as_u16(), 400);
|
||||
}
|
Loading…
Reference in New Issue
Block a user