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__ |