shh 0.0.6 → 0.0.7
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.
- data/README.rdoc +89 -0
 - data/bin/shh +1 -1
 - data/lib/shh/cli.rb +8 -85
 - data/lib/shh/entries_menu.rb +63 -0
 - data/lib/shh/entry_menu.rb +60 -0
 - data/lib/shh/prompt.rb +11 -0
 - data/lib/shh/repository.rb +39 -0
 - metadata +6 -2
 
    
        data/README.rdoc
    CHANGED
    
    | 
         @@ -5,3 +5,92 @@ Secret Squirrel 
     | 
|
| 
       5 
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 
6 
     | 
    
         | 
| 
       7 
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 - show 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) > show username
         
     | 
| 
      
 63 
     | 
    
         
            +
              markryall
         
     | 
| 
      
 64 
     | 
    
         
            +
             
     | 
| 
      
 65 
     | 
    
         
            +
              list keys, show key, copy key or quit?  c password
         
     | 
| 
      
 66 
     | 
    
         
            +
             
     | 
| 
      
 67 
     | 
    
         
            +
            * list - show entry keys
         
     | 
| 
      
 68 
     | 
    
         
            +
            * show <key> - show entry value on screen
         
     | 
| 
      
 69 
     | 
    
         
            +
            * copy <key> - copy entry value to clipboard
         
     | 
| 
      
 70 
     | 
    
         
            +
            * quit
         
     | 
| 
      
 71 
     | 
    
         
            +
             
     | 
| 
      
 72 
     | 
    
         
            +
            == Editing mode
         
     | 
| 
      
 73 
     | 
    
         
            +
             
     | 
| 
      
 74 
     | 
    
         
            +
            This mode is viewing mode plus some editing commands
         
     | 
| 
      
 75 
     | 
    
         
            +
             
     | 
| 
      
 76 
     | 
    
         
            +
              > edit bitbucket
         
     | 
| 
      
 77 
     | 
    
         
            +
              (bitbucket) > edit foo
         
     | 
| 
      
 78 
     | 
    
         
            +
              Enter new value for foo
         
     | 
| 
      
 79 
     | 
    
         
            +
              bar
         
     | 
| 
      
 80 
     | 
    
         
            +
              (bitbucket) > delete foo
         
     | 
| 
      
 81 
     | 
    
         
            +
             
     | 
| 
      
 82 
     | 
    
         
            +
            * edit <key> - edit or create key
         
     | 
| 
      
 83 
     | 
    
         
            +
            * delete <key> - remove a key
         
     | 
| 
      
 84 
     | 
    
         
            +
             
     | 
| 
      
 85 
     | 
    
         
            +
            == Quitting mode
         
     | 
| 
      
 86 
     | 
    
         
            +
             
     | 
| 
      
 87 
     | 
    
         
            +
            You don't want to be a quitter
         
     | 
| 
      
 88 
     | 
    
         
            +
             
     | 
| 
      
 89 
     | 
    
         
            +
            = Future plans for world domination
         
     | 
| 
      
 90 
     | 
    
         
            +
             
     | 
| 
      
 91 
     | 
    
         
            +
            * Add some color
         
     | 
| 
      
 92 
     | 
    
         
            +
            * Add help
         
     | 
| 
      
 93 
     | 
    
         
            +
            * Launch applications for urls
         
     | 
| 
      
 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 
     | 
    
         
            +
            * add some source control (hg/git) commands
         
     | 
    
        data/bin/shh
    CHANGED
    
    
    
        data/lib/shh/cli.rb
    CHANGED
    
    | 
         @@ -1,93 +1,16 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            require 'rubygems'
         
     | 
| 
       2 
     | 
    
         
            -
            require ' 
     | 
| 
       3 
     | 
    
         
            -
            require ' 
     | 
| 
       4 
     | 
    
         
            -
            require ' 
     | 
| 
       5 
     | 
    
         
            -
            require 'yaml'
         
     | 
| 
       6 
     | 
    
         
            -
            require 'shh/crypt'
         
     | 
| 
       7 
     | 
    
         
            -
            require 'shh/clipboard'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'shh/repository'
         
     | 
| 
      
 3 
     | 
    
         
            +
            require 'shh/prompt'
         
     | 
| 
      
 4 
     | 
    
         
            +
            require 'shh/entries_menu'
         
     | 
| 
       8 
5 
     | 
    
         | 
| 
       9 
6 
     | 
    
         
             
            module Shh
         
     | 
