From 137a6ebcadea6ebceaa69517a5aec9d35ef1c39f Mon Sep 17 00:00:00 2001 From: Stefan Reiter Date: Mon, 9 Nov 2020 10:35:28 +0100 Subject: [PATCH] apt: allow changelog retrieval from enterprise repo If a package is or will be installed from the enterprise repo, retrieve the changelog from there as well (securely via HTTPS and authenticated with the subcription key). Extends the get_string method to take additional headers, in this case used for 'Authorization'. Hyper does not have built-in basic auth support AFAICT but it's simple enough to just build the header manually. Take the opportunity and also set the User-Agent sensibly for GET requests, just like for POST. Signed-off-by: Stefan Reiter --- src/api2/node/apt.rs | 30 ++++++++++++++++++++++++++++-- src/tools/apt.rs | 9 +++++++-- src/tools/http.rs | 18 ++++++++++++++++-- 3 files changed, 51 insertions(+), 6 deletions(-) diff --git a/src/api2/node/apt.rs b/src/api2/node/apt.rs index b9ed0c64..aa41d6a5 100644 --- a/src/api2/node/apt.rs +++ b/src/api2/node/apt.rs @@ -1,12 +1,13 @@ use anyhow::{Error, bail, format_err}; use serde_json::{json, Value}; +use std::collections::HashMap; use proxmox::list_subdirs_api_method; use proxmox::api::{api, RpcEnvironment, RpcEnvironmentType, Permission}; use proxmox::api::router::{Router, SubdirMap}; use crate::server::WorkerTask; -use crate::tools::{apt, http}; +use crate::tools::{apt, http, subscription}; use crate::config::acl::{PRIV_SYS_AUDIT, PRIV_SYS_MODIFY}; use crate::api2::types::{Authid, APTUpdateInfo, NODE_SCHEMA, UPID_SCHEMA}; @@ -202,9 +203,34 @@ fn apt_get_changelog( let changelog_url = &pkg_info[0].change_log_url; // FIXME: use 'apt-get changelog' for proxmox packages as well, once repo supports it if changelog_url.starts_with("http://download.proxmox.com/") { - let changelog = crate::tools::runtime::block_on(http::get_string(changelog_url)) + let changelog = crate::tools::runtime::block_on(http::get_string(changelog_url, None)) .map_err(|err| format_err!("Error downloading changelog from '{}': {}", changelog_url, err))?; return Ok(json!(changelog)); + + } else if changelog_url.starts_with("https://enterprise.proxmox.com/") { + let sub = match subscription::read_subscription()? { + Some(sub) => sub, + None => bail!("cannot retrieve changelog from enterprise repo: no subscription info found") + }; + let (key, id) = match sub.key { + Some(key) => { + match sub.serverid { + Some(id) => (key, id), + None => + bail!("cannot retrieve changelog from enterprise repo: no server id found") + } + }, + None => bail!("cannot retrieve changelog from enterprise repo: no subscription key found") + }; + + let mut auth_header = HashMap::new(); + auth_header.insert("Authorization".to_owned(), + format!("Basic {}", base64::encode(format!("{}:{}", key, id)))); + + let changelog = crate::tools::runtime::block_on(http::get_string(changelog_url, Some(&auth_header))) + .map_err(|err| format_err!("Error downloading changelog from '{}': {}", changelog_url, err))?; + return Ok(json!(changelog)); + } else { let mut command = std::process::Command::new("apt-get"); command.arg("changelog"); diff --git a/src/tools/apt.rs b/src/tools/apt.rs index 6ea2565c..841b7447 100644 --- a/src/tools/apt.rs +++ b/src/tools/apt.rs @@ -128,8 +128,13 @@ fn get_changelog_url( None => bail!("incompatible filename, doesn't match regex") }; - return Ok(format!("http://download.proxmox.com/{}/{}_{}.changelog", - base, package, version)); + if component == "pbs-enterprise" { + return Ok(format!("https://enterprise.proxmox.com/{}/{}_{}.changelog", + base, package, version)); + } else { + return Ok(format!("http://download.proxmox.com/{}/{}_{}.changelog", + base, package, version)); + } } bail!("unknown origin ({}) or component ({})", origin, component) diff --git a/src/tools/http.rs b/src/tools/http.rs index 168bb107..d8603fe5 100644 --- a/src/tools/http.rs +++ b/src/tools/http.rs @@ -2,6 +2,7 @@ use anyhow::{Error, format_err, bail}; use lazy_static::lazy_static; use std::task::{Context, Poll}; use std::os::unix::io::AsRawFd; +use std::collections::HashMap; use hyper::{Uri, Body}; use hyper::client::{Client, HttpConnector}; @@ -26,8 +27,21 @@ lazy_static! { }; } -pub async fn get_string(uri: &str) -> Result { - let res = HTTP_CLIENT.get(uri.parse()?).await?; +pub async fn get_string(uri: &str, extra_headers: Option<&HashMap>) -> Result { + let mut request = Request::builder() + .method("GET") + .uri(uri) + .header("User-Agent", "proxmox-backup-client/1.0"); + + if let Some(hs) = extra_headers { + for (h, v) in hs.iter() { + request = request.header(h, v); + } + } + + let request = request.body(Body::empty())?; + + let res = HTTP_CLIENT.request(request).await?; let status = res.status(); if !status.is_success() {