#!perl

# simple-cve-ssvc-calculator.pl - Simple CVE SSVC Calculator
#
# (C) 2026, Giuseppe Di Terlizzi <giuseppe.diterlizzi@gmail.com>
# License MIT

use strict;
use warnings;
use v5.10;

use Carp;
use SSVC::CISA;
use Net::NVD;

my $usage = "Usage $0 <CVE> <MISSION PREVALENCE> <PUBLIC WELL BEIGN IMPACT>\n";

my $cve_id                   = shift || Carp::croak "$usage\nMissing CVE id";
my $mission_prevalence       = shift || Carp::croak "$usage\nMissing mission_prevalence";
my $public_well_being_impact = shift || Carp::croak "$usage\nMissing public_well_being_impact";

my $nvd = Net::NVD->new;
my $cve = $nvd->get($cve_id);

unless ($cve) {
    Carp::croak "CVE not found!";
}

unless (defined $cve->{metrics}->{ssvcV203}) {
    Carp::croak "NO SSVC Metrics for $cve_id";
}

my $data            = $cve->{metrics}->{ssvcV203}->[0]->{ssvcData}->{options};
my %decision_points = ();

foreach (@{$data}) {
    my ($decision_point, $value) = %{$_};
    $decision_point = 'technical_impact' if ($decision_point eq 'technicalImpact');
    $decision_points{$decision_point} = $value;
}

$decision_points{mission_prevalence}       = $mission_prevalence;
$decision_points{public_well_being_impact} = $public_well_being_impact;

my $ssvc = SSVC::CISA->new(%decision_points);

my $mission_well_being_impact = $ssvc->mission_well_being_impact;
my $decision                  = $ssvc->decision;
my $cisa_url                  = "https://www.cisa.gov/ssvc-calculator#$ssvc&$cve_id&Coordinator";

say "Simple SSVC calculator for $cve_id\n";
say sprintf "%s\n",                                      $cve->{descriptions}[0]{value};
say sprintf "(E) Exploitation             (CISA)  %s",   $decision_points{exploitation};
say sprintf "(A) Automatable              (CISA)  %s",   $decision_points{automatable};
say sprintf "(T) Technical Impact         (CISA)  %s",   $decision_points{technical_impact};
say sprintf "(P) Mission Prevalence       (USER)  %s",   $decision_points{mission_prevalence};
say sprintf "(B) Public Well-being Impact (USER)  %s",   $decision_points{public_well_being_impact};
say sprintf "(M) Mission Well-being               %s",   $mission_well_being_impact;
say sprintf "(D) Decision                       [ %s ]", $decision;
say sprintf "    Vector String                    %s",   $ssvc;
say sprintf "    URL                              %s",   $cisa_url;

exit 0;