| 
       10 
7 
     | 
    
         
             
              class Cli
         
     | 
| 
       11 
     | 
    
         
            -
                def execute *args
         
     | 
| 
       12 
     | 
    
         
            -
                   
     | 
| 
      
 8 
     | 
    
         
            +
                def self.execute *args
         
     | 
| 
      
 9 
     | 
    
         
            +
                  prompt = Prompt.new
         
     | 
| 
      
 10 
     | 
    
         
            +
                  passphrase = prompt.get('Enter your passphrase', :silent => true)
         
     | 
| 
      
 11 
     | 
    
         
            +
                  path = args.shift || ('~')
         
     | 
| 
       13 
12 
     | 
    
         | 
| 
       14 
     | 
    
         
            -
                   
     | 
| 
       15 
     | 
    
         
            -
                  @folder = path ? Pathname.new(path) : Pathname.new(File.expand_path('~'))+'.secret'
         
     | 
| 
       16 
     | 
    
         
            -
                  @folder.mkdir_p
         
     | 
| 
       17 
     | 
    
         
            -
                  @crypt = Crypt.new(passphrase)
         
     | 
| 
       18 
     | 
    
         
            -
                  @clipboard = Shh.clipboard
         
     | 
| 
       19 
     | 
    
         
            -
             
     | 
| 
       20 
     | 
    
         
            -
                  loop do
         
     | 
| 
       21 
     | 
    
         
            -
                    choose do |menu|
         
     | 
| 
       22 
     | 
    
         
            -
                      menu.layout = :menu_only
         
     | 
| 
       23 
     | 
    
         
            -
                      menu.shell  = true
         
     | 
| 
       24 
     | 
    
         
            -
                      menu.choice('list entries') { list }
         
     | 
| 
       25 
     | 
    
         
            -
                      menu.choice('edit entry') { |command, details| edit details }
         
     | 
| 
       26 
     | 
    
         
            -
                      menu.choice('view entry') { |command, details| view details }
         
     | 
| 
       27 
     | 
    
         
            -
                      menu.choice('quit') { exit }
         
     | 
| 
       28 
     | 
    
         
            -
                    end
         
     | 
| 
       29 
     | 
    
         
            -
                  end
         
     | 
| 
       30 
     | 
    
         
            -
                end
         
     | 
| 
       31 
     | 
    
         
            -
             
     | 
| 
       32 
     | 
    
         
            -
                def list
         
     | 
| 
       33 
     | 
    
         
            -
                  each_entry {|entry| say "#{entry['name']} (#{entry['id']})" }
         
     | 
| 
       34 
     | 
    
         
            -
                end
         
     | 
| 
       35 
     | 
    
         
            -
             
     | 
| 
       36 
     | 
    
         
            -
                def edit name=''
         
     | 
| 
       37 
     | 
    
         
            -
                  entry = find_entry(check_name(name))
         
     | 
| 
       38 
     | 
    
         
            -
                  entry ||= {'name' => check_name(name), 'id' => UUIDTools::UUID.random_create.to_s}
         
     | 
| 
       39 
     | 
    
         
            -
                  persist_entry prompt_loop(entry)
         
     | 
| 
       40 
     | 
    
         
            -
                end
         
     | 
| 
       41 
     | 
    
         
            -
             
     | 
| 
       42 
     | 
    
         
            -
                def view name=''
         
     | 
| 
       43 
     | 
    
         
            -
                  prompt_loop find_entry(check_name(name)), true
         
     | 
| 
       44 
     | 
    
         
            -
                end
         
     | 
| 
       45 
     | 
    
         
            -
             
     | 
| 
       46 
     | 
    
         
            -
            private
         
     | 
| 
       47 
     | 
    
         
            -
             
     | 
| 
       48 
     | 
    
         
            -
                def each_entry
         
     | 
| 
       49 
     | 
    
         
            -
                  @folder.children.each do |child|
         
     | 
| 
       50 
     | 
    
         
            -
                    yield load_entry(child)
         
     | 
| 
       51 
     | 
    
         
            -
                  end
         
     | 
| 
       52 
     | 
    
         
            -
                end
         
     | 
| 
       53 
     | 
    
         
            -
             
     | 
| 
       54 
     | 
    
         
            -
                def check_name name
         
     | 
| 
       55 
     | 
    
         
            -
                  name = ask('Enter the entry name') unless name.size > 0
         
     | 
| 
       56 
     | 
    
         
            -
                  name
         
     | 
