use crate::database::package_scope::PackageScope;
use crate::{
advisory::{Advisory, Severity},
collection::Collection,
package,
platforms::target::{Arch, OS},
version::Version,
};
#[derive(Clone, Debug, Default)]
pub struct Query {
pub(super) collection: Option<Collection>,
pub(super) package: Option<package::Name>,
version: Option<Version>,
severity: Option<Severity>,
target_arch: Option<Arch>,
target_os: Option<OS>,
year: Option<u32>,
obsolete: Option<bool>,
informational: Option<bool>,
package_scope: Option<PackageScope>,
}
impl Query {
pub fn new() -> Self {
Self::default()
}
pub fn crate_scope() -> Self {
Self::new()
.collection(Collection::Crates)
.obsolete(false)
.informational(false)
}
pub fn collection(mut self, collection: Collection) -> Self {
self.collection = Some(collection);
self
}
pub fn package(mut self, package: impl Into<package::Name>) -> Self {
self.package = Some(package.into());
self
}
pub fn package_version(
mut self,
package: impl Into<package::Name>,
version: impl Into<Version>,
) -> Self {
self.package = Some(package.into());
self.version = Some(version.into());
self
}
pub fn severity(mut self, severity: Severity) -> Self {
self.severity = Some(severity);
self
}
pub fn target_arch(mut self, arch: Arch) -> Self {
self.target_arch = Some(arch);
self
}
pub fn target_os(mut self, os: OS) -> Self {
self.target_os = Some(os);
self
}
pub fn year(mut self, year: u32) -> Self {
self.year = Some(year);
self
}
pub fn obsolete(mut self, setting: bool) -> Self {
self.obsolete = Some(setting);
self
}
pub fn informational(mut self, setting: bool) -> Self {
self.informational = Some(setting);
self
}
pub fn matches(&self, advisory: &Advisory) -> bool {
if let Some(collection) = self.collection {
if Some(collection) != advisory.metadata.collection {
return false;
}
}
if let Some(package) = &self.package {
if package != &advisory.metadata.package {
return false;
}
}
if let Some(version) = &self.version {
if !advisory.versions.is_vulnerable(version) {
return false;
}
}
if let Some(severity_threshold) = self.severity {
if let Some(advisory_severity) = advisory.severity() {
if advisory_severity < severity_threshold {
return false;
}
}
}
if let Some(affected) = &advisory.affected {
if let Some(target_arch) = self.target_arch {
if !affected.arch.is_empty() && !affected.arch.contains(&target_arch) {
return false;
}
}
if let Some(target_os) = self.target_os {
if !affected.os.is_empty() && !affected.os.contains(&target_os) {
return false;
}
}
}
if let Some(query_year) = self.year {
if let Some(advisory_year) = advisory.metadata.id.year() {
if query_year != advisory_year {
return false;
}
}
}
if let Some(obsolete) = self.obsolete {
if obsolete != advisory.metadata.obsolete {
return false;
}
}
if let Some(informational) = self.informational {
if informational != advisory.metadata.informational.is_some() {
return false;
}
}
true
}
}