anyhow = "1.0"
futures = "0.3"
h2 = { version = "0.2", features = ["stream"] }
+handlebars = "3.0"
http = "0.2"
hyper = "0.13"
lazy_static = "1.4"
usr/lib/x86_64-linux-gnu/proxmox-backup/proxmox-backup-proxy
usr/lib/x86_64-linux-gnu/proxmox-backup/proxmox-backup-banner
usr/sbin/proxmox-backup-manager
+usr/share/javascript/proxmox-backup/index.hbs
usr/share/javascript/proxmox-backup/css/ext6-pbs.css
usr/share/javascript/proxmox-backup/images/logo-128.png
usr/share/javascript/proxmox-backup/images/proxmox_logo.png
let _ = csrf_secret(); // load with lazy_static
let config = server::ApiConfig::new(
- buildcfg::JS_DIR, &proxmox_backup::api2::ROUTER, RpcEnvironmentType::PRIVILEGED);
+ buildcfg::JS_DIR, &proxmox_backup::api2::ROUTER, RpcEnvironmentType::PRIVILEGED)?;
let rest_server = RestServer::new(config);
let _ = csrf_secret(); // load with lazy_static
let mut config = ApiConfig::new(
- buildcfg::JS_DIR, &proxmox_backup::api2::ROUTER, RpcEnvironmentType::PUBLIC);
+ buildcfg::JS_DIR, &proxmox_backup::api2::ROUTER, RpcEnvironmentType::PUBLIC)?;
// add default dirs which includes jquery and bootstrap
// my $base = '/usr/share/libpve-http-server-perl';
use std::collections::HashMap;
use std::path::{PathBuf};
+use anyhow::Error;
use hyper::Method;
+use handlebars::Handlebars;
use proxmox::api::{ApiMethod, Router, RpcEnvironmentType};
router: &'static Router,
aliases: HashMap<String, PathBuf>,
env_type: RpcEnvironmentType,
+ pub templates: Handlebars<'static>,
}
impl ApiConfig {
- pub fn new<B: Into<PathBuf>>(basedir: B, router: &'static Router, env_type: RpcEnvironmentType) -> Self {
- Self {
- basedir: basedir.into(),
+ pub fn new<B: Into<PathBuf>>(basedir: B, router: &'static Router, env_type: RpcEnvironmentType) -> Result<Self, Error> {
+ let mut templates = Handlebars::new();
+ let basedir = basedir.into();
+ templates.register_template_file("index", basedir.join("index.hbs"))?;
+ Ok(Self {
+ basedir,
router,
aliases: HashMap::new(),
env_type,
- }
+ templates
+ })
}
pub fn find_method(
use tokio::fs::File;
use tokio::time::Instant;
use url::form_urlencoded;
+use handlebars::Handlebars;
use proxmox::http_err;
use proxmox::api::{ApiHandler, ApiMethod, HttpError};
Ok(resp)
}
-fn get_index(username: Option<String>, token: Option<String>) -> Response<Body> {
+fn get_index(username: Option<String>, token: Option<String>, template: &Handlebars, parts: Parts) -> Response<Body> {
let nodename = proxmox::tools::nodename();
let username = username.unwrap_or_else(|| String::from(""));
let token = token.unwrap_or_else(|| String::from(""));
- let setup = json!({
- "Setup": { "auth_cookie_name": "PBSAuthCookie" },
+ let mut debug = false;
+
+ 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 == "1" || v == "true" {
+ debug = true;
+ }
+ }
+ }
+
+ let data = json!({
"NodeName": nodename,
"UserName": username,
"CSRFPreventionToken": token,
+ "debug": debug,
});
- let index = format!(r###"
-<!DOCTYPE html>
-<html>
- <head>
- <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
- <meta http-equiv="X-UA-Compatible" content="IE=edge">
- <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
- <title>Proxmox Backup Server</title>
- <link rel="icon" sizes="128x128" href="/images/logo-128.png" />
- <link rel="apple-touch-icon" sizes="128x128" href="/pve2/images/logo-128.png" />
- <link rel="stylesheet" type="text/css" href="/extjs/theme-crisp/resources/theme-crisp-all.css" />
- <link rel="stylesheet" type="text/css" href="/extjs/crisp/resources/charts-all.css" />
- <link rel="stylesheet" type="text/css" href="/fontawesome/css/font-awesome.css" />
- <link rel="stylesheet" type="text/css" href="/css/ext6-pbs.css" />
- <script type='text/javascript'> function gettext(buf) {{ return buf; }} </script>
- <script type="text/javascript" src="/extjs/ext-all-debug.js"></script>
- <script type="text/javascript" src="/extjs/charts-debug.js"></script>
- <script type="text/javascript">
- Proxmox = {};
- </script>
- <script type="text/javascript" src="/widgettoolkit/proxmoxlib.js"></script>
- <script type="text/javascript" src="/extjs/locale/locale-en.js"></script>
- <script type="text/javascript">
- Ext.History.fieldid = 'x-history-field';
- </script>
- <script type="text/javascript" src="/js/proxmox-backup-gui.js"></script>
- </head>
- <body>
- <!-- Fields required for history management -->
- <form id="history-form" class="x-hidden">
- <input type="hidden" id="x-history-field"/>
- </form>
- </body>
-</html>
-"###, setup.to_string());
+ let mut ct = "text/html";
+
+ let index = match template.render("index", &data) {
+ Ok(index) => index,
+ Err(err) => {
+ ct = "text/plain";
+ format!("Error rendering template: {}", err.desc)
+ },
+ };
Response::builder()
.status(StatusCode::OK)
- .header(header::CONTENT_TYPE, "text/html")
+ .header(header::CONTENT_TYPE, ct)
.body(index.into())
.unwrap()
}
match check_auth(&method, &ticket, &token, &user_info) {
Ok(username) => {
let new_token = assemble_csrf_prevention_token(csrf_secret(), &username);
- return Ok(get_index(Some(username), Some(new_token)));
+ return Ok(get_index(Some(username), Some(new_token), &api.templates, parts));
}
_ => {
tokio::time::delay_until(Instant::from_std(delay_unauth_time)).await;
- return Ok(get_index(None, None));
+ return Ok(get_index(None, None, &api.templates, parts));
}
}
} else {
- return Ok(get_index(None, None));
+ return Ok(get_index(None, None, &api.templates, parts));
}
} else {
let filename = api.find_alias(&components);
find . -name '*~' -exec rm {} ';'
rm -rf js
-install: js/proxmox-backup-gui.js css/ext6-pbs.css
+install: js/proxmox-backup-gui.js css/ext6-pbs.css index.hbs
install -dm755 $(DESTDIR)$(JSDIR)
+ install -m644 index.hbs $(DESTDIR)$(JSDIR)/
install -dm755 $(DESTDIR)$(JSDIR)/js
install -m644 js/proxmox-backup-gui.js $(DESTDIR)$(JSDIR)/js/
install -dm755 $(DESTDIR)$(JSDIR)/css
--- /dev/null
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
+ <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
+ <title>Proxmox Backup Server</title>
+ <link rel="icon" sizes="128x128" href="/images/logo-128.png" />
+ <link rel="apple-touch-icon" sizes="128x128" href="/pve2/images/logo-128.png" />
+ <link rel="stylesheet" type="text/css" href="/extjs/theme-crisp/resources/theme-crisp-all.css" />
+ <link rel="stylesheet" type="text/css" href="/extjs/crisp/resources/charts-all.css" />
+ <link rel="stylesheet" type="text/css" href="/fontawesome/css/font-awesome.css" />
+ <link rel="stylesheet" type="text/css" href="/css/ext6-pbs.css" />
+ <script type='text/javascript'> function gettext(buf) { return buf; } </script>
+ {{#if debug}}
+ <script type="text/javascript" src="/extjs/ext-all-debug.js"></script>
+ <script type="text/javascript" src="/extjs/charts-debug.js"></script>
+ {{else}}
+ <script type="text/javascript" src="/extjs/ext-all.js"></script>
+ <script type="text/javascript" src="/extjs/charts.js"></script>
+ {{/if}}
+ <script type="text/javascript">
+ Proxmox = {
+ Setup: { auth_cookie_name: 'PBSAuthCookie' },
+ NodeName: "{{ NodeName }}",
+ UserName: "{{ UserName }}",
+ CSRFPreventionToken: "{{ CSRFPreventionToken }}",
+ };
+ </script>
+ <script type="text/javascript" src="/widgettoolkit/proxmoxlib.js"></script>
+ <script type="text/javascript" src="/extjs/locale/locale-en.js"></script>
+ <script type="text/javascript">
+ Ext.History.fieldid = 'x-history-field';
+ </script>
+ <script type="text/javascript" src="/js/proxmox-backup-gui.js"></script>
+ </head>
+ <body>
+ <!-- Fields required for history management -->
+ <form id="history-form" class="x-hidden">
+ <input type="hidden" id="x-history-field"/>
+ </form>
+ </body>
+</html>