use crate::{Error, osv};
use semver::{Version, VersionReq};
use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
#[serde(try_from = "RawVersions")]
pub struct Versions {
patched: Vec<VersionReq>,
#[serde(default)]
unaffected: Vec<VersionReq>,
}
impl Versions {
pub fn is_vulnerable(&self, version: &Version) -> bool {
for range in osv::ranges_for_advisory(self).iter() {
if range.affects(version) {
return true;
}
}
false
}
pub fn new(patched: Vec<VersionReq>, unaffected: Vec<VersionReq>) -> Result<Self, Error> {
RawVersions {
patched,
unaffected,
}
.try_into()
}
pub fn patched(&self) -> &[VersionReq] {
self.patched.as_slice()
}
pub fn unaffected(&self) -> &[VersionReq] {
self.unaffected.as_slice()
}
}
impl TryFrom<RawVersions> for Versions {
type Error = Error;
fn try_from(raw: RawVersions) -> Result<Self, Self::Error> {
validate_ranges(&raw)?;
Ok(Versions {
patched: raw.patched,
unaffected: raw.unaffected,
})
}
}
#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
pub(crate) struct RawVersions {
pub patched: Vec<VersionReq>,
#[serde(default)]
pub unaffected: Vec<VersionReq>,
}
fn validate_ranges(versions: &RawVersions) -> Result<(), Error> {
let _ = osv::ranges_for_unvalidated_advisory(versions)?;
Ok(())
}