chupacabra 0.0.4 → 0.1.0

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: 292aa1a38a82238b386ed03e4285bc28ef45a9ff
4
- data.tar.gz: a6a88c629ed0f410d9c3a68c88d1196705d20b9e
3
+ metadata.gz: 9ec68bad383e9cceb15138495e74860362e0b12d
4
+ data.tar.gz: f24efc3d43cf7ff35f298592b0afc9a0de163142
5
5
  SHA512:
6
- metadata.gz: af9d4bf003b618e1807bccfbdf4798d6b46b1a6b2512941e92665e819a8255915fe42dbffc43c8427756df8a227bf82a67f3ec71dd098f7382379c28ef3814fb
7
- data.tar.gz: 71a86980d2a5236f0cf9f4e779984175f79277764eacfef2cbcfe82178d740108ddc43c724223b5c853e8fc1f3c5693be76ff60891379276416e5cf5422fd752
6
+ metadata.gz: 3e46a7c47897dc75e21840bbf7b164b578fb81e0fd847ba8c8ba93d9fd198bb0bf821f26a37c022fdded16b5116a238bb43ff3272e25e709b22f5e98667e567a
7
+ data.tar.gz: e50b37e32d503cfd6b8ee1ffbe21b3998f9fd372023f0fe186ce0e29ed1352d4d8cd679a2c0c103609548cc675d034318c059e6b02cab1f2807b0430b4b919a1
data/bin/chupacabra CHANGED
@@ -21,8 +21,8 @@ OptionParser.new do |opts|
21
21
  end
22
22
 
23
23
  opts.on("-i", "--install", "Install Apple service") do |port|
24
- Chupacabra::System.install
25
- puts "Service installed in #{Chupacabra::System.user_service_path}"
24
+ Chupacabra::System::Install.install
25
+ puts "Service installed in #{Chupacabra::System::Install.user_service_path}"
26
26
  puts ""
27
27
  puts "You can create keyboard shortcut with:"
28
28
  puts "System Preferences -> Keyboard -> Keyboard Shortcuts -> Services -> Chupacabra"
@@ -36,7 +36,7 @@ OptionParser.new do |opts|
36
36
  end
37
37
 
38
38
  opts.on("-u", "--uninstall", "Uninstall Apple service") do |port|
39
- Chupacabra::System.uninstall
39
+ Chupacabra::System::Install.uninstall
40
40
  puts "Service removed from #{Chupacabra::System.user_service_path}"
41
41
  exit
42
42
  end
data/lib/chupacabra.rb CHANGED
@@ -1,10 +1,10 @@
1
- require 'chupacabra/system'
2
- require 'chupacabra/crypto'
3
- require 'chupacabra/storage'
4
- require 'chupacabra/version'
1
+ require 'fileutils'
5
2
 
6
3
  module Chupacabra
7
4
  extend self
5
+
6
+ class Error < StandardError; end
7
+
8
8
  attr_accessor :env
9
9
  attr_accessor :log
10
10
 
@@ -30,6 +30,20 @@ module Chupacabra
30
30
  env == 'test'
31
31
  end
32
32
 
33
+ def root
34
+ Pathname.new(File.expand_path('../..', __FILE__))
35
+ end
36
+
37
+ def tmp_dir
38
+ dir = root + 'tmp'
39
+ dir.mkpath unless dir.exist?
40
+ dir
41
+ end
42
+
43
+ def clear_tmp
44
+ FileUtils.rm_rf(tmp_dir)
45
+ end
46
+
33
47
  private
34
48
 
35
49
  def output(text)
@@ -44,4 +58,12 @@ module Chupacabra
44
58
  return unless key
45
59
  "web: #{$1}" if key =~ /https?\:\/\/(?:www.)?([^\/\?]+)/
46
60
  end
47
- end
61
+ end
62
+
63
+ require 'chupacabra/system'
64
+ require 'chupacabra/system/scripts'
65
+ require 'chupacabra/system/install'
66
+ require 'chupacabra/crypto'
67
+ require 'chupacabra/storage'
68
+ require 'chupacabra/version'
69
+ require 'pathname'
@@ -1,14 +1,32 @@
1
1
  require 'pathname'
