keystorage 0.5.1 → 0.5.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.
- checksums.yaml +4 -4
- data/.travis.yml +9 -0
- data/Gemfile +2 -6
- data/README.md +7 -0
- data/Rakefile +1 -1
- data/VERSION +1 -1
- data/bin/keystorage +1 -0
- data/keystorage.gemspec +3 -2
- data/lib/keystorage.rb +0 -56
- data/lib/keystorage/cli.rb +17 -5
- data/lib/keystorage/manager.rb +74 -0
- data/spec/keystorage/cli_spec.rb +117 -4
- data/spec/keystorage/files/1.yml +3 -0
- data/spec/keystorage/manager_spec.rb +378 -8
- data/spec/keystorage_spec.rb +19 -0
- data/spec/spec_helper.rb +10 -0
- metadata +21 -6
- data/test/helper.rb +0 -18
- data/test/test_keystorage.rb +0 -36
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5772937588dc3df5bec1a71d4decdb377c44cc5d
|
4
|
+
data.tar.gz: cea3aa650a0c1e8ff6737b5c89a24efd19c3d926
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3c94373cfc511b914ed78315639242b650bd79158d2f0c7dff814f8490ad1e555b7c280f30fd9e5175d9c8336be2d9a8343fe07a91c6bc16344bdaaa2f58bcfe
|
7
|
+
data.tar.gz: bf1b0665cd890f17fb6c3c0294224861038f942ee1a5b60f585c1fd93d976fe2d394b07b22346ce79ce15437f29d9197313f0f81fc16ab6c7e119892872dd1d3
|
data/.travis.yml
ADDED
data/Gemfile
CHANGED
@@ -1,9 +1,5 @@
|
|
1
1
|
source "http://rubygems.org"
|
2
2
|
gemspec
|
3
3
|
|
4
|
-
|
5
|
-
|
6
|
-
# gem "activesupport", ">= 2.3.5"
|
7
|
-
|
8
|
-
# Add dependencies to develop your gem here.
|
9
|
-
# Include everything needed to run rake, tests, features, etc.
|
4
|
+
gem "simplecov", :require=>false, group: :test
|
5
|
+
gem "codeclimate-test-reporter", group: :test
|
data/README.md
CHANGED
@@ -1,6 +1,11 @@
|
|
1
1
|
keystorage
|
2
2
|
----------
|
3
3
|
|
4
|
+
[](http://badge.fury.io/rb/keystorage)
|
5
|
+
[](https://travis-ci.org/tumf/keystorage)
|
6
|
+
[](https://codeclimate.com/github/tumf/keystorage)
|
7
|
+
[](https://codeclimate.com/github/tumf/keystorage)
|
8
|
+
|
4
9
|
Simple password storage.
|
5
10
|
|
6
11
|
## Install
|
@@ -12,12 +17,14 @@ Simple password storage.
|
|
12
17
|
|
13
18
|
-> % keystorage
|
14
19
|
Commands:
|
20
|
+
keystorage exec # execute child process with set envvars
|
15
21
|
keystorage get # Get a encrypted value of the key of the group
|
16
22
|
keystorage groups # List groups
|
17
23
|
keystorage help [COMMAND] # Describe available commands or one specific command
|
18
24
|
keystorage keys # List keys of the group
|
19
25
|
keystorage password # Update storage secret
|
20
26
|
keystorage set # Set a value of the key of the group
|
27
|
+
keystorage version # show version info
|
21
28
|
|
22
29
|
Options:
|
23
30
|
-v, [--verbose], [--no-verbose]
|
data/Rakefile
CHANGED
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.5.
|
1
|
+
0.5.7
|
data/bin/keystorage
CHANGED
data/keystorage.gemspec
CHANGED
@@ -27,8 +27,9 @@ Gem::Specification.new do |s|
|
|
27
27
|
s.summary = "Simple password storage"
|
28
28
|
|
29
29
|
s.add_dependency('thor')
|
30
|
-
|
30
|
+
s.add_dependency('version')
|
31
|
+
|
31
32
|
s.add_development_dependency('rake')
|
32
33
|
s.add_development_dependency('rspec')
|
33
|
-
s.add_development_dependency('
|
34
|
+
s.add_development_dependency('fakefs')
|
34
35
|
end
|
data/lib/keystorage.rb
CHANGED
@@ -15,62 +15,6 @@ module Keystorage
|
|
15
15
|
class NoSecret < StandardError; end
|
16
16
|
class FormatNotSupport < StandardError; end
|
17
17
|
|
18
|
-
def sign message,secret=secret
|
19
|
-
raise NoSecret.new("set env KEYSTORAGE_SECRET") unless secret
|
20
|
-
OpenSSL::HMAC.hexdigest('sha512',secret, message)
|
21
|
-
end
|
22
|
-
|
23
|
-
def token
|
24
|
-
SecureRandom.urlsafe_base64(nil, false)
|
25
|
-
end
|
26
|
-
|
27
|
-
def root
|
28
|
-
raise NoRootGroup unless file.has_key?("@")
|
29
|
-
file["@"] || {}
|
30
|
-
end
|
31
|
-
|
32
|
-
def root! secret=secret,data=file
|
33
|
-
data["@"] = {}
|
34
|
-
data["@"]["token"] = token
|
35
|
-
data["@"]["sig"] = sign(data["@"]["token"],secret)
|
36
|
-
data
|
37
|
-
end
|
38
|
-
|
39
|
-
# file validation
|
40
|
-
def valid?
|
41
|
-
sign(root["token"]) == root["sig"]
|
42
|
-
rescue NoRootGroup
|
43
|
-
write root!
|
44
|
-
end
|
45
|
-
|
46
|
-
def encode(str,secret=secret)
|
47
|
-
enc = OpenSSL::Cipher::Cipher.new('aes256')
|
48
|
-
enc.encrypt.pkcs5_keyivgen(secret)
|
49
|
-
((enc.update(str) + enc.final).unpack("H*")).first.to_s
|
50
|
-
end
|
51
|
-
|
52
|
-
def decode(str,secret=secret)
|
53
|
-
dec = OpenSSL::Cipher::Cipher.new('aes256')
|
54
|
-
dec.decrypt.pkcs5_keyivgen(secret)
|
55
|
-
(dec.update(Array.new([str]).pack("H*")) + dec.final)
|
56
|
-
end
|
57
|
-
|
58
|
-
def path
|
59
|
-
options[:file] || ENV['KEYSTORAGE_FILE'] || DEFAULT_FILE
|
60
|
-
end
|
61
|
-
|
62
|
-
def file
|
63
|
-
YAML.load(File.new(path)) || {}
|
64
|
-
end
|
65
|
-
|
66
|
-
def write data
|
67
|
-
File.open(path,'w',0600) { |f| YAML.dump(data,f) }
|
68
|
-
end
|
69
|
-
|
70
|
-
def secret
|
71
|
-
options[:secret] || ENV['KEYSTORAGE_SECRET'] || DEFAULT_SECRET
|
72
|
-
end
|
73
|
-
|
74
18
|
def render out,format =:text
|
75
19
|
case format
|
76
20
|
when :text then
|
data/lib/keystorage/cli.rb
CHANGED
@@ -3,6 +3,7 @@ require 'keystorage'
|
|
3
3
|
require 'keystorage/manager'
|
4
4
|
require 'thor'
|
5
5
|
require 'optparse'
|
6
|
+
require 'version'
|
6
7
|
|
7
8
|
module Keystorage
|
8
9
|
class CLI < Thor
|
@@ -12,22 +13,22 @@ module Keystorage
|
|
12
13
|
def start(given_args = ARGV, config = {})
|
13
14
|
# parse global options: Thor is not support global-options.
|
14
15
|
# Like: command global-options subcommand options
|
15
|
-
|
16
|
+
new_global_options = []
|
16
17
|
OptionParser.new do |opt|
|
17
18
|
@global_options.each { |name,config|
|
18
19
|
case config[:type]
|
19
20
|
when :boolean then
|
20
|
-
opt.on(config[:aliases],"--#{name.to_s}") { |v|
|
21
|
-
opt.on(config[:aliases],"--no-#{name.to_s}") { |v| global_options << "--no-#{name.to_s}"}
|
21
|
+
opt.on(config[:aliases],"--#{name.to_s}") { |v| new_global_options << "--#{name.to_s}"}
|
22
22
|
when :string then
|
23
|
-
opt.on(config[:aliases],"--#{name.to_s}=VALUE") { |v|
|
23
|
+
opt.on(config[:aliases],"--#{name.to_s}=VALUE") { |v| new_global_options << "--#{name.to_s}=#{v}"}
|
24
24
|
end
|
25
25
|
}
|
26
26
|
opt.parse!(given_args)
|
27
27
|
end
|
28
|
-
given_args+=
|
28
|
+
given_args+=new_global_options
|
29
29
|
super(given_args,config)
|
30
30
|
end
|
31
|
+
attr_reader :global_options
|
31
32
|
|
32
33
|
def global_option *params
|
33
34
|
@global_options ||= {}
|
@@ -68,5 +69,16 @@ module Keystorage
|
|
68
69
|
Manager.new(options).password(new_secret)
|
69
70
|
end
|
70
71
|
|
72
|
+
desc "exec","execute child process with set envvars"
|
73
|
+
def exec *command
|
74
|
+
#@todo: ask if new_secret == nil
|
75
|
+
Manager.new(options).exec(command)
|
76
|
+
end
|
77
|
+
|
78
|
+
desc "version","show version info"
|
79
|
+
def version
|
80
|
+
puts Version.current
|
81
|
+
end
|
82
|
+
|
71
83
|
end
|
72
84
|
end
|
data/lib/keystorage/manager.rb
CHANGED
@@ -56,5 +56,79 @@ module Keystorage
|
|
56
56
|
retry
|
57
57
|
end
|
58
58
|
|
59
|
+
def exec *cmd
|
60
|
+
raise SecretMissMatch unless valid?
|
61
|
+
system(envs.collect{ |k,v| "#{k}='#{v}'" }.join(' ') + " " + cmd.join(' '))
|
62
|
+
end
|
63
|
+
|
64
|
+
private
|
65
|
+
|
66
|
+
def envs
|
67
|
+
result = {}
|
68
|
+
groups.each { |g|
|
69
|
+
keys(g).each { |k|
|
70
|
+
result["#{g}_#{k}"] = get(g,k)
|
71
|
+
}
|
72
|
+
}
|
73
|
+
result
|
74
|
+
end
|
75
|
+
|
76
|
+
def sign message,_secret=secret
|
77
|
+
raise NoSecret.new("set env KEYSTORAGE_SECRET") unless _secret
|
78
|
+
OpenSSL::HMAC.hexdigest('sha512',_secret, message)
|
79
|
+
end
|
80
|
+
|
81
|
+
def token
|
82
|
+
SecureRandom.urlsafe_base64(nil, false)
|
83
|
+
end
|
84
|
+
|
85
|
+
def root
|
86
|
+
raise NoRootGroup unless file.has_key?("@")
|
87
|
+
file["@"] || {}
|
88
|
+
end
|
89
|
+
|
90
|
+
def root! _secret=secret,data=file
|
91
|
+
data["@"] = {}
|
92
|
+
data["@"]["token"] = token
|
93
|
+
data["@"]["sig"] = sign(data["@"]["token"],_secret)
|
94
|
+
data
|
95
|
+
end
|
96
|
+
|
97
|
+
# file validation
|
98
|
+
def valid?
|
99
|
+
sign(root["token"]) == root["sig"]
|
100
|
+
rescue NoRootGroup
|
101
|
+
write root! and true
|
102
|
+
end
|
103
|
+
|
104
|
+
def encode(str,_secret=secret)
|
105
|
+
enc = OpenSSL::Cipher::Cipher.new('aes256')
|
106
|
+
enc.encrypt.pkcs5_keyivgen(_secret)
|
107
|
+
((enc.update(str) + enc.final).unpack("H*")).first.to_s
|
108
|
+
end
|
109
|
+
|
110
|
+
def decode(str,_secret=secret)
|
111
|
+
dec = OpenSSL::Cipher::Cipher.new('aes256')
|
112
|
+
dec.decrypt.pkcs5_keyivgen(_secret)
|
113
|
+
(dec.update(Array.new([str]).pack("H*")) + dec.final)
|
114
|
+
end
|
115
|
+
|
116
|
+
def path
|
117
|
+
options[:file] || ENV['KEYSTORAGE_FILE'] || DEFAULT_FILE
|
118
|
+
end
|
119
|
+
|
120
|
+
def file
|
121
|
+
YAML.load(File.new(path)) || {}
|
122
|
+
end
|
123
|
+
|
124
|
+
def write data
|
125
|
+
FileUtils.mkdir_p(File.dirname(path))
|
126
|
+
File.open(path,'w',0600) { |f| YAML.dump(data,f) }
|
127
|
+
end
|
128
|
+
|
129
|
+
def secret
|
130
|
+
options[:secret] || ENV['KEYSTORAGE_SECRET'] || DEFAULT_SECRET
|
131
|
+
end
|
132
|
+
|
59
133
|
end
|
60
134
|
end
|
data/spec/keystorage/cli_spec.rb
CHANGED
@@ -1,7 +1,120 @@
|
|
1
|
+
# coding: utf-8
|
1
2
|
require 'keystorage/cli'
|
3
|
+
|
2
4
|
describe Keystorage::CLI do
|
3
|
-
subject { Keystorage::CLI
|
4
|
-
|
5
|
-
|
6
|
-
|
5
|
+
subject { Keystorage::CLI.start(argv) }
|
6
|
+
|
7
|
+
describe ".start" do
|
8
|
+
context "unknown global-options are specified" do
|
9
|
+
let(:argv) { ['--aaa=myfile','groups'] }
|
10
|
+
it "puts options back of subcommand" do
|
11
|
+
expect { subject }.to raise_error(OptionParser::InvalidOption)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
context "string-type global-options are specified" do
|
16
|
+
let(:argv) { ['-f','myfile','groups'] }
|
17
|
+
it "puts options back of subcommand" do
|
18
|
+
expect(Thor).to receive(:start).with(['groups','--file=myfile'],{}).once
|
19
|
+
subject
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
context "boolean-type `-v` global-options are specified" do
|
24
|
+
let(:argv) { ['-v','groups'] }
|
25
|
+
it "puts options back of subcommand" do
|
26
|
+
expect(Thor).to receive(:start).with(['groups','--verbose'],{}).once
|
27
|
+
subject
|
28
|
+
end
|
29
|
+
end
|
30
|
+
context "boolean-type `--no-verbose` global-options are specified" do
|
31
|
+
let(:argv) { ['--no-verbose','groups'] }
|
32
|
+
it "puts options back of subcommand" do
|
33
|
+
expect { subject }.to raise_error(OptionParser::InvalidOption)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
describe ".global_option" do
|
39
|
+
it "adds to @global_options and call `class_option`" do
|
40
|
+
expect(Keystorage::CLI).to receive(:class_option)
|
41
|
+
.with(:test, :aliases =>"-t", :type => :boolean).once
|
42
|
+
Keystorage::CLI.global_option(:test, :aliases =>"-t", :type => :boolean)
|
43
|
+
expect(Keystorage::CLI.global_options.has_key?(:test)).to be true
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
describe "#groups" do
|
48
|
+
let(:argv) { ['groups'] }
|
49
|
+
it "puts list of groups" do
|
50
|
+
allow(Keystorage::Manager).to receive_message_chain('new.groups')
|
51
|
+
.and_return( ["group1","group2","group3"] )
|
52
|
+
expect(STDOUT).to receive(:puts).with("group1\ngroup2\ngroup3").once
|
53
|
+
subject
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
describe "#keys" do
|
58
|
+
let(:argv) { ['keys','group1'] }
|
59
|
+
it "puts keys in the group" do
|
60
|
+
allow(Keystorage::Manager).to receive_message_chain('new.keys')
|
61
|
+
.and_return( ["key1","key2","key3"] )
|
62
|
+
|
63
|
+
expect(STDOUT).to receive(:puts).with("key1\nkey2\nkey3").once
|
64
|
+
subject
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
describe "#get" do
|
69
|
+
let(:argv) { ['get','group1','key1'] }
|
70
|
+
it "puts value of the key in the group" do
|
71
|
+
allow(Keystorage::Manager).to receive_message_chain('new.get')
|
72
|
+
.and_return( ["value"] )
|
73
|
+
|
74
|
+
expect(STDOUT).to receive(:puts).with("value").once
|
75
|
+
subject
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
|
80
|
+
describe "#set" do
|
81
|
+
let(:argv) { ['set','group1','key1','vaule'] }
|
82
|
+
it "sets value of the key in the group" do
|
83
|
+
allow(Keystorage::Manager).to receive_message_chain('new.set')
|
84
|
+
.and_return("value")
|
85
|
+
|
86
|
+
expect(STDOUT).to receive(:puts).with("value").once
|
87
|
+
subject
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
describe "#password" do
|
92
|
+
let(:argv) { ['password','p@ssw0rd'] }
|
93
|
+
it "updates secret of all keys in the file" do
|
94
|
+
expect(Keystorage::Manager).to receive_message_chain('new.password')
|
95
|
+
.with('p@ssw0rd')
|
96
|
+
subject
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
describe "#exec" do
|
101
|
+
let(:argv) { ['exec','mycommand','arg1','arg2'] }
|
102
|
+
it "updates secret of all keys in the file" do
|
103
|
+
expect(Keystorage::Manager).to receive_message_chain('new.exec')
|
104
|
+
.with(['mycommand','arg1','arg2'])
|
105
|
+
subject
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
describe "#version" do
|
110
|
+
let(:argv) { ['version'] }
|
111
|
+
let(:ver) {
|
112
|
+
File.read(File.join(File.dirname(__FILE__),'..','..','VERSION')).chomp
|
113
|
+
}
|
114
|
+
it "shows version" do
|
115
|
+
expect(STDOUT).to receive(:puts).with(ver).once
|
116
|
+
subject
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
7
120
|
end
|
@@ -1,13 +1,383 @@
|
|
1
1
|
require 'keystorage/manager'
|
2
|
+
|
3
|
+
def yaml name
|
4
|
+
File.join(File.dirname(__FILE__),'files',"#{name}.yml")
|
5
|
+
end
|
6
|
+
|
2
7
|
describe Keystorage::Manager do
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
is_expected.to be ""
|
8
|
+
let(:files){
|
9
|
+
{
|
10
|
+
"1"=>{"@"=>{"sig"=>"abc"}},
|
11
|
+
"2"=>{"@"=>{"sig"=>"abc","token"=>"def"},"g1"=>{ "k1" => "abcdefg", "k2" =>"" },"g2"=>{}},
|
12
|
+
}
|
9
13
|
}
|
14
|
+
before { @manager = Keystorage::Manager.new }
|
15
|
+
|
16
|
+
# public methods
|
17
|
+
describe "#groups" do
|
18
|
+
subject { @manager.groups }
|
19
|
+
it "returns array of groups" do
|
20
|
+
allow(@manager).to receive(:file)
|
21
|
+
.and_return(files["2"])
|
22
|
+
is_expected.to eq ["g1","g2"]
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe "#keys" do
|
27
|
+
subject { @manager.keys("g1") }
|
28
|
+
it "returns array of keys" do
|
29
|
+
allow(@manager).to receive(:file)
|
30
|
+
.and_return(files["2"])
|
31
|
+
|
32
|
+
is_expected.to eq ["k1","k2"]
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
describe "#get" do
|
37
|
+
subject { @manager.get("g1","k1") }
|
38
|
+
before {
|
39
|
+
allow(@manager).to receive(:file)
|
40
|
+
.and_return(files["2"])
|
41
|
+
}
|
42
|
+
context "has valid secret" do
|
43
|
+
before {
|
44
|
+
allow(@manager).to receive(:valid?)
|
45
|
+
.and_return(true)
|
46
|
+
}
|
47
|
+
it "returns value of the key in the group" do
|
48
|
+
expect(@manager).to receive(:decode).with("abcdefg").once
|
49
|
+
subject
|
50
|
+
end
|
51
|
+
end
|
52
|
+
context "has no valid secret" do
|
53
|
+
before {
|
54
|
+
allow(@manager).to receive(:valid?)
|
55
|
+
.and_return(false) }
|
56
|
+
it "raise Keystorage::SecretMissMatch" do
|
57
|
+
expect { subject }.to raise_error(Keystorage::SecretMissMatch)
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
describe "#set" do
|
64
|
+
before {
|
65
|
+
allow(@manager).to receive(:file)
|
66
|
+
.and_return(files["2"])
|
67
|
+
}
|
68
|
+
|
69
|
+
context "group name '@'" do
|
70
|
+
subject { @manager.set("@","k1","v1") }
|
71
|
+
it "raise Keystorage::RejectGroupName" do
|
72
|
+
expect { subject }.to raise_error(Keystorage::RejectGroupName)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
context "has valid secret" do
|
77
|
+
subject { @manager.set("g1","k1","v1") }
|
78
|
+
before {
|
79
|
+
allow(@manager).to receive(:valid?)
|
80
|
+
.and_return(true)
|
81
|
+
}
|
82
|
+
it "sets the value to the key in the group" do
|
83
|
+
FakeFS do
|
84
|
+
subject
|
85
|
+
expect(@manager.get('g1','k1')).to eq "v1"
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
context "has no valid secret" do
|
91
|
+
subject { @manager.set("g1","k1","v1") }
|
92
|
+
before {
|
93
|
+
allow(@manager).to receive(:valid?)
|
94
|
+
.and_return(false)
|
95
|
+
}
|
96
|
+
it "raise Keystorage::SecretMissMatch" do
|
97
|
+
expect { subject }.to raise_error(Keystorage::SecretMissMatch)
|
98
|
+
end
|
99
|
+
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
describe "#password" do
|
104
|
+
let(:new_password) { "zxcvbnm" }
|
105
|
+
subject { @manager.password(new_password) }
|
106
|
+
|
107
|
+
context "file not found" do
|
108
|
+
before {
|
109
|
+
@manager = Keystorage::Manager.new( {:file=>"hoge",:secret=>"fuga"})
|
110
|
+
}
|
111
|
+
it "creates new keystorage file" do
|
112
|
+
FakeFS do
|
113
|
+
subject
|
114
|
+
expect(File.exists?("hoge")).to eq true
|
115
|
+
expect(@manager.send(:file).has_key?("@")).to eq true
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
context "has valid secret" do
|
121
|
+
|
122
|
+
before {
|
123
|
+
@manager = Keystorage::Manager.new( {:file=>"hoge",:secret=>"fuga"})
|
124
|
+
}
|
125
|
+
it "updates password to `new_password`" do
|
126
|
+
FakeFS do
|
127
|
+
@manager.set("a","b","c")
|
128
|
+
subject
|
129
|
+
expect { @manager.get("a","b") }.to raise_error(Keystorage::SecretMissMatch)
|
130
|
+
@manager = Keystorage::Manager.new( {:file=>"hoge",:secret=>new_password})
|
131
|
+
expect(@manager.get("a","b")).to eq "c"
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
context "has no valid secret" do
|
137
|
+
before {
|
138
|
+
allow(@manager).to receive(:valid?)
|
139
|
+
.and_return(false)
|
140
|
+
}
|
141
|
+
it "raise Keystorage::SecretMissMatch" do
|
142
|
+
expect { subject }.to raise_error(Keystorage::SecretMissMatch)
|
143
|
+
end
|
144
|
+
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
describe "#exec" do
|
149
|
+
let(:cmd) { ["ls","-a b"] }
|
150
|
+
subject { @manager.exec(cmd) }
|
151
|
+
|
152
|
+
context "has valid secret" do
|
153
|
+
before {
|
154
|
+
@manager = Keystorage::Manager.new( {:file=>"hoge",:secret=>"fuga"} )
|
155
|
+
allow(@manager).to receive(:valid?)
|
156
|
+
.and_return(true)
|
157
|
+
}
|
158
|
+
it "execute command with env-vars" do
|
159
|
+
FakeFS do
|
160
|
+
@manager.set("a","b","c")
|
161
|
+
@manager.set("a","b","d e f")
|
162
|
+
@manager.set("x","y","z")
|
163
|
+
|
164
|
+
expect(@manager).to receive(:system)
|
165
|
+
.with("a_b='d e f' x_y='z' ls -a b")
|
166
|
+
.and_return(true)
|
167
|
+
subject
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
context "has no valid secret" do
|
173
|
+
before {
|
174
|
+
allow(@manager).to receive(:valid?)
|
175
|
+
.and_return(false)
|
176
|
+
}
|
177
|
+
it "raise Keystorage::SecretMissMatch" do
|
178
|
+
expect { subject }.to raise_error(Keystorage::SecretMissMatch)
|
179
|
+
end
|
180
|
+
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
|
185
|
+
# private methods
|
186
|
+
describe "#sign" do
|
187
|
+
context "secret is nil" do
|
188
|
+
it "raise NoSecret" do
|
189
|
+
expect { @manager.send(:sign,"text",nil) }
|
190
|
+
.to raise_error(Keystorage::NoSecret)
|
191
|
+
end
|
192
|
+
|
193
|
+
end
|
194
|
+
context "secret is not nil" do
|
195
|
+
subject { @manager.send(:sign,"text","p@ssw0rd") }
|
196
|
+
it "returns sign" do
|
197
|
+
allow(OpenSSL::HMAC).to receive(:hexdigest)
|
198
|
+
.and_return("sample-sig")
|
199
|
+
|
200
|
+
is_expected.to eq "sample-sig"
|
201
|
+
end
|
202
|
+
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
describe "#token" do
|
207
|
+
subject { @manager.send(:token) }
|
208
|
+
|
209
|
+
it "returns token" do
|
210
|
+
allow(SecureRandom).to receive(:urlsafe_base64)
|
211
|
+
.and_return("sample-token")
|
212
|
+
is_expected.to eq "sample-token"
|
213
|
+
end
|
214
|
+
|
215
|
+
end
|
216
|
+
|
217
|
+
describe "#root" do
|
218
|
+
context "file has '@' key" do
|
219
|
+
let(:root) { {"test1"=>"test2"} }
|
220
|
+
let(:data) { { "@" => root,"group1" => {"key1"=>"value1"} } }
|
221
|
+
subject { @manager.send(:root) }
|
222
|
+
|
223
|
+
it "returns Hash of root" do
|
224
|
+
allow(@manager).to receive(:file)
|
225
|
+
.and_return(data)
|
226
|
+
is_expected.to eq root
|
227
|
+
end
|
228
|
+
end
|
229
|
+
context "file has no '@' key" do
|
230
|
+
let(:data) { { "group1" => {"key1"=>"value1"} } }
|
231
|
+
it "raise NoRootGroup" do
|
232
|
+
allow(@manager).to receive(:file)
|
233
|
+
.and_return(data)
|
234
|
+
|
235
|
+
expect { @manager.send(:root) }
|
236
|
+
.to raise_error(Keystorage::NoRootGroup)
|
237
|
+
end
|
238
|
+
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
describe "#valid?" do
|
243
|
+
context "file has no root" do
|
244
|
+
subject { @manager.send(:valid?) }
|
245
|
+
let(:data) { { "group1" => {"key1"=>"value1"} } }
|
246
|
+
it "writes root and return true" do
|
247
|
+
allow(@manager).to receive(:file)
|
248
|
+
.and_return(data)
|
249
|
+
allow(@manager).to receive(:write)
|
250
|
+
.and_return(true)
|
251
|
+
expect(@manager).to receive(:write)
|
252
|
+
is_expected.to eq true
|
253
|
+
end
|
254
|
+
end
|
255
|
+
end
|
256
|
+
|
257
|
+
describe "#encode" do
|
258
|
+
let(:str) { "test message" }
|
259
|
+
let(:secret) { "s3cr3t" }
|
260
|
+
subject { @manager.send(:encode,str,secret) }
|
261
|
+
it "returns encoded string" do
|
262
|
+
is_expected.to eq "a191a5111cfee36a94bba4dc0a17c31d"
|
263
|
+
end
|
264
|
+
end
|
265
|
+
|
266
|
+
describe "#decode" do
|
267
|
+
let(:str) { "test message" }
|
268
|
+
let(:encoded) { "a191a5111cfee36a94bba4dc0a17c31d" }
|
269
|
+
let(:secret) { "s3cr3t" }
|
270
|
+
subject { @manager.send(:decode,encoded,secret) }
|
271
|
+
it "returns decoded string" do
|
272
|
+
is_expected.to eq str
|
273
|
+
end
|
274
|
+
end
|
275
|
+
|
276
|
+
describe "#file" do
|
277
|
+
subject { @manager.send(:file) }
|
278
|
+
it "returns data from path" do
|
279
|
+
allow(@manager).to receive(:path)
|
280
|
+
.and_return(yaml("1"))
|
281
|
+
is_expected.to eq files["1"]
|
282
|
+
end
|
283
|
+
end
|
284
|
+
|
285
|
+
describe "#write" do
|
286
|
+
let(:data) { { :test => "rspec"} }
|
287
|
+
subject { @manager.send(:write,data) }
|
288
|
+
it "writes data to file" do
|
289
|
+
FakeFS do
|
290
|
+
expect { subject }.not_to raise_error
|
291
|
+
expect(@manager.send(:file).has_key?(:test)).to eq true
|
292
|
+
end
|
293
|
+
end
|
294
|
+
end
|
295
|
+
|
296
|
+
describe "#path" do
|
297
|
+
subject { @manager.send(:path) }
|
298
|
+
let(:file_path) { "abcdefgh" }
|
299
|
+
|
300
|
+
context "options[:path] is set" do
|
301
|
+
before{
|
302
|
+
allow(@manager).to receive(:options)
|
303
|
+
.and_return({:file =>file_path})
|
304
|
+
}
|
305
|
+
|
306
|
+
it "returns options[:path]" do
|
307
|
+
is_expected.to eq file_path
|
308
|
+
end
|
309
|
+
end
|
310
|
+
context "options[:path] is not set" do
|
311
|
+
before {
|
312
|
+
allow(@manager).to receive(:options)
|
313
|
+
.and_return({})
|
314
|
+
}
|
315
|
+
|
316
|
+
context "ENV KEYSTORAGE_FILE is set" do
|
317
|
+
before{
|
318
|
+
allow(ENV).to receive(:[])
|
319
|
+
.with('KEYSTORAGE_FILE')
|
320
|
+
.and_return(file_path)
|
321
|
+
}
|
322
|
+
it "returns KEYSTORAGE_FILE" do
|
323
|
+
is_expected.to eq file_path
|
324
|
+
end
|
325
|
+
end
|
326
|
+
|
327
|
+
context "ENV KEYSTORAGE_FILE is not set" do
|
328
|
+
before{
|
329
|
+
allow(ENV).to receive(:[])
|
330
|
+
.with('KEYSTORAGE_FILE')
|
331
|
+
.and_return(nil)
|
332
|
+
}
|
333
|
+
it "returns DEFAULT_FILE" do
|
334
|
+
is_expected.to eq Keystorage::DEFAULT_FILE
|
335
|
+
end
|
336
|
+
end
|
337
|
+
end
|
338
|
+
|
339
|
+
end
|
340
|
+
|
341
|
+
describe "#secret" do
|
342
|
+
subject { @manager.send(:secret) }
|
343
|
+
let(:password) { "abcedfg" }
|
344
|
+
|
345
|
+
context "options[:secret] is set" do
|
346
|
+
it "returns options[:secret]" do
|
347
|
+
allow(@manager).to receive(:options)
|
348
|
+
.and_return({:secret =>password})
|
349
|
+
is_expected.to eq password
|
350
|
+
end
|
351
|
+
end
|
352
|
+
context "options[:secret] is not set" do
|
353
|
+
before {
|
354
|
+
allow(@manager).to receive(:options)
|
355
|
+
.and_return({})
|
356
|
+
}
|
357
|
+
context "ENV KEYSTORAGE_SECRET is set" do
|
358
|
+
before {
|
359
|
+
allow(ENV).to receive(:[])
|
360
|
+
.with('KEYSTORAGE_SECRET')
|
361
|
+
.and_return(password)
|
362
|
+
}
|
363
|
+
|
364
|
+
it "returns secret ENV[:secret]" do
|
365
|
+
is_expected.to eq password
|
366
|
+
end
|
367
|
+
end
|
368
|
+
context "ENV KEYSTORAGE_SECRET is not set" do
|
369
|
+
before {
|
370
|
+
allow(ENV).to receive(:[])
|
371
|
+
.with('KEYSTORAGE_SECRET')
|
372
|
+
.and_return(nil)
|
373
|
+
}
|
374
|
+
it "returns DEFAULT_SECRET" do
|
375
|
+
is_expected.to eq Keystorage::DEFAULT_SECRET
|
376
|
+
end
|
377
|
+
end
|
378
|
+
end
|
379
|
+
|
380
|
+
end
|
10
381
|
|
382
|
+
after { FakeFS::FileSystem.clear }
|
11
383
|
end
|
12
|
-
# ks = keystorage::Manager.new(:file =>"",:secret=> "P@ssword")
|
13
|
-
# ks.get("mygroup","mykey") # => "mysecret"
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
require 'keystorage'
|
3
|
+
|
4
|
+
describe Keystorage do
|
5
|
+
let(:test_class) { Struct.new(:a){ include Keystorage } }
|
6
|
+
subject { test_class.new }
|
7
|
+
|
8
|
+
describe "#render" do
|
9
|
+
|
10
|
+
context "Unknown format ':unknown' given" do
|
11
|
+
let(:format) { :unknown }
|
12
|
+
let(:string) { SecureRandom.urlsafe_base64(nil, false) }
|
13
|
+
it "raises Keystorage::FormatNotSupport" do
|
14
|
+
expect { subject.render(string,format) }.to raise_error(Keystorage::FormatNotSupport)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,3 +1,12 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
require 'simplecov'
|
3
|
+
require "codeclimate-test-reporter"
|
4
|
+
SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
|
5
|
+
SimpleCov::Formatter::HTMLFormatter,
|
6
|
+
CodeClimate::TestReporter::Formatter
|
7
|
+
]
|
8
|
+
SimpleCov.start
|
9
|
+
|
1
10
|
# This file was generated by the `rspec --init` command. Conventionally, all
|
2
11
|
# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
|
3
12
|
# The generated `.rspec` file contains `--require spec_helper` which will cause
|
@@ -89,3 +98,4 @@ RSpec.configure do |config|
|
|
89
98
|
Kernel.srand config.seed
|
90
99
|
=end
|
91
100
|
end
|
101
|
+
require 'fakefs/spec_helpers'
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: keystorage
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.5.
|
4
|
+
version: 0.5.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Yoshihiro TAKAHARA
|
@@ -24,6 +24,20 @@ dependencies:
|
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: version
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
27
41
|
- !ruby/object:Gem::Dependency
|
28
42
|
name: rake
|
29
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -53,7 +67,7 @@ dependencies:
|
|
53
67
|
- !ruby/object:Gem::Version
|
54
68
|
version: '0'
|
55
69
|
- !ruby/object:Gem::Dependency
|
56
|
-
name:
|
70
|
+
name: fakefs
|
57
71
|
requirement: !ruby/object:Gem::Requirement
|
58
72
|
requirements:
|
59
73
|
- - ">="
|
@@ -76,6 +90,7 @@ extra_rdoc_files:
|
|
76
90
|
files:
|
77
91
|
- ".gitignore"
|
78
92
|
- ".rspec"
|
93
|
+
- ".travis.yml"
|
79
94
|
- Gemfile
|
80
95
|
- LICENSE.txt
|
81
96
|
- README.md
|
@@ -87,10 +102,10 @@ files:
|
|
87
102
|
- lib/keystorage/cli.rb
|
88
103
|
- lib/keystorage/manager.rb
|
89
104
|
- spec/keystorage/cli_spec.rb
|
105
|
+
- spec/keystorage/files/1.yml
|
90
106
|
- spec/keystorage/manager_spec.rb
|
107
|
+
- spec/keystorage_spec.rb
|
91
108
|
- spec/spec_helper.rb
|
92
|
-
- test/helper.rb
|
93
|
-
- test/test_keystorage.rb
|
94
109
|
homepage: http://github.com/tumf/keystorage
|
95
110
|
licenses:
|
96
111
|
- MIT
|
@@ -117,8 +132,8 @@ specification_version: 4
|
|
117
132
|
summary: Simple password storage
|
118
133
|
test_files:
|
119
134
|
- spec/keystorage/cli_spec.rb
|
135
|
+
- spec/keystorage/files/1.yml
|
120
136
|
- spec/keystorage/manager_spec.rb
|
137
|
+
- spec/keystorage_spec.rb
|
121
138
|
- spec/spec_helper.rb
|
122
|
-
- test/helper.rb
|
123
|
-
- test/test_keystorage.rb
|
124
139
|
has_rdoc:
|
data/test/helper.rb
DELETED
@@ -1,18 +0,0 @@
|
|
1
|
-
require 'rubygems'
|
2
|
-
require 'bundler'
|
3
|
-
begin
|
4
|
-
Bundler.setup(:default, :development)
|
5
|
-
rescue Bundler::BundlerError => e
|
6
|
-
$stderr.puts e.message
|
7
|
-
$stderr.puts "Run `bundle install` to install missing gems"
|
8
|
-
exit e.status_code
|
9
|
-
end
|
10
|
-
require 'test/unit'
|
11
|
-
require 'shoulda'
|
12
|
-
|
13
|
-
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
14
|
-
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
15
|
-
require 'keystorage'
|
16
|
-
|
17
|
-
class Test::Unit::TestCase
|
18
|
-
end
|
data/test/test_keystorage.rb
DELETED
@@ -1,36 +0,0 @@
|
|
1
|
-
require 'helper'
|
2
|
-
require 'fileutils'
|
3
|
-
|
4
|
-
class TestKeystorage < Test::Unit::TestCase
|
5
|
-
@@file = ".testkey"
|
6
|
-
context "set / delete" do
|
7
|
-
setup do
|
8
|
-
Keystorage.set("abc","def","ghi",@@file)
|
9
|
-
Keystorage.set("abc","123","456",@@file)
|
10
|
-
end
|
11
|
-
teardown do
|
12
|
-
FileUtils.rm(@@file)
|
13
|
-
end
|
14
|
-
|
15
|
-
should "file exists" do
|
16
|
-
assert File.exists?(@@file)
|
17
|
-
end
|
18
|
-
|
19
|
-
should "exist def and 123" do
|
20
|
-
assert_equal "ghi",Keystorage.get("abc","def",@@file)
|
21
|
-
assert_equal "456",Keystorage.get("abc","123",@@file)
|
22
|
-
end
|
23
|
-
|
24
|
-
should "delete only def" do
|
25
|
-
Keystorage.delete("abc","def",@@file)
|
26
|
-
assert_equal "456",Keystorage.get("abc","123",@@file)
|
27
|
-
assert_equal false,Keystorage.get("abc","def",@@file)
|
28
|
-
end
|
29
|
-
|
30
|
-
should "delete abc group" do
|
31
|
-
Keystorage.delete("abc",nil,@@file)
|
32
|
-
assert_equal false,Keystorage.get("abc","123",@@file)
|
33
|
-
assert_equal false,Keystorage.get("abc","def",@@file)
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|