clockker 0.1.4 → 0.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a5917fe8052498f65072fe075093b1af5d725ea0
4
- data.tar.gz: 0c09c0cbb7b630660b8f0326ba799a5c08fea671
3
+ metadata.gz: c7404b361d1f21b145d39ff872ed9901c19f7944
4
+ data.tar.gz: 7af9d8d18fdbfaf1779250f579a24fa8ef7e57c7
5
5
  SHA512:
6
- metadata.gz: 4c674892ffb7178e58fa8430582014ae8d456e92dce3c303aa344f0e8c53cab6897298638b5b0c58a243beb6f4d8aa821ea0a58d639f3a22b9610d77d7574f2d
7
- data.tar.gz: efe5566b8355c97fc08f2015047aae7450231c39b8001e8658c582488a587afe388bfe75bcc33171b4392dac4936f519be0492c950d97a3e12c36924eff155c4
6
+ metadata.gz: 66432b991bcbd96026f1761bd87211afad2b626e47df12b9627367cb767574ea2eb34f255b58fca4e17c369970e4bcbd7b1327d95f8b0eb981283317d68c7bf8
7
+ data.tar.gz: 69bd52efc272a2fa17ed05893e234b81a533d148548c5a1da5bb1afbd215d84b76fac85fb7adda1775cae0eefe5096ff38de45e084bff90cc106ea06b1e5ece6
data/README.md CHANGED
@@ -8,6 +8,18 @@ Install it with:
8
8
 
9
9
  $ gem install clockker
10
10
 
11
+ To access your Safari history when using macOS Mojave (10.14) and higher, you must give the Terminal app "Full Disk Access".
12
+
13
+ 1. Settings
14
+ 2. Security & Privacy
15
+ 3. Privacy
16
+ 4. Full Disk Access
17
+ 5. <unlock>
18
+ 6. + to add
19
+ 7. Browse to find /Applications/Utilities/Terminal
20
+ 8. Quit and restart Terminal
21
+
22
+
11
23
  ## Usage
12
24
 
13
25
  Run it with:
@@ -68,6 +80,8 @@ After checking out the repo, run `bin/setup` to install dependencies. You can al
68
80
 
69
81
  To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
70
82
 
83
+ To run a development version run `bundle exec exe/clockker <params>`.
84
+
71
85
  ## Contributing
72
86
 
73
87
  Bug reports and pull requests are welcome on GitHub at https://github.com/liquidmedia/clockker. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
data/clockker.gemspec CHANGED
@@ -32,6 +32,7 @@ Gem::Specification.new do |spec|
32
32
 
33
33
  spec.add_dependency 'rb-fsevent', '>= 0.10.2'
34
34
  spec.add_dependency 'thor'
35
+ spec.add_dependency 'sqlite3'
35
36
 
36
37
  spec.add_development_dependency "bundler", "~> 1.15"
37
38
  spec.add_development_dependency "rake", "~> 10.0"
@@ -1,5 +1,5 @@
1
1
  module Clockker
2
- VERSION = "0.1.4"
2
+ VERSION = "0.1.5"
3
3
 
4
4
  def self.macos_version
5
5
  @mov ||= `sw_vers -productVersion`
@@ -1,6 +1,7 @@
1
1
  require 'rb-fsevent'
2
2
  require 'logger'
3
3
  require 'net/http'
4
+ require 'sqlite3'
4
5
 
5
6
  module Clockker
6
7
  class Watcher
@@ -9,21 +10,33 @@ module Clockker
9
10
 
10
11
  trap "INT" do
11
12
  @fsevent.stop
12
- # @watcher.kill # this also works, but the former is a bit more elegant
13
- @queue << :exit # this shuts down the submitter, first letting it submit its changeset
13
+ @timer.kill # the timer can just go away; it doesn't need a graceful shutdown.
14
+ @safari_watcher_queue << :exit
15
+ @submitter_queue << :exit # this shuts down the submitter, first letting it submit its changeset
14
16
  end
15
17
 
16
18
  white_black_list = WhiteBlackList.new(config)
17
19
 
18
- @queue = Queue.new
19
- @watcher = Thread.new { create_watcher('/', white_black_list, logger) }
20
+ @submitter_queue = Queue.new
21
+ @safari_watcher_queue = Queue.new
22
+ @timer = Thread.new { create_timer(@safari_watcher_queue) }
23
+ @file_watcher = Thread.new { create_file_watcher('/', white_black_list, logger) }
24
+ @safari_watcher = Thread.new { create_safari_watcher(logger) }
20
25
  @submitter = Thread.new { create_submitter(config.submit_frequency, config.region, config.token, config.identifier, logger, config.development) }
