[pve-devel] [PATCH proxmox-perl-rs 2/6] import pve-rs

Wolfgang Bumiller w.bumiller at proxmox.com
Tue Nov 9 12:26:51 CET 2021


Signed-off-by: Wolfgang Bumiller <w.bumiller at proxmox.com>
---
 Cargo.toml                     |   3 +
 pve-rs/Cargo.toml              |  40 ++++++++
 pve-rs/Makefile                |  76 ++++++++++++++++
 pve-rs/debian/changelog        |  55 +++++++++++
 pve-rs/debian/compat           |   1 +
 pve-rs/debian/control          |  41 +++++++++
 pve-rs/debian/copyright        |  16 ++++
 pve-rs/debian/debcargo.toml    |   8 ++
 pve-rs/debian/rules            |   8 ++
 pve-rs/debian/source/format    |   1 +
 pve-rs/debian/triggers         |   1 +
 pve-rs/src/apt/mod.rs          |   1 +
 pve-rs/src/apt/repositories.rs | 162 +++++++++++++++++++++++++++++++++
 pve-rs/src/lib.rs              |   2 +
 pve-rs/src/openid/mod.rs       |  88 ++++++++++++++++++
 15 files changed, 503 insertions(+)
 create mode 100644 pve-rs/Cargo.toml
 create mode 100644 pve-rs/Makefile
 create mode 100644 pve-rs/debian/changelog
 create mode 100644 pve-rs/debian/compat
 create mode 100644 pve-rs/debian/control
 create mode 100644 pve-rs/debian/copyright
 create mode 100644 pve-rs/debian/debcargo.toml
 create mode 100755 pve-rs/debian/rules
 create mode 100644 pve-rs/debian/source/format
 create mode 100644 pve-rs/debian/triggers
 create mode 100644 pve-rs/src/apt/mod.rs
 create mode 100644 pve-rs/src/apt/repositories.rs
 create mode 100644 pve-rs/src/lib.rs
 create mode 100644 pve-rs/src/openid/mod.rs

diff --git a/Cargo.toml b/Cargo.toml
index e2c6ef8..c413d77 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,2 +1,5 @@
 [workspace]
 exclude = [ "build", "perl-*" ]
