mirror of
https://git.proxmox.com/git/proxmox-perl-rs
synced 2025-05-23 10:00:16 +00:00
common: add proxmox_subscription wrapper
and expose it for PVE and PMG. Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com>
This commit is contained in:
parent
8fe90d189c
commit
8d143f8f9e
3
Makefile
3
Makefile
@ -51,7 +51,8 @@ gen:
|
|||||||
$(call package_template,PVE,pve_rs)
|
$(call package_template,PVE,pve_rs)
|
||||||
perl ./scripts/genpackage.pl Common \
|
perl ./scripts/genpackage.pl Common \
|
||||||
Proxmox::RS::APT::Repositories \
|
Proxmox::RS::APT::Repositories \
|
||||||
Proxmox::RS::CalendarEvent
|
Proxmox::RS::CalendarEvent \
|
||||||
|
Proxmox::RS::Subscription
|
||||||
perl ./scripts/genpackage.pl PVE \
|
perl ./scripts/genpackage.pl PVE \
|
||||||
PVE::RS::APT::Repositories \
|
PVE::RS::APT::Repositories \
|
||||||
PVE::RS::OpenId \
|
PVE::RS::OpenId \
|
||||||
|
@ -1,2 +1,3 @@
|
|||||||
pub mod apt;
|
pub mod apt;
|
||||||
mod calendar_event;
|
mod calendar_event;
|
||||||
|
mod subscription;
|
||||||
|
165
common/src/subscription.rs
Normal file
165
common/src/subscription.rs
Normal file
@ -0,0 +1,165 @@
|
|||||||
|
mod client {
|
||||||
|
use anyhow::{format_err, Error};
|
||||||
|
use http::Response;
|
||||||
|
|
||||||
|
pub(crate) struct UreqClient {
|
||||||
|
pub user_agent: String,
|
||||||
|
pub proxy: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UreqClient {
|
||||||
|
fn agent(&self) -> Result<ureq::Agent, Error> {
|
||||||
|
let mut builder = ureq::AgentBuilder::new();
|
||||||
|
if let Some(proxy) = &self.proxy {
|
||||||
|
builder = builder.proxy(ureq::Proxy::new(proxy)?);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(builder.build())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn exec_request(
|
||||||
|
&self,
|
||||||
|
req: ureq::Request,
|
||||||
|
body: Option<&str>,
|
||||||
|
) -> Result<Response<String>, Error> {
|
||||||
|
let req = req.set("User-Agent", &self.user_agent);
|
||||||
|
let res = match body {
|
||||||
|
Some(body) => req.send_string(body),
|
||||||
|
None => req.call(),
|
||||||
|
}?;
|
||||||
|
|
||||||
|
let mut builder = http::response::Builder::new()
|
||||||
|
.status(http::status::StatusCode::from_u16(res.status())?);
|
||||||
|
|
||||||
|
for header in res.headers_names() {
|
||||||
|
if let Some(value) = res.header(&header) {
|
||||||
|
builder = builder.header(header, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
builder
|
||||||
|
.body(res.into_string()?)
|
||||||
|
.map_err(|err| format_err!("Failed to convert HTTP response - {err}"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl proxmox_http::HttpClient<String> for UreqClient {
|
||||||
|
fn get(&self, uri: &str) -> Result<Response<String>, Error> {
|
||||||
|
let req = self.agent()?.get(uri);
|
||||||
|
|
||||||
|
self.exec_request(req, None)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn post(
|
||||||
|
&self,
|
||||||
|
uri: &str,
|
||||||
|
body: Option<&str>,
|
||||||
|
content_type: Option<&str>,
|
||||||
|
) -> Result<Response<String>, Error> {
|
||||||
|
let mut req = self.agent()?.post(uri);
|
||||||
|
if let Some(content_type) = content_type {
|
||||||
|
req = req.set("Content-Type", content_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.exec_request(req, body)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[perlmod::package(name = "Proxmox::RS::Subscription")]
|
||||||
|
mod export {
|
||||||
|
use anyhow::{bail, format_err, Error};
|
||||||
|
|
||||||
|
use proxmox_subscription::SubscriptionInfo;
|
||||||
|
use proxmox_sys::fs::{file_get_contents, CreateOptions};
|
||||||
|
|
||||||
|
use super::client::UreqClient;
|
||||||
|
|
||||||
|
#[export]
|
||||||
|
fn read_subscription(path: String) -> Result<Option<SubscriptionInfo>, Error> {
|
||||||
|
let key = file_get_contents("/usr/share/keyrings/proxmox-offline-signing-key.pub")?;
|
||||||
|
let key = openssl::pkey::PKey::public_key_from_pem(&key)
|
||||||
|
.map_err(|err| format_err!("Failed to parse public key - {err}"))?;
|
||||||
|
|
||||||
|
proxmox_subscription::files::read_subscription(path, &key)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[export]
|
||||||
|
fn write_subscription(
|
||||||
|
path: String,
|
||||||
|
apt_path: String,
|
||||||
|
url: &str,
|
||||||
|
info: SubscriptionInfo,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
let mode = nix::sys::stat::Mode::from_bits_truncate(0o0640);
|
||||||
|
let www_data = nix::unistd::Group::from_name("www-data")?
|
||||||
|
.ok_or(format_err!("no 'www-data' group found!"))?
|
||||||
|
.gid;
|
||||||
|
let opts = CreateOptions::new()
|
||||||
|
.perm(mode)
|
||||||
|
.owner(nix::unistd::ROOT)
|
||||||
|
.group(www_data);
|
||||||
|
|
||||||
|
let mode = nix::sys::stat::Mode::from_bits_truncate(0o0600);
|
||||||
|
let apt_opts = CreateOptions::new().perm(mode).owner(nix::unistd::ROOT);
|
||||||
|
|
||||||
|
proxmox_subscription::files::write_subscription(path, opts, &info).and_then(|_| {
|
||||||
|
proxmox_subscription::files::update_apt_auth(
|
||||||
|
apt_path,
|
||||||
|
apt_opts,
|
||||||
|
url,
|
||||||
|
info.key,
|
||||||
|
info.serverid,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[export]
|
||||||
|
fn delete_subscription(path: String, apt_path: String, url: &str) -> Result<(), Error> {
|
||||||
|
let mode = nix::sys::stat::Mode::from_bits_truncate(0o0600);
|
||||||
|
let apt_opts = CreateOptions::new().perm(mode).owner(nix::unistd::ROOT);
|
||||||
|
|
||||||
|
proxmox_subscription::files::delete_subscription(path).and_then(|_| {
|
||||||
|
proxmox_subscription::files::update_apt_auth(apt_path, apt_opts, url, None, None)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[export]
|
||||||
|
fn check_subscription(
|
||||||
|
key: String,
|
||||||
|
server_id: String,
|
||||||
|
product_url: String,
|
||||||
|
user_agent: String,
|
||||||
|
proxy: Option<String>,
|
||||||
|
) -> Result<SubscriptionInfo, Error> {
|
||||||
|
let client = UreqClient { user_agent, proxy };
|
||||||
|
|
||||||
|
proxmox_subscription::check::check_subscription(key, server_id, product_url, client)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[export]
|
||||||
|
fn check_server_id(mut info: SubscriptionInfo) -> SubscriptionInfo {
|
||||||
|
info.check_server_id();
|
||||||
|
info
|
||||||
|
}
|
||||||
|
|
||||||
|
#[export]
|
||||||
|
fn check_age(mut info: SubscriptionInfo, re_check: bool) -> SubscriptionInfo {
|
||||||
|
info.check_age(re_check);
|
||||||
|
info
|
||||||
|
}
|
||||||
|
|
||||||
|
#[export]
|
||||||
|
fn check_signature(mut info: SubscriptionInfo) -> Result<SubscriptionInfo, Error> {
|
||||||
|
if !info.is_signed() {
|
||||||
|
bail!("SubscriptionInfo is not signed!");
|
||||||
|
}
|
||||||
|
|
||||||
|
let key = file_get_contents("/usr/share/keyrings/proxmox-offline-signing-key.pub")?;
|
||||||
|
let key = openssl::pkey::PKey::public_key_from_pem(&key)
|
||||||
|
.map_err(|err| format_err!("Failed to parse public key - {err}"))?;
|
||||||
|
|
||||||
|
info.check_signature(&key);
|
||||||
|
|
||||||
|
Ok(info)
|
||||||
|
}
|
||||||
|
}
|
@ -21,16 +21,22 @@ crate-type = [ "cdylib" ]
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "1.0"
|
anyhow = "1.0"
|
||||||
hex = "0.4"
|
hex = "0.4"
|
||||||
|
http = "0.2.7"
|
||||||
libc = "0.2"
|
libc = "0.2"
|
||||||
nix = "0.24"
|
nix = "0.24"
|
||||||
|
openssl = "0.10.40"
|
||||||
serde = "1.0"
|
serde = "1.0"
|
||||||
serde_bytes = "0.11.3"
|
serde_bytes = "0.11.3"
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
|
ureq = { version = "2.4", features = ["native-certs"] }
|
||||||
url = "2"
|
url = "2"
|
||||||
|
|
||||||
perlmod = { version = "0.13", features = [ "exporter" ] }
|
perlmod = { version = "0.13", features = [ "exporter" ] }
|
||||||
|
|
||||||
proxmox-acme-rs = { version = "0.4", features = ["client"] }
|
proxmox-acme-rs = { version = "0.4", features = ["client"] }
|
||||||
proxmox-apt = "0.8.0"
|
proxmox-apt = "0.8.0"
|
||||||
|
proxmox-http = { version = "0.6.3", features = ["client-trait"] }
|
||||||
|
proxmox-subscription = "0.1"
|
||||||
|
proxmox-sys = "0.3"
|
||||||
proxmox-tfa = { version = "2", features = ["api"] }
|
proxmox-tfa = { version = "2", features = ["api"] }
|
||||||
proxmox-time = "1.1.3"
|
proxmox-time = "1.1.3"
|
||||||
|
@ -19,16 +19,22 @@ anyhow = "1.0"
|
|||||||
base32 = "0.4"
|
base32 = "0.4"
|
||||||
base64 = "0.13"
|
base64 = "0.13"
|
||||||
hex = "0.4"
|
hex = "0.4"
|
||||||
|
http = "0.2.7"
|
||||||
libc = "0.2"
|
libc = "0.2"
|
||||||
nix = "0.24"
|
nix = "0.24"
|
||||||
|
openssl = "0.10.40"
|
||||||
serde = "1.0"
|
serde = "1.0"
|
||||||
serde_bytes = "0.11"
|
serde_bytes = "0.11"
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
|
ureq = { version = "2.4", features = ["native-certs"] }
|
||||||
url = "2"
|
url = "2"
|
||||||
|
|
||||||
perlmod = { version = "0.13", features = [ "exporter" ] }
|
perlmod = { version = "0.13", features = [ "exporter" ] }
|
||||||
|
|
||||||
proxmox-apt = "0.8"
|
proxmox-apt = "0.8"
|
||||||
|
proxmox-http = { version = "0.6.3", features = ["client-trait"] }
|
||||||
proxmox-openid = "0.9.5"
|
proxmox-openid = "0.9.5"
|
||||||
|
proxmox-subscription = "0.1"
|
||||||
|
proxmox-sys = "0.3"
|
||||||
proxmox-tfa = { version = "2", features = ["api"] }
|
proxmox-tfa = { version = "2", features = ["api"] }
|
||||||
proxmox-time = "1.1.3"
|
proxmox-time = "1.1.3"
|
||||||
|
Loading…
Reference in New Issue
Block a user