2
+ require 'fileutils'
2
3
 
3
4
  module Chupacabra
4
5
  class Storage
5
6
 
6
- def self.filepath
7
- Pathname.new(ENV['HOME']) + filename
7
+ class Error < Chupacabra::Error; end
8
+
9
+ def self.path
10
+ path = if Chupacabra.test?
11
+ Chupacabra.root + 'tmp' + '.chupacabra'
12
+ else
13
+ Pathname.new(ENV['HOME']) + '.chupacabra'
14
+ end
15
+ raise Error, 'Chupacabra path cant be a file' if path.file?
16
+ path.mkpath unless path.exist?
17
+ path
18
+ end
19
+
20
+ def self.passwords_path
21
+ path + 'pw'
8
22
  end
9
23
 
10
24
  def self.clear
11
- filepath.unlink if filepath.exist?
25
+ FileUtils.rm_rf(path)
26
+ end
27
+
28
+ def self.version_path
29
+ path + 'version'
12
30
  end
13
31
 
14
32
  def initialize(password)
@@ -30,21 +48,17 @@ module Chupacabra
30
48
 
31
49
  private
32
50
 
33
- def self.filename
34
- Chupacabra.test? ? '.chupacabra_test' : '.chupacabra'
35
- end
36
-
37
51
  def data
38
52
  @data ||=
39
- if File.exists?(self.class.filepath)
40
- Marshal.load(Crypto.decrypt(File.read(self.class.filepath), @password))
53
+ if File.exists?(self.class.passwords_path)
54
+ Marshal.load(Crypto.decrypt(File.read(self.class.passwords_path), @password))
41
55
  else
42
56
  { }
43
57
  end
44
58
  end
45
59
 
46
60
  def save
47
- File.open(self.class.filepath, 'w') do |file|
61
+ File.open(self.class.passwords_path, 'w') do |file|
48
62
  file << Crypto.encrypt(Marshal.dump(@data), @password)
49
63
  end
50
64
  end
@@ -7,6 +7,20 @@ module Chupacabra
7
7
  module System
8
8
  extend self
9
9
 
10
+ class Error < Chupacabra::Error; end
11
+
12
+ BROWSERS = ['Google Chrome', 'Google Chrome Canary', 'Camino', 'Safari', 'Webkit', 'Opera', 'Firefox']
13
+
14
+ def execute(command, run_in_test = false)
15
+ log(command)
16
+ if Chupacabra.test? && !run_in_test
17
+ `echo #{command}`
18
+ else
19
+ log(command)
20
+ `#{command}`
21
+ end.strip
22
+ end
23
+
10
24
  def get_password
11
25
  return get_env_password unless get_env_password.empty?
12
26
  password = Digest::SHA1.hexdigest(get_password_from_dialog)
@@ -16,16 +30,16 @@ module Chupacabra
16
30
  end
17
31
 
18
32
  def clear
19
- `launchctl unsetenv #{password_variable}` if osx?
33
+ System.execute("launchctl unsetenv #{password_variable}")
20
34
  end
21
35
 
22
36
  def get_clipboard
23
- `pbpaste`.strip
37
+ System.execute("pbpaste", true).strip
24
38
  end
25
39
 
26
40
  def set_clipboard(text)
27
41
  raise 'Unsupported string' if text =~ /'/
28
- `echo '#{text}' | pbcopy`
42
+ System.execute("echo '#{text}' | pbcopy", true)
29
43
  end
30
44
 
31
45
  def osx?
@@ -37,78 +51,24 @@ module Chupacabra
37
51
  end
38
52
 
39
53
  def front_app
40
- run_script(
41
- <<-EOS
42
- tell application "System Events"
43
- return name of first application process whose frontmost is true
44
- end tell
45
- EOS
46
- )
54
+ run_script(:script => :front_app)
47
55
  end
48
56
 
49
57
  def get_browser_url
50
58
  app = front_app
