make get_index and ApiConfig property (callback)
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
This commit is contained in:
parent
f533d16ef6
commit
7fa9a37c7c
|
@ -5,7 +5,9 @@ use std::fs::metadata;
|
||||||
use std::sync::{Arc, Mutex, RwLock};
|
use std::sync::{Arc, Mutex, RwLock};
|
||||||
|
|
||||||
use anyhow::{bail, Error, format_err};
|
use anyhow::{bail, Error, format_err};
|
||||||
use hyper::Method;
|
use hyper::{Method, Body, Response};
|
||||||
|
use hyper::http::request::Parts;
|
||||||
|
|
||||||
use handlebars::Handlebars;
|
use handlebars::Handlebars;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
|
@ -14,6 +16,8 @@ use proxmox::tools::fs::{create_path, CreateOptions};
|
||||||
|
|
||||||
use crate::{ApiAuth, FileLogger, FileLogOptions, CommandoSocket};
|
use crate::{ApiAuth, FileLogger, FileLogOptions, CommandoSocket};
|
||||||
|
|
||||||
|
pub type GetIndexFn = fn(Option<String>, Option<String>, &ApiConfig, Parts) -> Response<Body>;
|
||||||
|
|
||||||
pub struct ApiConfig {
|
pub struct ApiConfig {
|
||||||
basedir: PathBuf,
|
basedir: PathBuf,
|
||||||
router: &'static Router,
|
router: &'static Router,
|
||||||
|
@ -23,6 +27,7 @@ pub struct ApiConfig {
|
||||||
template_files: RwLock<HashMap<String, (SystemTime, PathBuf)>>,
|
template_files: RwLock<HashMap<String, (SystemTime, PathBuf)>>,
|
||||||
request_log: Option<Arc<Mutex<FileLogger>>>,
|
request_log: Option<Arc<Mutex<FileLogger>>>,
|
||||||
pub api_auth: Arc<dyn ApiAuth + Send + Sync>,
|
pub api_auth: Arc<dyn ApiAuth + Send + Sync>,
|
||||||
|
get_index_fn: GetIndexFn,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ApiConfig {
|
impl ApiConfig {
|
||||||
|
@ -31,6 +36,7 @@ impl ApiConfig {
|
||||||
router: &'static Router,
|
router: &'static Router,
|
||||||
env_type: RpcEnvironmentType,
|
env_type: RpcEnvironmentType,
|
||||||
api_auth: Arc<dyn ApiAuth + Send + Sync>,
|
api_auth: Arc<dyn ApiAuth + Send + Sync>,
|
||||||
|
get_index_fn: GetIndexFn,
|
||||||
) -> Result<Self, Error> {
|
) -> Result<Self, Error> {
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
basedir: basedir.into(),
|
basedir: basedir.into(),
|
||||||
|
@ -41,9 +47,19 @@ impl ApiConfig {
|
||||||
template_files: RwLock::new(HashMap::new()),
|
template_files: RwLock::new(HashMap::new()),
|
||||||
request_log: None,
|
request_log: None,
|
||||||
api_auth,
|
api_auth,
|
||||||
|
get_index_fn,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_index(
|
||||||
|
&self,
|
||||||
|
auth_id: Option<String>,
|
||||||
|
language: Option<String>,
|
||||||
|
parts: Parts,
|
||||||
|
) -> Response<Body> {
|
||||||
|
(self.get_index_fn)(auth_id, language, self, parts)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn find_method(
|
pub fn find_method(
|
||||||
&self,
|
&self,
|
||||||
components: &[&str],
|
components: &[&str],
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
use anyhow::{bail, Error};
|
use anyhow::{bail, Error};
|
||||||
use futures::*;
|
use futures::*;
|
||||||
|
use http::request::Parts;
|
||||||
|
use http::Response;
|
||||||
|
use hyper::{Body, StatusCode};
|
||||||
|
use hyper::header;
|
||||||
|
|
||||||
use proxmox::try_block;
|
use proxmox::try_block;
|
||||||
use proxmox::api::RpcEnvironmentType;
|
use proxmox::api::RpcEnvironmentType;
|
||||||
|
@ -27,6 +31,22 @@ fn main() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_index(
|
||||||
|
_auth_id: Option<String>,
|
||||||
|
_language: Option<String>,
|
||||||
|
_api: &ApiConfig,
|
||||||
|
_parts: Parts,
|
||||||
|
) -> Response<Body> {
|
||||||
|
|
||||||
|
let index = "<center><h1>Proxmox Backup API Server</h1></center>";
|
||||||
|
|
||||||
|
Response::builder()
|
||||||
|
.status(StatusCode::OK)
|
||||||
|
.header(header::CONTENT_TYPE, "text/html")
|
||||||
|
.body(index.into())
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
async fn run() -> Result<(), Error> {
|
async fn run() -> Result<(), Error> {
|
||||||
if let Err(err) = syslog::init(
|
if let Err(err) = syslog::init(
|
||||||
syslog::Facility::LOG_DAEMON,
|
syslog::Facility::LOG_DAEMON,
|
||||||
|
@ -65,6 +85,7 @@ async fn run() -> Result<(), Error> {
|
||||||
&proxmox_backup::api2::ROUTER,
|
&proxmox_backup::api2::ROUTER,
|
||||||
RpcEnvironmentType::PRIVILEGED,
|
RpcEnvironmentType::PRIVILEGED,
|
||||||
default_api_auth(),
|
default_api_auth(),
|
||||||
|
get_index,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let backup_user = pbs_config::backup_user()?;
|
let backup_user = pbs_config::backup_user()?;
|
||||||
|
|
|
@ -4,10 +4,15 @@ use std::os::unix::io::AsRawFd;
|
||||||
|
|
||||||
use anyhow::{bail, format_err, Error};
|
use anyhow::{bail, format_err, Error};
|
||||||
use futures::*;
|
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 openssl::ssl::{SslMethod, SslAcceptor, SslFiletype};
|
||||||
use tokio_stream::wrappers::ReceiverStream;
|
use tokio_stream::wrappers::ReceiverStream;
|
||||||
use serde_json::Value;
|
use serde_json::{json, Value};
|
||||||
|
|
||||||
use proxmox::try_block;
|
use proxmox::try_block;
|
||||||
use proxmox::api::RpcEnvironmentType;
|
use proxmox::api::RpcEnvironmentType;
|
||||||
|
@ -73,6 +78,79 @@ fn main() -> Result<(), Error> {
|
||||||
pbs_runtime::main(run())
|
pbs_runtime::main(run())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_index(
|
||||||
|
auth_id: Option<String>,
|
||||||
|
language: Option<String>,
|
||||||
|
api: &ApiConfig,
|
||||||
|
parts: Parts,
|
||||||
|
) -> Response<Body> {
|
||||||
|
|
||||||
|
let (userid, csrf_token) = match auth_id {
|
||||||
|
Some(auth_id) => {
|
||||||
|
let auth_id = auth_id.parse::<Authid>();
|
||||||
|
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> {
|
async fn run() -> Result<(), Error> {
|
||||||
if let Err(err) = syslog::init(
|
if let Err(err) = syslog::init(
|
||||||
syslog::Facility::LOG_DAEMON,
|
syslog::Facility::LOG_DAEMON,
|
||||||
|
@ -93,6 +171,7 @@ async fn run() -> Result<(), Error> {
|
||||||
&proxmox_backup::api2::ROUTER,
|
&proxmox_backup::api2::ROUTER,
|
||||||
RpcEnvironmentType::PUBLIC,
|
RpcEnvironmentType::PUBLIC,
|
||||||
default_api_auth(),
|
default_api_auth(),
|
||||||
|
get_index,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
config.add_alias("novnc", "/usr/share/novnc-pve");
|
config.add_alias("novnc", "/usr/share/novnc-pve");
|
||||||
|
|
|
@ -13,6 +13,10 @@ use lazy_static::lazy_static;
|
||||||
use log::{error, info};
|
use log::{error, info};
|
||||||
use tokio::sync::mpsc;
|
use tokio::sync::mpsc;
|
||||||
use tokio_stream::wrappers::ReceiverStream;
|
use tokio_stream::wrappers::ReceiverStream;
|
||||||
|
use http::request::Parts;
|
||||||
|
use http::Response;
|
||||||
|
use hyper::{Body, StatusCode};
|
||||||
|
use hyper::header;
|
||||||
|
|
||||||
use proxmox::api::RpcEnvironmentType;
|
use proxmox::api::RpcEnvironmentType;
|
||||||
|
|
||||||
|
@ -89,13 +93,29 @@ fn setup_system_env() -> Result<(), Error> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_index(
|
||||||
|
_auth_id: Option<String>,
|
||||||
|
_language: Option<String>,
|
||||||
|
_api: &ApiConfig,
|
||||||
|
_parts: Parts,
|
||||||
|
) -> Response<Body> {
|
||||||
|
|
||||||
|
let index = "<center><h1>Proxmox Backup Restore Daemon/h1></center>";
|
||||||
|
|
||||||
|
Response::builder()
|
||||||
|
.status(StatusCode::OK)
|
||||||
|
.header(header::CONTENT_TYPE, "text/html")
|
||||||
|
.body(index.into())
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
async fn run() -> Result<(), Error> {
|
async fn run() -> Result<(), Error> {
|
||||||
watchdog_init();
|
watchdog_init();
|
||||||
|
|
||||||
let auth_config = Arc::new(
|
let auth_config = Arc::new(
|
||||||
auth::ticket_auth().map_err(|err| format_err!("reading ticket file failed: {}", err))?,
|
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 rest_server = RestServer::new(config);
|
||||||
|
|
||||||
let vsock_fd = get_vsock_fd()?;
|
let vsock_fd = get_vsock_fd()?;
|
||||||
|
|
|
@ -15,7 +15,7 @@ use hyper::http::request::Parts;
|
||||||
use hyper::{Body, Request, Response, StatusCode};
|
use hyper::{Body, Request, Response, StatusCode};
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use serde_json::{json, Value};
|
use serde_json::Value;
|
||||||
use tokio::fs::File;
|
use tokio::fs::File;
|
||||||
use tokio::time::Instant;
|
use tokio::time::Instant;
|
||||||
use url::form_urlencoded;
|
use url::form_urlencoded;
|
||||||
|
@ -42,8 +42,6 @@ use proxmox_rest_server::formatter::*;
|
||||||
|
|
||||||
use pbs_config::CachedUserInfo;
|
use pbs_config::CachedUserInfo;
|
||||||
|
|
||||||
use crate::auth_helpers::*;
|
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
fn tzset();
|
fn tzset();
|
||||||
}
|
}
|
||||||
|
@ -468,78 +466,6 @@ pub async fn handle_api_request<Env: RpcEnvironment, S: 'static + BuildHasher +
|
||||||
Ok(resp)
|
Ok(resp)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_index(
|
|
||||||
auth_id: Option<String>,
|
|
||||||
language: Option<String>,
|
|
||||||
api: &Arc<ApiConfig>,
|
|
||||||
parts: Parts,
|
|
||||||
) -> Response<Body> {
|
|
||||||
|
|
||||||
let (userid, csrf_token) = match auth_id {
|
|
||||||
Some(auth_id) => {
|
|
||||||
let auth_id = auth_id.parse::<Authid>();
|
|
||||||
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) {
|
fn extension_to_content_type(filename: &Path) -> (&'static str, bool) {
|
||||||
if let Some(ext) = filename.extension().and_then(|osstr| osstr.to_str()) {
|
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);
|
let language = extract_lang_header(&parts.headers);
|
||||||
match auth.check_auth(&parts.headers, &method) {
|
match auth.check_auth(&parts.headers, &method) {
|
||||||
Ok(auth_id) => {
|
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(_)) => {
|
Err(AuthError::Generic(_)) => {
|
||||||
tokio::time::sleep_until(Instant::from_std(delay_unauth_time)).await;
|
tokio::time::sleep_until(Instant::from_std(delay_unauth_time)).await;
|
||||||
}
|
}
|
||||||
Err(AuthError::NoData) => {}
|
Err(AuthError::NoData) => {}
|
||||||
}
|
}
|
||||||
return Ok(get_index(None, language, &api, parts));
|
return Ok(api.get_index(None, language, parts));
|
||||||
} else {
|
} else {
|
||||||
let filename = api.find_alias(&components);
|
let filename = api.find_alias(&components);
|
||||||
let compression = extract_compression_method(&parts.headers);
|
let compression = extract_compression_method(&parts.headers);
|
||||||
|
|
Loading…
Reference in New Issue