-use anyhow::{Error};
-use serde_json::{json, Value};
+use anyhow::{Error, format_err, bail};
+use serde_json::Value;
use proxmox::api::{api, Router, RpcEnvironment, Permission};
use crate::tools;
-use crate::config::acl::PRIV_SYS_AUDIT;
+use crate::tools::subscription::{self, SubscriptionStatus, SubscriptionInfo};
+use crate::config::acl::{PRIV_SYS_AUDIT,PRIV_SYS_MODIFY};
use crate::config::cached_user_info::CachedUserInfo;
-use crate::api2::types::{NODE_SCHEMA, Userid};
+use crate::api2::types::{NODE_SCHEMA, SUBSCRIPTION_KEY_SCHEMA, Authid};
#[api(
input: {
node: {
schema: NODE_SCHEMA,
},
+ force: {
+ description: "Always connect to server, even if information in cache is up to date.",
+ type: bool,
+ optional: true,
+ default: false,
+ },
},
},
- returns: {
- description: "Subscription status.",
+ protected: true,
+ access: {
+ permission: &Permission::Privilege(&["system"], PRIV_SYS_MODIFY, false),
+ },
+)]
+/// Check and update subscription status.
+fn check_subscription(
+ force: bool,
+) -> Result<(), Error> {
+ // FIXME: drop once proxmox-api-macro is bumped to >> 5.0.0-1
+ let _remove_me = API_METHOD_CHECK_SUBSCRIPTION_PARAM_DEFAULT_FORCE;
+
+ let info = match subscription::read_subscription() {
+ Err(err) => bail!("could not read subscription status: {}", err),
+ Ok(Some(info)) => info,
+ Ok(None) => return Ok(()),
+ };
+
+ let server_id = tools::get_hardware_address()?;
+ let key = if let Some(key) = info.key {
+ // always update apt auth if we have a key to ensure user can access enterprise repo
+ subscription::update_apt_auth(Some(key.to_owned()), Some(server_id.to_owned()))?;
+ key
+ } else {
+ String::new()
+ };
+
+ if !force && info.status == SubscriptionStatus::ACTIVE {
+ let age = proxmox::tools::time::epoch_i64() - info.checktime.unwrap_or(i64::MAX);
+ if age < subscription::MAX_LOCAL_KEY_AGE {
+ return Ok(());
+ }
+ }
+
+ let info = subscription::check_subscription(key, server_id)?;
+
+ subscription::write_subscription(info)
+ .map_err(|e| format_err!("Error writing updated subscription status - {}", e))?;
+
+ Ok(())
+}
+
+#[api(
+ input: {
properties: {
- status: {
- type: String,
- description: "'NotFound', 'active' or 'inactive'."
- },
- message: {
- type: String,
- description: "Human readable problem description.",
- },
- serverid: {
- type: String,
- description: "The unique server ID, if permitted to access.",
- },
- url: {
- type: String,
- description: "URL to Web Shop.",
+ node: {
+ schema: NODE_SCHEMA,
},
},
},
+ returns: {
+ description: "Subscription status.",
+ type: SubscriptionInfo,
+ },
access: {
permission: &Permission::Anybody,
},
fn get_subscription(
_param: Value,
rpcenv: &mut dyn RpcEnvironment,
-) -> Result<Value, Error> {
- let userid: Userid = rpcenv.get_user().unwrap().parse()?;
+) -> Result<SubscriptionInfo, Error> {
+ let url = "https://www.proxmox.com/en/proxmox-backup-server/pricing";
+
+ let info = match subscription::read_subscription() {
+ Err(err) => bail!("could not read subscription status: {}", err),
+ Ok(Some(info)) => info,
+ Ok(None) => SubscriptionInfo {
+ status: SubscriptionStatus::NOTFOUND,
+ message: Some("There is no subscription key".into()),
+ serverid: Some(tools::get_hardware_address()?),
+ url: Some(url.into()),
+ ..Default::default()
+ },
+ };
+
+ let auth_id: Authid = rpcenv.get_auth_id().unwrap().parse()?;
let user_info = CachedUserInfo::new()?;
- let user_privs = user_info.lookup_privs(&userid, &[]);
- let server_id = if (user_privs & PRIV_SYS_AUDIT) != 0 {
- tools::get_hardware_address()?
- } else {
- "hidden".to_string()
+ let user_privs = user_info.lookup_privs(&auth_id, &[]);
+
+ if (user_privs & PRIV_SYS_AUDIT) == 0 {
+ // not enough privileges for full state
+ return Ok(SubscriptionInfo {
+ status: info.status,
+ message: info.message,
+ url: info.url,
+ ..Default::default()
+ });
};
- let url = "https://www.proxmox.com/en/proxmox-backup-server/pricing";
- Ok(json!({
- "status": "NotFound",
- "message": "There is no subscription key",
- "serverid": server_id,
- "url": url,
- }))
+ Ok(info)
+}
+
+#[api(
+ input: {
+ properties: {
+ node: {
+ schema: NODE_SCHEMA,
+ },
+ key: {
+ schema: SUBSCRIPTION_KEY_SCHEMA,
+ },
+ },
+ },
+ protected: true,
+ access: {
+ permission: &Permission::Privilege(&["system"], PRIV_SYS_MODIFY, false),
+ },
+)]
+/// Set a subscription key and check it.
+fn set_subscription(
+ key: String,
+) -> Result<(), Error> {
+
+ let server_id = tools::get_hardware_address()?;
+
+ let info = subscription::check_subscription(key, server_id.to_owned())?;
+
+ subscription::write_subscription(info)
+ .map_err(|e| format_err!("Error writing subscription status - {}", e))?;
+
+ Ok(())
+}
+
+#[api(
+ input: {
+ properties: {
+ node: {
+ schema: NODE_SCHEMA,
+ },
+ },
+ },
+ protected: true,
+ access: {
+ permission: &Permission::Privilege(&["system"], PRIV_SYS_MODIFY, false),
+ },
+)]
+/// Delete subscription info.
+fn delete_subscription() -> Result<(), Error> {
+
+ subscription::delete_subscription()
+ .map_err(|err| format_err!("Deleting subscription failed: {}", err))?;
+
+ Ok(())
}
pub const ROUTER: Router = Router::new()
+ .post(&API_METHOD_CHECK_SUBSCRIPTION)
+ .put(&API_METHOD_SET_SUBSCRIPTION)
+ .delete(&API_METHOD_DELETE_SUBSCRIPTION)
.get(&API_METHOD_GET_SUBSCRIPTION);