apt/keyring: download 3 keyrings for sid
This commit is contained in:
+96
-64
@@ -16,99 +16,131 @@ struct LaunchpadPpaResponse {
|
||||
signing_key_fingerprint: String,
|
||||
}
|
||||
|
||||
/// Download a keyring to the application cache directory and return the path
|
||||
/// Download keyrings to a shared keyring directory and return the directory path
|
||||
///
|
||||
/// This function downloads the keyring to a user-writable cache directory
|
||||
/// This function downloads keyrings to a user-writable cache directory
|
||||
/// instead of the system apt keyring directory, allowing non-root usage.
|
||||
/// The returned path can be passed to mmdebstrap via --keyring.
|
||||
/// The returned directory path can be passed to mmdebstrap via --keyring=.
|
||||
///
|
||||
/// For Debian keyrings (which are ASCII-armored .asc files), the key is
|
||||
/// For Debian keyrings (which are ASCII-armored .asc files), the keys are
|
||||
/// converted to binary GPG format using gpg --dearmor.
|
||||
///
|
||||
/// For 'sid' and 'experimental', this downloads keyrings from the 3 latest
|
||||
/// releases since sid needs keys from all recent releases.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `ctx` - Optional context to use
|
||||
/// * `series` - The distribution series (e.g., "noble", "sid")
|
||||
///
|
||||
/// # Returns
|
||||
/// The path to the downloaded keyring file (in binary GPG format)
|
||||
pub async fn download_cache_keyring(
|
||||
/// The path to the keyring directory containing all downloaded keyring files
|
||||
pub async fn download_cache_keyrings(
|
||||
ctx: Option<Arc<context::Context>>,
|
||||
series: &str,
|
||||
) -> Result<PathBuf, Box<dyn Error>> {
|
||||
let ctx = ctx.unwrap_or_else(context::current);
|
||||
|
||||
// Obtain keyring URL from distro_info
|
||||
let keyring_url = distro_info::get_keyring_url(series).await?;
|
||||
log::debug!("Downloading keyring from: {}", keyring_url);
|
||||
// Obtain keyring URLs from distro_info
|
||||
let keyring_urls = distro_info::get_keyring_urls(series).await?;
|
||||
log::debug!("Downloading keyrings from: {:?}", keyring_urls);
|
||||
|
||||
// Get the application cache directory
|
||||
let proj_dirs = directories::ProjectDirs::from("com", "pkh", "pkh")
|
||||
.ok_or("Could not determine project directories")?;
|
||||
let cache_dir = proj_dirs.cache_dir();
|
||||
// Use system temp directory for keyrings since it's accessible from unshare mode
|
||||
// The home directory may not be accessible from mmdebstrap's unshare namespace
|
||||
let temp_dir = std::env::temp_dir();
|
||||
let keyring_dir = temp_dir.join("pkh-keyrings");
|
||||
|
||||
// Create cache directory if it doesn't exist
|
||||
if !ctx.exists(cache_dir)? {
|
||||
ctx.command("mkdir").arg("-p").arg(cache_dir).status()?;
|
||||
// Create keyring directory if it doesn't exist
|
||||
if !ctx.exists(&keyring_dir)? {
|
||||
ctx.command("mkdir").arg("-p").arg(&keyring_dir).status()?;
|
||||
}
|
||||
|
||||
// Extract the original filename from the keyring URL
|
||||
let filename = keyring_url
|
||||
.split('/')
|
||||
.next_back()
|
||||
.unwrap_or("pkh-{}.gpg")
|
||||
.replace("{}", series);
|
||||
let download_path = cache_dir.join(&filename);
|
||||
// Make keyring directory world-accessible so mmdebstrap in unshare mode can access it
|
||||
ctx.command("chmod")
|
||||
.arg("a+rwx")
|
||||
.arg(&keyring_dir)
|
||||
.status()?;
|
||||
|
||||
// Download the keyring using curl
|
||||
let mut curl_cmd = ctx.command("curl");
|
||||
curl_cmd
|
||||
.arg("-s")
|
||||
.arg("-f")
|
||||
.arg("-L")
|
||||
.arg(&keyring_url)
|
||||
.arg("--output")
|
||||
.arg(&download_path);
|
||||
for keyring_url in keyring_urls {
|
||||
// Extract the original filename from the keyring URL
|
||||
let filename = keyring_url
|
||||
.split('/')
|
||||
.next_back()
|
||||
.unwrap_or("pkh-{}.gpg")
|
||||
.replace("{}", series);
|
||||
let download_path = keyring_dir.join(&filename);
|
||||
|
||||
let status = curl_cmd.status()?;
|
||||
if !status.success() {
|
||||
return Err(format!("Failed to download keyring from {}", keyring_url).into());
|
||||
}
|
||||
// Determine the binary keyring path
|
||||
let binary_path = if filename.ends_with(".asc") {
|
||||
// ASCII-armored key: convert to .gpg
|
||||
let binary_filename = filename.strip_suffix(".asc").unwrap_or(&filename);
|
||||
keyring_dir.join(format!("{}.gpg", binary_filename))
|
||||
} else {
|
||||
download_path.clone()
|
||||
};
|
||||
|
||||
// If the downloaded file is an ASCII-armored key (.asc), convert it to binary GPG format
|
||||
// mmdebstrap's --keyring option expects binary GPG keyrings
|
||||
let keyring_path = if filename.ends_with(".asc") {
|
||||
let binary_filename = filename.strip_suffix(".asc").unwrap_or(&filename);
|
||||
let binary_path = cache_dir.join(format!("{}.gpg", binary_filename));
|
||||
// Skip download if the binary keyring already exists
|
||||
if !ctx.exists(&binary_path)? {
|
||||
// Download the keyring using curl
|
||||
let mut curl_cmd = ctx.command("curl");
|
||||
curl_cmd
|
||||
.arg("-s")
|
||||
.arg("-f")
|
||||
.arg("-L")
|
||||
.arg(&keyring_url)
|
||||
.arg("--output")
|
||||
.arg(&download_path);
|
||||
|
||||
log::debug!("Converting ASCII-armored key to binary GPG format");
|
||||
let mut gpg_cmd = ctx.command("gpg");
|
||||
gpg_cmd
|
||||
.arg("--dearmor")
|
||||
.arg("--output")
|
||||
.arg(&binary_path)
|
||||
.arg(&download_path);
|
||||
let status = curl_cmd.status()?;
|
||||
if !status.success() {
|
||||
return Err(format!("Failed to download keyring from {}", keyring_url).into());
|
||||
}
|
||||
|
||||
let status = gpg_cmd.status()?;
|
||||
if !status.success() {
|
||||
return Err("Failed to convert keyring to binary format"
|
||||
.to_string()
|
||||
.into());
|
||||
// If the downloaded file is an ASCII-armored key (.asc), convert it to binary GPG format
|
||||
if filename.ends_with(".asc") {
|
||||
log::debug!("Converting ASCII-armored key to binary GPG format");
|
||||
let mut gpg_cmd = ctx.command("gpg");
|
||||
gpg_cmd
|
||||
.arg("--dearmor")
|
||||
.arg("--output")
|
||||
.arg(&binary_path)
|
||||
.arg(&download_path);
|
||||
|
||||
let status = gpg_cmd.status()?;
|
||||
if !status.success() {
|
||||
return Err("Failed to convert keyring to binary format"
|
||||
.to_string()
|
||||
.into());
|
||||
}
|
||||
|
||||
// Remove the original .asc file
|
||||
let _ = ctx.command("rm").arg("-f").arg(&download_path).status();
|
||||
}
|
||||
|
||||
// Make the keyring file world-readable so mmdebstrap in unshare mode can access it
|
||||
ctx.command("chmod").arg("a+r").arg(&binary_path).status()?;
|
||||
|
||||
log::info!(
|
||||
"Successfully downloaded keyring for {} to {}",
|
||||
series,
|
||||
binary_path.display()
|
||||
);
|
||||
} else {
|
||||
log::debug!(
|
||||
"Keyring already exists at {}, skipping download",
|
||||
binary_path.display()
|
||||
);
|
||||
// Ensure existing keyring is world-readable
|
||||
ctx.command("chmod").arg("a+r").arg(&binary_path).status()?;
|
||||
}
|
||||
|
||||
// Remove the original .asc file
|
||||
let _ = ctx.command("rm").arg("-f").arg(&download_path).status();
|
||||
|
||||
binary_path
|
||||
} else {
|
||||
download_path
|
||||
};
|
||||
}
|
||||
|
||||
log::info!(
|
||||
"Successfully downloaded keyring for {} to {}",
|
||||
"Keyrings for {} available in {}",
|
||||
series,
|
||||
keyring_path.display()
|
||||
keyring_dir.display()
|
||||
);
|
||||
Ok(keyring_path)
|
||||
|
||||
Ok(keyring_dir)
|
||||
}
|
||||
|
||||
/// Download and import a PPA key using Launchpad API
|
||||
|
||||
Reference in New Issue
Block a user