mirror of
https://github.com/storytold/winprint.rs.git
synced 2026-10-13 23:17:45 +00:00
build: verify pdfium downloads with sigstore
This commit is contained in:
2 files changed
+101
-32
No files matched your search
@@ -56,6 +56,9 @@ features = [
|
|||||||
reqwest = { version = "0.12", features = ["blocking"] }
|
reqwest = { version = "0.12", features = ["blocking"] }
|
||||||
flate2 = "1.0"
|
flate2 = "1.0"
|
||||||
tar = "0.4"
|
tar = "0.4"
|
||||||
|
sigstore-trust-root = { version = "0.6.5", default-features = false }
|
||||||
|
sigstore-types = "0.6.5"
|
||||||
|
sigstore-verify = { version = "0.6.5", default-features = false }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
ctor = "0.2"
|
ctor = "0.2"
|
||||||
|
|||||||
@@ -4,12 +4,22 @@ use std::{
|
|||||||
error::Error,
|
error::Error,
|
||||||
ffi::OsStr,
|
ffi::OsStr,
|
||||||
fs,
|
fs,
|
||||||
|
io::Cursor,
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
};
|
};
|
||||||
|
|
||||||
use flate2::read::GzDecoder;
|
use flate2::read::GzDecoder;
|
||||||
|
use reqwest::blocking::Response;
|
||||||
|
use sigstore_trust_root::{TrustedRoot, SIGSTORE_PRODUCTION_TRUSTED_ROOT};
|
||||||
|
use sigstore_types::Bundle;
|
||||||
|
use sigstore_verify::{verify, VerificationPolicy};
|
||||||
use tar::{Archive, EntryType};
|
use tar::{Archive, EntryType};
|
||||||
|
|
||||||
|
const DEFAULT_PDFIUM_BUILD_ID: &str = "7802";
|
||||||
|
const PDFIUM_ATTESTATION_NAME: &str = "pdfium-attestation.json";
|
||||||
|
const PDFIUM_CERTIFICATE_ISSUER: &str = "https://token.actions.githubusercontent.com";
|
||||||
|
const VERIFIED_MARKER_FILE: &str = ".sigstore-verified";
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
fn try_link_pdfium() -> Result<(), Box<dyn Error>> {
|
fn try_link_pdfium() -> Result<(), Box<dyn Error>> {
|
||||||
let bin_ext = [
|
let bin_ext = [
|
||||||
@@ -18,10 +28,12 @@ fn try_link_pdfium() -> Result<(), Box<dyn Error>> {
|
|||||||
OsStr::new("so"),
|
OsStr::new("so"),
|
||||||
OsStr::new("a"),
|
OsStr::new("a"),
|
||||||
];
|
];
|
||||||
let build_id = env::var("WINPRINT_PDFIUM_BUILD_ID").unwrap_or_else(|_| "6350".to_string());
|
let build_id = env::var("WINPRINT_PDFIUM_BUILD_ID")
|
||||||
|
.unwrap_or_else(|_| DEFAULT_PDFIUM_BUILD_ID.to_string());
|
||||||
let mut target_path = PathBuf::from(env::var("OUT_DIR")?);
|
let mut target_path = PathBuf::from(env::var("OUT_DIR")?);
|
||||||
target_path.push(format!("pdfium_binaries_{}", build_id));
|
target_path.push(format!("pdfium_binaries_{}", build_id));
|
||||||
fs::create_dir_all(target_path.as_path())?;
|
fs::create_dir_all(target_path.as_path())?;
|
||||||
|
|
||||||
let has_bin = fs::read_dir(target_path.as_path())?.any(|x| {
|
let has_bin = fs::read_dir(target_path.as_path())?.any(|x| {
|
||||||
bin_ext.iter().any(|s| {
|
bin_ext.iter().any(|s| {
|
||||||
x.as_ref()
|
x.as_ref()
|
||||||
@@ -36,7 +48,9 @@ fn try_link_pdfium() -> Result<(), Box<dyn Error>> {
|
|||||||
.is_some()
|
.is_some()
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
if !has_bin {
|
let verified_marker = target_path.join(VERIFIED_MARKER_FILE);
|
||||||
|
|
||||||
|
if !has_bin || !verified_marker.exists() {
|
||||||
let platform_name = match (
|
let platform_name = match (
|
||||||
env::var("CARGO_CFG_TARGET_OS")?.as_str(),
|
env::var("CARGO_CFG_TARGET_OS")?.as_str(),
|
||||||
env::var("CARGO_CFG_TARGET_ARCH")?.as_str(),
|
env::var("CARGO_CFG_TARGET_ARCH")?.as_str(),
|
||||||
@@ -47,36 +61,25 @@ fn try_link_pdfium() -> Result<(), Box<dyn Error>> {
|
|||||||
_ => return Err("Unsupported target arch".into()),
|
_ => return Err("Unsupported target arch".into()),
|
||||||
};
|
};
|
||||||
|
|
||||||
let binary_package_url = format!("https://github.com/bblanchon/pdfium-binaries/releases/download/chromium%2F{}/pdfium-{}.tgz", build_id, platform_name);
|
let binary_package_name = format!("pdfium-{}.tgz", platform_name);
|
||||||
let resp = reqwest::blocking::get(binary_package_url.as_str())?;
|
let binary_package_url = release_asset_url(&build_id, &binary_package_name);
|
||||||
if resp.status() != 200 {
|
let binary_package = download_asset(binary_package_url.as_str())?;
|
||||||
return Err(format!(
|
|
||||||
"Failed to download pdfium binaries from {}",
|
let attestation_url = release_asset_url(&build_id, PDFIUM_ATTESTATION_NAME);
|
||||||
binary_package_url
|
let attestation = download_asset(attestation_url.as_str())?;
|
||||||
)
|
|
||||||
.into());
|
verify_pdfium_attestation(binary_package.as_slice(), attestation.as_slice())?;
|
||||||
}
|
|
||||||
let tar = GzDecoder::new(resp);
|
fs::remove_dir_all(target_path.as_path())?;
|
||||||
let mut archive = Archive::new(tar);
|
fs::create_dir_all(target_path.as_path())?;
|
||||||
for entry in archive.entries()? {
|
unpack_pdfium_archive(binary_package.as_slice(), target_path.as_path(), &bin_ext)?;
|
||||||
let mut file = entry?;
|
fs::write(
|
||||||
if file.header().entry_type() == EntryType::Regular {
|
verified_marker,
|
||||||
let file_path = file.path()?;
|
format!(
|
||||||
let file_extension = file_path.extension();
|
"Verified {} with {}\n",
|
||||||
let is_bin = bin_ext.iter().any(|s| file_extension == Some(s));
|
binary_package_name, PDFIUM_ATTESTATION_NAME
|
||||||
if is_bin {
|
),
|
||||||
if let Some(file_name_raw) = file_path.file_name() {
|
)?;
|
||||||
let mut file_name_str = file_name_raw.to_string_lossy();
|
|
||||||
if let Some(s) = file_name_str.strip_suffix(".dll.lib") {
|
|
||||||
file_name_str = Cow::Owned(s.to_owned() + ".lib");
|
|
||||||
}
|
|
||||||
target_path.push(file_name_str.as_ref());
|
|
||||||
file.unpack(target_path.as_path())?;
|
|
||||||
target_path.pop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
println!(
|
println!(
|
||||||
@@ -87,6 +90,69 @@ fn try_link_pdfium() -> Result<(), Box<dyn Error>> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn release_asset_url(build_id: &str, file_name: &str) -> String {
|
||||||
|
format!(
|
||||||
|
"https://github.com/bblanchon/pdfium-binaries/releases/download/chromium/{}/{}",
|
||||||
|
build_id, file_name
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn download_asset(url: &str) -> Result<Vec<u8>, Box<dyn Error>> {
|
||||||
|
let resp = reqwest::blocking::get(url)?;
|
||||||
|
ensure_success(resp, url)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ensure_success(resp: Response, url: &str) -> Result<Vec<u8>, Box<dyn Error>> {
|
||||||
|
if !resp.status().is_success() {
|
||||||
|
return Err(format!("Failed to download asset from {}", url).into());
|
||||||
|
}
|
||||||
|
Ok(resp.bytes()?.to_vec())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn verify_pdfium_attestation(
|
||||||
|
binary_package: &[u8],
|
||||||
|
attestation_json: &[u8],
|
||||||
|
) -> Result<(), Box<dyn Error>> {
|
||||||
|
let bundle = Bundle::from_json(std::str::from_utf8(attestation_json)?)?;
|
||||||
|
let trusted_root = TrustedRoot::from_json(SIGSTORE_PRODUCTION_TRUSTED_ROOT)?;
|
||||||
|
let policy = VerificationPolicy::default().require_issuer(PDFIUM_CERTIFICATE_ISSUER);
|
||||||
|
|
||||||
|
verify(binary_package, &bundle, &policy, &trusted_root)
|
||||||
|
.map_err(|err| format!("Failed to verify PDFium Sigstore attestation: {err}"))?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn unpack_pdfium_archive(
|
||||||
|
archive_bytes: &[u8],
|
||||||
|
target_path: &Path,
|
||||||
|
bin_ext: &[&OsStr],
|
||||||
|
) -> Result<(), Box<dyn Error>> {
|
||||||
|
let tar = GzDecoder::new(Cursor::new(archive_bytes));
|
||||||
|
let mut archive = Archive::new(tar);
|
||||||
|
|
||||||
|
for entry in archive.entries()? {
|
||||||
|
let mut file = entry?;
|
||||||
|
if file.header().entry_type() == EntryType::Regular {
|
||||||
|
let file_path = file.path()?;
|
||||||
|
let file_extension = file_path.extension();
|
||||||
|
let is_bin = bin_ext.iter().any(|s| file_extension == Some(s));
|
||||||
|
if is_bin {
|
||||||
|
if let Some(file_name_raw) = file_path.file_name() {
|
||||||
|
let mut file_name_str = file_name_raw.to_string_lossy();
|
||||||
|
if let Some(s) = file_name_str.strip_suffix(".dll.lib") {
|
||||||
|
file_name_str = Cow::Owned(s.to_owned() + ".lib");
|
||||||
|
}
|
||||||
|
let output_path = target_path.join(file_name_str.as_ref());
|
||||||
|
file.unpack(output_path.as_path())?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
println!("cargo:rerun-if-env-changed=WINPRINT_PDFIUM_BUILD_ID");
|
println!("cargo:rerun-if-env-changed=WINPRINT_PDFIUM_BUILD_ID");
|
||||||
// Skip downloading native libraries on docs.rs
|
// Skip downloading native libraries on docs.rs
|
||||||
|
|||||||
Reference in new issue
Block a user