commit: a9b91748db240b82d86b69ed8076bc352510633c
parent 5bf05d8e8e0f9701102a428a0049062d2d498412
Author: Haelwenn (lanodan) Monnier <contact@hacktivis.me>
Date: Mon, 27 Mar 2023 20:20:32 +0200
lib/App/CveClient: Move-in subs of cve-client
Diffstat:
M | MANIFEST | 1 | + |
M | cve-client | 178 | ++++--------------------------------------------------------------------------- |
A | lib/App/CveClient.pm | 175 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
3 files changed, 183 insertions(+), 171 deletions(-)
diff --git a/MANIFEST b/MANIFEST
@@ -1,5 +1,6 @@
.perltidyrc
cve-client
+lib/App/CveClient.pm
Makefile.PL
MANIFEST This list of files
README.md
diff --git a/cve-client b/cve-client
@@ -1,17 +1,18 @@
#!/usr/bin/env perl
# CVE-Client: CLI-based client / toolbox for CVE.org
-# Copyright © 2021 CVE-Client Authors <https://hacktivis.me/git/cve-client/>
+# Copyright © 2021-2023 CVE-Client Authors <https://hacktivis.me/git/cve-client/>
# SPDX-License-Identifier: AGPL-3.0-only
+our $VERSION = '1.0.3';
use strict;
use utf8;
no warnings; # Wide Character…
+use App::CveClient qw(print_cve);
+
use Getopt::Std;
use LWP::UserAgent;
use JSON::MaybeXS;
-our $VERSION = "1.0.3";
-
$Getopt::Std::STANDARD_HELP_VERSION = 1;
my $json = JSON::MaybeXS->new(utf8 => 1);
@@ -27,169 +28,6 @@ sub HELP_MESSAGE {
exit 1;
}
-sub print_cve {
- my ($object, $cve_id) = @_;
-
- print "CVE ID: ", $cve_id, "\n";
-
- if ($object->{'error'} and $object->{'message'}) {
- print "Error (", $object->{'error'}, "): ", $object->{'message'}, "\n";
- exit 1;
- }
-
- if ($object->{'dataVersion'} == "5.0") {
- print_cve50($object, $cve_id);
- } elsif ($object->{'data_version'} == "4.0") {
- print_cve40($object, $cve_id);
- } else {
- print "Error: unknown CVE format:\n";
- print "- data_version: ", $object->{'data_version'}, "\n"
- if $object->{'data_version'};
- print "- dataVersion: ", $object->{'dataVersion'}, "\n"
- if $object->{'dataVersion'};
- }
-}
-
-# https://github.com/CVEProject/cve-schema/blob/master/schema/v5.0/
-sub print_cve50 {
- my ($object, $cve_id) = @_;
-
- if ($object->{'cveMetadata'}->{'cveId'} != $cve_id) {
- print "Warning: Got ", $object->{'cveMetadata'}->{'cveId'},
- " instead of ", $cve_id, "\n";
- }
-
- my $affected = $object->{'containers'}->{'cna'}->{'affected'};
- if ($affected) {
- foreach (@{$affected}) {
- print "Vendor Name: ", $_->{'vendor'}, "\n"; # vendor required
- print "Product Name: ", $_->{'product'}, "\n"; # product required
-
- foreach (@{$_->{'versions'}}) {
- print "- ", $_->{'status'}, ": ", $_->{'version'}, "\n";
- }
- }
- } else {
- print
-"Warning: No CVE affected versions could be found! (as required by the spec)\n";
- }
-
- print "\n";
-
- my $metrics = $object->{'containers'}->{'cna'}->{'metrics'};
- if ($metrics) {
- foreach (@{$metrics}) {
- if ($_->{'cvssV3_1'}) {
- my $metric = $_->{'cvssV3_1'};
- print "- Score: ", $metric->{'baseScore'}, " ",
- $metric->{'baseSeverity'}, "\n";
- } else {
- print "Notice: unhandled metrics (CVSS) data\n";
- }
- }
- } else {
- print
-"Warning: No CVE metrics (CVSS) could be found! (as required by the spec)\n";
- }
-
- print "\n";
-
- my $desc = $object->{'containers'}->{'cna'}->{'descriptions'};
- if ($desc) {
- foreach (@{$desc}) {
- print "Description Language: ", $_->{'lang'}, "\n";
- print "Description:\n", $_->{'value'}, "\n\n";
- }
- } else {
- print
-"Warning: No CVE description could be found! (as required by the spec)\n";
- }
-
- print "\n";
-
- my $refs = $object->{'containers'}->{'cna'}->{'references'};
- if ($refs) {
- print "References: \n";
-
- foreach (@{$refs}) {
- print "=> ", $_->{'url'}, "\n";
- }
- } else {
- print
-"Warning: No CVE references could be found! (as required by the spec)\n";
- }
-}
-
-# https://github.com/CVEProject/cve-schema/blob/master/schema/v4.0/
-sub print_cve40 {
- my ($object, $cve_id) = @_;
-
- if ($object->{'CVE_data_meta'}->{'ID'} != $cve_id) {
- print "Warning: Got ", $object->{'CVE_data_meta'}->{'ID'},
- " instead of ", $cve_id, "\n";
- }
-
- print "TITLE: ", $object->{'CVE_data_meta'}->{'TITLE'}, "\n"
- if $object->{'CVE_data_meta'}->{'TITLE'};
-
- print "\n";
-
- if ($object->{'affects'}->{'vendor'}) {
- foreach (@{$object->{'affects'}->{'vendor'}->{'vendor_data'}}) {
- print "Vendor Name: ", $_->{'vendor_name'}, "\n"
- if $_->{'vendor_name'};
-
- foreach (@{$_->{'product'}->{'product_data'}}) {
- print "Product name: ", $_->{'product_name'}, "\n";
- print "Product versions: ";
-
- foreach (@{$_->{'version'}->{'version_data'}}) {
- print $_->{'version_value'}, "; ";
- }
-
- print "\n";
- }
- }
- }
-
- print "\n";
-
- if ($object->{'description'}->{'description_data'}) {
- my $descs = $object->{'description'}->{'description_data'};
-
- foreach (@{$descs}) {
- print "Description Language: ", $_->{'lang'}, "\n";
- print "Description:\n", $_->{'value'}, "\n\n";
- }
- } else {
- print "Warning: No CVE description could be found!\n";
- }
-
- if ($object->{'references'}->{'reference_data'}) {
- my $refs = $object->{'references'}->{'reference_data'};
-
- foreach (@{$refs}) {
- if (defined $options{g}) {
- print "Reference Source: ", $_->{'refsource'}, "\n";
-
- print "=> ", $_->{'url'} if $_->{'url'};
- if ($_->{'name'}) {
- print " ", $_->{'name'}, "\n\n";
- } else {
- print "\n\n";
- }
- } else {
- print "Reference Source: ", $_->{'refsource'}, "\n";
- print "- Name: ", $_->{'name'}, "\n" if $_->{'name'};
- print "- URL: ", $_->{'url'}, "\n" if $_->{'url'};
- print "\n";
- }
- }
- } else {
- print "Warning: No CVE references could be found!\n";
- }
-}
-
sub fetch_cve {
my ($cve_id) = @_;
my $url = 'https://www.cve.org/api/?action=getCveById&cveId=' . $cve_id;
@@ -203,6 +41,8 @@ sub fetch_cve {
my $res = $ua->request($req);
+ my $format = $options{g} ? 'gemini' : 'plain';
+
if ($res->is_success) {
my $content_type = $res->header("Content-Type");
my $content_match = 'application/json';
@@ -216,7 +56,7 @@ sub fetch_cve {
print $pipe_out $res->content;
} else {
my $object = $json->decode($res->content);
- print_cve($object, $cve_id);
+ print_cve($object, $cve_id, $format);
}
} else {
print "Got $content_type instead of $content_match";
@@ -236,7 +76,3 @@ if ($#ARGV < 0) {
for (@ARGV) {
fetch_cve($_) if $_ =~ /^CVE-[0-9]{4}-[0-9]{4,19}$/;
}
-=head1 CVE-Client
-App::CVE-Client CLI-based client / toolbox for CVE.org
-
-Because why would you ever rely on someone else's clobbered together JavaScript code to get important security information.
diff --git a/lib/App/CveClient.pm b/lib/App/CveClient.pm
@@ -0,0 +1,175 @@
+# CVE-Client: CLI-based client / toolbox for CVE.org
+# Copyright © 2021-2023 CVE-Client Authors <https://hacktivis.me/git/cve-client/>
+# SPDX-License-Identifier: AGPL-3.0-only
+package App::CveClient;
+
+use warnings;
+use strict;
+
+use Exporter qw(import);
+
+our @EXPORT_OK = qw(print_cve print_cve50 print_cve40);
+
+sub print_cve {
+ my ($object, $cve_id, $format) = @_;
+
+ print "CVE ID: ", $cve_id, "\n";
+
+ if ($object->{'error'} and $object->{'message'}) {
+ die "Error ($object->{'error'}): $object->{'message'}\n";
+ }
+
+ if ($object->{'dataVersion'} == "5.0") {
+ print_cve50($object, $cve_id, $format);
+ } elsif ($object->{'data_version'} == "4.0") {
+ print_cve40($object, $cve_id, $format);
+ } else {
+ print STDERR "Error: unknown CVE format:\n";
+ print STDERR "- data_version: ", $object->{'data_version'}, "\n"
+ if $object->{'data_version'};
+ print STDERR "- dataVersion: ", $object->{'dataVersion'}, "\n"
+ if $object->{'dataVersion'};
+ }
+}
+
+# https://github.com/CVEProject/cve-schema/blob/master/schema/v5.0/
+sub print_cve50 {
+ my ($object, $cve_id, $format) = @_;
+
+ if ($object->{'cveMetadata'}->{'cveId'} ne $cve_id) {
+ print STDERR "Warning: Got <", $object->{'cveMetadata'}->{'cveId'},
+ "> instead of <", $cve_id, ">\n";
+ }
+
+ my $affected = $object->{'containers'}->{'cna'}->{'affected'};
+ if ($affected) {
+ foreach (@{$affected}) {
+ print "Vendor Name: ", $_->{'vendor'}, "\n"; # vendor required
+ print "Product Name: ", $_->{'product'}, "\n"; # product required
+
+ foreach (@{$_->{'versions'}}) {
+ print "- ", $_->{'status'}, ": ", $_->{'version'}, "\n";
+ }
+ }
+ } else {
+ print STDERR
+"Warning: No CVE affected versions could be found! (as required by the spec)\n";
+ }
+
+ print "\n";
+
+ my $metrics = $object->{'containers'}->{'cna'}->{'metrics'};
+ if ($metrics) {
+ foreach (@{$metrics}) {
+ if ($_->{'cvssV3_1'}) {
+ my $metric = $_->{'cvssV3_1'};
+ print "- Score: ", $metric->{'baseScore'}, " ",
+ $metric->{'baseSeverity'}, "\n";
+ } else {
+ print "Notice: unhandled metrics (CVSS) data\n";
+ }
+ }
+ } else {
+ print STDERR
+"Warning: No CVE metrics (CVSS) could be found! (as required by the spec)\n";
+ }
+
+ print "\n";
+
+ my $desc = $object->{'containers'}->{'cna'}->{'descriptions'};
+ if ($desc) {
+ foreach (@{$desc}) {
+ print "Description Language: ", $_->{'lang'}, "\n";
+ print "Description:\n", $_->{'value'}, "\n\n";
+ }
+ } else {
+ print STDERR
+"Warning: No CVE description could be found! (as required by the spec)\n";
+ }
+
+ print "\n";
+
+ my $refs = $object->{'containers'}->{'cna'}->{'references'};
+ if ($refs) {
+ print "References: \n";
+
+ foreach (@{$refs}) {
+ print "=> ", $_->{'url'}, "\n";
+ }
+ } else {
+ print STDERR
+"Warning: No CVE references could be found! (as required by the spec)\n";
+ }
+}
+
+# https://github.com/CVEProject/cve-schema/blob/master/schema/v4.0/
+sub print_cve40 {
+ my ($object, $cve_id, $format) = @_;
+
+ if ($object->{'CVE_data_meta'}->{'ID'} ne $cve_id) {
+ print STDERR "Warning: Got ", $object->{'CVE_data_meta'}->{'ID'},
+ " instead of ", $cve_id, "\n";
+ }
+
+ print "TITLE: ", $object->{'CVE_data_meta'}->{'TITLE'}, "\n"
+ if $object->{'CVE_data_meta'}->{'TITLE'};
+
+ print "\n";
+
+ if ($object->{'affects'}->{'vendor'}) {
+ foreach (@{$object->{'affects'}->{'vendor'}->{'vendor_data'}}) {
+ print "Vendor Name: ", $_->{'vendor_name'}, "\n"
+ if $_->{'vendor_name'};
+
+ foreach (@{$_->{'product'}->{'product_data'}}) {
+ print "Product name: ", $_->{'product_name'}, "\n";
+ print "Product versions: ";
+
+ foreach (@{$_->{'version'}->{'version_data'}}) {
+ print $_->{'version_value'}, "; ";
+ }
+
+ print "\n";
+ }
+ }
+ }
+
+ print "\n";
+
+ if ($object->{'description'}->{'description_data'}) {
+ my $descs = $object->{'description'}->{'description_data'};
+
+ foreach (@{$descs}) {
+ print "Description Language: ", $_->{'lang'}, "\n";
+ print "Description:\n", $_->{'value'}, "\n\n";
+ }
+ } else {
+ print STDERR "Warning: No CVE description could be found!\n";
+ }
+
+ if ($object->{'references'}->{'reference_data'}) {
+ my $refs = $object->{'references'}->{'reference_data'};
+
+ foreach (@{$refs}) {
+ if ($format == 'gemini') {
+ print "Reference Source: ", $_->{'refsource'}, "\n";
+
+ print "=> ", $_->{'url'} if $_->{'url'};
+ if ($_->{'name'}) {
+ print " ", $_->{'name'}, "\n\n";
+ } else {
+ print "\n\n";
+ }
+ } else {
+ print "Reference Source: ", $_->{'refsource'}, "\n";
+ print "- Name: ", $_->{'name'}, "\n" if $_->{'name'};
+ print "- URL: ", $_->{'url'}, "\n" if $_->{'url'};
+ print "\n";
+ }
+ }
+ } else {
+ print STDERR "Warning: No CVE references could be found!\n";
+ }
+}
+
+1;