diff options
| author | nsfisis <nsfisis@gmail.com> | 2026-05-14 19:56:23 +0900 |
|---|---|---|
| committer | nsfisis <nsfisis@gmail.com> | 2026-05-14 19:56:23 +0900 |
| commit | 6ffb4b4db1da067ca88f98d8164940a570c2b2af (patch) | |
| tree | 3011821fd2652c867a0701f0a634bdf41b245538 | |
| parent | 9a65b4a9d24fe9b5759df05d4c2b06a6d2186dec (diff) | |
| download | php-shirabe-6ffb4b4db1da067ca88f98d8164940a570c2b2af.tar.gz php-shirabe-6ffb4b4db1da067ca88f98d8164940a570c2b2af.tar.zst php-shirabe-6ffb4b4db1da067ca88f98d8164940a570c2b2af.zip | |
feat(port): port PartialSecurityAdvisory.php
| -rw-r--r-- | crates/shirabe-php-shim/src/lib.rs | 4 | ||||
| -rw-r--r-- | crates/shirabe/src/advisory/partial_security_advisory.rs | 88 |
2 files changed, 92 insertions, 0 deletions
diff --git a/crates/shirabe-php-shim/src/lib.rs b/crates/shirabe-php-shim/src/lib.rs index 758dd1c..56b29e5 100644 --- a/crates/shirabe-php-shim/src/lib.rs +++ b/crates/shirabe-php-shim/src/lib.rs @@ -220,6 +220,10 @@ impl PharData { } } +pub trait JsonSerializable { + fn json_serialize(&self) -> PhpMixed; +} + pub fn class_exists(name: &str) -> bool { todo!() } diff --git a/crates/shirabe/src/advisory/partial_security_advisory.rs b/crates/shirabe/src/advisory/partial_security_advisory.rs index 894ed17..63fe998 100644 --- a/crates/shirabe/src/advisory/partial_security_advisory.rs +++ b/crates/shirabe/src/advisory/partial_security_advisory.rs @@ -1 +1,89 @@ //! ref: composer/src/Composer/Advisory/PartialSecurityAdvisory.php + +use anyhow::Result; +use chrono::{DateTime, TimeZone, Utc}; +use indexmap::IndexMap; +use shirabe_external_packages::composer::pcre::preg::Preg; +use shirabe_php_shim::{JsonSerializable, PhpMixed, UnexpectedValueException}; +use shirabe_semver::constraint::constraint::Constraint; +use shirabe_semver::constraint::constraint_interface::ConstraintInterface; +use shirabe_semver::version_parser::VersionParser; +use crate::advisory::security_advisory::SecurityAdvisory; + +#[derive(Debug)] +pub struct PartialSecurityAdvisory { + pub advisory_id: String, + pub package_name: String, + pub affected_versions: Box<dyn ConstraintInterface>, +} + +impl PartialSecurityAdvisory { + pub fn create( + package_name: &str, + data: &IndexMap<String, PhpMixed>, + parser: &VersionParser, + ) -> Result<Box<dyn std::any::Any>> { + let affected_versions_str = data["affectedVersions"].as_string().unwrap_or(""); + + let constraint: Box<dyn ConstraintInterface> = match parser.parse_constraints(affected_versions_str) { + Ok(c) => c, + Err(_) => { + let affected_version = Preg::replace(r"(^[>=<^~]*[\d.]+).*", "$1", affected_versions_str); + match parser.parse_constraints(&affected_version) { + Ok(c) => c, + Err(_) => Box::new(Constraint::new("==", "0.0.0-invalid-version")), + } + } + }; + + let has_full_data = data.contains_key("title") + && data.contains_key("sources") + && data.contains_key("reportedAt"); + + if has_full_data { + let reported_at: DateTime<Utc> = Utc + .datetime_from_str( + data["reportedAt"].as_string().unwrap_or(""), + "%Y-%m-%dT%H:%M:%S+00:00", + ) + .unwrap_or_default(); + let advisory = SecurityAdvisory::new( + package_name.to_string(), + data["advisoryId"].as_string().unwrap_or("").to_string(), + constraint, + data["title"].as_string().unwrap_or("").to_string(), + data["sources"].clone(), + reported_at, + data.get("cve").and_then(|v| v.as_string()).map(|s| s.to_string()), + data.get("link").and_then(|v| v.as_string()).map(|s| s.to_string()), + data.get("severity").and_then(|v| v.as_string()).map(|s| s.to_string()), + ); + return Ok(Box::new(advisory)); + } + + Ok(Box::new(Self { + advisory_id: data["advisoryId"].as_string().unwrap_or("").to_string(), + package_name: package_name.to_string(), + affected_versions: constraint, + })) + } + + pub fn new( + package_name: String, + advisory_id: String, + affected_versions: Box<dyn ConstraintInterface>, + ) -> Self { + Self { advisory_id, package_name, affected_versions } + } +} + +impl JsonSerializable for PartialSecurityAdvisory { + fn json_serialize(&self) -> PhpMixed { + use indexmap::IndexMap; + let mut data: IndexMap<String, Box<PhpMixed>> = IndexMap::new(); + data.insert("advisoryId".to_string(), Box::new(PhpMixed::String(self.advisory_id.clone()))); + data.insert("packageName".to_string(), Box::new(PhpMixed::String(self.package_name.clone()))); + data.insert("affectedVersions".to_string(), Box::new(PhpMixed::String(self.affected_versions.get_pretty_string()))); + PhpMixed::Array(data) + } +} |