51
- run_script(
52
- case app
53
- when 'Google Chrome', 'Google Chrome Canary'
54
- %Q(tell application "#{app}" to return URL of active tab of front window)
55
- when 'Camino'
56
- %Q(tell application "#{app}" to return URL of current tab of front browser window)
57
- when 'Safari', 'Webkit', 'Opera'
58
- %Q(tell application "#{app}" to return URL of front document)
59
- when 'firefox'
60
- <<-EOS
61
- tell application "System Events"
62
- keystroke "l" using command down
63
- keystroke "c" using command down
64
- end tell
65
- delay 0.1
66
- return the clipboard
67
- EOS
68
- end
69
- )
59
+ return unless BROWSERS.include?(app)
60
+ run_script(:script => :get_browser_url, :compile_argument => app)
70
61
  end
71
62
 
72
63
  def paste_clipboard
73
- run_script(%Q{tell application "System Events" to keystroke "v" using command down})
64
+ run_script(:script => :paste_clipboard)
74
65
  end
75
66
 
76
67
  def alert(message)
77
- run_script(
78
- <<-EOS
79
- tell application "#{front_app}"
80
- activate
81
- display alert "#{message}" as warning
82
- end tell
83
- EOS
84
- )
85
- end
86
-
87
- def install
88
- user_service_contents = user_service_path + 'Contents'
89
- user_service_contents.mkpath unless user_service_contents.exist?
90
- chupacabra_service_contents = Pathname.new(
91
- File.expand_path('../../../osx/Chupacabra.workflow/Contents', __FILE__)
92
- )
93
-
94
- %w(document.wflow Info.plist).each do |filename|
95
- (user_service_contents + filename).open('w') do |file|
96
- file << (chupacabra_service_contents + filename).read
97
- end
98
- end
68
+ run_script(:script => :alert, :arguments => [front_app, message])
99
69
  end
100
70
 
101
- def uninstall
102
- FileUtils.rm_rf user_service_path
103
- end
104
71
 
105
- def user_service_path
106
- if Chupacabra.test?
107
- Pathname.new(ENV['HOME']) + 'Library/Services/Chupacabra_test.workflow'
108
- else
109
- Pathname.new(ENV['HOME']) + 'Library/Services/Chupacabra.workflow'
110
- end
111
- end
112
72
 
113
73
  def log(message)
114
74
  return unless Chupacabra.log
@@ -120,15 +80,23 @@ module Chupacabra
120
80
  end
121
81
 
122
82
  def log_path
123
- (Pathname.new(ENV['HOME']) + 'chupacabra.log')
83
+ if Chupacabra.test?
84
+ (Chupacabra.root + 'log' + 'chupacabra_test.log')
85
+ else
86
+ (Pathname.new(ENV['HOME']) + 'chupacabra.log')
87
+ end
124
88
  end
125
89
 
126
90
  private
127
91
 
128
- def run_script(script)
129
- return unless script
130
- raise ArgumentError, "Script can't contain single quotes" if script =~ /'/
131
- `osascript #{script.split("\n").collect{|line| " -e '#{line.strip}'"}.join}`.strip
92
+ def run_script(options ={})
93
+ return if Chupacabra.test? or !Chupacabra::System.osx?
94
+ script = options.fetch(:script)
95
+ compile_argument = options.fetch(:compile_argument, nil)
96
+ arguments = options.fetch(:arguments) { [] }
97
+ script_file = Chupacabra::System::Scripts.script_or_compile(script, compile_argument)
98
+ script = "osascript #{script_file} #{arguments.collect{ |arg| "'" + arg + "'" }.join(' ') }"
99
+ System.execute(script)
132
100
  end
133
101
 
134
102
  def password_variable
@@ -140,31 +108,20 @@ module Chupacabra
140
108
  end
141
109
 
142
110
  def strip_dialog_response(response)
143
- response.match(/text returned:(.+), button returned:OK/)[1]
111
+ System.log(response)
112
+ response.match(/.class ttxt.:(.+), .class bhit.:OK/)[1]
144
113
  end
145
114
 
146
115
  def ask_for_password