21
26
 
22
- @watcher.join
27
+ @file_watcher.join
28
+ @safari_watcher.join
23
29
  @submitter.join
24
30
  end
25
31
 
26
- def create_watcher(dir, white_black_list, logger)
32
+ def create_timer(*queues)
33
+ loop do
34
+ sleep 5
35
+ queues.each {|q| q << :run}
36
+ end
37
+ end
38
+
39
+ def create_file_watcher(dir, white_black_list, logger)
27
40
  @fsevent = FSEvent.new
28
41
  @fsevent.watch dir, {file_events: true} do |directories, event_meta|
29
42
  t = Time.now.utc
@@ -31,9 +44,9 @@ module Clockker
31
44
  event_meta['events'].each do |event|
32
45
  next if white_black_list.ignore?(event['path'])
33
46
  count += 1
34
- @queue << {created_at: t, event_id: event['id'], filepath: event['path'], flags: event['flags']}
47
+ @submitter_queue << {touched_at: t, contents: event['path'], type: "file", metadata: {flags: event['flags'], id: event['id']}}
35
48
  end
36
- logger.debug "#{Time.now} checked #{event_meta['numEvents']} events and added #{count} to the queue"
49
+ logger.debug "#{Time.now} checked #{event_meta['numEvents']} events and added #{count} to the submitter_queue"
37
50
  end
38
51
  logger.info "#{Time.now} now watching /"
39
52
  logger.info "#{Time.now} whitelist paths: #{white_black_list.whitelist}"
@@ -42,8 +55,50 @@ module Clockker
42
55
  logger.info "#{Time.now} fswatcher done"
43
56
  end
44
57
 
