shh 0.0.9 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/MIT-LICENSE +20 -20
- data/README.rdoc +95 -95
- data/bin/shh +5 -5
- data/lib/shh/cli.rb +16 -16
- data/lib/shh/clipboard.rb +13 -0
- data/lib/shh/crypt.rb +24 -24
- data/lib/shh/darwin10_clipboard.rb +4 -4
- data/lib/shh/darwin10_launcher.rb +5 -5
- data/lib/shh/entries_menu.rb +63 -64
- data/lib/shh/entry_menu.rb +101 -102
- data/lib/shh/prompt.rb +10 -10
- data/lib/shh/repository.rb +39 -39
- data/lib/shh/win32_clipboard.rb +6 -6
- data/lib/shh/win32_launcher.rb +5 -5
- data/lib/shh.rb +25 -25
- metadata +2 -1
data/MIT-LICENSE
CHANGED
@@ -1,20 +1,20 @@
|
|
1
|
-
Copyright (c) 2009 Mark Ryall
|
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.
|
1
|
+
Copyright (c) 2009 Mark Ryall
|
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
CHANGED
@@ -1,96 +1,96 @@
|
|
1
|
-
= SHH
|
2
|
-
|
3
|
-
Secret Squirrel
|
4
|
-
|
5
|
-
This is a command line utility for managing secure information such as accounts, passwords as individual files so that they can be easily managed in a version control repository.
|
6
|
-
|
7
|
-
You won't be hiding anything from the NSA with this level of encryption so it isn't recommended that you make your repository publicly accessible.
|
8
|
-
|
9
|
-
Now with more tab completion!
|
10
|
-
|
11
|
-
= Usage
|
12
|
-
|
13
|
-
Here you sit expectantly in front of a computer at the command line.
|
14
|
-
|
15
|
-
== Install
|
16
|
-
|
17
|
-
gem install shh
|
18
|
-
|
19
|
-
(you may need to install gemcutter first)
|
20
|
-
|
21
|
-
== Launch
|
22
|
-
|
23
|
-
Open all 'secrets' stored in ~/.secret
|
24
|
-
|
25
|
-
> shh
|
26
|
-
|
27
|
-
Opens all 'secrets' stored in foo/.secret
|
28
|
-
|
29
|
-
> shh foo
|
30
|
-
|
31
|
-
== Authenticate
|
32
|
-
|
33
|
-
Enter your passphrase
|
34
|
-
|
35
|
-
This passphrase will be used to encrypt and decrypt all of your secrets so don't make it too obvious.
|
36
|
-
|
37
|
-
== Listing mode
|
38
|
-
|
39
|
-
This mode allows you to view and edit 'entries' (which are encrypted hashes stored in files)
|
40
|
-
|
41
|
-
> list
|
42
|
-
|
43
|
-
bitbucket (260f34de-6779-4367-af2a-44184dec1cc1)
|
44
|
-
amazon (291a3e6c-2c7b-4960-a146-1f6635d9a74e)
|
45
|
-
yahoo (2fe408e7-7f2b-4dc0-854a-c92c21f131ae)
|
46
|
-
evernote (41ad0a21-eafc-4f70-9b0d-0251be207b9e)
|
47
|
-
gmail (8b35c1f2-851d-40fc-bd12-c2aad12c370a)
|
48
|
-
rememberthemilk (a499f612-d034-4e49-82a8-6967d29653a1)
|
49
|
-
|
50
|
-
* list -
|
51
|
-
* edit
|
52
|
-
* view
|
53
|
-
* quit
|
54
|
-
|
55
|
-
== Viewing mode
|
56
|
-
|
57
|
-
This mode allows you to view (but not edit) an existing entry
|
58
|
-
|
59
|
-
> view
|
60
|
-
(bitbucket) > list
|
61
|
-
id,name,password,username
|
62
|
-
(bitbucket) >
|
63
|
-
markryall
|
64
|
-
|
65
|
-
list keys, show key, copy key or quit? c password
|
66
|
-
|
67
|
-
* list - show entry keys
|
68
|
-
*
|
69
|
-
* copy
|
70
|
-
*
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
*
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
* Add
|
93
|
-
*
|
94
|
-
* Add multi line values (edit with default text editor)
|
95
|
-
* Include uuid as part of encryption key (and upgrade encryption on existing entries)
|
1
|
+
= SHH
|
2
|
+
|
3
|
+
Secret Squirrel
|
4
|
+
|
5
|
+
This is a command line utility for managing secure information such as accounts, passwords as individual files so that they can be easily managed in a version control repository.
|
6
|
+
|
7
|
+
You won't be hiding anything from the NSA with this level of encryption so it isn't recommended that you make your repository publicly accessible.
|
8
|
+
|
9
|
+
Now with more tab completion!
|
10
|
+
|
11
|
+
= Usage
|
12
|
+
|
13
|
+
Here you sit expectantly in front of a computer at the command line.
|
14
|
+
|
15
|
+
== Install
|
16
|
+
|
17
|
+
gem install shh
|
18
|
+
|
19
|
+
(you may need to install gemcutter first)
|
20
|
+
|
21
|
+
== Launch
|
22
|
+
|
23
|
+
Open all 'secrets' stored in ~/.secret
|
24
|
+
|
25
|
+
> shh
|
26
|
+
|
27
|
+
Opens all 'secrets' stored in foo/.secret
|
28
|
+
|
29
|
+
> shh foo
|
30
|
+
|
31
|
+
== Authenticate
|
32
|
+
|
33
|
+
Enter your passphrase
|
34
|
+
|
35
|
+
This passphrase will be used to encrypt and decrypt all of your secrets so don't make it too obvious.
|
36
|
+
|
37
|
+
== Listing mode
|
38
|
+
|
39
|
+
This mode allows you to view and edit 'entries' (which are encrypted hashes stored in files)
|
40
|
+
|
41
|
+
> list
|
42
|
+
|
43
|
+
bitbucket (260f34de-6779-4367-af2a-44184dec1cc1)
|
44
|
+
amazon (291a3e6c-2c7b-4960-a146-1f6635d9a74e)
|
45
|
+
yahoo (2fe408e7-7f2b-4dc0-854a-c92c21f131ae)
|
46
|
+
evernote (41ad0a21-eafc-4f70-9b0d-0251be207b9e)
|
47
|
+
gmail (8b35c1f2-851d-40fc-bd12-c2aad12c370a)
|
48
|
+
rememberthemilk (a499f612-d034-4e49-82a8-6967d29653a1)
|
49
|
+
|
50
|
+
* list - list entries
|
51
|
+
* edit,<name> - edit or create entry
|
52
|
+
* view,<name> - view entry
|
53
|
+
* quit
|
54
|
+
|
55
|
+
== Viewing mode
|
56
|
+
|
57
|
+
This mode allows you to view (but not edit) an existing entry
|
58
|
+
|
59
|
+
> view,bitbucket
|
60
|
+
(bitbucket) > list
|
61
|
+
id,name,password,username
|
62
|
+
(bitbucket) > view,username
|
63
|
+
markryall
|
64
|
+
|
65
|
+
list keys, show key, copy key or quit? c password
|
66
|
+
|
67
|
+
* list - show entry keys
|
68
|
+
* view,<key> - view entry value on screen
|
69
|
+
* copy,<key> - copy entry value to clipboard
|
70
|
+
* launch,<key> - launch entry value in default browser (available if it starts with http)
|
71
|
+
* quit
|
72
|
+
|
73
|
+
== Editing mode
|
74
|
+
|
75
|
+
This mode is viewing mode plus some editing commands
|
76
|
+
|
77
|
+
> edit,bitbucket
|
78
|
+
(bitbucket) > edit,foo
|
79
|
+
Enter new value for foo
|
80
|
+
bar
|
81
|
+
(bitbucket) > delete,foo
|
82
|
+
|
83
|
+
* edit,<key> - edit or create key
|
84
|
+
* delete,<key> - remove a key
|
85
|
+
|
86
|
+
== Quitting mode
|
87
|
+
|
88
|
+
You don't want to be a quitter
|
89
|
+
|
90
|
+
= Future plans for world domination
|
91
|
+
|
92
|
+
* Add some color
|
93
|
+
* Add help
|
94
|
+
* Add multi line values (edit with default text editor)
|
95
|
+
* Include uuid as part of encryption key (and upgrade encryption on existing entries)
|
96
96
|
* add some source control (hg/git) commands
|
data/bin/shh
CHANGED
@@ -1,5 +1,5 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
|
3
|
-
$:.unshift File.dirname(__FILE__)+'/../lib'
|
4
|
-
require 'shh/cli'
|
5
|
-
Shh::Cli.execute(*ARGV)
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
$:.unshift File.dirname(__FILE__)+'/../lib'
|
4
|
+
require 'shh/cli'
|
5
|
+
Shh::Cli.execute(*ARGV)
|
data/lib/shh/cli.rb
CHANGED
@@ -1,16 +1,16 @@
|
|
1
|
-
require 'rubygems'
|
2
|
-
require 'shh/repository'
|
3
|
-
require 'shh/prompt'
|
4
|
-
require 'shh/entries_menu'
|
5
|
-
|
6
|
-
module Shh
|
7
|
-
class Cli
|
8
|
-
def self.execute *args
|
9
|
-
prompt = Prompt.new
|
10
|
-
passphrase = prompt.get('Enter your passphrase', :silent => true)
|
11
|
-
path = args.shift || ('~')
|
12
|
-
|
13
|
-
EntriesMenu.new(prompt, Repository.new(passphrase, path)).main_loop
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
1
|
+
require 'rubygems'
|
2
|
+
require 'shh/repository'
|
3
|
+
require 'shh/prompt'
|
4
|
+
require 'shh/entries_menu'
|
5
|
+
|
6
|
+
module Shh
|
7
|
+
class Cli
|
8
|
+
def self.execute *args
|
9
|
+
prompt = Prompt.new
|
10
|
+
passphrase = prompt.get('Enter your passphrase', :silent => true)
|
11
|
+
path = args.shift || ('~')
|
12
|
+
|
13
|
+
EntriesMenu.new(prompt, Repository.new(passphrase, path)).main_loop
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module Shh
|
2
|
+
def self.clipboard
|
3
|
+
if RUBY_PLATFORM =~ /mswin32/
|
4
|
+
require 'shh/win32_clipboard'
|
5
|
+
return Win32Clipboard.new
|
6
|
+
end
|
7
|
+
if RUBY_PLATFORM =~ /darwin10/
|
8
|
+
require 'shh/darwin10_clipboard'
|
9
|
+
return Darwin10Clipboard.new
|
10
|
+
end
|
11
|
+
nil
|
12
|
+
end
|
13
|
+
end
|
data/lib/shh/crypt.rb
CHANGED
@@ -1,25 +1,25 @@
|
|
1
|
-
require 'crypt/blowfish'
|
2
|
-
|
3
|
-
module Shh
|
4
|
-
class Crypt
|
5
|
-
def initialize passphrase
|
6
|
-
@blowfish = ::Crypt::Blowfish.new(passphrase)
|
7
|
-
end
|
8
|
-
|
9
|
-
def encrypt text, out_io
|
10
|
-
in_io = StringIO.new(text)
|
11
|
-
while l = in_io.read(8) do
|
12
|
-
while l.size < 8 do l += "\0" end
|
13
|
-
out_io.print @blowfish.encrypt_block(l)
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
def decrypt in_io
|
18
|
-
out_io = StringIO.new
|
19
|
-
while l = in_io.read(8) do
|
20
|
-
out_io.print @blowfish.decrypt_block(l)
|
21
|
-
end
|
22
|
-
out_io.string.gsub("\0",'')
|
23
|
-
end
|
24
|
-
end
|
1
|
+
require 'crypt/blowfish'
|
2
|
+
|
3
|
+
module Shh
|
4
|
+
class Crypt
|
5
|
+
def initialize passphrase
|
6
|
+
@blowfish = ::Crypt::Blowfish.new(passphrase)
|
7
|
+
end
|
8
|
+
|
9
|
+
def encrypt text, out_io
|
10
|
+
in_io = StringIO.new(text)
|
11
|
+
while l = in_io.read(8) do
|
12
|
+
while l.size < 8 do l += "\0" end
|
13
|
+
out_io.print @blowfish.encrypt_block(l)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def decrypt in_io
|
18
|
+
out_io = StringIO.new
|
19
|
+
while l = in_io.read(8) do
|
20
|
+
out_io.print @blowfish.decrypt_block(l)
|
21
|
+
end
|
22
|
+
out_io.string.gsub("\0",'')
|
23
|
+
end
|
24
|
+
end
|
25
25
|
end
|
@@ -1,5 +1,5 @@
|
|
1
|
-
class Darwin10Clipboard
|
2
|
-
def content= text
|
3
|
-
`echo "#{text}" | pbcopy`
|
4
|
-
end
|
1
|
+
class Darwin10Clipboard
|
2
|
+
def content= text
|
3
|
+
`echo "#{text}" | pbcopy`
|
4
|
+
end
|
5
5
|
end
|
@@ -1,5 +1,5 @@
|
|
1
|
-
class Darwin10Launcher
|
2
|
-
def launch text
|
3
|
-
`open #{text}`
|
4
|
-
end
|
5
|
-
end
|
1
|
+
class Darwin10Launcher
|
2
|
+
def launch text
|
3
|
+
`open #{text}`
|
4
|
+
end
|
5
|
+
end
|
data/lib/shh/entries_menu.rb
CHANGED
@@ -1,64 +1,63 @@
|
|
1
|
-
require 'uuidtools'
|
2
|
-
require 'readline'
|
3
|
-
require 'shh/entry_menu'
|
4
|
-
|
5
|
-
module Shh
|
6
|
-
class EntriesMenu
|
7
|
-
def initialize prompt, repository
|
8
|
-
@prompt, @repository = prompt, repository
|
9
|
-
refresh
|
10
|
-
end
|
11
|
-
|
12
|
-
def main_loop
|
13
|
-
prompt_text = 'shh > '
|
14
|
-
|
15
|
-
begin
|
16
|
-
while line = Readline.readline(prompt_text, true)
|
17
|
-
line.strip!
|
18
|
-
case line
|
19
|
-
when 'quit'
|
20
|
-
|
21
|
-
when 'refresh'
|
22
|
-
refresh
|
23
|
-
when 'list'
|
24
|
-
@entries.each {|entry| say entry }
|
25
|
-
when /^view
|
26
|
-
view $1
|
27
|
-
when /^edit
|
28
|
-
edit $1
|
29
|
-
end
|
30
|
-
puts
|
31
|
-
end
|
32
|
-
rescue Interrupt => e
|
33
|
-
exit
|
34
|
-
end
|
35
|
-
puts
|
36
|
-
end
|
37
|
-
|
38
|
-
def refresh
|
39
|
-
commands = ['list', 'refresh', 'quit']
|
40
|
-
@entries = []
|
41
|
-
@repository.each_entry do |entry|
|
42
|
-
@entries << "#{entry['name']} (#{entry['id']})"
|
43
|
-
commands << "edit
|
44
|
-
commands << "view
|
45
|
-
end
|
46
|
-
Readline.completion_proc = lambda do |text|
|
47
|
-
commands.grep( /^#{Regexp.escape(text)}/ ).sort
|
48
|
-
end
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
entry
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
end
|
1
|
+
require 'uuidtools'
|
2
|
+
require 'readline'
|
3
|
+
require 'shh/entry_menu'
|
4
|
+
|
5
|
+
module Shh
|
6
|
+
class EntriesMenu
|
7
|
+
def initialize prompt, repository
|
8
|
+
@prompt, @repository = prompt, repository
|
9
|
+
refresh
|
10
|
+
end
|
11
|
+
|
12
|
+
def main_loop
|
13
|
+
prompt_text = 'shh > '
|
14
|
+
|
15
|
+
begin
|
16
|
+
while line = Readline.readline(prompt_text, true)
|
17
|
+
line.strip!
|
18
|
+
case line
|
19
|
+
when 'quit'
|
20
|
+
return
|
21
|
+
when 'refresh'
|
22
|
+
refresh
|
23
|
+
when 'list'
|
24
|
+
@entries.sort.each {|entry| say entry }
|
25
|
+
when /^view,(.*)/
|
26
|
+
view $1
|
27
|
+
when /^edit,(.*)/
|
28
|
+
edit $1
|
29
|
+
end
|
30
|
+
puts
|
31
|
+
end
|
32
|
+
rescue Interrupt => e
|
33
|
+
exit
|
34
|
+
end
|
35
|
+
puts
|
36
|
+
end
|
37
|
+
|
38
|
+
def refresh
|
39
|
+
commands = ['list', 'refresh', 'quit']
|
40
|
+
@entries = []
|
41
|
+
@repository.each_entry do |entry|
|
42
|
+
@entries << "#{entry['name']} (#{entry['id']})"
|
43
|
+
commands << "edit,#{entry['name']}"
|
44
|
+
commands << "view,#{entry['name']}"
|
45
|
+
end
|
46
|
+
Readline.completion_proc = lambda do |text|
|
47
|
+
commands.grep( /^#{Regexp.escape(text)}/ ).sort
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def edit name
|
52
|
+
entry = @repository.find_entry(name)
|
53
|
+
entry ||= {'name' => name, 'id' => UUIDTools::UUID.random_create.to_s}
|
54
|
+
@repository.persist_entry EntryMenu.new(@prompt, entry).main_loop
|
55
|
+
refresh
|
56
|
+
end
|
57
|
+
|
58
|
+
def view name
|
59
|
+
EntryMenu.new(@prompt, @repository.find_entry(name), true).main_loop
|
60
|
+
refresh
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
data/lib/shh/entry_menu.rb
CHANGED
@@ -1,102 +1,101 @@
|
|
1
|
-
require 'shh'
|
2
|
-
|
3
|
-
module Shh
|
4
|
-
class EntryMenu
|
5
|
-
def initialize prompt, hash, read_only=false
|
6
|
-
@prompt, @hash, @read_only = prompt, hash, read_only
|
7
|
-
@clipboard = Shh.clipboard
|
8
|
-
@launcher = Shh.launcher
|
9
|
-
refresh
|
10
|
-
end
|
11
|
-
|
12
|
-
def main_loop
|
13
|
-
prompt_text = "shh:#{@hash['name']} > "
|
14
|
-
|
15
|
-
begin
|
16
|
-
while line = Readline.readline(prompt_text, true)
|
17
|
-
line.strip!
|
18
|
-
case line
|
19
|
-
when 'quit'
|
20
|
-
|
21
|
-
when 'list'
|
22
|
-
say(@hash.keys.sort.join(','))
|
23
|
-
when /^edit
|
24
|
-
edit $1
|
25
|
-
when /^copy
|
26
|
-
copy $1
|
27
|
-
when /^launch
|
28
|
-
launch $1
|
29
|
-
when /^delete
|
30
|
-
delete $1
|
31
|
-
when /^
|
32
|
-
|
33
|
-
end
|
34
|
-
end
|
35
|
-
rescue Interrupt => e
|
36
|
-
exit
|
37
|
-
end
|
38
|
-
|
39
|
-
puts
|
40
|
-
@hash
|
41
|
-
end
|
42
|
-
|
43
|
-
private
|
44
|
-
|
45
|
-
def can_copy? key
|
46
|
-
@clipboard and @hash[key]
|
47
|
-
end
|
48
|
-
|
49
|
-
def can_edit?
|
50
|
-
!@read_only
|
51
|
-
end
|
52
|
-
|
53
|
-
def can_launch? key
|
54
|
-
@launcher and @hash[key] =~ /^http
|
55
|
-
end
|
56
|
-
|
57
|
-
def
|
58
|
-
say(@hash[key]) if @hash[key]
|
59
|
-
end
|
60
|
-
|
61
|
-
def copy key
|
62
|
-
@clipboard.content = @hash[key] if can_copy?(key)
|
63
|
-
end
|
64
|
-
|
65
|
-
def edit key
|
66
|
-
if can_edit?
|
67
|
-
@hash[key] = new_value(key)
|
68
|
-
refresh
|
69
|
-
end
|
70
|
-
end
|
71
|
-
|
72
|
-
def delete key
|
73
|
-
if can_edit?
|
74
|
-
@hash.delete(key)
|
75
|
-
refresh
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
def launch key
|
80
|
-
@launcher.launch @hash[key] if can_launch?(key)
|
81
|
-
end
|
82
|
-
|
83
|
-
def refresh
|
84
|
-
commands = ['list', 'quit']
|
85
|
-
@hash.keys.each do |key|
|
86
|
-
commands << "edit
|
87
|
-
commands << "delete
|
88
|
-
commands << "
|
89
|
-
commands << "copy
|
90
|
-
commands << "launch
|
91
|
-
end
|
92
|
-
Readline.completion_proc = lambda do |text|
|
93
|
-
commands.grep( /^#{Regexp.escape(text)}/ ).sort
|
94
|
-
end
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
end
|
1
|
+
require 'shh'
|
2
|
+
|
3
|
+
module Shh
|
4
|
+
class EntryMenu
|
5
|
+
def initialize prompt, hash, read_only=false
|
6
|
+
@prompt, @hash, @read_only = prompt, hash, read_only
|
7
|
+
@clipboard = Shh.clipboard
|
8
|
+
@launcher = Shh.launcher
|
9
|
+
refresh
|
10
|
+
end
|
11
|
+
|
12
|
+
def main_loop
|
13
|
+
prompt_text = "shh:#{@hash['name']} > "
|
14
|
+
|
15
|
+
begin
|
16
|
+
while line = Readline.readline(prompt_text, true)
|
17
|
+
line.strip!
|
18
|
+
case line
|
19
|
+
when 'quit'
|
20
|
+
return @hash
|
21
|
+
when 'list'
|
22
|
+
say(@hash.keys.sort.join(','))
|
23
|
+
when /^edit,(.*)/
|
24
|
+
edit $1
|
25
|
+
when /^copy,(.*)/
|
26
|
+
copy $1
|
27
|
+
when /^launch,(.*)/
|
28
|
+
launch $1
|
29
|
+
when /^delete,(.*)/
|
30
|
+
delete $1
|
31
|
+
when /^view,(.*)/
|
32
|
+
view $1
|
33
|
+
end
|
34
|
+
end
|
35
|
+
rescue Interrupt => e
|
36
|
+
exit
|
37
|
+
end
|
38
|
+
|
39
|
+
puts
|
40
|
+
@hash
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def can_copy? key
|
46
|
+
@clipboard and @hash[key]
|
47
|
+
end
|
48
|
+
|
49
|
+
def can_edit?
|
50
|
+
!@read_only
|
51
|
+
end
|
52
|
+
|
53
|
+
def can_launch? key
|
54
|
+
@launcher and @hash[key] =~ /^http/
|
55
|
+
end
|
56
|
+
|
57
|
+
def view key
|
58
|
+
say(@hash[key]) if @hash[key]
|
59
|
+
end
|
60
|
+
|
61
|
+
def copy key
|
62
|
+
@clipboard.content = @hash[key] if can_copy?(key)
|
63
|
+
end
|
64
|
+
|
65
|
+
def edit key
|
66
|
+
if can_edit?
|
67
|
+
@hash[key] = new_value(key)
|
68
|
+
refresh
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def delete key
|
73
|
+
if can_edit?
|
74
|
+
@hash.delete(key)
|
75
|
+
refresh
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def launch key
|
80
|
+
@launcher.launch @hash[key] if can_launch?(key)
|
81
|
+
end
|
82
|
+
|
83
|
+
def refresh
|
84
|
+
commands = ['list', 'quit']
|
85
|
+
@hash.keys.each do |key|
|
86
|
+
commands << "edit,#{key}" if can_edit?
|
87
|
+
commands << "delete,#{key}" if can_edit?
|
88
|
+
commands << "view,#{key}"
|
89
|
+
commands << "copy,#{key}" if can_copy?(key)
|
90
|
+
commands << "launch,#{key}" if can_launch?(key)
|
91
|
+
end
|
92
|
+
Readline.completion_proc = lambda do |text|
|
93
|
+
commands.grep( /^#{Regexp.escape(text)}/ ).sort
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def new_value key
|
98
|
+
@prompt.get "Enter new value for #{key}", :silent => (key =~ /pass/)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
data/lib/shh/prompt.rb
CHANGED
@@ -1,11 +1,11 @@
|
|
1
|
-
require 'highline/import'
|
2
|
-
|
3
|
-
module Shh
|
4
|
-
class Prompt
|
5
|
-
def get text, params={}
|
6
|
-
return params[:value] if params[:value] and params[:value].size > 0
|
7
|
-
echo = params[:silent] ? false : true
|
8
|
-
ask(text) { |q| q.echo = echo }
|
9
|
-
end
|
10
|
-
end
|
1
|
+
require 'highline/import'
|
2
|
+
|
3
|
+
module Shh
|
4
|
+
class Prompt
|
5
|
+
def get text, params={}
|
6
|
+
return params[:value] if params[:value] and params[:value].size > 0
|
7
|
+
echo = params[:silent] ? false : true
|
8
|
+
ask(text) { |q| q.echo = echo }
|
9
|
+
end
|
10
|
+
end
|
11
11
|
end
|
data/lib/shh/repository.rb
CHANGED
@@ -1,39 +1,39 @@
|
|
1
|
-
require 'pathname2'
|
2
|
-
require 'yaml'
|
3
|
-
require 'shh/crypt'
|
4
|
-
|
5
|
-
module Shh
|
6
|
-
class Repository
|
7
|
-
attr_reader :folder
|
8
|
-
|
9
|
-
def initialize passphrase, path
|
10
|
-
@folder = Pathname.new(File.expand_path(path)) + '.secret'
|
11
|
-
@folder.mkdir_p
|
12
|
-
@crypt = Crypt.new(passphrase)
|
13
|
-
end
|
14
|
-
|
15
|
-
def each_entry
|
16
|
-
@folder.children.each do |child|
|
17
|
-
entry = load_entry(child)
|
18
|
-
yield entry if entry
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
def find_entry name
|
23
|
-
each_entry {|e| return e if e['name'] == name}
|
24
|
-
nil
|
25
|
-
end
|
26
|
-
|
27
|
-
def load_entry path
|
28
|
-
return nil if path.directory?
|
29
|
-
yaml = path.open('rb') {|io| @crypt.decrypt(io) }
|
30
|
-
entry = YAML::load(yaml)
|
31
|
-
return nil unless entry
|
32
|
-
path.basename.to_s == entry['id'] ? entry : nil
|
33
|
-
end
|
34
|
-
|
35
|
-
def persist_entry entry
|
36
|
-
(@folder + entry['id']).open('wb') {|io| @crypt.encrypt(entry.to_yaml, io) }
|
37
|
-
end
|
38
|
-
end
|
39
|
-
end
|
1
|
+
require 'pathname2'
|
2
|
+
require 'yaml'
|
3
|
+
require 'shh/crypt'
|
4
|
+
|
5
|
+
module Shh
|
6
|
+
class Repository
|
7
|
+
attr_reader :folder
|
8
|
+
|
9
|
+
def initialize passphrase, path
|
10
|
+
@folder = Pathname.new(File.expand_path(path)) + '.secret'
|
11
|
+
@folder.mkdir_p
|
12
|
+
@crypt = Crypt.new(passphrase)
|
13
|
+
end
|
14
|
+
|
15
|
+
def each_entry
|
16
|
+
@folder.children.each do |child|
|
17
|
+
entry = load_entry(child)
|
18
|
+
yield entry if entry
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def find_entry name
|
23
|
+
each_entry {|e| return e if e['name'] == name}
|
24
|
+
nil
|
25
|
+
end
|
26
|
+
|
27
|
+
def load_entry path
|
28
|
+
return nil if path.directory?
|
29
|
+
yaml = path.open('rb') {|io| @crypt.decrypt(io) }
|
30
|
+
entry = YAML::load(yaml)
|
31
|
+
return nil unless entry
|
32
|
+
path.basename.to_s == entry['id'] ? entry : nil
|
33
|
+
end
|
34
|
+
|
35
|
+
def persist_entry entry
|
36
|
+
(@folder + entry['id']).open('wb') {|io| @crypt.encrypt(entry.to_yaml, io) }
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
data/lib/shh/win32_clipboard.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
|
-
require 'win32/clipboard'
|
2
|
-
|
3
|
-
class Win32Clipboard
|
4
|
-
def content= text
|
5
|
-
Win32::Clipboard.set_data(text)
|
6
|
-
end
|
1
|
+
require 'win32/clipboard'
|
2
|
+
|
3
|
+
class Win32Clipboard
|
4
|
+
def content= text
|
5
|
+
Win32::Clipboard.set_data(text)
|
6
|
+
end
|
7
7
|
end
|
data/lib/shh/win32_launcher.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
|
-
class Win32Launcher
|
2
|
-
def launch text
|
3
|
-
`start #{text}`
|
4
|
-
end
|
5
|
-
end
|
1
|
+
class Win32Launcher
|
2
|
+
def launch text
|
3
|
+
`start #{text}`
|
4
|
+
end
|
5
|
+
end
|
data/lib/shh.rb
CHANGED
@@ -1,25 +1,25 @@
|
|
1
|
-
module Shh
|
2
|
-
def self.clipboard
|
3
|
-
if RUBY_PLATFORM =~ /mswin32/
|
4
|
-
require 'shh/win32_clipboard'
|
5
|
-
return Win32Clipboard.new
|
6
|
-
end
|
7
|
-
if RUBY_PLATFORM =~ /darwin10/
|
8
|
-
require 'shh/darwin10_clipboard'
|
9
|
-
return Darwin10Clipboard.new
|
10
|
-
end
|
11
|
-
nil
|
12
|
-
end
|
13
|
-
|
14
|
-
def self.launcher
|
15
|
-
if RUBY_PLATFORM =~ /mswin32/
|
16
|
-
require 'shh/win32_launcher'
|
17
|
-
return Win32Launcher.new
|
18
|
-
end
|
19
|
-
if RUBY_PLATFORM =~ /darwin10/
|
20
|
-
require 'shh/darwin10_launcher'
|
21
|
-
return Darwin10Launcher.new
|
22
|
-
end
|
23
|
-
nil
|
24
|
-
end
|
25
|
-
end
|
1
|
+
module Shh
|
2
|
+
def self.clipboard
|
3
|
+
if RUBY_PLATFORM =~ /mswin32/
|
4
|
+
require 'shh/win32_clipboard'
|
5
|
+
return Win32Clipboard.new
|
6
|
+
end
|
7
|
+
if RUBY_PLATFORM =~ /darwin10/
|
8
|
+
require 'shh/darwin10_clipboard'
|
9
|
+
return Darwin10Clipboard.new
|
10
|
+
end
|
11
|
+
nil
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.launcher
|
15
|
+
if RUBY_PLATFORM =~ /mswin32/
|
16
|
+
require 'shh/win32_launcher'
|
17
|
+
return Win32Launcher.new
|
18
|
+
end
|
19
|
+
if RUBY_PLATFORM =~ /darwin10/
|
20
|
+
require 'shh/darwin10_launcher'
|
21
|
+
return Darwin10Launcher.new
|
22
|
+
end
|
23
|
+
nil
|
24
|
+
end
|
25
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: shh
|
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
|
- Mark Ryall
|
@@ -64,6 +64,7 @@ extra_rdoc_files: []
|
|
64
64
|
|
65
65
|
files:
|
66
66
|
- lib/shh/cli.rb
|
67
|
+
- lib/shh/clipboard.rb
|
67
68
|
- lib/shh/crypt.rb
|
68
69
|
- lib/shh/darwin10_clipboard.rb
|
69
70
|
- lib/shh/darwin10_launcher.rb
|