From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from firstgate.proxmox.com (firstgate.proxmox.com [212.224.123.68]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits)) (No client certificate requested) by lists.proxmox.com (Postfix) with ESMTPS id 0B4026B862 for ; Tue, 21 Sep 2021 07:59:59 +0200 (CEST) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id 269F58FC3 for ; Tue, 21 Sep 2021 07:59:07 +0200 (CEST) Received: from proxmox-new.maurer-it.com (proxmox-new.maurer-it.com [94.136.29.106]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits)) (No client certificate requested) by firstgate.proxmox.com (Proxmox) with ESMTPS id 560FF8E96 for ; Tue, 21 Sep 2021 07:59:00 +0200 (CEST) Received: from proxmox-new.maurer-it.com (localhost.localdomain [127.0.0.1]) by proxmox-new.maurer-it.com (Proxmox) with ESMTP id 2FEE3449B4; Tue, 21 Sep 2021 07:59:00 +0200 (CEST) From: Dietmar Maurer To: pbs-devel@lists.proxmox.com Date: Tue, 21 Sep 2021 07:58:47 +0200 Message-Id: <20210921055854.3799470-10-dietmar@proxmox.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20210921055854.3799470-1-dietmar@proxmox.com> References: <20210921055854.3799470-1-dietmar@proxmox.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-SPAM-LEVEL: Spam detection results: 0 AWL 0.596 Adjusted score from AWL reputation of From: address BAYES_00 -1.9 Bayes spam probability is 0 to 1% KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_PASS -0.001 SPF: sender matches SPF record URIBL_BLOCKED 0.001 ADMINISTRATOR NOTICE: The query to URIBL was blocked. See http://wiki.apache.org/spamassassin/DnsBlocklists#dnsbl-block for more information. [proxmox-restore-daemon.rs, rest.rs, proxmox-backup-api.rs, proxmox-backup-proxy.rs] Subject: [pbs-devel] [PATCH proxmox-backup v2 09/16] make get_index and ApiConfig property (callback) X-BeenThere: pbs-devel@lists.proxmox.com X-Mailman-Version: 2.1.29 Precedence: list List-Id: Proxmox Backup Server development discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 21 Sep 2021 05:59:59 -0000 --- 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); -- 2.30.2