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 +4 -4
- data/bin/chupacabra +3 -3
- data/lib/chupacabra.rb +27 -5
- data/lib/chupacabra/storage.rb +24 -10
- data/lib/chupacabra/system.rb +40 -83
- data/lib/chupacabra/system/install.rb +62 -0
- data/lib/chupacabra/system/scripts.rb +121 -0
- data/lib/chupacabra/version.rb +1 -1
- data/lib/tasks/compile.rake +5 -0
- metadata +4 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9ec68bad383e9cceb15138495e74860362e0b12d
|
4
|
+
data.tar.gz: f24efc3d43cf7ff35f298592b0afc9a0de163142
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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 '
|
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'
|
data/lib/chupacabra/storage.rb
CHANGED
@@ -1,14 +1,32 @@
|
|
1
1
|
require 'pathname'
|
2
|
+
require 'fileutils'
|
2
3
|
|
3
4
|
module Chupacabra
|
4
5
|
class Storage
|
5
6
|
|
6
|
-
|
7
|
-
|
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
|
-
|
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.
|
40
|
-
Marshal.load(Crypto.decrypt(File.read(self.class.
|
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.
|
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
|
data/lib/chupacabra/system.rb
CHANGED
@@ -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
|
-
|
33
|
+
System.execute("launchctl unsetenv #{password_variable}")
|
20
34
|
end
|
21
35
|
|
22
36
|
def get_clipboard
|
23
|
-
|
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
|
-
|
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
|
-
|
52
|
-
|
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(
|
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
|
-
|
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(
|
129
|
-
return
|
130
|
-
|
131
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
120
|
+
System.execute("launchctl getenv #{password_variable}", true).strip
|
164
121
|
end
|
165
122
|
|
166
123
|
def set_env_password(password)
|
167
|
-
|
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
|
+
|
data/lib/chupacabra/version.rb
CHANGED
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
|
+
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
|