From 7fa9a37c7c36b74953e64abd9b86eb12759ac2f2 Mon Sep 17 00:00:00 2001 From: Dietmar Maurer Date: Tue, 21 Sep 2021 07:58:47 +0200 Subject: [PATCH] make get_index and ApiConfig property (callback) Signed-off-by: Thomas Lamprecht --- proxmox-rest-server/src/api_config.rs | 18 +++++- src/bin/proxmox-backup-api.rs | 21 +++++++ src/bin/proxmox-backup-proxy.rs | 81 ++++++++++++++++++++++++++- src/bin/proxmox-restore-daemon.rs | 22 +++++++- src/server/rest.rs | 80 +------------------------- 5 files changed, 142 insertions(+), 80 deletions(-) diff --git a/proxmox-rest-server/src/api_config.rs b/proxmox-rest-server/src/api_config.rs index a319e204..fee94e88 100644 --- a/proxmox-rest-server/src/api_config.rs +++ b/proxmox-rest-server/src/api_config.rs @@ -5,7 +5,9 @@ use std::fs::metadata; use std::sync::{Arc, Mutex, RwLock}; use anyhow::{bail, Error, format_err}; -use hyper::Method; +use hyper::{Method, Body, Response}; +use hyper::http::request::Parts; + use handlebars::Handlebars; use serde::Serialize; @@ -14,6 +16,8 @@ use proxmox::tools::fs::{create_path, CreateOptions}; use crate::{ApiAuth, FileLogger, FileLogOptions, CommandoSocket}; +pub type GetIndexFn = fn(Option, Option, &ApiConfig, Parts) -> Response; + pub struct ApiConfig { basedir: PathBuf, router: &'static Router, @@ -23,6 +27,7 @@ pub struct ApiConfig { template_files: RwLock>, request_log: Option>>, pub api_auth: Arc, + get_index_fn: GetIndexFn, } impl ApiConfig { @@ -31,6 +36,7 @@ impl ApiConfig { router: &'static Router, env_type: RpcEnvironmentType, api_auth: Arc, + get_index_fn: GetIndexFn, ) -> Result { Ok(Self { basedir: basedir.into(), @@ -41,9 +47,19 @@ impl ApiConfig { template_files: RwLock::new(HashMap::new()), request_log: None, api_auth, + get_index_fn, }) } + pub fn get_index( + &self, + auth_id: Option, + language: Option, + parts: Parts, + ) -> Response { + (self.get_index_fn)(auth_id, language, self, parts) + } + pub fn find_method( &self, components: &[&str], diff --git a/src/bin/proxmox-backup-api.rs b/src/bin/proxmox-backup-api.rs index 17b6f184..3bc02639 100644 --- a/src/bin/proxmox-backup-api.rs +++ b/src/bin/proxmox-backup-api.rs @@ -1,5 +1,9 @@ use anyhow::{bail, Error}; use futures::*; +use http::request::Parts; +use http::Response; +use hyper::{Body, StatusCode}; +use hyper::header; use proxmox::try_block; use proxmox::api::RpcEnvironmentType; @@ -27,6 +31,22 @@ fn main() { } } +fn get_index( + _auth_id: Option, + _language: Option, + _api: &ApiConfig, + _parts: Parts, +) -> Response { + + let index = "

Proxmox Backup API Server

"; + + Response::builder() + .status(StatusCode::OK) + .header(header::CONTENT_TYPE, "text/html") + .body(index.into()) + .unwrap() +} + async fn run() -> Result<(), Error> { if let Err(err) = syslog::init( syslog::Facility::LOG_DAEMON, @@ -65,6 +85,7 @@ async fn run() -> Result<(), Error> { &proxmox_backup::api2::ROUTER, RpcEnvironmentType::PRIVILEGED, default_api_auth(), + get_index, )?; let backup_user = pbs_config::backup_user()?; diff --git a/src/bin/proxmox-backup-proxy.rs b/src/bin/proxmox-backup-proxy.rs index d4ac2a85..6a4fddef 100644 --- a/src/bin/proxmox-backup-proxy.rs +++ b/src/bin/proxmox-backup-proxy.rs @@ -4,10 +4,15 @@ use std::os::unix::io::AsRawFd; use anyhow::{bail, format_err, Error}; use futures::*; +use http::request::Parts; +use http::Response; +use hyper::{Body, StatusCode}; +use hyper::header; +use url::form_urlencoded; use openssl::ssl::{SslMethod, SslAcceptor, SslFiletype}; use tokio_stream::wrappers::ReceiverStream; -use serde_json::Value; +use serde_json::{json, Value}; use proxmox::try_block; use proxmox::api::RpcEnvironmentType; @@ -73,6 +78,79 @@ fn main() -> Result<(), Error> { pbs_runtime::main(run()) } +fn get_index( + auth_id: Option, + language: Option, + api: &ApiConfig, + parts: Parts, +) -> Response { + + let (userid, csrf_token) = match auth_id { + Some(auth_id) => { + let auth_id = auth_id.parse::(); + match auth_id { + Ok(auth_id) if !auth_id.is_token() => { + let userid = auth_id.user().clone(); + let new_csrf_token = assemble_csrf_prevention_token(csrf_secret(), &userid); + (Some(userid), Some(new_csrf_token)) + } + _ => (None, None) + } + } + None => (None, None), + }; + + let nodename = proxmox::tools::nodename(); + let user = userid.as_ref().map(|u| u.as_str()).unwrap_or(""); + + let csrf_token = csrf_token.unwrap_or_else(|| String::from("")); + + let mut debug = false; + let mut template_file = "index"; + + if let Some(query_str) = parts.uri.query() { + for (k, v) in form_urlencoded::parse(query_str.as_bytes()).into_owned() { + if k == "debug" && v != "0" && v != "false" { + debug = true; + } else if k == "console" { + template_file = "console"; + } + } + } + + let mut lang = String::from(""); + if let Some(language) = language { + if Path::new(&format!("/usr/share/pbs-i18n/pbs-lang-{}.js", language)).exists() { + lang = language; + } + } + + let data = json!({ + "NodeName": nodename, + "UserName": user, + "CSRFPreventionToken": csrf_token, + "language": lang, + "debug": debug, + }); + + let (ct, index) = match api.render_template(template_file, &data) { + Ok(index) => ("text/html", index), + Err(err) => ("text/plain", format!("Error rendering template: {}", err)), + }; + + let mut resp = Response::builder() + .status(StatusCode::OK) + .header(header::CONTENT_TYPE, ct) + .body(index.into()) + .unwrap(); + + if let Some(userid) = userid { + resp.extensions_mut().insert(Authid::from((userid, None))); + } + + resp +} + async fn run() -> Result<(), Error> { if let Err(err) = syslog::init( syslog::Facility::LOG_DAEMON, @@ -93,6 +171,7 @@ async fn run() -> Result<(), Error> { &proxmox_backup::api2::ROUTER, RpcEnvironmentType::PUBLIC, default_api_auth(), + get_index, )?; config.add_alias("novnc", "/usr/share/novnc-pve"); diff --git a/src/bin/proxmox-restore-daemon.rs b/src/bin/proxmox-restore-daemon.rs index c5122cff..d9a8eff0 100644 --- a/src/bin/proxmox-restore-daemon.rs +++ b/src/bin/proxmox-restore-daemon.rs @@ -13,6 +13,10 @@ use lazy_static::lazy_static; use log::{error, info}; use tokio::sync::mpsc; use tokio_stream::wrappers::ReceiverStream; +use http::request::Parts; +use http::Response; +use hyper::{Body, StatusCode}; +use hyper::header; use proxmox::api::RpcEnvironmentType; @@ -89,13 +93,29 @@ fn setup_system_env() -> Result<(), Error> { Ok(()) } +fn get_index( + _auth_id: Option, + _language: Option, + _api: &ApiConfig, + _parts: Parts, +) -> Response { + + let index = "

Proxmox Backup Restore Daemon/h1>

"; + + Response::builder() + .status(StatusCode::OK) + .header(header::CONTENT_TYPE, "text/html") + .body(index.into()) + .unwrap() +} + async fn run() -> Result<(), Error> { watchdog_init(); let auth_config = Arc::new( auth::ticket_auth().map_err(|err| format_err!("reading ticket file failed: {}", err))?, ); - let config = ApiConfig::new("", &ROUTER, RpcEnvironmentType::PUBLIC, auth_config)?; + let config = ApiConfig::new("", &ROUTER, RpcEnvironmentType::PUBLIC, auth_config, get_index)?; let rest_server = RestServer::new(config); let vsock_fd = get_vsock_fd()?; diff --git a/src/server/rest.rs b/src/server/rest.rs index 3cc6bccb..9ed0eb32 100644 --- a/src/server/rest.rs +++ b/src/server/rest.rs @@ -15,7 +15,7 @@ use hyper::http::request::Parts; use hyper::{Body, Request, Response, StatusCode}; use lazy_static::lazy_static; use regex::Regex; -use serde_json::{json, Value}; +use serde_json::Value; use tokio::fs::File; use tokio::time::Instant; use url::form_urlencoded; @@ -42,8 +42,6 @@ use proxmox_rest_server::formatter::*; use pbs_config::CachedUserInfo; -use crate::auth_helpers::*; - extern "C" { fn tzset(); } @@ -468,78 +466,6 @@ pub async fn handle_api_request, - language: Option, - api: &Arc, - parts: Parts, -) -> Response { - - let (userid, csrf_token) = match auth_id { - Some(auth_id) => { - let auth_id = auth_id.parse::(); - match auth_id { - Ok(auth_id) if !auth_id.is_token() => { - let userid = auth_id.user().clone(); - let new_csrf_token = assemble_csrf_prevention_token(csrf_secret(), &userid); - (Some(userid), Some(new_csrf_token)) - } - _ => (None, None) - } - } - None => (None, None), - }; - - let nodename = proxmox::tools::nodename(); - let user = userid.as_ref().map(|u| u.as_str()).unwrap_or(""); - - let csrf_token = csrf_token.unwrap_or_else(|| String::from("")); - - let mut debug = false; - let mut template_file = "index"; - - if let Some(query_str) = parts.uri.query() { - for (k, v) in form_urlencoded::parse(query_str.as_bytes()).into_owned() { - if k == "debug" && v != "0" && v != "false" { - debug = true; - } else if k == "console" { - template_file = "console"; - } - } - } - - let mut lang = String::from(""); - if let Some(language) = language { - if Path::new(&format!("/usr/share/pbs-i18n/pbs-lang-{}.js", language)).exists() { - lang = language; - } - } - - let data = json!({ - "NodeName": nodename, - "UserName": user, - "CSRFPreventionToken": csrf_token, - "language": lang, - "debug": debug, - }); - - let (ct, index) = match api.render_template(template_file, &data) { - Ok(index) => ("text/html", index), - Err(err) => ("text/plain", format!("Error rendering template: {}", err)), - }; - - let mut resp = Response::builder() - .status(StatusCode::OK) - .header(header::CONTENT_TYPE, ct) - .body(index.into()) - .unwrap(); - - if let Some(userid) = userid { - resp.extensions_mut().insert(Authid::from((userid, None))); - } - - resp -} fn extension_to_content_type(filename: &Path) -> (&'static str, bool) { if let Some(ext) = filename.extension().and_then(|osstr| osstr.to_str()) { @@ -802,14 +728,14 @@ async fn handle_request( let language = extract_lang_header(&parts.headers); match auth.check_auth(&parts.headers, &method) { Ok(auth_id) => { - return Ok(get_index(Some(auth_id), language, &api, parts)); + return Ok(api.get_index(Some(auth_id), language, parts)); } Err(AuthError::Generic(_)) => { tokio::time::sleep_until(Instant::from_std(delay_unauth_time)).await; } Err(AuthError::NoData) => {} } - return Ok(get_index(None, language, &api, parts)); + return Ok(api.get_index(None, language, parts)); } else { let filename = api.find_alias(&components); let compression = extract_compression_method(&parts.headers);