File Coverage

blib/lib/Mojo/UserAgent/CookieJar/ChromeMacOS.pm
Criterion Covered Total %
statement 29 78 37.1
branch 0 20 0.0
condition 0 11 0.0
subroutine 10 17 58.8
pod 4 4 100.0
total 43 130 33.0


line stmt bran cond sub pod time code
1             package Mojo::UserAgent::CookieJar::ChromeMacOS;
2              
3 1     1   64097 use strict;
  1         23  
  1         28  
4 1     1   5 use warnings;
  1         2  
  1         32  
5 1     1   13 use v5.10;
  1         2  
6             our $VERSION = '0.02';
7              
8 1     1   517 use Mojo::Base 'Mojo::UserAgent::CookieJar';
  1         205286  
  1         11  
9              
10 1     1   5691 use Mojo::Cookie::Request;
  1         3  
  1         6  
11 1     1   1418 use DBI;
  1         16261  
  1         96  
12 1     1   924 use File::Temp qw/tempfile/;
  1         11050  
  1         65  
13 1     1   417 use File::Copy ();
  1         2183  
  1         31  
14 1     1   565 use PBKDF2::Tiny qw/derive/;
  1         1223  
  1         61  
15 1     1   618 use Crypt::CBC;
  1         7060  
  1         872  
16              
17             # default Chrome cookie file for MacOSx
18             has 'file' => sub {
19             return $ENV{HOME} . "/Library/Application Support/Google/Chrome/Default/Cookies";
20             };
21             has 'pass'; # for Linux
22              
23             # readonly
24       0 1   sub add {}
25       0 1   sub collect {}
26              
27             sub find {
28 0     0 1   my ($self, $url) = @_;
29              
30 0 0         return [] unless my $domain = my $host = $url->ihost;
31              
32 0           my $salt = 'saltysalt';
33 0           my $iv = ' ' x 16;
34 0           my $salt_len = 16;
35 0           my $pass = $self->_get_pass();
36 0           my $iterations = 1003;
37 0 0         $iterations = 1 if $pass eq 'peanuts'; # Linux
38 0           my $key = derive( 'SHA-1', $pass, $salt, $iterations, $salt_len );
39 0           my $cipher = Crypt::CBC->new(
40             -cipher => 'Crypt::OpenSSL::AES',
41             -key => $key,
42             -keysize => 16,
43             -iv => $iv,
44             -header => 'none',
45             -literal_key => 1,
46             );
47              
48 0           my @found;
49 0           my $dbh = $self->__get_dbh;
50              
51 0           my $path = $url->path->to_abs_string;
52 0           while ($domain) {
53 0 0         next if $domain eq 'com'; # skip bad
54 0           my $new = $self->{jar}{$domain} = [];
55              
56 0           my $sth = $dbh->prepare('SELECT * FROM cookies WHERE host_key = ? OR host_key = ?');
57 0           $sth->execute($domain, '.' . $domain);
58 0           while (my $row = $sth->fetchrow_hashref) {
59 0   0       my $value = $row->{value} || $row->{encrypted_value} || '';
60 0 0         if ( $value =~ /^v10/ ) {
61 0           $value =~ s/^v10//;
62 0           $value = $cipher->decrypt( $value );
63             }
64              
65 0           my $cookie = Mojo::Cookie::Request->new(name => $row->{name}, value => $value);
66 0           push @$new, $cookie;
67              
68             # Taste cookie (no care about expires since Chrome will handle it)
69 0 0 0       next if $row->{secure} && $url->protocol ne 'https';
70 0 0         next unless _path($row->{path}, $path);
71              
72 0           push @found, $cookie;
73             }
74             }
75             # Remove another part
76 0           continue { $domain =~ s/^[^.]*\.*// }
77              
78 0           return \@found;
79             }
80              
81             sub prepare {
82 0     0 1   my ($self, $tx) = @_;
83 0           my $req = $tx->req;
84 0           $req->cookies(@{$self->find($req->url)});
  0            
85             }
86              
87             sub __get_dbh {
88 0     0     my ($self) = @_;
89              
90 0           state $dbh;
91 0 0 0       return $dbh if $dbh && $dbh->ping;
92              
93             # copy to read
94 0           my ($fh, $filename) = tempfile();
95 0           File::Copy::copy($self->file, $filename);
96 0 0         my $sqlite_file = -e $filename ? $filename : $self->file; # make sure copy works
97              
98 0           $dbh = DBI->connect( "dbi:SQLite:dbname=" . $sqlite_file, '', '', {
99             sqlite_see_if_its_a_number => 1,
100             } );
101              
102 0           return $dbh;
103             }
104              
105             sub _get_pass {
106 0     0     my ($self) = @_;
107              
108 0 0         return $self->pass if $self->pass; # for Linux which passed in ->new
109 0           my $pass = `security find-generic-password -w -s "Chrome Safe Storage"`;
110 0           chomp( $pass );
111 0           $self->pass($pass);
112              
113 0           return $pass;
114             }
115              
116             # copied from Mojo::UserAgent::CookieJar
117 0 0 0 0     sub _path { $_[0] eq '/' || $_[0] eq $_[1] || index($_[1], "$_[0]/") == 0 }
118              
119             1;
120             __END__