File Coverage

blib/lib/App/TenableSC/API.pm
Criterion Covered Total %
statement 18 133 13.5
branch 0 60 0.0
condition 0 41 0.0
subroutine 6 10 60.0
pod 1 4 25.0
total 25 248 10.0


line stmt bran cond sub pod time code
1             package App::TenableSC::API;
2              
3 1     1   898 use strict;
  1         2  
  1         35  
4 1     1   5 use warnings;
  1         1  
  1         22  
5              
6 1     1   4 use JSON;
  1         1  
  1         7  
7 1     1   122 use Pod::Usage;
  1         1  
  1         63  
8              
9 1     1   6 use parent 'App::TenableSC';
  1         2  
  1         5  
10              
11 1     1   62 use App::TenableSC::Utils qw(:all);
  1         2  
  1         1185  
12              
13             our $VERSION = '0.310';
14              
15             @App::TenableSC::command_options = (
16             'output|format|f=s',
17              
18             'json',
19             'table',
20             'csv',
21             'tsv',
22             'yaml',
23             'dumper',
24              
25             'verbose'
26             );
27              
28             sub startup {
29              
30 0     0 1   my ($self) = @_;
31              
32 0           my @output_formats = qw/json table csv tsv yaml dumper/;
33              
34 0 0         if ( $self->options->{'format'} ) {
35 0 0         if ( !grep { $self->options->{'format'} eq $_ } @output_formats ) {
  0            
36 0           print "ERROR: Unknown output format\n\n";
37 0           pod2usage( -exitstatus => 0, -verbose => 0 );
38             }
39             }
40              
41 0   0       $self->options->{'format'} ||= 'json';
42              
43 0           foreach (@output_formats) {
44 0 0         $self->options->{'format'} = $_ if ( $self->options->{$_} );
45             }
46              
47 0           my $params = {};
48 0           my $results = undef;
49 0   0       my $api = $ARGV[0] || undef;
50 0   0       my $method = $ARGV[1] || undef;
51              
52 0 0         $api =~ s/-/_/g if ($api);
53 0 0         $method =~ s/-/_/g if ($method);
54              
55 0 0 0       pod2usage( -verbose => 0 ) if ( !$api || !$method );
56              
57 0           foreach my $arg (@ARGV) {
58              
59 0 0         if ( $arg =~ m{^([^=]+)=(.*)$} ) {
60              
61 0           my ( $key, $value ) = ( $1, $2 );
62 0           $key =~ s{-}{_}g;
63 0           $params->{$key} = $value;
64              
65             }
66              
67             }
68              
69 0           my $sc = $self->connect;
70              
71 0 0         $results = $sc->$api->$method( %{$params} ) or cli_error( $sc->error );
  0            
72              
73 0 0 0       if ( ref $results eq 'ARRAY' || ref $results eq 'HASH' ) {
74              
75 0 0         if ( $self->options->{'format'} eq 'json' ) {
76              
77             # Convert bessed Time::Piece and Time::Seconds object for JSON encoding
78 0           require Time::Piece;
79              
80             sub Time::Piece::TO_JSON {
81 0     0 0   my ($time) = @_;
82 0           return $time->datetime; # convert all date to ISO 8601 format
83             }
84              
85             sub Time::Seconds::TO_JSON {
86 0     0 0   my ($time) = @_;
87 0           return $time->seconds;
88             }
89              
90 0           print JSON->new->pretty(1)->convert_blessed(1)->encode($results);
91 0           exit;
92              
93             }
94              
95 0 0         if ( $self->options->{'format'} eq 'dumper' ) {
96 0           print dumper($results);
97 0           exit;
98             }
99              
100 0 0         if ( $self->options->{'format'} eq 'yaml' ) {
101              
102 0 0         if ( eval { require YAML::XS } ) {
  0            
103 0           print YAML::XS::Dump($results);
104 0           exit;
105             }
106 0 0         if ( eval { require YAML } ) {
  0            
107 0           print YAML::Dump($results);
108 0           exit;
109             }
110              
111 0           print "ERROR: YAML or YAML::XS module are missing\n";
112 0           exit(255);
113             }
114              
115 0 0 0       if ( $self->options->{'format'} eq 'tsv'
      0        
116             || $self->options->{'format'} eq 'csv'
117             || $self->options->{'format'} eq 'table' )
118             {
119              
120 0           my @rows = ();
121 0           my @fields = ();
122              
123 0 0         if ( ref $results ne 'ARRAY' ) {
124 0           $results = [$results];
125             }
126              
127 0           foreach my $row ( @{$results} ) {
  0            
128              
129 0 0         if ( !@fields ) {
130 0           @fields = sort keys %{$row};
  0            
131             }
132              
133 0           my @row = ();
134              
135 0           foreach (@fields) {
136              
137 0 0         if ( ref $row->{$_} eq 'HASH' ) {
138 0           push @row, encode_json( $row->{$_} );
139             } else {
140 0           my $value = $row->{$_};
141              
142 0 0         if ( $self->options->{'format'} ne 'table' ) {
143 0 0 0       $value = sprintf '"%s"', $value if ( $value =~ /\n/ || $value =~ /\,/ );
144 0           $value =~ s/\n/\r\n/g;
145             }
146 0           push @row, $value;
147             }
148              
149             }
150              
151 0           push @rows, \@row;
152             }
153              
154 0 0         if (@rows) {
155              
156             print $self->table(
157             rows => \@rows,
158             headers => \@fields,
159 0           format => $self->options->{'format'},
160             column_separator => ' | ',
161             header_separator => '-',
162             );
163              
164             }
165              
166 0           exit;
167              
168             }
169              
170             }
171              
172 0           print "$results\n";
173 0           exit;
174              
175             }
176              
177             sub table {
178              
179 0     0 0   my ( $self, %args ) = @_;
180              
181 0   0       my $col_separator = $args{'column_separator'} || ' ';
182 0   0       my $header_separator = $args{'header_separator'} || undef;
183 0   0       my $rows = $args{'rows'} || ();
184 0   0       my $headers = $args{'headers'} || ();
185 0   0       my $output_format = $args{'format'} || 'table';
186 0           my $widths = ();
187              
188 0           my @checks = @{$rows};
  0            
189              
190 0 0         push( @checks, $headers ) if ($headers);
191              
192 0 0         if ( $output_format eq 'table' ) {
193              
194 0           for my $row (@checks) {
195              
196 0           for my $idx ( 0 .. @{$row} ) {
  0            
197              
198 0 0 0       if ( defined( $args{'widths'}->[$idx] ) && $args{'widths'}->[$idx] > 0 ) {
199 0           $widths->[$idx] = $args{'widths'}->[$idx];
200 0           next;
201             }
202              
203 0           my $col = $row->[$idx];
204 0 0 0       $widths->[$idx] = length($col) if ( $col && length($col) > ( $widths->[$idx] || 0 ) );
      0        
205              
206             }
207             }
208              
209             } else {
210              
211 0           for my $i ( 0 .. @{ $rows->[0] } - 1 ) {
  0            
212 0           $widths->[$i] = 0;
213             }
214              
215 0           $header_separator = undef;
216              
217 0 0         $col_separator = ',' if ( $output_format eq 'csv' );
218 0 0         $col_separator = "\t" if ( $output_format eq 'tsv' );
219              
220             }
221              
222 0           my $format = join( $col_separator, map {"%-${_}s"} @{$widths} ) . "\n";
  0            
  0            
223 0           my $table = '';
224              
225 0 0         if ($headers) {
226              
227 0           my $header_row = sprintf( $format, @{$headers} );
  0            
228 0           my $header_width = length($header_row);
229              
230 0           $table .= $header_row;
231              
232 0 0         if ($header_separator) {
233 0           $table .= sprintf( "%s\n", $header_separator x $header_width );
234             }
235              
236             }
237              
238 0           for my $row ( @{$rows} ) {
  0            
239 0 0         $table .= sprintf( $format, map { $_ || '' } @{$row} );
  0            
  0            
240             }
241              
242 0           return $table;
243              
244             }
245              
246             1;
247              
248             =pod
249              
250             =encoding UTF-8
251              
252              
253             =head1 NAME
254              
255             App::TenableSC::API - API application for App::TenableSC
256              
257              
258             =head1 SYNOPSIS
259              
260             use App::TenableSC::API;
261              
262             App::TenableSC::API->run;
263              
264              
265             =head1 DESCRIPTION
266              
267             This module provides Perl scripts easy way to interface the REST API of Tenable.sc
268             (SecurityCenter).
269              
270             For more information about the Tenable.sc (SecurityCenter) REST API follow the online documentation:
271              
272             L
273              
274              
275             =head1 METHODS
276              
277              
278             =head1 SUPPORT
279              
280             =head2 Bugs / Feature Requests
281              
282             Please report any bugs or feature requests through the issue tracker
283             at L.
284             You will be notified automatically of any progress on your issue.
285              
286             =head2 Source Code
287              
288             This is open source software. The code repository is available for
289             public review and contribution under the terms of the license.
290              
291             L
292              
293             git clone https://github.com/giterlizzi/perl-Net-SecurityCenter.git
294              
295              
296             =head1 AUTHOR
297              
298             =over 4
299              
300             =item * Giuseppe Di Terlizzi
301              
302             =back
303              
304              
305             =head1 LICENSE AND COPYRIGHT
306              
307             This software is copyright (c) 2018-2021 by Giuseppe Di Terlizzi.
308              
309             This is free software; you can redistribute it and/or modify it under
310             the same terms as the Perl 5 programming language system itself.
311              
312             =cut