chupacabra 0.0.4 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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