clandestine 0.0.1 → 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/.gitignore +2 -9
- data/.rspec +2 -0
- data/README.md +30 -18
- data/Rakefile +0 -24
- data/bin/clandestine +1 -1
- data/clandestine.gemspec +3 -1
- data/lib/clandestine.rb +1 -9
- data/lib/clandestine/clandestine_error.rb +4 -0
- data/lib/clandestine/command_line_options.rb +52 -0
- data/lib/clandestine/command_line_runner.rb +86 -0
- data/lib/clandestine/commands.rb +52 -0
- data/lib/clandestine/commands/add.rb +29 -0
- data/lib/clandestine/commands/delete.rb +25 -0
- data/lib/clandestine/commands/get.rb +37 -0
- data/lib/clandestine/commands/remove_safe.rb +18 -0
- data/lib/clandestine/commands/update.rb +32 -0
- data/lib/clandestine/crypt.rb +44 -21
- data/lib/clandestine/io.rb +32 -0
- data/lib/clandestine/password_generator.rb +18 -0
- data/lib/clandestine/safe.rb +71 -44
- data/lib/clandestine/safe_authentication.rb +18 -0
- data/lib/clandestine/safe_location.rb +3 -0
- data/lib/clandestine/version.rb +1 -1
- data/spec/commands_spec.rb +98 -0
- data/spec/crypt_spec.rb +20 -5
- data/spec/safe_authentication_spec.rb +30 -0
- data/spec/spec_helper.rb +0 -8
- metadata +50 -12
- data/lib/clandestine/config.rb +0 -25
- data/lib/clandestine/guard.rb +0 -217
- data/spec/config_spec.rb +0 -47
- data/spec/guard_spec.rb +0 -127
- data/spec/safe_spec.rb +0 -40
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 28199bdaabcdce860096d540533772d884633985
|
4
|
+
data.tar.gz: d50ae77ce56c28705d610713563a04a6a0a64418
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e735a21d659094d197fc01ef14dab5be103bea886b9c6ee5cd94eb56514f75fe995c1c1f279aa1e986c43e98425ea92daea992beacc9dae54fa41668bc951672
|
7
|
+
data.tar.gz: 24d36dede0d1e12f9c872743f746ce95d1a4b0e29299fffae3e29297ade654c7fbc45cf97a10b1fa0c5bc6f4ea56b3f34e7a60862773fad6da1096cd657c8b81
|
data/.gitignore
CHANGED
data/.rspec
ADDED
data/README.md
CHANGED
@@ -1,32 +1,44 @@
|
|
1
|
-
|
1
|
+
Clandestine
|
2
|
+
-----------
|
2
3
|
|
3
4
|
Clandestine allows you to store passwords in a local file using AES-CBC-256 encryption.
|
4
5
|
|
5
|
-
|
6
|
+
Requirements
|
7
|
+
------------
|
6
8
|
|
7
|
-
Ruby
|
9
|
+
Ruby v2.0+
|
8
10
|
|
9
11
|
Currently only supported on OSX
|
10
12
|
|
11
|
-
|
13
|
+
Installation
|
14
|
+
------------
|
12
15
|
|
13
16
|
Clandestine can be installed using RubyGems:
|
14
17
|
|
15
18
|
$ gem install clandestine
|
16
19
|
|
17
|
-
|
20
|
+
Usage
|
21
|
+
-----
|
18
22
|
|
19
23
|
user$ clandestine
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
-
|
24
|
-
-g
|
25
|
-
-d <key>
|
26
|
-
-
|
27
|
-
-l
|
28
|
-
-
|
29
|
-
-
|
30
|
-
-
|
31
|
-
|
32
|
-
|
24
|
+
Clandestine v0.1.0
|
25
|
+
Usage: clandestine [option] [key]
|
26
|
+
|
27
|
+
-a, --add <key> Add password for <key> (Passwords are randomly generated)
|
28
|
+
-g, --get [key] Get password for [key] (Returns all keys if key isn't given)
|
29
|
+
-d, --delete <key> Delete <key> and related password
|
30
|
+
-u, --update [key] Update password for [key] (Updates password for safe if key isn't given)
|
31
|
+
-l, --location Print location of safe (Default is ~/.cls if env variable CLANDESTINE_SAFE isn't set)
|
32
|
+
-r, --remove Remove safe completely
|
33
|
+
-v, --version Print version number
|
34
|
+
-h, --help Print these options
|
35
|
+
|
36
|
+
|
37
|
+
Contributing
|
38
|
+
------------
|
39
|
+
1. Fork it
|
40
|
+
2. Create your feature branch (git checkout -b my-new-feature)
|
41
|
+
3. Write specs (bundle exec rspec spec)
|
42
|
+
4. Commit your changes (git commit -am 'Add some feature')
|
43
|
+
5. Push to the branch (git push origin my-new-feature)
|
44
|
+
6. Create new Pull Request
|
data/Rakefile
CHANGED
@@ -1,25 +1 @@
|
|
1
1
|
#!/usr/bin/env rake
|
2
|
-
require "bundler/gem_tasks"
|
3
|
-
require 'rspec/core/rake_task'
|
4
|
-
|
5
|
-
namespace :spec do
|
6
|
-
desc 'Run specs for Crypt'
|
7
|
-
RSpec::Core::RakeTask.new :crypt do |t|
|
8
|
-
t.pattern = 'spec/crypt_spec.rb'
|
9
|
-
end
|
10
|
-
desc 'Run specs for Safe'
|
11
|
-
RSpec::Core::RakeTask.new :safe do |t|
|
12
|
-
t.pattern = 'spec/safe_spec.rb'
|
13
|
-
end
|
14
|
-
desc 'Run specs for Guard'
|
15
|
-
RSpec::Core::RakeTask.new :guard do |t|
|
16
|
-
t.pattern = 'spec/guard_spec.rb'
|
17
|
-
end
|
18
|
-
desc 'Rub specs for Config'
|
19
|
-
RSpec::Core::RakeTask.new :config do |t|
|
20
|
-
t.pattern = 'spec/config_spec.rb'
|
21
|
-
end
|
22
|
-
task :all => [:safe, :guard, :crypt, :config]
|
23
|
-
end
|
24
|
-
|
25
|
-
task :default => 'spec:all'
|
data/bin/clandestine
CHANGED
data/clandestine.gemspec
CHANGED
@@ -15,5 +15,7 @@ Gem::Specification.new do |gem|
|
|
15
15
|
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
16
16
|
gem.require_paths = ["lib"]
|
17
17
|
gem.add_dependency 'highline'
|
18
|
-
gem.
|
18
|
+
gem.add_dependency 'json'
|
19
|
+
gem.add_dependency 'bcrypt-ruby'
|
20
|
+
gem.add_development_dependency 'rspec', '~> 2'
|
19
21
|
end
|
data/lib/clandestine.rb
CHANGED
@@ -1,9 +1 @@
|
|
1
|
-
|
2
|
-
require 'base64'
|
3
|
-
require 'digest/sha2'
|
4
|
-
require 'fileutils'
|
5
|
-
require 'clandestine/version'
|
6
|
-
require 'clandestine/crypt'
|
7
|
-
require 'clandestine/config'
|
8
|
-
require 'clandestine/safe'
|
9
|
-
require 'clandestine/guard'
|
1
|
+
require_relative 'clandestine/command_line_runner'
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module Clandestine
|
2
|
+
class CommandLineOptions
|
3
|
+
|
4
|
+
attr_reader :parser
|
5
|
+
attr_accessor :options
|
6
|
+
private :options
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
@options = {}
|
10
|
+
@parser = OptionParser.new
|
11
|
+
end
|
12
|
+
|
13
|
+
def parse
|
14
|
+
parser.banner = "Clandestine v#{Clandestine::VERSION}\nUsage: clandestine [option] [key]\n\n"
|
15
|
+
|
16
|
+
parser.on('-a', '--add <key>', 'Add password for <key>') do |key|
|
17
|
+
options[:add] = key
|
18
|
+
end
|
19
|
+
|
20
|
+
parser.on('-g', '--get [key]', 'Get password for [key] (Returns all keys if key isn\'t given)') do |key|
|
21
|
+
options[:get] = key
|
22
|
+
end
|
23
|
+
|
24
|
+
parser.on('-d', '--delete <key>', 'Delete <key> and related password') do |key|
|
25
|
+
options[:delete] = key
|
26
|
+
end
|
27
|
+
|
28
|
+
parser.on('-u', '--update [key]', 'Update password for [key] (Updates password for safe if key isn\'t given)') do |key|
|
29
|
+
options[:update] = key
|
30
|
+
end
|
31
|
+
|
32
|
+
parser.on '-l', '--location', 'Print location of safe (Default is ~/.cls if env variable CLANDESTINE_SAFE isn\'t set)' do
|
33
|
+
options[:location] = nil
|
34
|
+
end
|
35
|
+
|
36
|
+
parser.on '-r', '--remove', 'Remove safe completely' do
|
37
|
+
options[:remove] = nil
|
38
|
+
end
|
39
|
+
|
40
|
+
parser.on '-v', '--version', 'Print version number' do |h|
|
41
|
+
options[:version] = nil
|
42
|
+
end
|
43
|
+
|
44
|
+
parser.on_tail '-h', '--help', 'Print these options' do |h|
|
45
|
+
options[:help] = parser
|
46
|
+
end
|
47
|
+
|
48
|
+
parser.parse!
|
49
|
+
options
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
require 'optparse'
|
2
|
+
require_relative 'command_line_options'
|
3
|
+
require_relative 'commands'
|
4
|
+
require_relative 'version'
|
5
|
+
require_relative 'clandestine_error'
|
6
|
+
require_relative 'io'
|
7
|
+
|
8
|
+
module Clandestine
|
9
|
+
|
10
|
+
class CommandLineRunner
|
11
|
+
|
12
|
+
def self.run
|
13
|
+
clo = CommandLineOptions.new
|
14
|
+
options = clo.parse
|
15
|
+
|
16
|
+
command = options.keys.first
|
17
|
+
value = options[command]
|
18
|
+
|
19
|
+
case command
|
20
|
+
when :add
|
21
|
+
output = run_command(command, value)
|
22
|
+
if output
|
23
|
+
puts "Successfully added password for #{value}"
|
24
|
+
else
|
25
|
+
puts "Password already exists for #{value}"
|
26
|
+
end
|
27
|
+
when :get
|
28
|
+
output = run_command(command, value)
|
29
|
+
if value && !output.is_a?(Array)
|
30
|
+
IO.copy_to_clipboard(output)
|
31
|
+
else
|
32
|
+
IO.print_keys(output)
|
33
|
+
end
|
34
|
+
when :update
|
35
|
+
output = run_command(command, value)
|
36
|
+
if output
|
37
|
+
if value
|
38
|
+
puts "Password for #{value} has been updated"
|
39
|
+
else
|
40
|
+
puts "Password for safe has been updated"
|
41
|
+
end
|
42
|
+
else
|
43
|
+
if value
|
44
|
+
puts "#{value} does not exist"
|
45
|
+
else
|
46
|
+
puts "Failed to update safe password"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
when :delete
|
50
|
+
if run_command(command, value)
|
51
|
+
puts "#{value} has been deleted"
|
52
|
+
else
|
53
|
+
puts "#{value} does not exist"
|
54
|
+
end
|
55
|
+
when :remove
|
56
|
+
if run_command(command, value)
|
57
|
+
puts "Safe has been successfully removed"
|
58
|
+
else
|
59
|
+
puts "Failed to remve safe"
|
60
|
+
end
|
61
|
+
when :version
|
62
|
+
puts Commands.version
|
63
|
+
when :location
|
64
|
+
puts Commands.location
|
65
|
+
when :help
|
66
|
+
puts clo.parser.on_tail
|
67
|
+
else
|
68
|
+
puts clo.parser.on_tail
|
69
|
+
end
|
70
|
+
puts
|
71
|
+
rescue OptionParser::MissingArgument, OptionParser::InvalidOption
|
72
|
+
puts clo.parser.on_tail
|
73
|
+
end
|
74
|
+
|
75
|
+
def self.run_command(command, value)
|
76
|
+
if command
|
77
|
+
if value
|
78
|
+
Commands.send(command, value)
|
79
|
+
else
|
80
|
+
Commands.send(command, nil)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require_relative 'version'
|
2
|
+
require_relative 'clandestine_error'
|
3
|
+
require_relative 'io'
|
4
|
+
require_relative 'safe_location'
|
5
|
+
require_relative 'commands/add'
|
6
|
+
require_relative 'commands/update'
|
7
|
+
require_relative 'commands/get'
|
8
|
+
require_relative 'commands/delete'
|
9
|
+
require_relative 'commands/remove_safe'
|
10
|
+
|
11
|
+
module Clandestine
|
12
|
+
module Commands
|
13
|
+
def self.add(key, password = nil)
|
14
|
+
password = IO.get_password unless password
|
15
|
+
Add.new(password, key).add
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.get(key = nil, password = nil)
|
19
|
+
if key && password.nil?
|
20
|
+
password = IO.get_password
|
21
|
+
end
|
22
|
+
Get.new(password, key).get
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.delete(key, password = nil)
|
26
|
+
password = IO.get_password unless password
|
27
|
+
Delete.new(password, key).delete
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.update(key = nil, password = nil)
|
31
|
+
password = IO.get_password unless password
|
32
|
+
Update.new(password, key).update
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.location
|
36
|
+
ENV['CLANDESTINE_SAFE'] || SAFE_LOCATION
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.remove(password = nil)
|
40
|
+
password = IO.get_password unless password
|
41
|
+
RemoveSafe.new(password).remove
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.version
|
45
|
+
Clandestine::VERSION
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.help(options)
|
49
|
+
options
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require_relative '../safe'
|
2
|
+
require_relative '../io'
|
3
|
+
require_relative '../password_generator'
|
4
|
+
require_relative '../clandestine_error'
|
5
|
+
|
6
|
+
module Clandestine
|
7
|
+
module Commands
|
8
|
+
class Add
|
9
|
+
attr_reader :safe_password, :key
|
10
|
+
private :safe_password, :key
|
11
|
+
|
12
|
+
def initialize(safe_password, key)
|
13
|
+
raise ClandestineError.new 'Missing required key argument' unless key
|
14
|
+
@safe_password = safe_password
|
15
|
+
@key = key.to_sym
|
16
|
+
end
|
17
|
+
|
18
|
+
def add
|
19
|
+
Safe.new(safe_password).open do |safe|
|
20
|
+
if !safe.exists?(key)
|
21
|
+
safe.add(key, PasswordGenerator.random_password)
|
22
|
+
else
|
23
|
+
false
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require_relative '../safe'
|
2
|
+
|
3
|
+
module Clandestine
|
4
|
+
module Commands
|
5
|
+
class Delete
|
6
|
+
attr_reader :safe_password, :key
|
7
|
+
private :safe_password, :key
|
8
|
+
|
9
|
+
def initialize(safe_password, key)
|
10
|
+
@safe_password = safe_password
|
11
|
+
@key = key.to_sym
|
12
|
+
end
|
13
|
+
|
14
|
+
def delete
|
15
|
+
Safe.new(safe_password).open do |safe|
|
16
|
+
if safe.exists?(key)
|
17
|
+
safe.delete(key)
|
18
|
+
else
|
19
|
+
false
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require_relative '../safe'
|
2
|
+
require_relative '../io'
|
3
|
+
|
4
|
+
module Clandestine
|
5
|
+
module Commands
|
6
|
+
class Get
|
7
|
+
|
8
|
+
attr_reader :safe_password, :key
|
9
|
+
private :safe_password, :key
|
10
|
+
|
11
|
+
def initialize(safe_password, key)
|
12
|
+
@safe_password = safe_password
|
13
|
+
@key = key.to_sym if key
|
14
|
+
end
|
15
|
+
|
16
|
+
def get
|
17
|
+
Safe.new(safe_password).open do |safe|
|
18
|
+
if no_key_or_value?(safe)
|
19
|
+
safe.contents
|
20
|
+
else
|
21
|
+
safe[key]
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def no_key_or_value?(safe)
|
29
|
+
!key || key_missing?(safe)
|
30
|
+
end
|
31
|
+
|
32
|
+
def key_missing?(safe)
|
33
|
+
!safe[key]
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|