| 
       57 
     | 
    
         
            -
                end
         
     | 
| 
       58 
     | 
    
         
            -
             
     | 
| 
       59 
     | 
    
         
            -
                def find_entry name
         
     | 
| 
       60 
     | 
    
         
            -
                  each_entry {|e| return e if e['name'] == name}
         
     | 
| 
       61 
     | 
    
         
            -
                  nil
         
     | 
| 
       62 
     | 
    
         
            -
                end
         
     | 
| 
       63 
     | 
    
         
            -
             
     | 
| 
       64 
     | 
    
         
            -
                def load_entry path
         
     | 
| 
       65 
     | 
    
         
            -
                  entry = path.open('rb') {|io| @crypt.decrypt(io) }
         
     | 
| 
       66 
     | 
    
         
            -
                  YAML::load(entry)
         
     | 
| 
       67 
     | 
    
         
            -
                end
         
     | 
| 
       68 
     | 
    
         
            -
             
     | 
| 
       69 
     | 
    
         
            -
                def persist_entry entry
         
     | 
| 
       70 
     | 
    
         
            -
                  (@folder + entry['id']).open('wb') {|io| @crypt.encrypt(entry.to_yaml, io) }
         
     | 
| 
       71 
     | 
    
         
            -
                end
         
     | 
| 
       72 
     | 
    
         
            -
             
     | 
| 
       73 
     | 
    
         
            -
                def prompt_loop hash, read_only=false
         
     | 
| 
       74 
     | 
    
         
            -
                  loop do
         
     | 
| 
       75 
     | 
    
         
            -
                    choose do |menu|
         
     | 
| 
       76 
     | 
    
         
            -
                      menu.layout = :menu_only
         
     | 
| 
       77 
     | 
    
         
            -
                      menu.shell  = true
         
     | 
| 
       78 
     | 
    
         
            -
                      menu.choice('edit key') { |command, name| hash[name] = new_value(name) } unless read_only
         
     | 
| 
       79 
     | 
    
         
            -
                      menu.choice('list keys') { say(hash.keys.sort.join(',')) }
         
     | 
| 
       80 
     | 
    
         
            -
                      menu.choice('show key') { |command, name| say(hash[name]) if hash[name] }
         
     | 
| 
       81 
     | 
    
         
            -
                      menu.choice('delete key') { |command, name| hash[name] = nil } unless read_only
         
     | 
| 
       82 
     | 
    
         
            -
                      menu.choice('copy key') { |command, name| @clipboard.content = hash[name] } if @clipboard
         
     | 
| 
       83 
     | 
    
         
            -
                      menu.choice('quit') { return hash }
         
     | 
| 
       84 
     | 
    
         
            -
                    end
         
     | 
| 
       85 
     | 
    
         
            -
                  end
         
     | 
| 
       86 
     | 
    
         
            -
                end
         
     | 
| 
       87 
     | 
    
         
            -
             
     | 
| 
       88 
     | 
    
         
            -
                def new_value name
         
     | 
| 
       89 
     | 
    
         
            -
                  echo = (name =~ /pass/) ? false : true
         
     | 
| 
       90 
     | 
    
         
            -
                  ask("Enter new value for #{name}") {|q| q.echo = echo }
         
     | 
| 
      
 13 
     | 
    
         
            +
                  EntriesMenu.new(prompt, Repository.new(passphrase, path)).main_loop
         
     | 
| 
       91 
14 
     | 
    
         
             
                end
         
     | 
| 
       92 
15 
     | 
    
         
             
              end
         
     | 
| 
       93 
16 
     | 
    
         
             
            end
         
     | 
| 
         @@ -0,0 +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 = ' > '
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                  begin
         
     | 
| 
      
 16 
     | 
    
         
            +
                    while line = Readline.readline(prompt_text, true).strip
         
     | 
| 
      
 17 
     | 
    
         
            +
                      case line
         
     | 
| 
      
 18 
     | 
    
         
            +
                        when 'quit'
         
     | 
| 
      
 19 
     | 
    
         
            +
                          return
         
     | 
| 
      
 20 
     | 
    
         
            +
                        when 'refresh'
         
     | 
| 
      
 21 
     | 
    
         
            +
                          refresh
         
     | 
| 
      
 22 
     | 
    
         
            +
                        when 'list'
         
     | 
| 
      
 23 
     | 
    
         
            +
                          list
         
     | 
