App-Spoor

 view release on metacpan or  search on metacpan

lib/App/Spoor/AccessEntryParser.pm  view on Meta::CPAN

use utf8;

=head1 NAME

App::Spoor::AccessEntryParser

=head1 VERSION

Version 0.02

=cut

our $VERSION = '0.02';


=head1 SYNOPSIS

This package contains the necessary functionality to parse CPanel access log entries.

=head1 SUBROUTINES/METHODS

=head2 parse

This subroutine accepts a single line from a CPanel access log (as a string) and returns a reference to a hash 
representation of that entry.

The hash representation contains the following elements when the entry could be successfully parsed:

=over 2

=item * type: This is hardcoded to 'access'

=item * log_time: A DateTime instance representing the time of the log entry

=item * event: A description of the event that the entry refers to - can be one of forward_added_partial_ip, forward_removed, unrecognised.

=item * ip: The IP address listed in the entry

=item * credential: The user performing the request

=item * context: The context within which the operation is being performed can be either 'mailbox' or 'unrecognised'

=item * status: The status of the request can be one of 'success' or 'failed'

=back

If the entry could not be successfully parsed, it will contain the following items:

=over 2

=item * type: This is hardcoded to 'access'

=item * event: This is hardcoded to 'unrecognised'.

=back

=cut

sub parse {
  use DateTime::Format::Strptime;
  use URI::Escape qw( uri_unescape );

  my $log_entry = shift; 
  my $level;
  my $event;
  my $status;
  my $forward_recipient;
  my %result;
  my $date_parser = DateTime::Format::Strptime->new(pattern => '%m/%d/%Y:%H:%M:%S %z', on_error => 'croak');

  if ($log_entry =~ /
    \A
    (?<ip>\S+)\s
    -\s
    (?<username>.+)\s
    \[(?<timestamp>[^\]]+)\]\s
    "(?<http_request>[^"]+)"\s
    (?<response_code>\d{3})\s
  /x) {
    my $log_time = $date_parser->parse_datetime($+{timestamp})->epoch();
    my $credential = uri_unescape($+{username});
    my $ip = $+{ip};
    my $http_request = $+{http_request};
    my $response_code = $+{response_code};

    if ($credential =~ /@/) {
      $level = 'mailbox';
    } else {
      $level = 'unrecognised';
    }

    if ($response_code eq '200') {
      $status = 'success';
    } else {
      $status = 'failed';
    }

    if ($credential =~ /@/ && $http_request =~ /\APOST.+doaddfwd.html/) {
      $event = 'forward_added_partial_ip';
    } elsif (
      $credential =~ /@/ &&
      $http_request =~ /\AGET.+dodelfwd.html\?.*emaildest=(?<forward_recipient>[^\s?]+)/
    ) {
      $event = 'forward_removed';
      $forward_recipient = uri_unescape($+{forward_recipient});
    } else {
      $event = 'unrecognised';
    }

    %result = (
      type => 'access',
      log_time => $log_time,
      event => $event,
      ip => $ip,
      credential => $credential,
      context => $level,
      status => $status,
    );

    $result{forward_recipient} = $forward_recipient if($forward_recipient);
  } else {
    %result = (
      type  => 'access',
      event => 'unrecognised',
    );
  }

  \%result;
}

=head1 AUTHOR

Rory McKinley, C<< <rorymckinley at capefox.co> >>

=head1 BUGS

Please report any bugs or feature requests to C<bug-app-spoor at rt.cpan.org>, or through
the web interface at L<https://rt.cpan.org/NoAuth/ReportBug.html?Queue=App-Spoor>.  I will be notified, and then you'll
automatically be notified of progress on your bug as I make changes.

=head1 SUPPORT

You can find documentation for this module with the perldoc command.

    perldoc App::Spoor::AccessEntryParser

You can also look for information at:

=over 4

=item * RT: CPAN's request tracker (report bugs here)

L<https://rt.cpan.org/NoAuth/Bugs.html?Dist=App-Spoor>

=item * AnnoCPAN: Annotated CPAN documentation

L<http://annocpan.org/dist/App-Spoor>

=item * CPAN Ratings

L<https://cpanratings.perl.org/d/App-Spoor>

=item * Search CPAN

L<https://metacpan.org/release/App-Spoor>



( run in 2.161 seconds using v1.01-cache-2.11-cpan-39bf76dae61 )