kentaroi-okayu 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/.gitignore +6 -0
- data/LICENSE +20 -0
- data/README.rdoc +18 -0
- data/Rakefile +63 -0
- data/VERSION +1 -0
- data/bin/okayu +6 -0
- data/lib/app.rb +25 -0
- data/lib/app_dir.rb +29 -0
- data/lib/client.rb +210 -0
- data/lib/controllers/listeners_controller.rb +18 -0
- data/lib/controllers/live_controller.rb +82 -0
- data/lib/controllers/visitors_controller.rb +19 -0
- data/lib/controllers.rb +3 -0
- data/lib/cookie_thief.rb +172 -0
- data/lib/db/migrate/000_create_lives.rb +14 -0
- data/lib/db/migrate/001_create_comments.rb +22 -0
- data/lib/db/migrate/002_create_visitors.rb +15 -0
- data/lib/db/migrate/003_create_listeners.rb +15 -0
- data/lib/db/migrate/004_create_communities.rb +13 -0
- data/lib/db/migrate/005_create_listeners_lives.rb +12 -0
- data/lib/db/migrate/006_create_lives_visitors.rb +13 -0
- data/lib/factory.rb +16 -0
- data/lib/models/comment.rb +22 -0
- data/lib/models/community.rb +3 -0
- data/lib/models/listener.rb +5 -0
- data/lib/models/live.rb +6 -0
- data/lib/models/visitor.rb +5 -0
- data/lib/models.rb +23 -0
- data/lib/okayu.rb +10 -0
- data/lib/player_status.rb +16 -0
- data/lib/sample_msg +2 -0
- data/lib/thread_info.rb +32 -0
- data/lib/user_info.rb +49 -0
- data/lib/views/app_frame.rb +89 -0
- data/lib/views/color_dialog.rb +56 -0
- data/lib/views/colors.rb +168 -0
- data/lib/views/live_panel.rb +335 -0
- data/lib/views/login_dialog.rb +80 -0
- data/lib/views/main_panel.rb +50 -0
- data/lib/views.rb +11 -0
- data/logged_in_page +893 -0
- data/login_error_page +83 -0
- data/okayu.gemspec +126 -0
- data/tcp_log +0 -0
- data/test/client_test.rb +61 -0
- data/test/cookie_thief_test.rb +36 -0
- data/test/ie_cookie.txt +63 -0
- data/test/okayu_test.rb +8 -0
- data/test/player_status_test.rb +61 -0
- data/test/raw_player_status +2 -0
- data/test/raw_player_status_community_only +3 -0
- data/test/raw_player_status_notlogged_in +2 -0
- data/test/test_helper.rb +11 -0
- data/test/thread_info_test.rb +11 -0
- metadata +193 -0
data/.document
ADDED
data/.gitignore
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 Kentaro Imai
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
= okayu
|
2
|
+
|
3
|
+
Description goes here.
|
4
|
+
|
5
|
+
== Note on Patches/Pull Requests
|
6
|
+
|
7
|
+
* Fork the project.
|
8
|
+
* Make your feature addition or bug fix.
|
9
|
+
* Add tests for it. This is important so I don't break it in a
|
10
|
+
future version unintentionally.
|
11
|
+
* Commit, do not mess with rakefile, version, or history.
|
12
|
+
(if you want to have your own version, that is fine but
|
13
|
+
bump version in a commit by itself I can ignore when I pull)
|
14
|
+
* Send me a pull request. Bonus points for topic branches.
|
15
|
+
|
16
|
+
== Copyright
|
17
|
+
|
18
|
+
Copyright (c) 2009 Kentaro Imai. See LICENSE for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = "okayu"
|
8
|
+
gem.summary = %Q{A comment viewer for http://live.nicovideo.jp/}
|
9
|
+
gem.description = %Q{A comment viewer for http://live.nicovideo.jp/}
|
10
|
+
gem.email = "kentaroi@gmail.com"
|
11
|
+
gem.homepage = "http://github.com/kentaroi/okayu"
|
12
|
+
gem.authors = ["Kentaro Imai"]
|
13
|
+
gem.add_dependency "mechanize"
|
14
|
+
gem.add_dependency "nokogiri"
|
15
|
+
gem.add_dependency "facter"
|
16
|
+
gem.add_dependency "sqlite3-ruby"
|
17
|
+
gem.add_dependency "activerecord", ">=2.2.0"
|
18
|
+
gem.add_dependency "wxruby"
|
19
|
+
gem.add_development_dependency "thoughtbot-shoulda"
|
20
|
+
gem.add_development_dependency "redgreen"
|
21
|
+
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
22
|
+
end
|
23
|
+
rescue LoadError
|
24
|
+
puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
|
25
|
+
end
|
26
|
+
|
27
|
+
require 'rake/testtask'
|
28
|
+
Rake::TestTask.new(:test) do |test|
|
29
|
+
test.libs << 'lib' << 'test'
|
30
|
+
test.pattern = 'test/**/*_test.rb'
|
31
|
+
test.verbose = true
|
32
|
+
end
|
33
|
+
|
34
|
+
begin
|
35
|
+
require 'rcov/rcovtask'
|
36
|
+
Rcov::RcovTask.new do |test|
|
37
|
+
test.libs << 'test'
|
38
|
+
test.pattern = 'test/**/*_test.rb'
|
39
|
+
test.verbose = true
|
40
|
+
end
|
41
|
+
rescue LoadError
|
42
|
+
task :rcov do
|
43
|
+
abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
task :test => :check_dependencies
|
48
|
+
|
49
|
+
task :default => :test
|
50
|
+
|
51
|
+
require 'rake/rdoctask'
|
52
|
+
Rake::RDocTask.new do |rdoc|
|
53
|
+
if File.exist?('VERSION')
|
54
|
+
version = File.read('VERSION')
|
55
|
+
else
|
56
|
+
version = ""
|
57
|
+
end
|
58
|
+
|
59
|
+
rdoc.rdoc_dir = 'rdoc'
|
60
|
+
rdoc.title = "okayu #{version}"
|
61
|
+
rdoc.rdoc_files.include('README*')
|
62
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
63
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.0.1
|
data/bin/okayu
ADDED
data/lib/app.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
module Okayu
|
2
|
+
class App < Wx::App
|
3
|
+
def initialize
|
4
|
+
@teardowned = false
|
5
|
+
super()
|
6
|
+
end
|
7
|
+
|
8
|
+
|
9
|
+
def on_init
|
10
|
+
UserInfo.load
|
11
|
+
Okayu::connect_db
|
12
|
+
|
13
|
+
frame = AppFrame.new("おかゆ")
|
14
|
+
frame.show
|
15
|
+
end
|
16
|
+
|
17
|
+
def on_exit
|
18
|
+
unless @teardowned
|
19
|
+
UserInfo.save
|
20
|
+
@teardowned = true
|
21
|
+
puts "teardown!!"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
data/lib/app_dir.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'facter'
|
3
|
+
|
4
|
+
module Okayu
|
5
|
+
class AppDir
|
6
|
+
if Facter.value(:kernel) == 'Linux'
|
7
|
+
if File.exist?(@@app_dir = ENV['HOME'] + '/.okayu')
|
8
|
+
else
|
9
|
+
Dir.mkdir(@@app_dir)
|
10
|
+
end
|
11
|
+
elsif Facter.value(:kernel) == 'windows'
|
12
|
+
if Facter.value(:operatingsystemrelease).slice(/^\d*/).to_i < 6 # Before Vista
|
13
|
+
if File.exist?(@@app_dir = ENV['HOME'] + '/Local Settings/Application Data/okayu')
|
14
|
+
else
|
15
|
+
Dir.mkdir(@@app_dir)
|
16
|
+
end
|
17
|
+
else # From Vista
|
18
|
+
if File.exist?(@@app_dir = ENV['HOME'] + '/AppData/Local/okayu')
|
19
|
+
else
|
20
|
+
Dir.mkdir(@@app_dir)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.to_s
|
26
|
+
@@app_dir
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
data/lib/client.rb
ADDED
@@ -0,0 +1,210 @@
|
|
1
|
+
require 'singleton'
|
2
|
+
require 'rubygems'
|
3
|
+
require 'mechanize'
|
4
|
+
require 'thread'
|
5
|
+
require 'player_status.rb'
|
6
|
+
require 'thread_info.rb'
|
7
|
+
require 'ruby-debug'
|
8
|
+
|
9
|
+
class WWW::Mechanize::CookieJar
|
10
|
+
def load_cookie cookie
|
11
|
+
@jar = cookie
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
|
16
|
+
module Okayu
|
17
|
+
|
18
|
+
class Channel
|
19
|
+
attr_accessor :id, :player_status, :thread, :queue
|
20
|
+
def initialize
|
21
|
+
@queue = Queue.new
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
class Client
|
26
|
+
TOP_URL = 'http://www.nicovideo.jp/'
|
27
|
+
LOGIN_URL = 'https://secure.nicovideo.jp/secure/login?site=niconico'
|
28
|
+
PLAYER_STATUS_URL = 'http://live.nicovideo.jp/api/getplayerstatus?v='
|
29
|
+
@@channels = []
|
30
|
+
@@connected = false
|
31
|
+
|
32
|
+
class << self
|
33
|
+
def channels
|
34
|
+
@@channels
|
35
|
+
end
|
36
|
+
def connected?
|
37
|
+
@@connected
|
38
|
+
end
|
39
|
+
|
40
|
+
def agent
|
41
|
+
@@agent
|
42
|
+
end
|
43
|
+
|
44
|
+
def connect auth={}
|
45
|
+
@@agent = WWW::Mechanize.new
|
46
|
+
begin
|
47
|
+
if auth[:mail] && auth[:password]
|
48
|
+
@@login_page = @@agent.post(LOGIN_URL, 'mail' => auth[:mail], 'password' => auth[:password])
|
49
|
+
elsif auth[:cookie]
|
50
|
+
@@agent.cookie_jar.load_cookiestxt(auth[:cookie])
|
51
|
+
@@login_page = @@agent.get(TOP_URL)
|
52
|
+
end
|
53
|
+
|
54
|
+
if @@login_page
|
55
|
+
@@connected = true unless @@login_page.forms.first.name == 'login'
|
56
|
+
else
|
57
|
+
@@connected = false
|
58
|
+
end
|
59
|
+
rescue
|
60
|
+
@@connected = false
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def live_id_from_url url
|
65
|
+
if /lv\d+/ =~ url
|
66
|
+
$&
|
67
|
+
else
|
68
|
+
nil
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def open live_id, res_from=-200
|
73
|
+
if live_id
|
74
|
+
channel = Channel.new
|
75
|
+
channel.id = live_id
|
76
|
+
channel.player_status = get_player_status(live_id)
|
77
|
+
if channel.player_status.status
|
78
|
+
@@channels << channel
|
79
|
+
channel.thread = Thread.new(@@channels.index(channel), channel.player_status, res_from) do |index, ps, res_from|
|
80
|
+
begin
|
81
|
+
s = TCPSocket.open(ps.addr, ps.port)
|
82
|
+
s.print live_query_msg(ps.thread, res_from)
|
83
|
+
thread_info = ThreadInfo.new s.gets("\0")
|
84
|
+
while true
|
85
|
+
@@channels[index].queue.enq s.gets("\0").slice(0...-1)
|
86
|
+
end
|
87
|
+
ensure
|
88
|
+
s.close
|
89
|
+
end
|
90
|
+
end
|
91
|
+
self.new channel
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def send_comment live_id, comment, mail
|
97
|
+
if live_id
|
98
|
+
player_status = get_player_status(live_id)
|
99
|
+
if player_status.status
|
100
|
+
s = TCPSocket.open(player_status.addr, player_status.port)
|
101
|
+
s.print live_query_msg(player_status.thread, -0)
|
102
|
+
thread_info = ThreadInfo.new s.gets("\0")
|
103
|
+
postkey = get_postkey(thread_info)
|
104
|
+
s.print(send_comment_msg(comment, mail, player_status, thread_info, postkey))
|
105
|
+
s.close
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def get_player_status live_id
|
111
|
+
PlayerStatus.new(@@agent.get(PLAYER_STATUS_URL + live_id).body)
|
112
|
+
end
|
113
|
+
|
114
|
+
def live_query_msg thread, res_from
|
115
|
+
%Q[<thread thread="#{thread}" res_from="#{res_from}" version="20061206" />\0]
|
116
|
+
end
|
117
|
+
|
118
|
+
def postkey_url thread, last_res
|
119
|
+
block_no = last_res.to_i / 100
|
120
|
+
%Q[http://live.nicovideo.jp/api/getpostkey?thread=#{thread}&block_no=#{block_no}]
|
121
|
+
end
|
122
|
+
|
123
|
+
def get_postkey thread_info
|
124
|
+
postkey_page = @@agent.get(postkey_url(thread_info.thread, thread_info.last_res))
|
125
|
+
if /postkey=(.+)/ =~ postkey_page.body
|
126
|
+
$1
|
127
|
+
else
|
128
|
+
nil
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
def send_comment_msg comment, mail, player_status, thread_info, postkey
|
133
|
+
vpos = ((Time.new - Time.at(player_status.open_time.to_i)) * 100).to_i
|
134
|
+
%Q[<chat thread="#{thread_info.thread}" ticket="#{thread_info.ticket}" vpos="#{vpos}" postkey="#{postkey}" mail="#{mail}" user_id="#{player_status.user_id}" premium="#{player_status.is_premium}">#{comment}</chat>\0]
|
135
|
+
end
|
136
|
+
|
137
|
+
def close channel
|
138
|
+
index = @@channels.index(channel)
|
139
|
+
@@channels[index].thread.kill
|
140
|
+
@@channels[index] = nil
|
141
|
+
end
|
142
|
+
|
143
|
+
def close_all
|
144
|
+
@@channels.each do |channel|
|
145
|
+
channel.thread.kill
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
# instance methods
|
151
|
+
#
|
152
|
+
attr_reader :channel
|
153
|
+
def initialize channel
|
154
|
+
@channel = channel
|
155
|
+
end
|
156
|
+
|
157
|
+
def close
|
158
|
+
self.class.close @channel
|
159
|
+
end
|
160
|
+
|
161
|
+
def comments
|
162
|
+
comments = []
|
163
|
+
until @channel.queue.empty?
|
164
|
+
comments << @channel.queue.deq
|
165
|
+
end
|
166
|
+
comments.map{|comment| comment_hash_from_xml(comment)}
|
167
|
+
end
|
168
|
+
|
169
|
+
def comment_hash_from_xml xml
|
170
|
+
hash = Hash.new
|
171
|
+
reader = Nokogiri::XML::Reader(xml)
|
172
|
+
reader.read
|
173
|
+
if reader.name == 'chat'
|
174
|
+
hash[:commented_at] = Time.at(reader.attribute('date').to_i)
|
175
|
+
hash[:mail] = reader.attribute('mail') || ''
|
176
|
+
hash[:number] = reader.attribute('no')
|
177
|
+
hash[:user_id] = reader.attribute('user_id')
|
178
|
+
case reader.attribute('premium')
|
179
|
+
when 1
|
180
|
+
hash[:premium] = true
|
181
|
+
hash[:owner] = false
|
182
|
+
hash[:command] = false
|
183
|
+
when 2
|
184
|
+
hash[:premium] = true
|
185
|
+
hash[:owner] = true
|
186
|
+
hash[:command] = true
|
187
|
+
when 3
|
188
|
+
hash[:premium] = true
|
189
|
+
hash[:owner] = true
|
190
|
+
hash[:command] = false
|
191
|
+
else
|
192
|
+
hash[:premium] = false
|
193
|
+
hash[:owner] = false
|
194
|
+
hash[:command] = false
|
195
|
+
end
|
196
|
+
reader.read
|
197
|
+
hash[:message] = reader.value
|
198
|
+
end
|
199
|
+
hash
|
200
|
+
end
|
201
|
+
|
202
|
+
def community
|
203
|
+
@channel.player_status.default_community
|
204
|
+
end
|
205
|
+
|
206
|
+
def base_time
|
207
|
+
Time.at(@channel.player_status.base_time.to_i)
|
208
|
+
end
|
209
|
+
end
|
210
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Okayu
|
2
|
+
class ListenersController
|
3
|
+
def self.set_color_index params
|
4
|
+
begin
|
5
|
+
listener = Listener.find params[:id]
|
6
|
+
listener.color_index = params[:color_index]
|
7
|
+
listener.save!
|
8
|
+
rescue
|
9
|
+
return false
|
10
|
+
end
|
11
|
+
true
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.unset_color_index params
|
15
|
+
self.set_color_index params
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
module Okayu
|
2
|
+
class LiveController
|
3
|
+
def initialize live_id
|
4
|
+
@live_id = live_id
|
5
|
+
if @client = Client.open(live_id)
|
6
|
+
@live_now = true
|
7
|
+
if @live = Live.find(:first, :conditions => {:live_id => @live_id})
|
8
|
+
@community = @live.community
|
9
|
+
else
|
10
|
+
@live = Live.new
|
11
|
+
@live.live_id = @live_id
|
12
|
+
@live.base_time = @client.base_time
|
13
|
+
unless @community = Community.find(:first, :conditions => {:community_id => @client.community})
|
14
|
+
@community = Community.new
|
15
|
+
@community.community_id = @client.community
|
16
|
+
@community.save
|
17
|
+
end
|
18
|
+
@live.community = @community
|
19
|
+
@live.save
|
20
|
+
end
|
21
|
+
else
|
22
|
+
@live_now = false
|
23
|
+
if @live = Live.find(:first, :conditions => {:live_id => @live_id})
|
24
|
+
@community = @live.community
|
25
|
+
else
|
26
|
+
@community = nil
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def valid?
|
32
|
+
!!@live
|
33
|
+
end
|
34
|
+
|
35
|
+
def live_now?
|
36
|
+
@live_now
|
37
|
+
end
|
38
|
+
|
39
|
+
|
40
|
+
def base_time
|
41
|
+
@live.base_time
|
42
|
+
end
|
43
|
+
|
44
|
+
def comments
|
45
|
+
@live.comments
|
46
|
+
end
|
47
|
+
|
48
|
+
def new_comments
|
49
|
+
if @live_now
|
50
|
+
@client.comments.map{|comment_hash|
|
51
|
+
if Comment.find :first, :conditions => {:live_id => @live_id, :number => comment_hash[:number]}
|
52
|
+
nil
|
53
|
+
else
|
54
|
+
comment = Comment.new(comment_hash)
|
55
|
+
comment.community = @community
|
56
|
+
comment.live = @live
|
57
|
+
if comment_hash[:user_id]
|
58
|
+
if visitor = Visitor.find(:first, :conditions => {:user_id => comment_hash[:user_id]})
|
59
|
+
comment.visitor = visitor
|
60
|
+
if visitor.listener
|
61
|
+
comment.listener = visitor.listener
|
62
|
+
end
|
63
|
+
else
|
64
|
+
comment.create_visitor(:user_id => comment_hash[:user_id])
|
65
|
+
end
|
66
|
+
end
|
67
|
+
comment.save
|
68
|
+
comment
|
69
|
+
end
|
70
|
+
}.compact
|
71
|
+
else
|
72
|
+
[]
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def close
|
77
|
+
if @live_now && @client
|
78
|
+
@client.close
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Okayu
|
2
|
+
class VisitorsController
|
3
|
+
def self.set_color_index params
|
4
|
+
begin
|
5
|
+
visitor = Visitor.find params[:id]
|
6
|
+
visitor.color_index = params[:color_index]
|
7
|
+
visitor.save!
|
8
|
+
rescue
|
9
|
+
return false
|
10
|
+
end
|
11
|
+
true
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.unset_color_index params
|
15
|
+
self.set_color_index params
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
data/lib/controllers.rb
ADDED
data/lib/cookie_thief.rb
ADDED
@@ -0,0 +1,172 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'sqlite3'
|
3
|
+
|
4
|
+
module Okayu
|
5
|
+
class CookieThief
|
6
|
+
class << self
|
7
|
+
def get args
|
8
|
+
cookiestxt_from_array(send_query(sql_from_hash(args)))
|
9
|
+
end
|
10
|
+
|
11
|
+
def send_query sql
|
12
|
+
db = SQLite3::Database.new(cookies_filename)
|
13
|
+
cookie_array = db.execute(sql).first
|
14
|
+
db.close
|
15
|
+
cookie_array
|
16
|
+
end
|
17
|
+
|
18
|
+
def cookiestxt_from_array cookie_array
|
19
|
+
if cookie_array
|
20
|
+
cookie_array[1] = 'TRUE'
|
21
|
+
cookie_array[3] = cookie_array[3] != '0' ? 'TRUE' : 'FALSE'
|
22
|
+
cookie_array.join("\t") + "\n"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
class IECookieThief < Okayu::CookieThief
|
29
|
+
class << self
|
30
|
+
def get args
|
31
|
+
cookies = []
|
32
|
+
if args[:host]
|
33
|
+
cookie_filenames(args[:host]).map do |cookie_filename|
|
34
|
+
cookies = cookies_from_cookie_file(cookie_filename)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
if args[:name]
|
39
|
+
cookies = select_by_name(cookies, args[:name])
|
40
|
+
end
|
41
|
+
cookies.join("\n")
|
42
|
+
end
|
43
|
+
|
44
|
+
def select_by_name cookies, name
|
45
|
+
cookies.select{|cookie|cookie.split("\t")[5] == name}
|
46
|
+
end
|
47
|
+
|
48
|
+
def cookies_from_cookie_file filename
|
49
|
+
cookies = []
|
50
|
+
File.open filename, 'r' do |f|
|
51
|
+
cookies = cookies_from_cookies_string(f.read)
|
52
|
+
end
|
53
|
+
cookies
|
54
|
+
end
|
55
|
+
|
56
|
+
def cookies_from_cookies_string str
|
57
|
+
str.split(/^\*\n/m).map{|s|cookie_from_cookie_string(s)}
|
58
|
+
end
|
59
|
+
|
60
|
+
def cookie_from_cookie_string str
|
61
|
+
a = str.split(/\n/m)
|
62
|
+
name = a[0]
|
63
|
+
value = a[1]
|
64
|
+
host = "." + a[2].sub(%r{/.*$}, '')
|
65
|
+
path = "/" + a[2].sub(%r{^.*/}, '')
|
66
|
+
expiry = ((10**-7) * (a[4].to_i * (2**32) + a[3].to_i) - 11644473600).to_i # 11644473600 is midnight January 1, 1970
|
67
|
+
"#{host}\tTRUE\t#{path}\tTRUE\t#{expiry}\t#{name}\t#{value}"
|
68
|
+
end
|
69
|
+
|
70
|
+
def cookie_filenames host
|
71
|
+
cookie_filename = []
|
72
|
+
case Facter.value(:kernel)
|
73
|
+
when 'windows'
|
74
|
+
cookie_filenames = Dir.glob("#{ENV['HOME']}/AppData/Roaming/Microsoft/Windows/Cookies/Low/*").select{|path| path =~ /#{host_main_str(host)}/}
|
75
|
+
end
|
76
|
+
cookie_filenames
|
77
|
+
end
|
78
|
+
def host_main_str host
|
79
|
+
host_main_str = host.sub(/^\./, '').sub(/\..*$/, '')
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
class FirefoxCookieThief < Okayu::CookieThief
|
85
|
+
class << self
|
86
|
+
def sql_from_hash args
|
87
|
+
sql = "select host, isHttpOnly, path, isSecure, expiry, name, value from moz_cookies where "
|
88
|
+
sql << args.map{|key, value|"#{key.to_s} = '#{value}'"}.join(' and ')
|
89
|
+
sql << ';'
|
90
|
+
end
|
91
|
+
|
92
|
+
def cookies_filename
|
93
|
+
cookies_filename = nil
|
94
|
+
case Facter.value(:kernel)
|
95
|
+
when 'Linux'
|
96
|
+
if dir = Dir.glob("#{ENV['HOME']}/.mozilla/firefox/*").select{|path| path =~ /.*\.default$/}.first
|
97
|
+
if File.exist?("#{dir}/cookies.sqlite")
|
98
|
+
cookies_filename = "#{dir}/cookies.sqlite"
|
99
|
+
end
|
100
|
+
end
|
101
|
+
when 'windows'
|
102
|
+
if Facter.value(:operatingsystemrelease).to_i < 6 # before Vista
|
103
|
+
unless dir = Dir.glob("#{ENV['HOME']}/Application Data/Mozilla/Firefox/Profiles/*").select{|path| path =~ /.*\.default$/}.first
|
104
|
+
dir = Dir.glob("#{ENV['HOME']}/../Administrator/Application Data/Mozilla/Firefox/Profiles/*").select{|path| path =~ /.*\.default$/}.first
|
105
|
+
end
|
106
|
+
if dir && File.exist?("#{dir}/cookies.sqlite")
|
107
|
+
cookies_filename = "#{dir}/cookies.sqlite"
|
108
|
+
end
|
109
|
+
else # from Vista
|
110
|
+
if dir = Dir.glob("#{ENV['HOME']}/AppData/Roaming/Mozilla/Firefox/Profiles/*").select{|path| path =~ /.*\.default$/}.first
|
111
|
+
if File.exist?("#{dir}/cookies.sqlite")
|
112
|
+
cookies_filename = "#{dir}/cookies.sqlite"
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
cookies_filename
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
class ChromeCookieThief < Okayu::CookieThief
|
123
|
+
class << self
|
124
|
+
def cookies_filename
|
125
|
+
cookies_filename = nil
|
126
|
+
case Facter.value(:kernel)
|
127
|
+
when 'windows'
|
128
|
+
if Facter.value(:operatingsystemrelease).to_i < 6 # before Vista
|
129
|
+
if File.exist?(filename = "#{ENV['HOME']}/LocalApplication Data/Google/Chrome/User Data/Default/Cookies")
|
130
|
+
cookies_filename = filename
|
131
|
+
elsif File.exist?(filename = "#{ENV['HOME']}/../Administrator/LocalApplication Data/Google/Chrome/User Data/Default/Cookies")
|
132
|
+
cookies_filename = filename
|
133
|
+
end
|
134
|
+
else # from Vista
|
135
|
+
if File.exist?(filename = "#{ENV['HOME']}/AppData/Local/Google/Chrome/User Data/Default/Cookies")
|
136
|
+
cookies_filename = filename
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
cookies_filename
|
141
|
+
end
|
142
|
+
|
143
|
+
def sql_from_hash args
|
144
|
+
args = chrome_from_firefox(args)
|
145
|
+
sql = "select host_key, httponly, path, secure, expires_utc, name, value from cookies where "
|
146
|
+
sql << args.map{|key, value|"#{key.to_s} = '#{value}'"}.join(' and ')
|
147
|
+
sql << ';'
|
148
|
+
end
|
149
|
+
|
150
|
+
def chrome_from_firefox args
|
151
|
+
chrome_args = {}
|
152
|
+
args.each do |key, value|
|
153
|
+
case key
|
154
|
+
when :host
|
155
|
+
chrome_args[:host_key] = value
|
156
|
+
when :isHttpOnly
|
157
|
+
chrome_args[:httponly] = value
|
158
|
+
when :isSecure
|
159
|
+
chrome_args[:secure] = value
|
160
|
+
when :expiry
|
161
|
+
chrome_args[:expires_utc] = value
|
162
|
+
else
|
163
|
+
chrome_args[key] = value
|
164
|
+
end
|
165
|
+
end
|
166
|
+
chrome_args
|
167
|
+
end
|
168
|
+
|
169
|
+
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|