secret_store 0.0.2 → 0.0.3
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/lib/secret_store/version.rb +1 -1
- data/lib/secret_store.rb +72 -40
- data/spec/secret_store_spec.rb +66 -4
- metadata +9 -9
data/lib/secret_store/version.rb
CHANGED
data/lib/secret_store.rb
CHANGED
@@ -3,33 +3,21 @@ require "yaml"
|
|
3
3
|
require "secret_store/version"
|
4
4
|
|
5
5
|
class SecretStore
|
6
|
-
attr_reader :file_path
|
7
|
-
|
8
6
|
def initialize(password, file_path)
|
9
7
|
self.password = password
|
10
|
-
|
8
|
+
@data = YamlBackend.new(file_path)
|
11
9
|
end
|
12
10
|
|
13
|
-
def store(key, secret
|
14
|
-
|
15
|
-
|
16
|
-
if @data[key.to_s]
|
17
|
-
raise "Key #{key} already stored"
|
18
|
-
end
|
19
|
-
|
20
|
-
@data.merge!(key.to_s => encrypt(secret))
|
21
|
-
store_data
|
22
|
-
load_data[key]
|
11
|
+
def store(key, secret)
|
12
|
+
@data.insert(key, encrypt(secret))
|
23
13
|
end
|
24
14
|
|
25
15
|
def store!(key, secret)
|
26
|
-
|
27
|
-
@data.delete(key.to_s)
|
28
|
-
store(key, secret, false)
|
16
|
+
@data.overwrite(key, encrypt(secret))
|
29
17
|
end
|
30
18
|
|
31
19
|
def get(key)
|
32
|
-
if ciphertext = @data[key
|
20
|
+
if ciphertext = @data[key]
|
33
21
|
cipher.decrypt(ciphertext)
|
34
22
|
end
|
35
23
|
end
|
@@ -46,17 +34,10 @@ class SecretStore
|
|
46
34
|
decrypted = decrypted_data
|
47
35
|
self.password = new_password
|
48
36
|
replace_with_decrypted(decrypted)
|
49
|
-
store_data
|
50
37
|
end
|
51
38
|
|
52
39
|
private
|
53
40
|
|
54
|
-
def file_path=(file_path)
|
55
|
-
@file_path = file_path
|
56
|
-
load_data
|
57
|
-
@file_path
|
58
|
-
end
|
59
|
-
|
60
41
|
def password=(password)
|
61
42
|
@cipher = nil
|
62
43
|
@password = password
|
@@ -66,22 +47,8 @@ class SecretStore
|
|
66
47
|
@cipher ||= Gibberish::AES.new(@password)
|
67
48
|
end
|
68
49
|
|
69
|
-
def load_data
|
70
|
-
begin
|
71
|
-
@data = YAML.load_file(file_path) || {}
|
72
|
-
rescue Errno::ENOENT
|
73
|
-
@data = {}
|
74
|
-
end
|
75
|
-
end
|
76
|
-
|
77
|
-
def store_data
|
78
|
-
File.open(@file_path, File::RDWR|File::CREAT|File::LOCK_EX, 0640) do |f|
|
79
|
-
f.puts YAML.dump @data
|
80
|
-
end
|
81
|
-
end
|
82
|
-
|
83
50
|
def decrypted_data
|
84
|
-
@data.
|
51
|
+
@data.keys.inject({}) do |decrypted_data, key|
|
85
52
|
decrypted_data[key] = get(key)
|
86
53
|
decrypted_data
|
87
54
|
end
|
@@ -89,7 +56,72 @@ class SecretStore
|
|
89
56
|
|
90
57
|
def replace_with_decrypted(decrypted)
|
91
58
|
decrypted.each do |key, plaintext|
|
92
|
-
@data
|
59
|
+
@data.overwrite(key, encrypt(plaintext))
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
class YamlBackend
|
64
|
+
SAVE_FLAGS = File::RDWR | File::CREAT | File::LOCK_EX
|
65
|
+
SAVE_PERMS = 0640
|
66
|
+
|
67
|
+
def initialize(file_path)
|
68
|
+
@file_path = file_path
|
69
|
+
end
|
70
|
+
|
71
|
+
def [](key)
|
72
|
+
data[key.to_s]
|
73
|
+
end
|
74
|
+
|
75
|
+
def keys
|
76
|
+
data.keys
|
77
|
+
end
|
78
|
+
|
79
|
+
def insert(key, value)
|
80
|
+
if self[key]
|
81
|
+
raise "Key #{key} already stored"
|
82
|
+
end
|
83
|
+
|
84
|
+
data[key.to_s] = value
|
85
|
+
save
|
86
|
+
value
|
87
|
+
end
|
88
|
+
|
89
|
+
def overwrite(key, value)
|
90
|
+
delete!(key.to_s)
|
91
|
+
insert(key, value)
|
92
|
+
end
|
93
|
+
|
94
|
+
def delete(key)
|
95
|
+
return unless self[key]
|
96
|
+
value = delete!(key)
|
97
|
+
save && value
|
98
|
+
end
|
99
|
+
|
100
|
+
def reload
|
101
|
+
@data = nil
|
102
|
+
data && true
|
103
|
+
end
|
104
|
+
|
105
|
+
private
|
106
|
+
|
107
|
+
def delete!(key)
|
108
|
+
data.delete(key.to_s)
|
109
|
+
end
|
110
|
+
|
111
|
+
def data
|
112
|
+
begin
|
113
|
+
@data ||= YAML.load_file(@file_path) || {}
|
114
|
+
rescue Errno::ENOENT
|
115
|
+
@data = {}
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
def save
|
120
|
+
File.open(@file_path, SAVE_FLAGS, SAVE_PERMS) do |f|
|
121
|
+
f.truncate(0)
|
122
|
+
f.puts YAML.dump(data)
|
123
|
+
end
|
124
|
+
true
|
93
125
|
end
|
94
126
|
end
|
95
127
|
end
|
data/spec/secret_store_spec.rb
CHANGED
@@ -5,7 +5,6 @@ describe SecretStore, "initializing" do
|
|
5
5
|
|
6
6
|
it "takes a password and file path" do
|
7
7
|
subject = SecretStore.new("pass", tmpfile.path)
|
8
|
-
subject.file_path.should == tmpfile.path
|
9
8
|
end
|
10
9
|
end
|
11
10
|
|
@@ -82,11 +81,15 @@ describe SecretStore, "changing the password" do
|
|
82
81
|
subject { SecretStore.new("the_pass", tmpfile.path) }
|
83
82
|
|
84
83
|
it "resets the value for each secret key" do
|
85
|
-
|
84
|
+
subject.store("foo", "bar")
|
85
|
+
subject.store("fizz", "buzz")
|
86
|
+
original_data = YAML.load_file(tmpfile.path)
|
87
|
+
|
86
88
|
subject.change_password("new_password")
|
89
|
+
|
87
90
|
data = YAML.load_file(tmpfile.path)
|
88
|
-
data["foo"].should_not == "
|
89
|
-
data["fizz"].should_not == "
|
91
|
+
data["foo"].should_not == original_data["foo"]
|
92
|
+
data["fizz"].should_not == original_data["fizz"]
|
90
93
|
end
|
91
94
|
|
92
95
|
it "leaves you with the ability to get secrets using the new password" do
|
@@ -99,3 +102,62 @@ describe SecretStore, "changing the password" do
|
|
99
102
|
subject.get("foo").should == "bar"
|
100
103
|
end
|
101
104
|
end
|
105
|
+
|
106
|
+
describe SecretStore::YamlBackend do
|
107
|
+
let(:tmpfile) { Tempfile.new("secret_store") }
|
108
|
+
subject { SecretStore::YamlBackend.new(tmpfile) }
|
109
|
+
|
110
|
+
before do
|
111
|
+
tmpfile.puts YAML.dump("foo" => "bar", "fizz" => "buzz")
|
112
|
+
tmpfile.flush
|
113
|
+
end
|
114
|
+
|
115
|
+
it "reads indifferently from its data using []" do
|
116
|
+
subject["foo"].should == "bar"
|
117
|
+
subject["fizz"].should == "buzz"
|
118
|
+
subject[:fizz].should == "buzz"
|
119
|
+
end
|
120
|
+
|
121
|
+
it "can return the keys on data" do
|
122
|
+
subject.keys.should =~ %w[foo fizz]
|
123
|
+
end
|
124
|
+
|
125
|
+
it "can reload data on demand" do
|
126
|
+
File.open(tmpfile.path, 'w') do |f|
|
127
|
+
f.puts YAML.dump("foo" => "reloaded")
|
128
|
+
end
|
129
|
+
|
130
|
+
subject.reload
|
131
|
+
subject["foo"].should == "reloaded"
|
132
|
+
end
|
133
|
+
|
134
|
+
it "can insert a value for a non-existant key" do
|
135
|
+
subject.insert("new", "value")
|
136
|
+
subject.reload
|
137
|
+
subject["new"].should == "value"
|
138
|
+
end
|
139
|
+
|
140
|
+
it "will raise an error trying to insert for an existing key" do
|
141
|
+
lambda {
|
142
|
+
subject.insert("foo", "123")
|
143
|
+
}.should raise_error
|
144
|
+
end
|
145
|
+
|
146
|
+
it "can overwrite an existing key" do
|
147
|
+
subject.overwrite("foo", "123")
|
148
|
+
subject.reload
|
149
|
+
subject["foo"].should == "123"
|
150
|
+
end
|
151
|
+
|
152
|
+
it "can delete a key" do
|
153
|
+
subject.delete("foo").should == "bar"
|
154
|
+
subject.reload
|
155
|
+
subject.keys.should == ["fizz"]
|
156
|
+
end
|
157
|
+
|
158
|
+
it "can save the data" do
|
159
|
+
subject.overwrite("foo", "123")
|
160
|
+
data = SecretStore::YamlBackend.new(tmpfile)
|
161
|
+
data["foo"].should == "123"
|
162
|
+
end
|
163
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: secret_store
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -13,7 +13,7 @@ date: 2012-08-11 00:00:00.000000000 Z
|
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: gibberish
|
16
|
-
requirement: &
|
16
|
+
requirement: &2153518960 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: '0'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *2153518960
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: rake
|
27
|
-
requirement: &
|
27
|
+
requirement: &2153518540 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ! '>='
|
@@ -32,10 +32,10 @@ dependencies:
|
|
32
32
|
version: '0'
|
33
33
|
type: :development
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *2153518540
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: rspec
|
38
|
-
requirement: &
|
38
|
+
requirement: &2153518120 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ! '>='
|
@@ -43,7 +43,7 @@ dependencies:
|
|
43
43
|
version: '0'
|
44
44
|
type: :development
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *2153518120
|
47
47
|
description: Store secrets for your app in a encrypted in a yaml file.
|
48
48
|
email:
|
49
49
|
- xternal1+github@gmail.com
|
@@ -74,7 +74,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
74
74
|
version: '0'
|
75
75
|
segments:
|
76
76
|
- 0
|
77
|
-
hash:
|
77
|
+
hash: -2358538595218873167
|
78
78
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
79
79
|
none: false
|
80
80
|
requirements:
|
@@ -83,7 +83,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
83
83
|
version: '0'
|
84
84
|
segments:
|
85
85
|
- 0
|
86
|
-
hash:
|
86
|
+
hash: -2358538595218873167
|
87
87
|
requirements: []
|
88
88
|
rubyforge_project: secret_store
|
89
89
|
rubygems_version: 1.8.15
|