147
- dialog = 'display dialog "Enter Chupacabra password"' +
148
- 'default answer ""' +
149
- 'with title "Chupacabra"' +
150
- 'with icon caution with hidden answer'
151
-
152
- script = <<-EOS
153
- tell application "#{front_app}"
154
- activate
155
- #{dialog}
156
- end tell
157
- EOS
158
-
159
- run_script(script)
116
+ run_script(:script => :ask_for_password, :arguments => [front_app])
160
117
  end
161
118
 
162
119
  def get_env_password
163
- `launchctl getenv #{password_variable}`.strip
120
+ System.execute("launchctl getenv #{password_variable}", true).strip
164
121
  end
165
122
 
166
123
  def set_env_password(password)
167
- `launchctl setenv #{password_variable} '#{password}'`
124
+ System.execute("launchctl setenv #{password_variable} '#{password}'", true)
168
125
  end
169
126
  end
170
127
  end
@@ -0,0 +1,62 @@
1
+ module Chupacabra
2
+ module System
3
+ module Install
4
+ extend self
5
+
6
+ def install
7
+ handle_legacy_file
8
+ install_service
9
+ Chupacabra::System::Scripts.compile_all
10
+ update_version
11
+ end
12
+
13
+ def uninstall
14
+ FileUtils.rm_rf user_service_path
15
+ end
16
+
17
+ def user_service_path
18
+ if Chupacabra.test?
19
+ Chupacabra.root + 'tmp' + 'Library' + 'Services' + 'Chupacabra.workflow'
20
+ else
21
+ Pathname.new(ENV['HOME']) + 'Library/Services/Chupacabra.workflow'
22
+ end
23
+ end
24
+
25
+ private
26
+
27
+ def install_service
28
+ user_service_contents = user_service_path + 'Contents'
29
+ user_service_contents.mkpath unless user_service_contents.exist?
30
+ chupacabra_service_contents = Chupacabra.root + 'osx' + 'Chupacabra.workflow' + 'Contents'
31
+ %w(document.wflow Info.plist).each do |filename|
32
+ (user_service_contents + filename).open('w') do |file|
33
+ file << (chupacabra_service_contents + filename).read
34
+ end
35
+ end
36
+ end
37
+
38
+ def handle_legacy_file
39
+ return unless legacy_passwords_path.file?
40
+ legacy_passwords_path.rename(legacy_passwords_path_tmp)
41
+ legacy_passwords_path_tmp.rename(Chupacabra::Storage.passwords_path)
42
+ end
43
+
44
+ def update_version
45
+ Chupacabra::Storage.version_path.open('w') { |file| file << Chupacabra::VERSION }
46
+ end
47
+
48
+ def legacy_passwords_path
49
+ unless Chupacabra.test?
50
+ Pathname.new(ENV['HOME']) + '.chupacabra'
51
+ else
52
+ Chupacabra.tmp_dir + '.chupacabra'
53
+ end
54
+ end
55
+
56
+ def legacy_passwords_path_tmp
57
+ Pathname.new(legacy_passwords_path.to_s + '_tmp')
58
+ end
59
+
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,121 @@
1
+ module Chupacabra
2
+ module System
3
+ module Scripts
4
+ extend self
5
+
6
+ class Error < Chupacabra::System::Error; end
7
+
8
+ def compile_all
9
+ scripts_path.mkpath unless scripts_path.exist?
10
+ clear_scripts
11
+ [:front_app, :paste_clipboard, :alert, :ask_for_password].each do |script|
12
+ compile(script)
13
+ end
14
+ Chupacabra::System::BROWSERS.each do |browser|
15
+ compile(:get_browser_url, browser)
16
+ end
17
+ end
18
+
19
+ def compile(script, argument = nil)
20
+ script_body = self.send(*[script, argument].compact)
21
+ raise Error, 'Empty script to compile' if script_body.empty?
22
+ output = System.execute "osacompile -e '#{script_body}' -o #{script_file(script, argument)}"
23
+ if $?.success?
24
+ output
25
+ else
26
+ puts "Failed to compile: #{script_file(script, argument)}"
27
+ puts output
28
+ nil
29
+ end
30
+ end
31
+
32
+ def script_or_compile(script, argument = nil)
33
+ file = script_file(script, argument)
34
+ return file if File.exist?(file)
35
+ compile(script, argument) or raise "Can't compile #{script}#{' with argument ' + argument if argument}"
36
+ file
37
+ end
38
+
39
+ private
40
+
41
+ def front_app
42
+ <<-SCPT
43
+ tell application "System Events"
44
+ return name of first application process whose frontmost is true
45
+ end tell
46
+ SCPT
47
+ end
48
+
49
+ def get_browser_url(app)
50
+ return unless BROWSERS.include?(app)
51
+ case app
52
+ when 'Google Chrome', 'Google Chrome Canary'
53
+ %Q(tell application "#{app}" to return URL of active tab of front window)
54
+ when 'Camino'
55
+ %Q(tell application "#{app}" to return URL of current tab of front browser window)
56
+ when 'Safari', 'Webkit', 'Opera'
57
+ %Q(tell application "#{app}" to return URL of front document)
58
+ when 'Firefox'
59
+ <<-EOS
60
+ tell application "System Events"
61
+ keystroke "l" using command down
62
+ keystroke "c" using command down
63
+ end tell
64
+ delay 0.1
65
+ return the clipboard
66
+ EOS
67
+ else
68
+ raise Error, "Uknown browser: #{app}"
69
+ end
70
+ end
71
+
72
+
73
+ def paste_clipboard
74
+ <<-SCPT
75
+ tell application "System Events" to keystroke "v" using command down
76
+ SCPT
77
+ end
78
+
79
+ # Script requires two arguments: application name, message
80
+ def alert
81
+ <<-SCPT
82
+ on run argv
83
+ set _application to item 1 of argv
84
+ set _message to item 2 of argv
85
+ tell application _application
86
+ activate
87
+ display alert _message as warning
88
+ end tell
89
+ end run
90
+ SCPT
91
+ end
92
+
93
+ # Script requires argument: application name
94
+ def ask_for_password
95
+ <<-SCPT
96
+ on run argv
97
+ set _application to item 1 of argv
98
+ tell application _application
99
+ activate
100
+ display dialog "Enter Chupacabra password" default answer "" with title "Chupacabra password" with icon caution with hidden answer
101
+ end tell
102
+ end run
103
+ SCPT
104
+ end
105
+
106
+ def script_file(script, argument = nil)
107
+ argument = '_' + argument.downcase.gsub(/ /, '_') if argument
108
+ scripts_path + "#{script}#{argument}.scpt"
109
+ end
110
+
111
+ def scripts_path
112
+ Chupacabra::Storage.path + 'apple_scripts'
113
+ end
114
+
115
+ def clear_scripts
116
+ Dir.glob(scripts_path + '*').each{ |file| Pathname.new(file).delete }
117
+ end
118
+ end
119
+ end
120
+ end
121
+
@@ -1,3 +1,3 @@
1
1
  module Chupacabra
2
- VERSION = '0.0.4'
2
+ VERSION = '0.1.0'
3
3
  end
@@ -0,0 +1,5 @@
1
+ desc 'Compile AppleScripts'
2
+ task :compile do
3
+ require 'chupacabra'
4
+ Chupacabra::System::Scripts.compile_all
5
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: chupacabra
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dawid Sklodowski
@@ -62,9 +62,12 @@ files:
62
62
  - bin/chupacabra
63
63
  - lib/chupacabra/crypto.rb
64
64
  - lib/chupacabra/storage.rb
65
+ - lib/chupacabra/system/install.rb
66
+ - lib/chupacabra/system/scripts.rb
65
67
  - lib/chupacabra/system.rb
66
68
  - lib/chupacabra/version.rb
67
69
  - lib/chupacabra.rb
70
+ - lib/tasks/compile.rake
68
71
  - osx/Chupacabra.workflow/Contents/document.wflow
69
72
  - osx/Chupacabra.workflow/Contents/Info.plist
70
73
  homepage: http://github.com/dawid-sklodowski/chupacabra