45
- def create_submitter(submit_frequency, region, token, identifier, logger, development)
46
- logger.info "#{Time.now} submitting to clockk.com #{"and localhost:4000 " if development}every #{submit_frequency} seconds with token #{token} from identifier #{identifier} with version #{Clockker.version}"
58
+ def create_safari_watcher(logger)
59
+ safari_db = SQLite3::Database.new(File.expand_path("~/Library/Safari/History.db"))
60
+ logger.info "#{Time.now} now watching Safari"
61
+ last_time = Time.now.to_i - 978307200 # convert to macOS Core Data time
62
+ loop do
63
+ submit_now = false
64
+ exit_now = false
65
+
66
+ value = @safari_watcher_queue.pop
67
+ case value
68
+ when :exit
69
+ submit_now = true
70
+ exit_now = true
71
+ when :run
72
+ # we just move forward
73
+ else
74
+ # On the off chance the message isn't :run
75
+ end
76
+
77
+ safari_db.execute("
78
+ SELECT hv.id, datetime(hv.visit_time+978307200, \"unixepoch\") as visited_at, hv.visit_time, hv.title, hi.url
79
+ FROM history_visits hv, history_items hi
80
+ WHERE hv.history_item=hi.id
81
+ AND hv.visit_time > #{last_time}
82
+ ORDER BY hv.visit_time ASC
83
+ ") do |row|
84
+ id, visited_at, visit_time, title, url = row
85
+ visited_at = Time.parse(visited_at+"Z") # the time is already UTC; let's make doubly sure!
86
+ # TODO check the whitelisted domain regexes to see if we can submit this one.
87
+ logger.info " - #{visited_at} - #{url} - #{title}"
88
+ @submitter_queue << {touched_at: visited_at, contents: url, type: "url", metadata: {title: title}}
89
+ last_time = visit_time
90
+ end
91
+
92
+ if exit_now
93
+ logger.info "#{Time.now} Safari watcher preparing to exit"
94
+ break
95
+ end
96
+ end
97
+ logger.info "#{Time.now} Safari watcher done"
98
+ end
99
+
100
+ def create_submitter(submit_frequency, region, token, identifier, logger, dev_mode)
101
+ logger.info "#{Time.now} submitting to clockk.com #{"and localhost:4000 " if dev_mode}every #{submit_frequency} seconds with token #{token} from identifier #{identifier} with version #{Clockker.version}"
47
102
  t_start = Time.now
48
103
  clockk_agent_uri = URI("https://#{region}.clockk.io/api/v1/agent/artifacts")
49
104
  clockk_local_uri = URI("http://localhost:4000/api/v1/agent/artifacts")
@@ -52,7 +107,7 @@ module Clockker
52
107
  submit_now = false
53
108
  exit_now = false
54
109
 
55
- value = @queue.pop
110
+ value = @submitter_queue.pop
56
111
  case value
57
112
  when :submit
58
113
  submit_now = true
@@ -68,29 +123,38 @@ module Clockker
68
123
  end
69
124
 
70
125
  if exit_now
71
- logger.info "#{Time.now} preparing to exit"
126
+ logger.info "#{Time.now} Submitter preparing to exit"
72
127
  end
73
128
 
74
- if submit_now
129
+ if submit_now && @changeset.length > 0
75
130
  logger.info "#{Time.now} submitting #{@changeset.length} items"
76
131
  @changeset.each_with_index do |cs, idx|
77
- logger.info " - #{idx} - #{cs[:created_at].strftime("%H:%M:%S")} #{cs[:filepath]}"
132
+ logger.info " - #{idx} - #{cs[:touched_at].strftime("%H:%M:%S")} #{cs[:contents]}"
78
133
  end
79
134
 
80
135
  begin
81
- data = {artifacts: @changeset.map{|c| {file_path: c[:filepath], touched_at: c[:created_at].strftime("%Y-%m-%d %H:%M:%S"), identifier: identifier, agent: Clockker.version}}}.to_json
136
+ dev_data = {artifacts: @changeset.map{|c| {contents: c[:contents], touched_at: c[:touched_at].strftime("%Y-%m-%d %H:%M:%S"), type: c[:type], metadata: c[:metadata], identifier: identifier, agent: Clockker.version}}}.to_json
137
+
138
+ # temporarily we're keeping the old data structure, until all of our APIs are up to date.
139
+ prod_data = @changeset.find_all{|c| c[:type] == "file"}
140
+ prod_data = {artifacts: prod_data.map{|c| {file_path: c[:contents], touched_at: c[:touched_at].strftime("%Y-%m-%d %H:%M:%S"), identifier: identifier, agent: Clockker.version}}}.to_json
141
+
82
142
  header = {"Authorization" => "Bearer #{token}", "Content-Type" => "application/json"}
83
143
 
144
+ # logger.info "PROD submission: #{prod_data.inspect}"
84
145
  Net::HTTP.start(clockk_agent_uri.hostname, clockk_agent_uri.port, use_ssl: clockk_agent_uri.scheme == 'https') do |http|
85
- http.post(clockk_agent_uri.path, data, header)
146
+ http.post(clockk_agent_uri.path, prod_data, header)
86
147
  end
87
148
 
88
- begin
89
- Net::HTTP.start(clockk_local_uri.hostname, clockk_local_uri.port, use_ssl: clockk_local_uri.scheme == 'https') do |http|
90
- http.post(clockk_local_uri.path, data, header)
149
+ if dev_mode
150
+ begin
151
+ # logger.info "DEV submission: #{dev_data.inspect}"
152
+ Net::HTTP.start(clockk_local_uri.hostname, clockk_local_uri.port, use_ssl: clockk_local_uri.scheme == 'https') do |http|
153
+ http.post(clockk_local_uri.path, dev_data, header)
154
+ end
155
+ rescue Exception => q
156
+ logger.info "#{Time.now} Failed to reach localhost:4000; ignoring"
91
157
  end
92
- rescue Exception => q
93
- logger.info "#{Time.now} Failed to reach localhost:4000; ignoring"
94
158
  end
95
159
 
96
160
  @changeset = []
@@ -102,7 +166,7 @@ module Clockker
102
166
  end
103
167
 
104
168
  if exit_now
105
- logger.info "#{Time.now} exiting"
169
+ logger.info "#{Time.now} Submitter done"
106
170
  break
107
171
  end
108
172
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: clockker
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.4
4
+ version: 0.1.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Paul Doerwald
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-10-02 00:00:00.000000000 Z
11
+ date: 2018-10-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rb-fsevent
@@ -38,6 +38,20 @@ dependencies:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: sqlite3
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
41
55
  - !ruby/object:Gem::Dependency
42
56
  name: bundler
43
57
  requirement: !ruby/object:Gem::Requirement