]>
Commit | Line | Data |
---|---|---|
7b22fb25 TL |
1 | use anyhow::{Error, format_err, bail}; |
2 | use serde_json::Value; | |
7e13b2d6 | 3 | |
9626c286 | 4 | use proxmox::api::{api, Router, RpcEnvironment, Permission}; |
a2479cfa WB |
5 | |
6 | use crate::tools; | |
7b22fb25 TL |
7 | use crate::tools::subscription::{self, SubscriptionStatus, SubscriptionInfo}; |
8 | use crate::config::acl::{PRIV_SYS_AUDIT,PRIV_SYS_MODIFY}; | |
9626c286 | 9 | use crate::config::cached_user_info::CachedUserInfo; |
926d2531 | 10 | use crate::api2::types::{NODE_SCHEMA, SUBSCRIPTION_KEY_SCHEMA, Authid}; |
7e13b2d6 | 11 | |
1bfc1efa | 12 | #[api( |
113c9b59 SR |
13 | input: { |
14 | properties: { | |
15 | node: { | |
16 | schema: NODE_SCHEMA, | |
17 | }, | |
7b22fb25 TL |
18 | force: { |
19 | description: "Always connect to server, even if information in cache is up to date.", | |
20 | type: bool, | |
21 | optional: true, | |
22 | default: false, | |
23 | }, | |
113c9b59 SR |
24 | }, |
25 | }, | |
7b22fb25 TL |
26 | protected: true, |
27 | access: { | |
28 | permission: &Permission::Privilege(&["system"], PRIV_SYS_MODIFY, false), | |
29 | }, | |
30 | )] | |
31 | /// Check and update subscription status. | |
652506e6 | 32 | pub fn check_subscription( |
7b22fb25 TL |
33 | force: bool, |
34 | ) -> Result<(), Error> { | |
b57b3c9b TL |
35 | // FIXME: drop once proxmox-api-macro is bumped to >> 5.0.0-1 |
36 | let _remove_me = API_METHOD_CHECK_SUBSCRIPTION_PARAM_DEFAULT_FORCE; | |
7b22fb25 TL |
37 | |
38 | let info = match subscription::read_subscription() { | |
39 | Err(err) => bail!("could not read subscription status: {}", err), | |
40 | Ok(Some(info)) => info, | |
41 | Ok(None) => return Ok(()), | |
42 | }; | |
43 | ||
44 | let server_id = tools::get_hardware_address()?; | |
45 | let key = if let Some(key) = info.key { | |
46 | // always update apt auth if we have a key to ensure user can access enterprise repo | |
47 | subscription::update_apt_auth(Some(key.to_owned()), Some(server_id.to_owned()))?; | |
48 | key | |
49 | } else { | |
50 | String::new() | |
51 | }; | |
52 | ||
53 | if !force && info.status == SubscriptionStatus::ACTIVE { | |
54 | let age = proxmox::tools::time::epoch_i64() - info.checktime.unwrap_or(i64::MAX); | |
55 | if age < subscription::MAX_LOCAL_KEY_AGE { | |
56 | return Ok(()); | |
57 | } | |
58 | } | |
59 | ||
60 | let info = subscription::check_subscription(key, server_id)?; | |
61 | ||
62 | subscription::write_subscription(info) | |
63 | .map_err(|e| format_err!("Error writing updated subscription status - {}", e))?; | |
64 | ||
65 | Ok(()) | |
66 | } | |
67 | ||
68 | #[api( | |
69 | input: { | |
1bfc1efa | 70 | properties: { |
7b22fb25 TL |
71 | node: { |
72 | schema: NODE_SCHEMA, | |
1bfc1efa DM |
73 | }, |
74 | }, | |
75 | }, | |
9b93c620 | 76 | returns: { type: SubscriptionInfo }, |
1bfc1efa | 77 | access: { |
9626c286 | 78 | permission: &Permission::Anybody, |
1bfc1efa DM |
79 | }, |
80 | )] | |
81 | /// Read subscription info. | |
652506e6 | 82 | pub fn get_subscription( |
9626c286 FG |
83 | _param: Value, |
84 | rpcenv: &mut dyn RpcEnvironment, | |
7b22fb25 TL |
85 | ) -> Result<SubscriptionInfo, Error> { |
86 | let url = "https://www.proxmox.com/en/proxmox-backup-server/pricing"; | |
87 | ||
88 | let info = match subscription::read_subscription() { | |
89 | Err(err) => bail!("could not read subscription status: {}", err), | |
90 | Ok(Some(info)) => info, | |
91 | Ok(None) => SubscriptionInfo { | |
92 | status: SubscriptionStatus::NOTFOUND, | |
93 | message: Some("There is no subscription key".into()), | |
94 | serverid: Some(tools::get_hardware_address()?), | |
95 | url: Some(url.into()), | |
96 | ..Default::default() | |
97 | }, | |
98 | }; | |
99 | ||
e6dc35ac | 100 | let auth_id: Authid = rpcenv.get_auth_id().unwrap().parse()?; |
9626c286 | 101 | let user_info = CachedUserInfo::new()?; |
e6dc35ac | 102 | let user_privs = user_info.lookup_privs(&auth_id, &[]); |
7b22fb25 TL |
103 | |
104 | if (user_privs & PRIV_SYS_AUDIT) == 0 { | |
105 | // not enough privileges for full state | |
106 | return Ok(SubscriptionInfo { | |
107 | status: info.status, | |
108 | message: info.message, | |
109 | url: info.url, | |
110 | ..Default::default() | |
111 | }); | |
9626c286 | 112 | }; |
7e13b2d6 | 113 | |
7b22fb25 TL |
114 | Ok(info) |
115 | } | |
116 | ||
117 | #[api( | |
118 | input: { | |
119 | properties: { | |
120 | node: { | |
121 | schema: NODE_SCHEMA, | |
122 | }, | |
123 | key: { | |
926d2531 | 124 | schema: SUBSCRIPTION_KEY_SCHEMA, |
7b22fb25 TL |
125 | }, |
126 | }, | |
127 | }, | |
128 | protected: true, | |
129 | access: { | |
130 | permission: &Permission::Privilege(&["system"], PRIV_SYS_MODIFY, false), | |
131 | }, | |
132 | )] | |
133 | /// Set a subscription key and check it. | |
652506e6 | 134 | pub fn set_subscription( |
7b22fb25 TL |
135 | key: String, |
136 | ) -> Result<(), Error> { | |
137 | ||
138 | let server_id = tools::get_hardware_address()?; | |
139 | ||
140 | let info = subscription::check_subscription(key, server_id.to_owned())?; | |
141 | ||
142 | subscription::write_subscription(info) | |
143 | .map_err(|e| format_err!("Error writing subscription status - {}", e))?; | |
144 | ||
145 | Ok(()) | |
146 | } | |
147 | ||
148 | #[api( | |
149 | input: { | |
150 | properties: { | |
151 | node: { | |
152 | schema: NODE_SCHEMA, | |
153 | }, | |
154 | }, | |
155 | }, | |
156 | protected: true, | |
157 | access: { | |
158 | permission: &Permission::Privilege(&["system"], PRIV_SYS_MODIFY, false), | |
159 | }, | |
160 | )] | |
161 | /// Delete subscription info. | |
652506e6 | 162 | pub fn delete_subscription() -> Result<(), Error> { |
7b22fb25 TL |
163 | |
164 | subscription::delete_subscription() | |
165 | .map_err(|err| format_err!("Deleting subscription failed: {}", err))?; | |
166 | ||
167 | Ok(()) | |
7e13b2d6 DM |
168 | } |
169 | ||
255f378a | 170 | pub const ROUTER: Router = Router::new() |
7b22fb25 TL |
171 | .post(&API_METHOD_CHECK_SUBSCRIPTION) |
172 | .put(&API_METHOD_SET_SUBSCRIPTION) | |
173 | .delete(&API_METHOD_DELETE_SUBSCRIPTION) | |
1bfc1efa | 174 | .get(&API_METHOD_GET_SUBSCRIPTION); |