mirror of
https://codeberg.org/Toasterson/ips.git
synced 2026-04-10 21:30:41 +00:00
Add legacy repository support and SHA-1 signature handling
- Introduced fallback for legacy `pkg5.repository` configuration in INI format alongside the existing `pkg6.repository` JSON format. - Enabled SHA-1 signature computation for compatibility with legacy catalog signatures. - Added methods to save update logs in legacy format and enhance catalog compatibility. - Updated dependencies to include `sha1` for hashing.
This commit is contained in:
parent
c4910bb434
commit
a948f87e6f
3 changed files with 103 additions and 6 deletions
12
Cargo.lock
generated
12
Cargo.lock
generated
|
|
@ -1483,6 +1483,7 @@ dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
"serde_cbor",
|
"serde_cbor",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
|
"sha1",
|
||||||
"sha2",
|
"sha2",
|
||||||
"sha3",
|
"sha3",
|
||||||
"strum",
|
"strum",
|
||||||
|
|
@ -2773,6 +2774,17 @@ dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sha1"
|
||||||
|
version = "0.10.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"cpufeatures",
|
||||||
|
"digest",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sha2"
|
name = "sha2"
|
||||||
version = "0.10.9"
|
version = "0.10.9"
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,8 @@ maplit = "1"
|
||||||
object = "0.37"
|
object = "0.37"
|
||||||
goblin = "0.8"
|
goblin = "0.8"
|
||||||
sha2 = "0.10"
|
sha2 = "0.10"
|
||||||
|
# For SHA-1 signatures required by legacy catalog format
|
||||||
|
sha1 = "0.10"
|
||||||
sha3 = "0.10"
|
sha3 = "0.10"
|
||||||
pest = "2.1.3"
|
pest = "2.1.3"
|
||||||
pest_derive = "2.1.0"
|
pest_derive = "2.1.0"
|
||||||
|
|
|
||||||
|
|
@ -661,9 +661,52 @@ impl ReadableRepository for FileBackend {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load the repository configuration
|
// Load the repository configuration
|
||||||
let config_path = path.join(REPOSITORY_CONFIG_FILENAME);
|
// Prefer pkg6.repository (JSON). If absent, try legacy pkg5.repository (INI)
|
||||||
let config_data = fs::read_to_string(&config_path).map_err(|e| RepositoryError::ConfigReadError(format!("{}: {}", config_path.display(), e)))?;
|
let config6_path = path.join(REPOSITORY_CONFIG_FILENAME);
|
||||||
let config: RepositoryConfig = serde_json::from_str(&config_data)?;
|
let config5_path = path.join("pkg5.repository");
|
||||||
|
|
||||||
|
let config: RepositoryConfig = if config6_path.exists() {
|
||||||
|
let config_data = fs::read_to_string(&config6_path)
|
||||||
|
.map_err(|e| RepositoryError::ConfigReadError(format!("{}: {}", config6_path.display(), e)))?;
|
||||||
|
serde_json::from_str(&config_data)?
|
||||||
|
} else if config5_path.exists() {
|
||||||
|
// Minimal mapping for legacy INI: take publishers only from INI; do not scan disk.
|
||||||
|
let ini = Ini::load_from_file(&config5_path)
|
||||||
|
.map_err(|e| RepositoryError::ConfigReadError(format!("{}: {}", config5_path.display(), e)))?;
|
||||||
|
|
||||||
|
// Default repository version for legacy format is v4
|
||||||
|
let mut cfg = RepositoryConfig::default();
|
||||||
|
|
||||||
|
// Try to read default publisher from [publisher] section (key: prefix)
|
||||||
|
if let Some(section) = ini.section(Some("publisher")) {
|
||||||
|
if let Some(prefix) = section.get("prefix") {
|
||||||
|
cfg.default_publisher = Some(prefix.to_string());
|
||||||
|
cfg.publishers.push(prefix.to_string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If INI enumerates publishers in an optional [publishers] section as comma-separated list
|
||||||
|
if let Some(section) = ini.section(Some("publishers")) {
|
||||||
|
if let Some(list) = section.get("list") {
|
||||||
|
// replace list strictly by INI contents per requirements
|
||||||
|
cfg.publishers.clear();
|
||||||
|
for p in list.split(',') {
|
||||||
|
let name = p.trim();
|
||||||
|
if !name.is_empty() {
|
||||||
|
cfg.publishers.push(name.to_string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg
|
||||||
|
} else {
|
||||||
|
return Err(RepositoryError::ConfigReadError(format!(
|
||||||
|
"No repository config found: expected {} or {}",
|
||||||
|
config6_path.display(),
|
||||||
|
config5_path.display()
|
||||||
|
)));
|
||||||
|
};
|
||||||
|
|
||||||
Ok(FileBackend {
|
Ok(FileBackend {
|
||||||
path: path.to_path_buf(),
|
path: path.to_path_buf(),
|
||||||
|
|
@ -2083,10 +2126,11 @@ impl FileBackend {
|
||||||
// Parse the manifest using parse_file which handles JSON correctly
|
// Parse the manifest using parse_file which handles JSON correctly
|
||||||
let manifest = Manifest::parse_file(&manifest_path)?;
|
let manifest = Manifest::parse_file(&manifest_path)?;
|
||||||
|
|
||||||
// Calculate SHA-256 hash of the manifest (as a substitute for SHA-1)
|
// Calculate SHA-1 hash of the manifest for legacy catalog signature compatibility
|
||||||
let mut hasher = sha2::Sha256::new();
|
let mut hasher = sha1::Sha1::new();
|
||||||
hasher.update(manifest_content.as_bytes());
|
hasher.update(manifest_content.as_bytes());
|
||||||
let signature = format!("{:x}", hasher.finalize());
|
let signature = hasher.finalize();
|
||||||
|
let signature = format!("{:x}", signature);
|
||||||
|
|
||||||
// Add to base entries
|
// Add to base entries
|
||||||
base_entries.push((fmri.clone(), None, signature.clone()));
|
base_entries.push((fmri.clone(), None, signature.clone()));
|
||||||
|
|
@ -2299,6 +2343,45 @@ impl FileBackend {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Save an update log file to the publisher's catalog directory.
|
||||||
|
///
|
||||||
|
/// The file name must follow the legacy pattern: `update.<logdate>.<locale>`
|
||||||
|
/// for example: `update.20090524T042841Z.C`.
|
||||||
|
pub fn save_update_log(
|
||||||
|
&self,
|
||||||
|
publisher: &str,
|
||||||
|
log_filename: &str,
|
||||||
|
log: &crate::repository::catalog::UpdateLog,
|
||||||
|
) -> Result<()> {
|
||||||
|
if log_filename.contains('/') || log_filename.contains('\\') {
|
||||||
|
return Err(RepositoryError::PathPrefixError(log_filename.to_string()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure catalog dir exists
|
||||||
|
let catalog_dir = Self::construct_catalog_path(&self.path, publisher);
|
||||||
|
std::fs::create_dir_all(&catalog_dir).map_err(|e| RepositoryError::DirectoryCreateError { path: catalog_dir.clone(), source: e })?;
|
||||||
|
|
||||||
|
// Serialize JSON
|
||||||
|
let json = serde_json::to_vec_pretty(log)
|
||||||
|
.map_err(|e| RepositoryError::JsonSerializeError(format!("Update log serialize error: {}", e)))?;
|
||||||
|
|
||||||
|
// Write atomically
|
||||||
|
let target = catalog_dir.join(log_filename);
|
||||||
|
let tmp = target.with_extension("tmp");
|
||||||
|
{
|
||||||
|
let mut f = std::fs::File::create(&tmp)
|
||||||
|
.map_err(|e| RepositoryError::FileWriteError { path: tmp.clone(), source: e })?;
|
||||||
|
use std::io::Write as _;
|
||||||
|
f.write_all(&json)
|
||||||
|
.map_err(|e| RepositoryError::FileWriteError { path: tmp.clone(), source: e })?;
|
||||||
|
f.flush().map_err(|e| RepositoryError::FileWriteError { path: tmp.clone(), source: e })?;
|
||||||
|
}
|
||||||
|
std::fs::rename(&tmp, &target)
|
||||||
|
.map_err(|e| RepositoryError::FileWriteError { path: target.clone(), source: e })?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
/// Generate the file path for a given hash using the new directory structure with publisher
|
/// Generate the file path for a given hash using the new directory structure with publisher
|
||||||
/// This is a wrapper around the construct_file_path_with_publisher helper method
|
/// This is a wrapper around the construct_file_path_with_publisher helper method
|
||||||
fn generate_file_path_with_publisher(&self, publisher: &str, hash: &str) -> PathBuf {
|
fn generate_file_path_with_publisher(&self, publisher: &str, hash: &str) -> PathBuf {
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue