File Coverage

blib/lib/App/Spoor/LoginEntryParser.pm
Criterion Covered Total %
statement 30 30 100.0
branch 12 14 85.7
condition 3 3 100.0
subroutine 6 6 100.0
pod 1 1 100.0
total 52 54 96.3


line stmt bran cond sub pod time code
1             package App::Spoor::LoginEntryParser;
2              
3 2     2   637546 use v5.10;
  2         15  
4 2     2   12 use strict;
  2         4  
  2         38  
5 2     2   10 use warnings;
  2         3  
  2         104  
6              
7             =head1 NAME
8              
9             App::Spoor::LoginEntryParser
10              
11             =head1 VERSION
12              
13             Version 0.01
14              
15             =cut
16              
17             our $VERSION = '0.01';
18              
19             =head1 SYNOPSIS
20              
21             This package contains the necessary functionality to parse CPanel error log entries.
22              
23             =head1 SUBROUTINES/METHODS
24              
25             =head2 parse
26              
27             This subroutine accepts a single line from a CPanel login log (as a string) and returns a reference to a hash
28             representation of that entry.
29              
30             The hash representation contains the following elements:
31              
32             =over 2
33              
34             =item * type: This is hardcoded to 'login'
35              
36             =item * event: This is hardcoded to 'login'.
37              
38             =item * log_time: A DateTime instance representing the time of the log entry.
39              
40             =item * context: The context within which the operation is being performed can be either 'mailbox', 'domain' or 'system'.
41              
42             =item * scope: Can be one of 'webmaild', 'cpaneld' or 'whostmgrd'.
43              
44             =item * ip: The ip logging in.
45              
46             =item * status: Can be one of 'success', 'deferred' or 'failed'.
47              
48             =item * credential: The credential (email address/username) presented.
49              
50             =item * possessor: In the case of an email address being provided, the domain user to which it belongs.
51              
52             =item * message: This is only set if the entry contained additional info (generally on a non-successful login), e.g. "security token missing".
53              
54             =item * endpoint: HTTP-related information, only present on a non-successful login.
55              
56             =back
57              
58             =cut
59              
60             sub parse {
61 2     2   598 use DateTime::Format::Strptime;
  2         55496  
  2         20  
62              
63 12     12 1 3830 my $log_entry = shift;
64 12         44 my $date_parser = DateTime::Format::Strptime->new(pattern => '%Y-%m-%d %H:%M:%S %z', on_error => 'croak');
65 12         15542 my %response;
66 12 100       121 if ($log_entry =~ /
    50          
67             \A
68             \[(?<timestamp>[^\]]+)\]\s
69             info\s
70             \[(?<scope>[^\]]+)\]\s
71             (?<ip>\S+)\s
72             -\s(?<credential_string>[^-]+)\s-\s
73             SUCCESS
74             /x) {
75              
76             %response = (
77             type => 'login',
78             event => 'login',
79 1     1   693 log_time => $date_parser->parse_datetime($+{timestamp})->epoch(),
  1         410  
  1         414  
80             scope => $+{scope},
81             ip => $+{ip},
82 8         43 status => 'success',
83             );
84              
85 8 100       6484 if ($+{credential_string} =~ /\A(?<credential>\S+)\s\(possessor: (?<possessor>[^\)]+)\)/) {
86 4         19 $response{credential} = $+{credential};
87 4         21 $response{possessor} = $+{possessor};
88             } else {
89 4         18 $response{credential} = $+{credential_string};
90             }
91             } elsif ($log_entry =~ /
92             \A
93             \[(?<timestamp>[^\]]+)\]\s
94             info\s
95             \[(?<scope>[^\]]+)\]\s
96             (?<ip>\S+)\s
97             -\s(?<credential>[^-]+)\s
98             "(?<endpoint>[^"]+)"\s
99             (?<status>[A-Z]+)\s
100             [^:]+:\s(?<message>.+)
101             \Z
102             /x) {
103             %response = (
104             type => 'login',
105             event => 'login',
106             log_time => $date_parser->parse_datetime($+{timestamp})->epoch(),
107             scope => $+{scope},
108             ip => $+{ip},
109             status => lc($+{status}),
110             credential => $+{credential},
111             message => $+{message},
112             endpoint => $+{endpoint}
113 4         20 );
114             }
115              
116 12 100 100     3124 if ($response{scope} eq 'webmaild' && $response{credential} =~ /@/) {
    100          
    100          
    50          
117 2         7 $response{context} = 'mailbox';
118             } elsif ($response{scope} eq 'webmaild') {
119 2         18 $response{context} = 'domain';
120             } elsif ($response{scope} eq 'cpaneld') {
121 4         12 $response{context} = 'domain';
122             } elsif ($response{scope} eq 'whostmgrd') {
123 4         12 $response{context} = 'system';
124             }
125              
126 12         459 return \%response;
127             }
128              
129             =head1 AUTHOR
130              
131             Rory McKinley, C<< <rorymckinley at capefox.co> >>
132              
133             =head1 BUGS
134              
135             Please report any bugs or feature requests to C<bug-app-spoor at rt.cpan.org>, or through
136             the web interface at L<https://rt.cpan.org/NoAuth/ReportBug.html?Queue=App-Spoor>. I will be notified, and then you'll
137             automatically be notified of progress on your bug as I make changes.
138              
139              
140             =head1 SUPPORT
141              
142             You can find documentation for this module with the perldoc command.
143              
144             perldoc App::Spoor::LoginEntryParser
145              
146              
147             You can also look for information at:
148              
149             =over 4
150              
151             =item * RT: CPAN's request tracker (report bugs here)
152              
153             L<https://rt.cpan.org/NoAuth/Bugs.html?Dist=App-Spoor>
154              
155             =item * AnnoCPAN: Annotated CPAN documentation
156              
157             L<http://annocpan.org/dist/App-Spoor>
158              
159             =item * CPAN Ratings
160              
161             L<https://cpanratings.perl.org/d/App-Spoor>
162              
163             =item * Search CPAN
164              
165             L<https://metacpan.org/release/App-Spoor>
166              
167             =back
168              
169             =head1 LICENSE AND COPYRIGHT
170              
171             Copyright 2019 Rory McKinley.
172              
173             This program is free software; you can redistribute it and/or modify it
174             under the terms of the the Artistic License (2.0). You may obtain a
175             copy of the full license at:
176              
177             L<http://www.perlfoundation.org/artistic_license_2_0>
178              
179             Any use, modification, and distribution of the Standard or Modified
180             Versions is governed by this Artistic License. By using, modifying or
181             distributing the Package, you accept this license. Do not use, modify,
182             or distribute the Package, if you do not accept this license.
183              
184             If your Modified Version has been derived from a Modified Version made
185             by someone other than you, you are nevertheless required to ensure that
186             your Modified Version complies with the requirements of this license.
187              
188             This license does not grant you the right to use any trademark, service
189             mark, tradename, or logo of the Copyright Holder.
190              
191             This license includes the non-exclusive, worldwide, free-of-charge
192             patent license to make, have made, use, offer to sell, sell, import and
193             otherwise transfer the Package with respect to any patent claims
194             licensable by the Copyright Holder that are necessarily infringed by the
195             Package. If you institute patent litigation (including a cross-claim or
196             counterclaim) against any party alleging that the Package constitutes
197             direct or contributory patent infringement, then this Artistic License
198             to you shall terminate on the date that such litigation is filed.
199              
200             Disclaimer of Warranty: THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER
201             AND CONTRIBUTORS "AS IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES.
202             THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
203             PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY
204             YOUR LOCAL LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR
205             CONTRIBUTOR WILL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR
206             CONSEQUENTIAL DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE,
207             EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
208              
209             =cut
210              
211             1; # End of App::Spoor::LoginEntryParser