+members = [
+    "pve-rs",
+]
diff --git a/pve-rs/Cargo.toml b/pve-rs/Cargo.toml
new file mode 100644
index 0000000..1c00edd
--- /dev/null
+++ b/pve-rs/Cargo.toml
@@ -0,0 +1,40 @@
+[package]
+name = "pve-rs"
+version = "0.3.0"
+authors = ["Proxmox Support Team <support at proxmox.com>"]
+edition = "2018"
+license = "AGPL-3"
+description = "PVE parts which have been ported to Rust"
+homepage = "https://www.proxmox.com"
+
+exclude = [
+    "debian",
+]
+
+[lib]
+crate-type = [ "cdylib" ]
+
+[dependencies]
+anyhow = "1.0"
+base32 = "0.4"
+base64 = "0.12"
+hex = "0.4"
+libc = "0.2"
+nix = "0.19"
+openssl = "0.10"
+serde = "1.0"
+serde_bytes = "0.11"
+serde_json = "1.0"
+
+perlmod = { version = "0.8.1", features = [ "exporter" ] }
+
+proxmox-apt = "0.8"
+proxmox-openid = "0.8"
+
+#proxmox-tfa-api = { path = "../proxmox-tfa-api", version = "0.1" }
+
+# Dependencies purely in proxmox-tfa-api:
+webauthn-rs = "0.2.5"
+proxmox-time = "1"
+proxmox-uuid = "1"
+proxmox-tfa = { version = "1.2", features = ["u2f"] }
diff --git a/pve-rs/Makefile b/pve-rs/Makefile
new file mode 100644
index 0000000..c912d9d
--- /dev/null
+++ b/pve-rs/Makefile
@@ -0,0 +1,76 @@
+include /usr/share/dpkg/default.mk
+
+PACKAGE=libpve-rs-perl
+export PERLMOD_PRODUCT=PVE
+
+ARCH:=$(shell dpkg-architecture -qDEB_BUILD_ARCH)
+export GITVERSION:=$(shell git rev-parse HEAD)
+
+PERL_INSTALLVENDORARCH != perl -MConfig -e 'print $$Config{installvendorarch};'
+PERL_INSTALLVENDORLIB != perl -MConfig -e 'print $$Config{installvendorlib};'
+
+MAIN_DEB=${PACKAGE}_${DEB_VERSION}_${ARCH}.deb
+DBGSYM_DEB=${PACKAGE}-dbgsym_${DEB_VERSION}_${ARCH}.deb
+DEBS=$(MAIN_DEB) $(DBGSYM_DEB)
+
+DESTDIR=
+
+PM_DIRS := \
+	PVE/RS/APT
+
+PM_FILES := \
+	PVE/RS/APT/Repositories.pm \
+	PVE/RS/OpenId.pm \
+	PVE/RS/TFA.pm
+
+ifeq ($(BUILD_MODE), release)
+CARGO_BUILD_ARGS += --release
+endif
+
+all:
+ifneq ($(BUILD_MODE), skip)
+	cargo build $(CARGO_BUILD_ARGS)
+endif
+
+# always re-create this dir
+# but also copy the local target/ and PVE/ dirs as a build-cache
+.PHONY: build
+build:
+	rm -rf build
+	cargo build --release
+	rsync -a debian Makefile Cargo.toml Cargo.lock src target PVE build/
+
+.PHONY: install
+install: target/release/libpve_rs.so
+	install -d -m755 $(DESTDIR)$(PERL_INSTALLVENDORARCH)/auto
+	install -m644 target/release/libpve_rs.so $(DESTDIR)$(PERL_INSTALLVENDORARCH)/auto/libpve_rs.so
+	install -d -m755 $(DESTDIR)$(PERL_INSTALLVENDORLIB)/PVE/RS
+	for i in $(PM_DIRS); do \
+	  install -d -m755 $(DESTDIR)$(PERL_INSTALLVENDORLIB)/$$i; \
+	done
+	for i in $(PM_FILES); do \
+	  install -m644 $$i $(DESTDIR)$(PERL_INSTALLVENDORLIB)/$$i; \
+	done
+
+.PHONY: deb
+deb: $(MAIN_DEB)
+$(MAIN_DEB): build
+	cd build; dpkg-buildpackage -b -us -uc --no-pre-clean
+	lintian $(DEBS)
+
+distclean: clean
+
+clean:
+	cargo clean
+	rm -rf *.deb *.dsc *.tar.gz *.buildinfo *.changes Cargo.lock build
+	find . -name '*~' -exec rm {} ';'
+
+.PHONY: dinstall
+dinstall: ${DEBS}
+	dpkg -i ${DEBS}
+
+.PHONY: upload
+upload: ${DEBS}
+	# check if working directory is clean
+	git diff --exit-code --stat && git diff --exit-code --stat --staged
+	tar cf - ${DEBS} | ssh -X repoman at repo.proxmox.com upload --product pve --dist bullseye
diff --git a/pve-rs/debian/changelog b/pve-rs/debian/changelog
new file mode 100644
index 0000000..62060bf
--- /dev/null
+++ b/pve-rs/debian/changelog
@@ -0,0 +1,55 @@
+libpve-rs-perl (0.3.0) UNRELEASED; urgency=medium
+
+  * add TFA api
+
+ -- Proxmox Support Team <support at proxmox.com>  Wed, 20 Oct 2021 10:11:47 +0200
+
+libpve-rs-perl (0.2.3) bullseye; urgency=medium
+
+  * use newer dependencies for apt to improve repo+suite handling
+
+ -- Proxmox Support Team <support at proxmox.com>  Thu, 29 Jul 2021 18:13:07 +0200
+
+libpve-rs-perl (0.2.2) bullseye; urgency=medium
+
+  * apt: avoid overwriting files that could not be parsed
+
+  * apt: check if repository is already configured before adding
+
+ -- Proxmox Support Team <support at proxmox.com>  Fri, 02 Jul 2021 13:06:42 +0200
+
+libpve-rs-perl (0.2.1) bullseye; urgency=medium
+
+  * depend on proxmox-apt 0.4.0
+
+ -- Proxmox Support Team <support at proxmox.com>  Thu, 01 Jul 2021 18:37:20 +0200
+
+libpve-rs-perl (0.2.0) bullseye; urgency=medium
+
+  * add bindings for proxmox-apt
+
+  * depend on proxmox-openid 0.6.0
+
+  * move to native version format
+
+ -- Proxmox Support Team <support at proxmox.com>  Wed, 30 Jun 2021 20:56:19 +0200
+
+libpve-rs-perl (0.1.2-1) unstable; urgency=medium
+
+  * depend on proxmox-openid 0.5.0
+
+  * set proxmox "default-features = false"
+
+ -- Proxmox Support Team <support at proxmox.com>  Wed, 23 Jun 2021 11:34:34 +0200
+
+libpve-rs-perl (0.1.1-1) unstable; urgency=medium
+
+  * depend on perlmod 0.5.1
+
+ -- Proxmox Support Team <support at proxmox.com>  Wed, 23 Jun 2021 11:09:31 +0200
+
+libpve-rs-perl (0.1.0-1) unstable; urgency=medium
+
+  * Initial release.
+
+ -- Proxmox Support Team <support at proxmox.com>  Thu, 27 May 2021 10:41:30 +0200
diff --git a/pve-rs/debian/compat b/pve-rs/debian/compat
new file mode 100644
index 0000000..f599e28
--- /dev/null
+++ b/pve-rs/debian/compat
@@ -0,0 +1 @@
+10
diff --git a/pve-rs/debian/control b/pve-rs/debian/control
new file mode 100644
index 0000000..18a99b2
--- /dev/null
+++ b/pve-rs/debian/control
@@ -0,0 +1,41 @@
+Source: libpve-rs-perl
+Section: perl
+Priority: optional
+Build-Depends: debhelper (>= 12),
+ dh-cargo (>= 24),
+ cargo:native <!nocheck>,
+ rustc:native <!nocheck>,
+ libstd-rust-dev <!nocheck>,
+ librust-anyhow-1+default-dev <!nocheck>,
+ librust-base32-0.4+default-dev <!nocheck>,
+ librust-base64-0.12+default-dev <!nocheck>,
+ librust-hex-0.4+default-dev <!nocheck>,
+ librust-libc-0.2+default-dev <!nocheck>,
+ librust-nix-0.19+default-dev <!nocheck>,
+ librust-openssl-0.10+default-dev <!nocheck>,
+ librust-perlmod-0.8+default-dev (>= 0.7.1-~~) <!nocheck>,
+ librust-perlmod-0.8+exporter-dev (>= 0.7.1-~~) <!nocheck>,
+ librust-proxmox-apt-0.8+default-dev <!nocheck>,
+ librust-proxmox-openid-0.8+default-dev <!nocheck>,
+ librust-proxmox-tfa-1+default-dev <!nocheck>,
+ librust-proxmox-tfa-1+u2f-dev <!nocheck>,
+ librust-proxmox-time-1+default-dev <!nocheck>,
+ librust-proxmox-uuid-1+default-dev <!nocheck>,
+ librust-serde-1+default-dev <!nocheck>,
+ librust-serde-json-1+default-dev <!nocheck>,
+ librust-webauthn-rs-0.2+default-dev (>= 0.2.5-~~) <!nocheck>
+Maintainer: Proxmox Support Team <support at proxmox.com>
+Standards-Version: 4.5.1
+Vcs-Git: git://git.proxmox.com/git/proxmox.git
+Vcs-Browser: https://git.proxmox.com/?p=proxmox.git
+Homepage: https://www.proxmox.com
+Rules-Requires-Root: no
+
+Package: libpve-rs-perl
+Architecture: any
+Depends:
+ ${misc:Depends},
+ ${shlibs:Depends},
+Description: PVE parts which have been ported to Rust - Rust source code
+ This package contains the source for the Rust pve-rs crate, packaged by
+ debcargo for use with cargo and dh-cargo.
diff --git a/pve-rs/debian/copyright b/pve-rs/debian/copyright
new file mode 100644
index 0000000..5661ef6
--- /dev/null
+++ b/pve-rs/debian/copyright
@@ -0,0 +1,16 @@
+Copyright (C) 2021 Proxmox Server Solutions GmbH
+
+This software is written by Proxmox Server Solutions GmbH <support at proxmox.com>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
diff --git a/pve-rs/debian/debcargo.toml b/pve-rs/debian/debcargo.toml
new file mode 100644
index 0000000..e642fe2
--- /dev/null
+++ b/pve-rs/debian/debcargo.toml
@@ -0,0 +1,8 @@
+overlay = "."
+crate_src_path = ".."
+maintainer = "Proxmox Support Team <support at proxmox.com>"
+
+[source]
+section = "perl"
+vcs_git = "git://git.proxmox.com/git/proxmox.git"
+vcs_browser = "https://git.proxmox.com/?p=proxmox.git"
diff --git a/pve-rs/debian/rules b/pve-rs/debian/rules
new file mode 100755
index 0000000..2b39115
--- /dev/null
+++ b/pve-rs/debian/rules
@@ -0,0 +1,8 @@
+#!/usr/bin/make -f
+
+#export DH_VERBOSE=1
+export BUILD_MODE=release
+export RUSTFLAGS=-C prefer-dynamic
+
+%:
+	dh $@
diff --git a/pve-rs/debian/source/format b/pve-rs/debian/source/format
new file mode 100644
index 0000000..89ae9db
--- /dev/null
+++ b/pve-rs/debian/source/format
@@ -0,0 +1 @@
+3.0 (native)
diff --git a/pve-rs/debian/triggers b/pve-rs/debian/triggers
new file mode 100644
index 0000000..59dd688
--- /dev/null
+++ b/pve-rs/debian/triggers
@@ -0,0 +1 @@
+activate-noawait pve-api-updates
diff --git a/pve-rs/src/apt/mod.rs b/pve-rs/src/apt/mod.rs
new file mode 100644
index 0000000..574c1a7
--- /dev/null
+++ b/pve-rs/src/apt/mod.rs
@@ -0,0 +1 @@
+mod repositories;
diff --git a/pve-rs/src/apt/repositories.rs b/pve-rs/src/apt/repositories.rs
new file mode 100644
index 0000000..2d5e1da
--- /dev/null
+++ b/pve-rs/src/apt/repositories.rs
@@ -0,0 +1,162 @@
+#[perlmod::package(name = "PVE::RS::APT::Repositories", lib = "pve_rs")]
+mod export {
+    use std::convert::TryInto;
+
+    use anyhow::{bail, Error};
+    use serde::{Deserialize, Serialize};
+
+    use proxmox_apt::repositories::{
+        APTRepositoryFile, APTRepositoryFileError, APTRepositoryHandle, APTRepositoryInfo,
+        APTStandardRepository,
+    };
+
+    #[derive(Deserialize, Serialize)]
+    #[serde(rename_all = "kebab-case")]
+    /// Result for the repositories() function
+    pub struct RepositoriesResult {
+        /// Successfully parsed files.
+        pub files: Vec<APTRepositoryFile>,
+
+        /// Errors for files that could not be parsed or read.
+        pub errors: Vec<APTRepositoryFileError>,
+
+        /// Common digest for successfully parsed files.
+        pub digest: String,
+
+        /// Additional information/warnings about repositories.
+        pub infos: Vec<APTRepositoryInfo>,
+
+        /// Standard repositories and their configuration status.
+        pub standard_repos: Vec<APTStandardRepository>,
+    }
+
+    #[derive(Deserialize, Serialize)]
+    #[serde(rename_all = "kebab-case")]
+    /// For changing an existing repository.
+    pub struct ChangeProperties {
+        /// Whether the repository should be enabled or not.
+        pub enabled: Option<bool>,
+    }
+
+    /// Get information about configured and standard repositories.
+    #[export]
+    pub fn repositories() -> Result<RepositoriesResult, Error> {
+        let (files, errors, digest) = proxmox_apt::repositories::repositories()?;
+        let digest = hex::encode(&digest);
+
+        let suite = proxmox_apt::repositories::get_current_release_codename()?;
+
+        let infos = proxmox_apt::repositories::check_repositories(&files, suite);
+        let standard_repos = proxmox_apt::repositories::standard_repositories(&files, "pve", suite);
+
+        Ok(RepositoriesResult {
+            files,
+            errors,
+            digest,
+            infos,
+            standard_repos,
+        })
+    }
+
+    /// Add the repository identified by the `handle`.
+    /// If the repository is already configured, it will be set to enabled.
+    ///
+    /// The `digest` parameter asserts that the configuration has not been modified.
+    #[export]
+    pub fn add_repository(handle: &str, digest: Option<&str>) -> Result<(), Error> {
+        let (mut files, errors, current_digest) = proxmox_apt::repositories::repositories()?;
+
+        let handle: APTRepositoryHandle = handle.try_into()?;
+        let suite = proxmox_apt::repositories::get_current_release_codename()?;
+
+        if let Some(digest) = digest {
+            let expected_digest = hex::decode(digest)?;
+            if expected_digest != current_digest {
+                bail!("detected modified configuration - file changed by other user? Try again.");
+            }
+        }
+
+        // check if it's already configured first
+        for file in files.iter_mut() {
+            for repo in file.repositories.iter_mut() {
+                if repo.is_referenced_repository(handle, "pve", &suite.to_string()) {
+                    if repo.enabled {
+                        return Ok(());
+                    }
+
+                    repo.set_enabled(true);
+                    file.write()?;
+
+                    return Ok(());
+                }
+            }
+        }
+
+        let (repo, path) = proxmox_apt::repositories::get_standard_repository(handle, "pve", suite);
+
+        if let Some(error) = errors.iter().find(|error| error.path == path) {
+            bail!(
+                "unable to parse existing file {} - {}",
+                error.path,
+                error.error,
+            );
+        }
+
+        if let Some(file) = files.iter_mut().find(|file| file.path == path) {
+            file.repositories.push(repo);
+
+            file.write()?;
+        } else {
+            let mut file = match APTRepositoryFile::new(&path)? {
+                Some(file) => file,
+                None => bail!("invalid path - {}", path),
+            };
+
+            file.repositories.push(repo);
+
+            file.write()?;
+        }
+
+        Ok(())
+    }
+
+    /// Change the properties of the specified repository.
+    ///
+    /// The `digest` parameter asserts that the configuration has not been modified.
+    #[export]
+    pub fn change_repository(
+        path: &str,
+        index: usize,
+        options: ChangeProperties,
+        digest: Option<&str>,
+    ) -> Result<(), Error> {
+        let (mut files, errors, current_digest) = proxmox_apt::repositories::repositories()?;
+
+        if let Some(digest) = digest {
+            let expected_digest = hex::decode(digest)?;
+            if expected_digest != current_digest {
+                bail!("detected modified configuration - file changed by other user? Try again.");
+            }
+        }
+
+        if let Some(error) = errors.iter().find(|error| error.path == path) {
+            bail!("unable to parse file {} - {}", error.path, error.error);
+        }
+
+        if let Some(file) = files.iter_mut().find(|file| file.path == path) {
+            if let Some(repo) = file.repositories.get_mut(index) {
+                if let Some(enabled) = options.enabled {
+                    repo.set_enabled(enabled);
+                }
+
+                file.write()?;
+            } else {
+                bail!("invalid index - {}", index);
+            }
+        } else {
+            bail!("invalid path - {}", path);
+        }
+
+        Ok(())
+    }
+}
diff --git a/pve-rs/src/lib.rs b/pve-rs/src/lib.rs
new file mode 100644
index 0000000..cad331d
--- /dev/null
+++ b/pve-rs/src/lib.rs
@@ -0,0 +1,2 @@
+pub mod apt;
+pub mod openid;
diff --git a/pve-rs/src/openid/mod.rs b/pve-rs/src/openid/mod.rs
new file mode 100644
index 0000000..febe927
--- /dev/null
+++ b/pve-rs/src/openid/mod.rs
@@ -0,0 +1,88 @@
+#[perlmod::package(name = "PVE::RS::OpenId", lib = "pve_rs")]
+mod export {
+    use std::sync::Mutex;
+    use std::convert::TryFrom;
+
+    use anyhow::Error;
+
+    use perlmod::{to_value, Value};
+
+    use proxmox_openid::{OpenIdConfig, OpenIdAuthenticator, PrivateAuthState};
+
+    const CLASSNAME: &str = "PVE::RS::OpenId";
+
+    /// An OpenIdAuthenticator client instance.
+    pub struct OpenId {
+        inner: Mutex<OpenIdAuthenticator>,
+    }
+
+    impl<'a> TryFrom<&'a Value> for &'a OpenId {
+        type Error = Error;
+
+        fn try_from(value: &'a Value) -> Result<&'a OpenId, Error> {
+            Ok(unsafe { value.from_blessed_box(CLASSNAME)? })
+        }
+    }
+
+    fn bless(class: Value, mut ptr: Box<OpenId>) -> Result<Value, Error> {
+        let value = Value::new_pointer::<OpenId>(&mut *ptr);
+        let value = Value::new_ref(&value);
+        let this = value.bless_sv(&class)?;
+        let _perl = Box::leak(ptr);
+        Ok(this)
+    }
+
+    #[export(name = "DESTROY")]
+    fn destroy(#[raw] this: Value) {
+        perlmod::destructor!(this, OpenId: CLASSNAME);
+    }
+
+    /// Create a new OpenId client instance
+    #[export(raw_return)]
+    pub fn discover(
+        #[raw] class: Value,
+        config: OpenIdConfig,
+        redirect_url: &str,
+    ) -> Result<Value, Error> {
+
+        let open_id = OpenIdAuthenticator::discover(&config, redirect_url)?;
+        bless(
+            class,
+            Box::new(OpenId {
+                inner: Mutex::new(open_id),
+            }),
+        )
+    }
+
+    #[export]
+    pub fn authorize_url(
+        #[try_from_ref] this: &OpenId,
+        state_dir: &str,
+        realm: &str,
+    ) -> Result<String, Error> {
+
+        let open_id = this.inner.lock().unwrap();
+        open_id.authorize_url(state_dir, realm)
+    }
+
+    #[export]
+    pub fn verify_public_auth_state(
+        state_dir: &str,
+        state: &str,
+    )  -> Result<(String, PrivateAuthState), Error> {
+        OpenIdAuthenticator::verify_public_auth_state(state_dir, state)
+    }
+
+    #[export(raw_return)]
+    pub fn verify_authorization_code(
+       #[try_from_ref] this: &OpenId,
+        code: &str,
+        private_auth_state: PrivateAuthState,
+    ) -> Result<Value, Error> {
+
+        let open_id = this.inner.lock().unwrap();
+        let claims = open_id.verify_authorization_code(code, &private_auth_state)?;
+
+        Ok(to_value(&claims)?)
+    }
+}
-- 
2.30.2






More information about the pve-devel mailing list