syde 0.0.1 → 0.0.2
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/{LICENSE.mit → LICENSE} +0 -0
- data/README.md +2 -1
- data/lib/syde.rb +4 -1
- data/syde.gemspec +2 -3
- data/test/test_vault.rb +10 -1
- metadata +20 -7
- data/lib/syde/vault.rb~ +0 -214
data/{LICENSE.mit → LICENSE}
RENAMED
File without changes
|
data/README.md
CHANGED
@@ -21,6 +21,7 @@ To contribute:
|
|
21
21
|
|
22
22
|
* Fork it
|
23
23
|
* Make a new feature branch: `git checkout -b some-new-thing master`
|
24
|
+
* Hack away and add tests
|
24
25
|
* Pull request
|
25
26
|
|
26
27
|
Basic usage
|
@@ -64,7 +65,7 @@ To delete something in the vault, use `delete`:
|
|
64
65
|
vault.contents #=> ["foo"]
|
65
66
|
string = vault.contents.first #=> "foo"
|
66
67
|
string.replace("bar")
|
67
|
-
vault.contents #=> ["
|
68
|
+
vault.contents #=> ["foo"]
|
68
69
|
|
69
70
|
Objects in the vault are serialised and then deserialised and as such are not modifiable.
|
70
71
|
|
data/lib/syde.rb
CHANGED
@@ -1,3 +1,6 @@
|
|
1
|
+
# Copyright (c) 2010 Adam Prescott
|
2
|
+
# Licensed under the MIT license. See LICENSE.
|
3
|
+
|
1
4
|
require "openssl"
|
2
5
|
require "yaml"
|
3
6
|
require "fileutils"
|
@@ -10,7 +13,7 @@ FileUtils.mkdir(File.expand_path("~/.syde")) unless File.exist?(File.expand_path
|
|
10
13
|
module Syde
|
11
14
|
SYDE_VERSION_MAJOR = "0"
|
12
15
|
SYDE_VERSION_MINOR = "0"
|
13
|
-
SYDE_VERSION_TINY = "
|
16
|
+
SYDE_VERSION_TINY = "2"
|
14
17
|
|
15
18
|
SYDE_VERSION = [SYDE_VERSION_MAJOR, SYDE_VERSION_MINOR, SYDE_VERSION_TINY].join(".")
|
16
19
|
|
data/syde.gemspec
CHANGED
@@ -1,15 +1,14 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = "syde"
|
3
|
-
s.version = "0.0.
|
3
|
+
s.version = "0.0.2"
|
4
4
|
s.authors = ["Adam Prescott"]
|
5
5
|
s.email = ["adam@aprescott.com"]
|
6
6
|
s.homepage = "https://github.com/aprescott/syde"
|
7
7
|
s.summary = "Symmetric data encryption library."
|
8
8
|
s.description = "Syde is a symmetric data encryption library written in Ruby, licensed under the MIT license. It provides a saved encrypted data storage under a single password."
|
9
|
-
s.files = Dir["{lib/**/*,test/**/*}"] + %w[LICENSE
|
9
|
+
s.files = Dir["{lib/**/*,test/**/*}"] + %w[LICENSE Gemfile rakefile README.md syde.gemspec .gemtest]
|
10
10
|
s.require_path = "lib"
|
11
11
|
s.test_files = Dir["test/*"]
|
12
|
-
s.has_rdoc = false
|
13
12
|
s.add_development_dependency "rake"
|
14
13
|
s.required_ruby_version = "~> 1.8.7"
|
15
14
|
s.requirements << "Ruby 1.8.7, does not work with 1.9 (yet) due to encodings"
|
data/test/test_vault.rb
CHANGED
@@ -65,4 +65,13 @@ class TC_Syde_Vault < Test::Unit::TestCase
|
|
65
65
|
@vault.unlock("test_password", 0)
|
66
66
|
assert @vault.locked?
|
67
67
|
end
|
68
|
-
|
68
|
+
|
69
|
+
def test_contents_not_overridable
|
70
|
+
@vault.unlock!("test_password")
|
71
|
+
@vault << "foo"
|
72
|
+
assert @vault.contents.last == "foo"
|
73
|
+
@vault.contents.last.replace("bar")
|
74
|
+
assert @vault.contents.last == "foo"
|
75
|
+
assert @vault.contents.last != "bar"
|
76
|
+
end
|
77
|
+
end
|
metadata
CHANGED
@@ -1,8 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: syde
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
+
hash: 27
|
4
5
|
prerelease:
|
5
|
-
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 0
|
9
|
+
- 2
|
10
|
+
version: 0.0.2
|
6
11
|
platform: ruby
|
7
12
|
authors:
|
8
13
|
- Adam Prescott
|
@@ -10,8 +15,7 @@ autorequire:
|
|
10
15
|
bindir: bin
|
11
16
|
cert_chain: []
|
12
17
|
|
13
|
-
date: 2011-05-
|
14
|
-
default_executable:
|
18
|
+
date: 2011-05-19 00:00:00 Z
|
15
19
|
dependencies:
|
16
20
|
- !ruby/object:Gem::Dependency
|
17
21
|
name: rake
|
@@ -21,6 +25,9 @@ dependencies:
|
|
21
25
|
requirements:
|
22
26
|
- - ">="
|
23
27
|
- !ruby/object:Gem::Version
|
28
|
+
hash: 3
|
29
|
+
segments:
|
30
|
+
- 0
|
24
31
|
version: "0"
|
25
32
|
type: :development
|
26
33
|
version_requirements: *id001
|
@@ -37,7 +44,6 @@ files:
|
|
37
44
|
- lib/syde.rb
|
38
45
|
- lib/syde.rb~
|
39
46
|
- lib/syde/vault.rb
|
40
|
-
- lib/syde/vault.rb~
|
41
47
|
- lib/syde/errors.rb
|
42
48
|
- lib/syde/storage.rb
|
43
49
|
- lib/syde/crypto.rb
|
@@ -45,13 +51,12 @@ files:
|
|
45
51
|
- test/test_vault.rb
|
46
52
|
- test/_test.rb
|
47
53
|
- test/test_crypto.rb
|
48
|
-
- LICENSE
|
54
|
+
- LICENSE
|
49
55
|
- Gemfile
|
50
56
|
- rakefile
|
51
57
|
- README.md
|
52
58
|
- syde.gemspec
|
53
59
|
- .gemtest
|
54
|
-
has_rdoc: true
|
55
60
|
homepage: https://github.com/aprescott/syde
|
56
61
|
licenses: []
|
57
62
|
|
@@ -65,17 +70,25 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
65
70
|
requirements:
|
66
71
|
- - ~>
|
67
72
|
- !ruby/object:Gem::Version
|
73
|
+
hash: 57
|
74
|
+
segments:
|
75
|
+
- 1
|
76
|
+
- 8
|
77
|
+
- 7
|
68
78
|
version: 1.8.7
|
69
79
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
70
80
|
none: false
|
71
81
|
requirements:
|
72
82
|
- - ">="
|
73
83
|
- !ruby/object:Gem::Version
|
84
|
+
hash: 3
|
85
|
+
segments:
|
86
|
+
- 0
|
74
87
|
version: "0"
|
75
88
|
requirements:
|
76
89
|
- Ruby 1.8.7, does not work with 1.9 (yet) due to encodings
|
77
90
|
rubyforge_project:
|
78
|
-
rubygems_version: 1.
|
91
|
+
rubygems_version: 1.8.2
|
79
92
|
signing_key:
|
80
93
|
specification_version: 3
|
81
94
|
summary: Symmetric data encryption library.
|
data/lib/syde/vault.rb~
DELETED
@@ -1,214 +0,0 @@
|
|
1
|
-
module Syde
|
2
|
-
class Vault
|
3
|
-
include Errors
|
4
|
-
|
5
|
-
attr_accessor :plaintext_secret_key
|
6
|
-
attr_reader :file
|
7
|
-
|
8
|
-
def self.open(file = Storage::DefaultStorageFile)
|
9
|
-
file = File.expand_path(file)
|
10
|
-
FileUtils.touch(file) unless File.exist?(file)
|
11
|
-
|
12
|
-
Vault.new(YAML.load_file(file) || "", file)
|
13
|
-
end
|
14
|
-
|
15
|
-
def self.create(password, file = Storage::DefaultStorageFile)
|
16
|
-
file = File.expand_path(file)
|
17
|
-
|
18
|
-
raise "#{file} contains content -- refusing to override." if File.exist?(file) && File.size(file) > 0
|
19
|
-
|
20
|
-
FileUtils.touch(file) unless File.exist?(file)
|
21
|
-
|
22
|
-
h = {}
|
23
|
-
[:plaintext, :encrypted].each { |e| h[e] = {} }
|
24
|
-
|
25
|
-
h[:plaintext][:iv] = Crypto.new_iv
|
26
|
-
new_secret_key = Vault.new_secret_key(password, h[:plaintext][:iv])
|
27
|
-
encrypted_key = new_secret_key[:encrypted_key]
|
28
|
-
hash = new_secret_key[:plaintext_key_hash]
|
29
|
-
plaintext_key = new_secret_key[:plaintext_key]
|
30
|
-
|
31
|
-
h[:encrypted][:secret_key] = encrypted_key
|
32
|
-
h[:plaintext][:secret_key_hash] = hash
|
33
|
-
|
34
|
-
h[:encrypted][:contents] = Crypto.encrypt(plaintext_key, h[:plaintext][:iv], YAML.dump([]))
|
35
|
-
h[:plaintext][:contents] = []
|
36
|
-
|
37
|
-
File.open(file, "w") do |f|
|
38
|
-
f << YAML.dump(h)
|
39
|
-
end
|
40
|
-
|
41
|
-
Vault.new(h, file)
|
42
|
-
end
|
43
|
-
|
44
|
-
def initialize(data, file)
|
45
|
-
@data = data
|
46
|
-
@file = file.freeze
|
47
|
-
|
48
|
-
raise ArgumentError, "unable to find any stored data." if @data.empty?
|
49
|
-
raise ArgumentError, "data is not valid." unless Storage.valid_format?(@data)
|
50
|
-
end
|
51
|
-
|
52
|
-
def data
|
53
|
-
if locked?
|
54
|
-
public_data
|
55
|
-
else
|
56
|
-
internal_data
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
|
-
def public_data
|
61
|
-
public_data = YAML.load(YAML.dump(internal_data))
|
62
|
-
public_data[:plaintext].delete(:contents)
|
63
|
-
public_data
|
64
|
-
end
|
65
|
-
|
66
|
-
private
|
67
|
-
|
68
|
-
def internal_data
|
69
|
-
@data
|
70
|
-
end
|
71
|
-
|
72
|
-
public
|
73
|
-
|
74
|
-
def iv
|
75
|
-
internal_data[:plaintext][:iv]
|
76
|
-
end
|
77
|
-
|
78
|
-
def secret_key_hash
|
79
|
-
internal_data[:plaintext][:secret_key_hash]
|
80
|
-
end
|
81
|
-
|
82
|
-
def decrypt_secret_key(password)
|
83
|
-
Crypto.aes(:decrypt, password, iv, internal_data[:encrypted][:secret_key])
|
84
|
-
end
|
85
|
-
|
86
|
-
def lock
|
87
|
-
internal_data[:encrypted][:contents] = Crypto.encrypt(@plaintext_secret_key, iv, YAML.dump(internal_data[:plaintext][:contents]))
|
88
|
-
internal_data[:plaintext][:contents] = nil
|
89
|
-
@plaintext_secret_key = nil
|
90
|
-
end
|
91
|
-
|
92
|
-
def unlock!(password = nil)
|
93
|
-
raise MissingPasswordError, "no password given." unless password
|
94
|
-
|
95
|
-
plaintext_secret_key = decrypt_secret_key(password)
|
96
|
-
if Crypto.digest(plaintext_secret_key) != secret_key_hash
|
97
|
-
raise PasswordIncorrectError
|
98
|
-
else
|
99
|
-
@plaintext_secret_key = plaintext_secret_key
|
100
|
-
internal_data[:encrypted][:contents] ||= Crypto.encrypt(@plaintext_secret_key, iv, YAML.dump([]))
|
101
|
-
internal_data[:plaintext][:contents] = YAML.load(Crypto.decrypt(@plaintext_secret_key, iv, internal_data[:encrypted][:contents]))
|
102
|
-
end
|
103
|
-
end
|
104
|
-
|
105
|
-
def unlock(password = nil, timeout = 5 * 60)
|
106
|
-
return false unless timeout > 0
|
107
|
-
unlock!(password)
|
108
|
-
start_locking_timer(timeout)
|
109
|
-
true
|
110
|
-
end
|
111
|
-
|
112
|
-
def start_locking_timer(seconds)
|
113
|
-
Thread.new do
|
114
|
-
sleep seconds
|
115
|
-
self.lock
|
116
|
-
end
|
117
|
-
end
|
118
|
-
|
119
|
-
def locked?
|
120
|
-
if plaintext_secret_key
|
121
|
-
false
|
122
|
-
else
|
123
|
-
true
|
124
|
-
end
|
125
|
-
end
|
126
|
-
|
127
|
-
def plaintext_contents
|
128
|
-
raise AccessError, "vault is locked; unable to access vault contents." if locked?
|
129
|
-
|
130
|
-
YAML.load(YAML.dump(internal_contents))
|
131
|
-
end
|
132
|
-
|
133
|
-
private
|
134
|
-
|
135
|
-
def internal_contents
|
136
|
-
internal_data[:plaintext][:contents]
|
137
|
-
end
|
138
|
-
|
139
|
-
public
|
140
|
-
|
141
|
-
def contents
|
142
|
-
if locked?
|
143
|
-
public_contents
|
144
|
-
else
|
145
|
-
plaintext_contents
|
146
|
-
end
|
147
|
-
end
|
148
|
-
|
149
|
-
def public_contents
|
150
|
-
raise AccessError, "vault is locked; unable to access vault contents." if locked?
|
151
|
-
|
152
|
-
public_data[:plaintext][:contents]
|
153
|
-
end
|
154
|
-
|
155
|
-
private
|
156
|
-
|
157
|
-
def update_contents(new_content)
|
158
|
-
internal_data[:encrypted][:contents] = Crypto.encrypt(@plaintext_secret_key, iv, YAML.dump(internal_contents))
|
159
|
-
|
160
|
-
Storage.write(YAML.dump(public_data), file)
|
161
|
-
|
162
|
-
plaintext_contents
|
163
|
-
end
|
164
|
-
|
165
|
-
public
|
166
|
-
|
167
|
-
def contents=(new_content)
|
168
|
-
raise AccessError, "vault is locked; unable to modify vault contents." if locked?
|
169
|
-
|
170
|
-
internal_contents.replace(new_content)
|
171
|
-
|
172
|
-
update_contents(new_content)
|
173
|
-
end
|
174
|
-
|
175
|
-
def add(*contents)
|
176
|
-
raise AccessError, "vault is locked; unable to add content to vault." if locked?
|
177
|
-
|
178
|
-
contents.each do |content|
|
179
|
-
internal_contents << content
|
180
|
-
end
|
181
|
-
|
182
|
-
update_contents(internal_contents)
|
183
|
-
end
|
184
|
-
alias_method :<<, :add
|
185
|
-
|
186
|
-
def remove(*contents)
|
187
|
-
raise AccessError, "vault is locked; unable to remove content from vault." if locked?
|
188
|
-
|
189
|
-
contents.each do |content|
|
190
|
-
internal_contents.delete(content)
|
191
|
-
end
|
192
|
-
|
193
|
-
update_contents(internal_contents)
|
194
|
-
end
|
195
|
-
|
196
|
-
def status
|
197
|
-
locked? ? "locked" : "unlocked"
|
198
|
-
end
|
199
|
-
|
200
|
-
def inspect
|
201
|
-
%Q{#<Vault (#{status})>}
|
202
|
-
end
|
203
|
-
|
204
|
-
def self.new_secret_key(password, iv)
|
205
|
-
plaintext = Crypto.digest(Crypto.random_bytes(4096))
|
206
|
-
new_key = Crypto.aes(:encrypt, password, iv, plaintext)
|
207
|
-
#? plaintext = nil
|
208
|
-
#? GC.start
|
209
|
-
{ :encrypted_key => new_key,
|
210
|
-
:plaintext_key_hash => Crypto.digest(plaintext),
|
211
|
-
:plaintext_key => plaintext }
|
212
|
-
end
|
213
|
-
end
|
214
|
-
end
|