| 
      
 24 
     | 
    
         
            +
                        when /^view (.*)/
         
     | 
| 
      
 25 
     | 
    
         
            +
                          view $1
         
     | 
| 
      
 26 
     | 
    
         
            +
                        when /^edit (.*)/
         
     | 
| 
      
 27 
     | 
    
         
            +
                          edit $1
         
     | 
| 
      
 28 
     | 
    
         
            +
                      end
         
     | 
| 
      
 29 
     | 
    
         
            +
                    end
         
     | 
| 
      
 30 
     | 
    
         
            +
                  rescue Interrupt => e
         
     | 
| 
      
 31 
     | 
    
         
            +
                    return
         
     | 
| 
      
 32 
     | 
    
         
            +
                  end
         
     | 
| 
      
 33 
     | 
    
         
            +
                end
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
                def refresh
         
     | 
| 
      
 36 
     | 
    
         
            +
                  commands = ['list', 'refresh', 'quit']
         
     | 
| 
      
 37 
     | 
    
         
            +
                  @repository.each_entry do |entry|
         
     | 
| 
      
 38 
     | 
    
         
            +
                    commands << "edit #{entry['name']}"
         
     | 
| 
      
 39 
     | 
    
         
            +
                    commands << "view #{entry['name']}"
         
     | 
| 
      
 40 
     | 
    
         
            +
                  end
         
     | 
| 
      
 41 
     | 
    
         
            +
                  Readline.completion_proc = lambda do |text|
         
     | 
| 
      
 42 
     | 
    
         
            +
                    commands.grep( /^#{Regexp.escape(text)}/ ).sort
         
     | 
| 
      
 43 
     | 
    
         
            +
                  end
         
     | 
| 
      
 44 
     | 
    
         
            +
                  Readline.completer_word_break_characters = ''
         
     | 
| 
      
 45 
     | 
    
         
            +
                end
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
                def list
         
     | 
| 
      
 48 
     | 
    
         
            +
                  @repository.each_entry {|entry| say "#{entry['name']} (#{entry['id']})" }
         
     | 
| 
      
 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
         
     | 
| 
         @@ -0,0 +1,60 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'shh/clipboard'
         
     | 
| 
      
 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 
     | 
    
         
            +
                  refresh
         
     | 
| 
      
 9 
     | 
    
         
            +
                end
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                def main_loop
         
     | 
| 
      
 12 
     | 
    
         
            +
                  prompt_text = "(#{@hash['name']}) > "
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
                  begin
         
     | 
| 
      
 15 
     | 
    
         
            +
                    while line = Readline.readline(prompt_text, true).strip
         
     | 
| 
      
 16 
     | 
    
         
            +
                      case line
         
     | 
| 
      
 17 
     | 
    
         
            +
                        when 'quit'
         
     | 
| 
      
 18 
     | 
    
         
            +
                          return @hash
         
     | 
| 
      
 19 
     | 
    
         
            +
                        when 'list'
         
     | 
| 
      
 20 
     | 
    
         
            +
                          say(@hash.keys.sort.join(','))
         
     | 
| 
      
 21 
     | 
    
         
            +
                        when /^edit (.*)/
         
     | 
| 
      
 22 
     | 
    
         
            +
                          name = $1
         
     | 
| 
      
 23 
     | 
    
         
            +
                          @hash[name] = new_value(name) unless @read_only
         
     | 
| 
      
 24 
     | 
    
         
            +
                        when /^copy (.*)/
         
     | 
| 
      
 25 
     | 
    
         
            +
                          name = $1
         
     | 
| 
      
 26 
     | 
    
         
            +
                          @clipboard.content = @hash[name] if @clipboard and @hash[name]
         
     | 
| 
      
 27 
     | 
    
         
            +
                        when /^delete (.*)/
         
     | 
| 
      
 28 
     | 
    
         
            +
                          name = $1
         
     | 
| 
      
 29 
     | 
    
         
            +
                          @hash.delete(name) unless @read_only
         
     | 
| 
      
 30 
     | 
    
         
            +
                        when /^show (.*)/
         
     | 
| 
      
 31 
     | 
    
         
            +
                          name = $1
         
     | 
| 
      
 32 
     | 
    
         
            +
                          say(@hash[name]) if @hash[name]
         
     | 
| 
      
 33 
     | 
    
         
            +
                      end
         
     | 
| 
      
 34 
     | 
    
         
            +
                    end
         
     | 
| 
      
 35 
     | 
    
         
            +
                  rescue Interrupt => e
         
     | 
| 
      
 36 
     | 
    
         
            +
                    return @hash
         
     | 
| 
      
 37 
     | 
    
         
            +
                  end
         
     | 
| 
      
 38 
     | 
    
         
            +
                end
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
            private
         
     | 
| 
      
 41 
     | 
    
         
            +
             
     | 
| 
      
 42 
     | 
    
         
            +
                def refresh
         
     | 
| 
      
 43 
     | 
    
         
            +
                  commands = ['list', 'quit']
         
     | 
| 
      
 44 
     | 
    
         
            +
                  @hash.keys.each do |key|
         
     | 
| 
      
 45 
     | 
    
         
            +
                    commands << "edit #{key}" unless @read_only
         
     | 
| 
      
 46 
     | 
    
         
            +
                    commands << "delete #{key}" unless @read_only
         
     | 
| 
      
 47 
     | 
    
         
            +
                    commands << "show #{key}"
         
     | 
| 
      
 48 
     | 
    
         
            +
                    commands << "copy #{key}"
         
     | 
| 
      
 49 
     | 
    
         
            +
                  end
         
     | 
| 
      
 50 
     | 
    
         
            +
                  Readline.completion_proc = lambda do |text|
         
     | 
| 
      
 51 
     | 
    
         
            +
                    commands.grep( /^#{Regexp.escape(text)}/ ).sort
         
     | 
| 
      
 52 
     | 
    
         
            +
                  end
         
     | 
| 
      
 53 
     | 
    
         
            +
                  Readline.completer_word_break_characters = ''
         
     | 
| 
      
 54 
     | 
    
         
            +
                end
         
     | 
| 
      
 55 
     | 
    
         
            +
             
     | 
| 
      
 56 
     | 
    
         
            +
                def new_value name
         
     | 
| 
      
 57 
     | 
    
         
            +
                  @prompt.get "Enter new value for #{name}", :silent => (name =~ /pass/)
         
     | 
| 
      
 58 
     | 
    
         
            +
                end
         
     | 
| 
      
 59 
     | 
    
         
            +
              end
         
     | 
| 
      
 60 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/shh/prompt.rb
    ADDED
    
    
| 
         @@ -0,0 +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
         
     | 
    
        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.0.7
         
     | 
| 
       5 
5 
     | 
    
         
             
            platform: ruby
         
     | 
| 
       6 
6 
     | 
    
         
             
            authors: 
         
     | 
| 
       7 
7 
     | 
    
         
             
            - Mark Ryall
         
     | 
| 
         @@ -9,7 +9,7 @@ autorequire: 
     | 
|
| 
       9 
9 
     | 
    
         
             
            bindir: bin
         
     | 
| 
       10 
10 
     | 
    
         
             
            cert_chain: []
         
     | 
| 
       11 
11 
     | 
    
         | 
| 
       12 
     | 
    
         
            -
            date: 2009-12- 
     | 
| 
      
 12 
     | 
    
         
            +
            date: 2009-12-26 00:00:00 +11:00
         
     | 
| 
       13 
13 
     | 
    
         
             
            default_executable: 
         
     | 
| 
       14 
14 
     | 
    
         
             
            dependencies: 
         
     | 
| 
       15 
15 
     | 
    
         
             
            - !ruby/object:Gem::Dependency 
         
     | 
| 
         @@ -67,6 +67,10 @@ files: 
     | 
|
| 
       67 
67 
     | 
    
         
             
            - lib/shh/clipboard.rb
         
     | 
| 
       68 
68 
     | 
    
         
             
            - lib/shh/crypt.rb
         
     | 
| 
       69 
69 
     | 
    
         
             
            - lib/shh/darwin10_clipboard.rb
         
     | 
| 
      
 70 
     | 
    
         
            +
            - lib/shh/entries_menu.rb
         
     | 
| 
      
 71 
     | 
    
         
            +
            - lib/shh/entry_menu.rb
         
     | 
| 
      
 72 
     | 
    
         
            +
            - lib/shh/prompt.rb
         
     | 
| 
      
 73 
     | 
    
         
            +
            - lib/shh/repository.rb
         
     | 
| 
       70 
74 
     | 
    
         
             
            - lib/shh/win32_clipboard.rb
         
     | 
| 
       71 
75 
     | 
    
         
             
            - lib/shh.rb
         
     | 
| 
       72 
76 
     | 
    
         
             
            - bin/shh
         
     |