slosilo 1.0.0 → 1.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/README.md +109 -3
- data/lib/slosilo/version.rb +1 -1
- data/slosilo.gemspec +2 -2
- data/spec/file_adapter_spec.rb +10 -10
- data/spec/key_spec.rb +57 -37
- data/spec/keystore_spec.rb +2 -2
- data/spec/random_spec.rb +12 -2
- data/spec/sequel_adapter_spec.rb +26 -30
- data/spec/slosilo_spec.rb +15 -15
- data/spec/spec_helper.rb +1 -19
- data/spec/symmetric_spec.rb +9 -9
- metadata +26 -25
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 19532fb817cc0d993257331452fd6fc36be49da8
|
4
|
+
data.tar.gz: 63c9b867b4e125aff0e5680e21a9a31605629716
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 799000b32ea19b4b5ca3fb63901007e16c659af8ea383f3d469ed4a91a1c23b10529eeffda3167b73e0bf67043258622c997b68fefd110cf5fb96cedc8b3769c
|
7
|
+
data.tar.gz: c017465fd76fd4aa9812924ead3c3342d66d3f87f222cd94c0f08c0eadd2dd66c7088e3bc5333ae6d4a83f165c2329456cc38158b2de5d17e76dd1fe0d098449
|
data/README.md
CHANGED
@@ -1,7 +1,11 @@
|
|
1
1
|
# Slosilo
|
2
2
|
|
3
|
-
Slosilo is a
|
4
|
-
|
3
|
+
Slosilo is providing a ruby interface to some cryptographic primitives:
|
4
|
+
- symmetric encryption,
|
5
|
+
- a mixin for easy encryption of object attributes (WARNING: unauthenticated, see below),
|
6
|
+
- asymmetric encryption and signing,
|
7
|
+
- a keystore in a postgres sequel db -- it allows easy storage and retrieval of keys,
|
8
|
+
- a keystore in files.
|
5
9
|
|
6
10
|
## Installation
|
7
11
|
|
@@ -13,6 +17,105 @@ And then execute:
|
|
13
17
|
|
14
18
|
$ bundle
|
15
19
|
|
20
|
+
## Usage
|
21
|
+
|
22
|
+
### Symmetric encryption
|
23
|
+
|
24
|
+
```ruby
|
25
|
+
sym = Slosilo::Symmetric.new
|
26
|
+
key = sym.random_key
|
27
|
+
ciphertext = sym.encrypt "secret message", key: key
|
28
|
+
```
|
29
|
+
|
30
|
+
```ruby
|
31
|
+
sym = Slosilo::Symmetric.new
|
32
|
+
message = sym.decrypt ciphertext, key: key
|
33
|
+
```
|
34
|
+
|
35
|
+
### Encryption mixin
|
36
|
+
|
37
|
+
```ruby
|
38
|
+
require 'slosilo'
|
39
|
+
|
40
|
+
class Foo
|
41
|
+
attr_accessor :foo
|
42
|
+
attr_encrypted :foo
|
43
|
+
|
44
|
+
def raw_foo
|
45
|
+
@foo
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
Slosilo::encryption_key = Slosilo::Symmetric.new.random_key
|
50
|
+
|
51
|
+
obj = Foo.new
|
52
|
+
obj.foo = "bar"
|
53
|
+
obj.raw_foo # => "\xC4\xEF\x87\xD3b\xEA\x12\xDF\xD0\xD4hk\xEDJ\v\x1Cr\xF2#\xA3\x11\xA4*k\xB7\x8F\x8F\xC2\xBD\xBB\xFF\xE3"
|
54
|
+
obj.foo # => "bar"
|
55
|
+
```
|
56
|
+
|
57
|
+
You can safely use it in ie. ActiveRecord::Base or Sequel::Model subclasses.
|
58
|
+
|
59
|
+
#### Warning
|
60
|
+
|
61
|
+
The encrypted data is not authenticated; it's intended to prevent
|
62
|
+
opportunistic access to secrets by a third party which gets hold of a database
|
63
|
+
dump. *IT DOES NOT prevent tampering.* If your threat model includes an attacker
|
64
|
+
which can modify the database, `attr_encrypted` by itself IS NOT SECURE.
|
65
|
+
|
66
|
+
### Asymmetric encryption and signing
|
67
|
+
|
68
|
+
```ruby
|
69
|
+
private_key = Slosilo::Key.new
|
70
|
+
public_key = private_key.public
|
71
|
+
```
|
72
|
+
|
73
|
+
#### Key dumping
|
74
|
+
```ruby
|
75
|
+
k = public_key.to_s # => "-----BEGIN PUBLIC KEY----- ...
|
76
|
+
(Slosilo::Key.new k) == public_key # => true
|
77
|
+
```
|
78
|
+
|
79
|
+
#### Encryption
|
80
|
+
|
81
|
+
```ruby
|
82
|
+
encrypted = public_key.encrypt_message "eagle one sees many clouds"
|
83
|
+
# => "\xA3\x1A\xD2\xFC\xB0 ...
|
84
|
+
|
85
|
+
public_key.decrypt_message encrypted
|
86
|
+
# => OpenSSL::PKey::RSAError: private key needed.
|
87
|
+
|
88
|
+
private_key.decrypt_message encrypted
|
89
|
+
# => "eagle one sees many clouds"
|
90
|
+
```
|
91
|
+
|
92
|
+
#### Signing
|
93
|
+
|
94
|
+
```ruby
|
95
|
+
token = private_key.signed_token "missile launch not authorized"
|
96
|
+
# => {"data"=>"missile launch not authorized", "timestamp"=>"2014-10-13 12:41:25 UTC", "signature"=>"bSImk...DzV3o", "key"=>"455f7ac42d2d483f750b4c380761821d"}
|
97
|
+
|
98
|
+
public_key.token_valid? token # => true
|
99
|
+
|
100
|
+
token["data"] = "missile launch authorized"
|
101
|
+
public_key.token_valid? token # => false
|
102
|
+
```
|
103
|
+
|
104
|
+
### Keystore
|
105
|
+
|
106
|
+
```ruby
|
107
|
+
Slosilo::encryption_key = ENV['SLOSILO_KEY']
|
108
|
+
Slosilo.adapter = Slosilo::Adapters::FileAdapter.new "~/.keys"
|
109
|
+
|
110
|
+
Slosilo[:own] = Slosilo::Key.new
|
111
|
+
Slosilo[:their] = Slosilo::Key.new File.read("foo.pem")
|
112
|
+
|
113
|
+
msg = Slosilo[:their].encrypt_message 'bar'
|
114
|
+
p Slosilo[:own].signed_token msg
|
115
|
+
```
|
116
|
+
|
117
|
+
### Keystore in database
|
118
|
+
|
16
119
|
Add a migration to create the necessary table:
|
17
120
|
|
18
121
|
require 'slosilo/adapters/sequel_adapter/migration'
|
@@ -21,7 +124,10 @@ Remember to migrate your database
|
|
21
124
|
|
22
125
|
$ rake db:migrate
|
23
126
|
|
24
|
-
|
127
|
+
Then
|
128
|
+
```ruby
|
129
|
+
Slosilo.adapter = Slosilo::Adapters::SequelAdapter.new
|
130
|
+
```
|
25
131
|
|
26
132
|
## Contributing
|
27
133
|
|
data/lib/slosilo/version.rb
CHANGED
data/slosilo.gemspec
CHANGED
@@ -18,8 +18,8 @@ Gem::Specification.new do |gem|
|
|
18
18
|
gem.required_ruby_version = '>= 1.9.3'
|
19
19
|
|
20
20
|
gem.add_development_dependency 'rake'
|
21
|
-
gem.add_development_dependency 'rspec', '~>
|
22
|
-
gem.add_development_dependency '
|
21
|
+
gem.add_development_dependency 'rspec', '~> 3.0'
|
22
|
+
gem.add_development_dependency 'ci_reporter_rspec'
|
23
23
|
gem.add_development_dependency 'simplecov'
|
24
24
|
gem.add_development_dependency 'io-grab', '~> 0.0.1'
|
25
25
|
gem.add_development_dependency 'sequel' # for sequel tests
|
data/spec/file_adapter_spec.rb
CHANGED
@@ -13,7 +13,7 @@ describe Slosilo::Adapters::FileAdapter do
|
|
13
13
|
describe "#get_key" do
|
14
14
|
context "when given key does not exist" do
|
15
15
|
it "returns nil" do
|
16
|
-
subject.get_key(:whatever).
|
16
|
+
expect(subject.get_key(:whatever)).not_to be
|
17
17
|
end
|
18
18
|
end
|
19
19
|
end
|
@@ -22,7 +22,7 @@ describe Slosilo::Adapters::FileAdapter do
|
|
22
22
|
context "unacceptable id" do
|
23
23
|
let(:id) { "foo.bar" }
|
24
24
|
it "isn't accepted" do
|
25
|
-
|
25
|
+
expect { subject.put_key id, key }.to raise_error
|
26
26
|
end
|
27
27
|
end
|
28
28
|
context "acceptable id" do
|
@@ -30,11 +30,11 @@ describe Slosilo::Adapters::FileAdapter do
|
|
30
30
|
let(:key_encrypted) { "encrypted key" }
|
31
31
|
let(:fname) { "#{dir}/#{id}.key" }
|
32
32
|
it "creates the key" do
|
33
|
-
Slosilo::EncryptedAttributes.
|
34
|
-
File.
|
35
|
-
File.
|
33
|
+
expect(Slosilo::EncryptedAttributes).to receive(:encrypt).with(key.to_der).and_return key_encrypted
|
34
|
+
expect(File).to receive(:write).with(fname, key_encrypted)
|
35
|
+
expect(File).to receive(:chmod).with(0400, fname)
|
36
36
|
subject.put_key id, key
|
37
|
-
subject.instance_variable_get("@keys")[id].
|
37
|
+
expect(subject.instance_variable_get("@keys")[id]).to eq(key)
|
38
38
|
end
|
39
39
|
end
|
40
40
|
end
|
@@ -45,7 +45,7 @@ describe Slosilo::Adapters::FileAdapter do
|
|
45
45
|
it "iterates over each key" do
|
46
46
|
results = []
|
47
47
|
adapter.each { |id,k| results << { id => k } }
|
48
|
-
results.
|
48
|
+
expect(results).to eq([ { one: :onek}, {two: :twok } ])
|
49
49
|
end
|
50
50
|
end
|
51
51
|
|
@@ -60,13 +60,13 @@ describe Slosilo::Adapters::FileAdapter do
|
|
60
60
|
|
61
61
|
describe '#get_key' do
|
62
62
|
it "loads and decrypts the key" do
|
63
|
-
adapter.get_key(id).
|
63
|
+
expect(adapter.get_key(id)).to eq(key)
|
64
64
|
end
|
65
65
|
end
|
66
66
|
|
67
67
|
describe '#get_by_fingerprint' do
|
68
68
|
it "can look up a key by a fingerprint" do
|
69
|
-
adapter.get_by_fingerprint(key_fingerprint).
|
69
|
+
expect(adapter.get_by_fingerprint(key_fingerprint)).to eq([key, id])
|
70
70
|
end
|
71
71
|
end
|
72
72
|
|
@@ -74,7 +74,7 @@ describe Slosilo::Adapters::FileAdapter do
|
|
74
74
|
it "enumerates the keys" do
|
75
75
|
results = []
|
76
76
|
adapter.each { |id,k| results << { id => k } }
|
77
|
-
results.
|
77
|
+
expect(results).to eq([ { id => key } ])
|
78
78
|
end
|
79
79
|
end
|
80
80
|
end
|
data/spec/key_spec.rb
CHANGED
@@ -4,38 +4,50 @@ describe Slosilo::Key do
|
|
4
4
|
include_context "with example key"
|
5
5
|
|
6
6
|
subject { key }
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
7
|
+
|
8
|
+
describe '#to_der' do
|
9
|
+
subject { super().to_der }
|
10
|
+
it { is_expected.to eq(rsa.to_der) }
|
11
|
+
end
|
12
|
+
|
13
|
+
describe '#to_s' do
|
14
|
+
subject { super().to_s }
|
15
|
+
it { is_expected.to eq(rsa.public_key.to_pem) }
|
16
|
+
end
|
17
|
+
|
18
|
+
describe '#fingerprint' do
|
19
|
+
subject { super().fingerprint }
|
20
|
+
it { is_expected.to eq(key_fingerprint) }
|
21
|
+
end
|
22
|
+
it { is_expected.to be_private }
|
11
23
|
|
12
24
|
context "with identical key" do
|
13
25
|
let(:other) { Slosilo::Key.new rsa.to_der }
|
14
26
|
it "is equal" do
|
15
|
-
subject.
|
27
|
+
expect(subject).to eq(other)
|
16
28
|
end
|
17
29
|
|
18
30
|
it "is eql?" do
|
19
|
-
subject.eql?(other).
|
31
|
+
expect(subject.eql?(other)).to be_truthy
|
20
32
|
end
|
21
33
|
|
22
34
|
it "has equal hash" do
|
23
|
-
subject.hash.
|
35
|
+
expect(subject.hash).to eq(other.hash)
|
24
36
|
end
|
25
37
|
end
|
26
38
|
|
27
39
|
context "with a different key" do
|
28
40
|
let(:other) { Slosilo::Key.new another_rsa }
|
29
41
|
it "is not equal" do
|
30
|
-
subject.
|
42
|
+
expect(subject).not_to eq(other)
|
31
43
|
end
|
32
44
|
|
33
45
|
it "is not eql?" do
|
34
|
-
subject.eql?(other).
|
46
|
+
expect(subject.eql?(other)).not_to be_truthy
|
35
47
|
end
|
36
48
|
|
37
49
|
it "has different hash" do
|
38
|
-
subject.hash.
|
50
|
+
expect(subject.hash).not_to eq(other.hash)
|
39
51
|
end
|
40
52
|
end
|
41
53
|
|
@@ -54,14 +66,14 @@ describe Slosilo::Key do
|
|
54
66
|
it "generates a symmetric encryption key and encrypts the plaintext with the public key" do
|
55
67
|
ctxt, skey = subject.encrypt plaintext
|
56
68
|
pskey = rsa.private_decrypt skey
|
57
|
-
Slosilo::Symmetric.new.decrypt(ctxt, key: pskey).
|
69
|
+
expect(Slosilo::Symmetric.new.decrypt(ctxt, key: pskey)).to eq(plaintext)
|
58
70
|
end
|
59
71
|
end
|
60
72
|
|
61
73
|
describe '#encrypt_message' do
|
62
74
|
it "#encrypts a message and then returns the result as a single string" do
|
63
|
-
subject.
|
64
|
-
subject.encrypt_message(plaintext).
|
75
|
+
expect(subject).to receive(:encrypt).with(plaintext).and_return ['fake ciphertext', 'fake key']
|
76
|
+
expect(subject.encrypt_message(plaintext)).to eq('fake keyfake ciphertext')
|
65
77
|
end
|
66
78
|
end
|
67
79
|
|
@@ -69,14 +81,14 @@ describe Slosilo::Key do
|
|
69
81
|
let(:skey) { "\x15\xFF\xD4>\x9C\xF4\x0F\xB6\x04C\x18\xC1\x96\xC3\xE0T\xA3\xF5\xE8\x17\xA6\xE0\x86~rrw\xC3\xDF\x11)$\x9B\r@\x0E\xE4Zv\rw-\xFC\x1C\x84\x17\xBD\xDB\x12u\xCD\r\xFEo\xD5\xC8[\x8FEA\\\xA9\xA2F#\x8BH -\xFA\xF7\xA9\xEBf\x97\xAAT}\x8E*\xC0r\x944p\xD0\x9A\xE7\xBD\a;O\f\xEF\xE4B.y\xFA\xB4e@O\xBB\x15>y\xC9\t=\x01\xE1J\xF3X\xA9\x9E3\x04^H\x1F\xFF\x19C\x93ve)@\xF7\t_\xCF\xDE\xF1\xB7]\x83lL\xB8%A\x93p{\xE9Y\xBAu\xCE\x99T\xDC\xDF\xE7\x0FD%\xB9AXb\x1CW\x94$P\xBB\xE1g\xDEE\t\xC4\x92\x9E\xFEt\xDF\xD0\xEA\x03\xC4\x12\xA9\x02~u\xF4\x92 ;\xA0\xCE.\b+)\x05\xEDo\xA5cF\xF8\x12\xD7F\x97\xE44\xBF\xF1@\xA5\xC5\xA8\xE5\a\xE8ra<\x04\xB5\xA2\f\t\xF7T\x97\e\xF5(^\xAB\xA5%84\x10\xD1\x13e<\xCA/\xBF}%\xF6\xB1%\xB2".force_encoding("ASCII-8BIT") }
|
70
82
|
describe '#decrypt' do
|
71
83
|
it "decrypts the symmetric key and then uses it to decrypt the ciphertext" do
|
72
|
-
subject.decrypt(ciphertext, skey).
|
84
|
+
expect(subject.decrypt(ciphertext, skey)).to eq(plaintext)
|
73
85
|
end
|
74
86
|
end
|
75
87
|
|
76
88
|
describe '#decrypt_message' do
|
77
89
|
it "splits the message into key and rest, then #decrypts it" do
|
78
|
-
subject.
|
79
|
-
subject.decrypt_message(skey + ciphertext).
|
90
|
+
expect(subject).to receive(:decrypt).with(ciphertext, skey).and_return plaintext
|
91
|
+
expect(subject.decrypt_message(skey + ciphertext)).to eq(plaintext)
|
80
92
|
end
|
81
93
|
end
|
82
94
|
|
@@ -85,17 +97,25 @@ describe Slosilo::Key do
|
|
85
97
|
subject { Slosilo::Key.new }
|
86
98
|
let (:rsa) { double "key" }
|
87
99
|
it "generates a new key pair" do
|
88
|
-
OpenSSL::PKey::RSA.
|
89
|
-
subject.key.
|
100
|
+
expect(OpenSSL::PKey::RSA).to receive(:new).with(2048).and_return(rsa)
|
101
|
+
expect(subject.key).to eq(rsa)
|
90
102
|
end
|
91
103
|
end
|
92
104
|
context "when given an armored key" do
|
93
105
|
subject { Slosilo::Key.new rsa.to_der }
|
94
|
-
|
106
|
+
|
107
|
+
describe '#to_der' do
|
108
|
+
subject { super().to_der }
|
109
|
+
it { is_expected.to eq(rsa.to_der) }
|
110
|
+
end
|
95
111
|
end
|
96
112
|
context "when given a key instance" do
|
97
113
|
subject { Slosilo::Key.new rsa }
|
98
|
-
|
114
|
+
|
115
|
+
describe '#to_der' do
|
116
|
+
subject { super().to_der }
|
117
|
+
it { is_expected.to eq(rsa.to_der) }
|
118
|
+
end
|
99
119
|
end
|
100
120
|
context "when given something else" do
|
101
121
|
subject { Slosilo::Key.new "foo" }
|
@@ -108,21 +128,21 @@ describe Slosilo::Key do
|
|
108
128
|
describe "#sign" do
|
109
129
|
context "when given a hash" do
|
110
130
|
it "converts to a sorted array and signs that" do
|
111
|
-
key.
|
131
|
+
expect(key).to receive(:sign_string).with '[["a",3],["b",42]]'
|
112
132
|
key.sign b: 42, a: 3
|
113
133
|
end
|
114
134
|
end
|
115
135
|
context "when given an array" do
|
116
136
|
it "signs a JSON representation instead" do
|
117
|
-
key.
|
137
|
+
expect(key).to receive(:sign_string).with '[2,[42,2]]'
|
118
138
|
key.sign [2, [42, 2]]
|
119
139
|
end
|
120
140
|
end
|
121
141
|
context "when given a string" do
|
122
142
|
let(:expected_signature) { "d[\xA4\x00\x02\xC5\x17\xF5P\x1AD\x91\xF9\xC1\x00P\x0EG\x14,IN\xDE\x17\xE1\xA2a\xCC\xABR\x99'\xB0A\xF5~\x93M/\x95-B\xB1\xB6\x92!\x1E\xEA\x9C\v\xC2O\xA8\x91\x1C\xF9\x11\x92a\xBFxm-\x93\x9C\xBBoM\x92%\xA9\xD06$\xC1\xBC.`\xF8\x03J\x16\xE1\xB0c\xDD\xBF\xB0\xAA\xD7\xD4\xF4\xFC\e*\xAB\x13A%-\xD3\t\xA5R\x18\x01let6\xC8\xE9\"\x7F6O\xC7p\x82\xAB\x04J(IY\xAA]b\xA4'\xD6\x873`\xAB\x13\x95g\x9C\x17\xCAB\xF8\xB9\x85B:^\xC5XY^\x03\xEA\xB6V\x17b2\xCA\xF5\xD6\xD4\xD2\xE3u\x11\xECQ\x0Fb\x14\xE2\x04\xE1<a\xC5\x01eW-\x15\x01X\x81K\x1A\xE5A\vVj\xBF\xFC\xFE#\xD5\x93y\x16\xDC\xB4\x8C\xF0\x02Y\xA8\x87i\x01qC\xA7#\xE8\f\xA5\xF0c\xDEJ\xB0\xDB BJ\x87\xA4\xB0\x92\x80\x03\x95\xEE\xE9\xB8K\xC0\xE3JbE-\xD4\xCBP\\\x13S\"\eZ\xE1\x93\xFDa pinch of salt".force_encoding("ASCII-8BIT") }
|
123
143
|
it "signs it" do
|
124
|
-
key.
|
125
|
-
key.sign("this sentence is not this sentence").
|
144
|
+
allow(key).to receive_messages shake_salt: 'a pinch of salt'
|
145
|
+
expect(key.sign("this sentence is not this sentence")).to eq(expected_signature)
|
126
146
|
end
|
127
147
|
end
|
128
148
|
end
|
@@ -136,44 +156,44 @@ describe Slosilo::Key do
|
|
136
156
|
let(:expected_signature) { Base64::urlsafe_encode64 "\xB0\xCE{\x9FP\xEDV\x9C\xE7b\x8B[\xFAil\x87^\x96\x17Z\x97\x1D\xC2?B\x96\x9C\x8Ep-\xDF_\x8F\xC21\xD9^\xBC\n\x16\x04\x8DJ\xF6\xAF-\xEC\xAD\x03\xF9\xEE:\xDF\xB5\x8F\xF9\xF6\x81m\xAB\x9C\xAB1\x1E\x837\x8C\xFB\xA8P\xA8<\xEA\x1Dx\xCEd\xED\x84f\xA7\xB5t`\x96\xCC\x0F\xA9t\x8B\x9Fo\xBF\x92K\xFA\xFD\xC5?\x8F\xC68t\xBC\x9F\xDE\n$\xCA\xD2\x8F\x96\x0EtX2\x8Cl\x1E\x8Aa\r\x8D\xCAi\x86\x1A\xBD\x1D\xF7\xBC\x8561j\x91YlO\xFA(\x98\x10iq\xCC\xAF\x9BV\xC6\v\xBC\x10Xm\xCD\xFE\xAD=\xAA\x95,\xB4\xF7\xE8W\xB8\x83;\x81\x88\xE6\x01\xBA\xA5F\x91\x17\f\xCE\x80\x8E\v\x83\x9D<\x0E\x83\xF6\x8D\x03\xC0\xE8A\xD7\x90i\x1D\x030VA\x906D\x10\xA0\xDE\x12\xEF\x06M\xD8\x8B\xA9W\xC8\x9DTc\x8AJ\xA4\xC0\xD3!\xFA\x14\x89\xD1p\xB4J7\xA5\x04\xC2l\xDC8<\x04Y\xD8\xA4\xFB[\x89\xB1\xEC\xDA\xB8\xD7\xEA\x03Ja pinch of salt".force_encoding("ASCII-8BIT") }
|
137
157
|
let(:expected_token) { token_to_sign.merge "signature" => expected_signature, "key" => key_fingerprint }
|
138
158
|
before do
|
139
|
-
key.
|
140
|
-
Time.
|
159
|
+
allow(key).to receive_messages shake_salt: salt
|
160
|
+
allow(Time).to receive_messages new: time
|
141
161
|
end
|
142
162
|
subject { key.signed_token data }
|
143
|
-
it {
|
163
|
+
it { is_expected.to eq(expected_token) }
|
144
164
|
end
|
145
165
|
|
146
166
|
describe "#token_valid?" do
|
147
167
|
let(:data) { { "foo" => :bar } }
|
148
168
|
let(:signature) { Base64::urlsafe_encode64 "\xB0\xCE{\x9FP\xEDV\x9C\xE7b\x8B[\xFAil\x87^\x96\x17Z\x97\x1D\xC2?B\x96\x9C\x8Ep-\xDF_\x8F\xC21\xD9^\xBC\n\x16\x04\x8DJ\xF6\xAF-\xEC\xAD\x03\xF9\xEE:\xDF\xB5\x8F\xF9\xF6\x81m\xAB\x9C\xAB1\x1E\x837\x8C\xFB\xA8P\xA8<\xEA\x1Dx\xCEd\xED\x84f\xA7\xB5t`\x96\xCC\x0F\xA9t\x8B\x9Fo\xBF\x92K\xFA\xFD\xC5?\x8F\xC68t\xBC\x9F\xDE\n$\xCA\xD2\x8F\x96\x0EtX2\x8Cl\x1E\x8Aa\r\x8D\xCAi\x86\x1A\xBD\x1D\xF7\xBC\x8561j\x91YlO\xFA(\x98\x10iq\xCC\xAF\x9BV\xC6\v\xBC\x10Xm\xCD\xFE\xAD=\xAA\x95,\xB4\xF7\xE8W\xB8\x83;\x81\x88\xE6\x01\xBA\xA5F\x91\x17\f\xCE\x80\x8E\v\x83\x9D<\x0E\x83\xF6\x8D\x03\xC0\xE8A\xD7\x90i\x1D\x030VA\x906D\x10\xA0\xDE\x12\xEF\x06M\xD8\x8B\xA9W\xC8\x9DTc\x8AJ\xA4\xC0\xD3!\xFA\x14\x89\xD1p\xB4J7\xA5\x04\xC2l\xDC8<\x04Y\xD8\xA4\xFB[\x89\xB1\xEC\xDA\xB8\xD7\xEA\x03Ja pinch of salt".force_encoding("ASCII-8BIT") }
|
149
169
|
let(:token) { { "data" => data, "timestamp" => "2012-01-01 01:01:01 UTC", "signature" => signature } }
|
150
|
-
before { Time.
|
170
|
+
before { allow(Time).to receive_messages now: Time.new(2012,1,1,1,2,1,0) }
|
151
171
|
subject { key.token_valid? token }
|
152
|
-
it {
|
172
|
+
it { is_expected.to be_truthy }
|
153
173
|
|
154
174
|
it "doesn't check signature on the advisory key field" do
|
155
|
-
key.token_valid?(token.merge "key" => key_fingerprint).
|
175
|
+
expect(key.token_valid?(token.merge "key" => key_fingerprint)).to be_truthy
|
156
176
|
end
|
157
177
|
|
158
178
|
it "rejects the token if the key field is present and doesn't match" do
|
159
|
-
key.token_valid?(token.merge "key" => "this is not the key you are looking for").
|
179
|
+
expect(key.token_valid?(token.merge "key" => "this is not the key you are looking for")).not_to be_truthy
|
160
180
|
end
|
161
181
|
|
162
182
|
context "when token is 1 hour old" do
|
163
|
-
before { Time.
|
164
|
-
it {
|
183
|
+
before { allow(Time).to receive_messages now: Time.new(2012,1,1,2,1,1,0) }
|
184
|
+
it { is_expected.to be_falsey }
|
165
185
|
context "when timestamp in the token is changed accordingly" do
|
166
186
|
let(:token) { { "data" => data, "timestamp" => "2012-01-01 02:00:01 UTC", "signature" => signature } }
|
167
|
-
it {
|
187
|
+
it { is_expected.to be_falsey }
|
168
188
|
end
|
169
189
|
end
|
170
190
|
context "when the data is changed" do
|
171
191
|
let(:data) { { "foo" => :baz } }
|
172
|
-
it {
|
192
|
+
it { is_expected.to be_falsey }
|
173
193
|
end
|
174
194
|
context "when RSA decrypt raises an error" do
|
175
|
-
before { OpenSSL::PKey::RSA.
|
176
|
-
it {
|
195
|
+
before { expect_any_instance_of(OpenSSL::PKey::RSA).to receive(:public_decrypt).and_raise(OpenSSL::PKey::RSAError) }
|
196
|
+
it { is_expected.to be_falsey }
|
177
197
|
end
|
178
198
|
end
|
179
199
|
end
|
data/spec/keystore_spec.rb
CHANGED
@@ -7,7 +7,7 @@ describe Slosilo::Keystore do
|
|
7
7
|
describe '#put' do
|
8
8
|
it "handles Slosilo::Keys" do
|
9
9
|
subject.put(:test, key)
|
10
|
-
adapter['test'].to_der.
|
10
|
+
expect(adapter['test'].to_der).to eq(rsa.to_der)
|
11
11
|
end
|
12
12
|
|
13
13
|
it "refuses to store a key with a nil id" do
|
@@ -19,7 +19,7 @@ describe Slosilo::Keystore do
|
|
19
19
|
end
|
20
20
|
|
21
21
|
it "passes the Slosilo key to the adapter" do
|
22
|
-
adapter.
|
22
|
+
expect(adapter).to receive(:put_key).with "test", key
|
23
23
|
subject.put :test, key
|
24
24
|
end
|
25
25
|
end
|
data/spec/random_spec.rb
CHANGED
@@ -4,6 +4,16 @@ describe Slosilo::Random do
|
|
4
4
|
subject { Slosilo::Random }
|
5
5
|
let(:other_salt) { Slosilo::Random::salt }
|
6
6
|
|
7
|
-
|
8
|
-
|
7
|
+
describe '#salt' do
|
8
|
+
subject { super().salt }
|
9
|
+
describe '#length' do
|
10
|
+
subject { super().length }
|
11
|
+
it { is_expected.to eq(32) }
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
describe '#salt' do
|
16
|
+
subject { super().salt }
|
17
|
+
it { is_expected.not_to eq(other_salt) }
|
18
|
+
end
|
9
19
|
end
|
data/spec/sequel_adapter_spec.rb
CHANGED
@@ -8,21 +8,21 @@ describe Slosilo::Adapters::SequelAdapter do
|
|
8
8
|
include_context "with example key"
|
9
9
|
|
10
10
|
let(:model) { double "model" }
|
11
|
-
before { subject.
|
11
|
+
before { allow(subject).to receive_messages create_model: model }
|
12
12
|
|
13
13
|
describe "#get_key" do
|
14
14
|
context "when given key does not exist" do
|
15
|
-
before { model.
|
15
|
+
before { allow(model).to receive_messages :[] => nil }
|
16
16
|
it "returns nil" do
|
17
|
-
subject.get_key(:whatever).
|
17
|
+
expect(subject.get_key(:whatever)).not_to be
|
18
18
|
end
|
19
19
|
end
|
20
20
|
|
21
21
|
context "when it exists" do
|
22
22
|
let(:id) { "id" }
|
23
|
-
before { model.
|
23
|
+
before { allow(model).to receive(:[]).with(id).and_return (double "key entry", id: id, key: rsa.to_der) }
|
24
24
|
it "returns it" do
|
25
|
-
subject.get_key(id).
|
25
|
+
expect(subject.get_key(id)).to eq(key)
|
26
26
|
end
|
27
27
|
end
|
28
28
|
end
|
@@ -30,14 +30,14 @@ describe Slosilo::Adapters::SequelAdapter do
|
|
30
30
|
describe "#put_key" do
|
31
31
|
let(:id) { "id" }
|
32
32
|
it "creates the key" do
|
33
|
-
model.
|
34
|
-
model.
|
33
|
+
expect(model).to receive(:create).with id: id, key: key.to_der
|
34
|
+
allow(model).to receive_messages columns: [:id, :key]
|
35
35
|
subject.put_key id, key
|
36
36
|
end
|
37
37
|
|
38
38
|
it "adds the fingerprint if feasible" do
|
39
|
-
model.
|
40
|
-
model.
|
39
|
+
expect(model).to receive(:create).with id: id, key: key.to_der, fingerprint: key.fingerprint
|
40
|
+
allow(model).to receive_messages columns: [:id, :key, :fingerprint]
|
41
41
|
subject.put_key id, key
|
42
42
|
end
|
43
43
|
end
|
@@ -46,25 +46,21 @@ describe Slosilo::Adapters::SequelAdapter do
|
|
46
46
|
describe "#each" do
|
47
47
|
let(:one) { double("one", id: :one, key: :onek) }
|
48
48
|
let(:two) { double("two", id: :two, key: :twok) }
|
49
|
-
before { model.
|
49
|
+
before { allow(model).to receive(:each).and_yield(one).and_yield(two) }
|
50
50
|
|
51
51
|
it "iterates over each key" do
|
52
52
|
results = []
|
53
|
-
Slosilo::Key.
|
53
|
+
allow(Slosilo::Key).to receive(:new) {|x|x}
|
54
54
|
adapter.each { |id,k| results << { id => k } }
|
55
|
-
results.
|
55
|
+
expect(results).to eq([ { one: :onek}, {two: :twok } ])
|
56
56
|
end
|
57
57
|
end
|
58
58
|
|
59
59
|
shared_context "database" do
|
60
60
|
let(:db) { Sequel.sqlite }
|
61
61
|
before do
|
62
|
-
subject.
|
63
|
-
|
64
|
-
Sequel::Model.cache_anonymous_models = false
|
65
|
-
rescue NoMethodError # sequel 4.0 moved the method
|
66
|
-
Sequel.cache_anonymous_models = false
|
67
|
-
end
|
62
|
+
allow(subject).to receive(:create_model).and_call_original
|
63
|
+
Sequel.cache_anonymous_models = false
|
68
64
|
Sequel::Model.db = db
|
69
65
|
end
|
70
66
|
end
|
@@ -91,24 +87,24 @@ describe Slosilo::Adapters::SequelAdapter do
|
|
91
87
|
before { subject.migrate! }
|
92
88
|
|
93
89
|
it "supports look up by id" do
|
94
|
-
subject.get_key("test").
|
90
|
+
expect(subject.get_key("test")).to eq(key)
|
95
91
|
end
|
96
92
|
|
97
93
|
it "supports look up by fingerprint, without a warning" do
|
98
|
-
$stderr.grab do
|
99
|
-
subject.get_by_fingerprint(key.fingerprint).
|
100
|
-
end.
|
94
|
+
expect($stderr.grab do
|
95
|
+
expect(subject.get_by_fingerprint(key.fingerprint)).to eq([key, 'test'])
|
96
|
+
end).to be_empty
|
101
97
|
end
|
102
98
|
end
|
103
99
|
|
104
100
|
it "supports look up by id" do
|
105
|
-
subject.get_key("test").
|
101
|
+
expect(subject.get_key("test")).to eq(key)
|
106
102
|
end
|
107
103
|
|
108
104
|
it "supports look up by fingerprint, but issues a warning" do
|
109
|
-
$stderr.grab do
|
110
|
-
subject.get_by_fingerprint(key.fingerprint).
|
111
|
-
end.
|
105
|
+
expect($stderr.grab do
|
106
|
+
expect(subject.get_by_fingerprint(key.fingerprint)).to eq([key, 'test'])
|
107
|
+
end).not_to be_empty
|
112
108
|
end
|
113
109
|
end
|
114
110
|
|
@@ -129,11 +125,11 @@ describe Slosilo::Adapters::SequelAdapter do
|
|
129
125
|
end
|
130
126
|
|
131
127
|
it "supports look up by id" do
|
132
|
-
subject.get_key("test").
|
128
|
+
expect(subject.get_key("test")).to eq(key)
|
133
129
|
end
|
134
130
|
|
135
131
|
it "supports look up by fingerprint" do
|
136
|
-
subject.get_by_fingerprint(key.fingerprint).
|
132
|
+
expect(subject.get_by_fingerprint(key.fingerprint)).to eq([key, 'test'])
|
137
133
|
end
|
138
134
|
end
|
139
135
|
|
@@ -141,7 +137,7 @@ describe Slosilo::Adapters::SequelAdapter do
|
|
141
137
|
include_context "encryption key"
|
142
138
|
include_context "current schema"
|
143
139
|
|
144
|
-
it {
|
140
|
+
it { is_expected.to be_secure }
|
145
141
|
|
146
142
|
it "saves the keys in encrypted form" do
|
147
143
|
subject.put_key 'test', key
|
@@ -158,7 +154,7 @@ describe Slosilo::Adapters::SequelAdapter do
|
|
158
154
|
|
159
155
|
include_context "current schema"
|
160
156
|
|
161
|
-
it {
|
157
|
+
it { is_expected.not_to be_secure }
|
162
158
|
|
163
159
|
it "refuses to store a private key" do
|
164
160
|
expect { subject.put_key 'test', key }.to raise_error(Slosilo::Error::InsecureKeyStorage)
|
data/spec/slosilo_spec.rb
CHANGED
@@ -7,32 +7,32 @@ describe Slosilo do
|
|
7
7
|
|
8
8
|
describe '[]' do
|
9
9
|
it "returns a Slosilo::Key" do
|
10
|
-
Slosilo[:test].
|
10
|
+
expect(Slosilo[:test]).to be_instance_of Slosilo::Key
|
11
11
|
end
|
12
12
|
|
13
13
|
it "allows looking up by fingerprint" do
|
14
|
-
Slosilo[fingerprint: key_fingerprint].
|
14
|
+
expect(Slosilo[fingerprint: key_fingerprint]).to eq(key)
|
15
15
|
end
|
16
16
|
|
17
17
|
context "when the requested key does not exist" do
|
18
18
|
it "returns nil instead of creating a new key" do
|
19
|
-
Slosilo[:aether].
|
19
|
+
expect(Slosilo[:aether]).not_to be
|
20
20
|
end
|
21
21
|
end
|
22
22
|
end
|
23
23
|
|
24
24
|
describe '.sign' do
|
25
25
|
let(:own_key) { double "own key" }
|
26
|
-
before { Slosilo.
|
26
|
+
before { allow(Slosilo).to receive(:[]).with(:own).and_return own_key }
|
27
27
|
let (:argument) { double "thing to sign" }
|
28
28
|
it "fetches the own key and signs using that" do
|
29
|
-
own_key.
|
29
|
+
expect(own_key).to receive(:sign).with(argument)
|
30
30
|
Slosilo.sign argument
|
31
31
|
end
|
32
32
|
end
|
33
33
|
|
34
34
|
describe '.token_valid?' do
|
35
|
-
before { adapter['test'].
|
35
|
+
before { allow(adapter['test']).to receive_messages token_valid?: false }
|
36
36
|
let(:key2) { double "key 2", token_valid?: false }
|
37
37
|
let(:key3) { double "key 3", token_valid?: false }
|
38
38
|
before do
|
@@ -44,19 +44,19 @@ describe Slosilo do
|
|
44
44
|
subject { Slosilo.token_valid? token }
|
45
45
|
|
46
46
|
context "when no key validates the token" do
|
47
|
-
before { Slosilo::Key.
|
48
|
-
it {
|
47
|
+
before { allow(Slosilo::Key).to receive_messages new: (double "key", token_valid?: false) }
|
48
|
+
it { is_expected.to be_falsey }
|
49
49
|
end
|
50
50
|
|
51
51
|
context "when a key validates the token" do
|
52
52
|
let(:valid_key) { double token_valid?: true }
|
53
53
|
let(:invalid_key) { double token_valid?: true }
|
54
54
|
before do
|
55
|
-
Slosilo::Key.
|
55
|
+
allow(Slosilo::Key).to receive_messages new: invalid_key
|
56
56
|
adapter[:key2] = valid_key
|
57
57
|
end
|
58
58
|
|
59
|
-
it {
|
59
|
+
it { is_expected.to be_truthy }
|
60
60
|
end
|
61
61
|
end
|
62
62
|
|
@@ -66,18 +66,18 @@ describe Slosilo do
|
|
66
66
|
let(:token) {{ 'data' => 'foo', 'key' => key.fingerprint, 'signature' => 'XXX' }}
|
67
67
|
|
68
68
|
context "and the signature is valid" do
|
69
|
-
before { key.
|
69
|
+
before { allow(key).to receive(:token_valid?).with(token).and_return true }
|
70
70
|
|
71
71
|
it "returns the key id" do
|
72
|
-
subject.token_signer(token).
|
72
|
+
expect(subject.token_signer(token)).to eq('test')
|
73
73
|
end
|
74
74
|
end
|
75
75
|
|
76
76
|
context "and the signature is invalid" do
|
77
|
-
before { key.
|
77
|
+
before { allow(key).to receive(:token_valid?).with(token).and_return false }
|
78
78
|
|
79
79
|
it "returns nil" do
|
80
|
-
subject.token_signer(token).
|
80
|
+
expect(subject.token_signer(token)).not_to be
|
81
81
|
end
|
82
82
|
end
|
83
83
|
end
|
@@ -85,7 +85,7 @@ describe Slosilo do
|
|
85
85
|
context "when token doesn't match a key" do
|
86
86
|
let(:token) {{ 'data' => 'foo', 'key' => "footprint", 'signature' => 'XXX' }}
|
87
87
|
it "returns nil" do
|
88
|
-
subject.token_signer(token).
|
88
|
+
expect(subject.token_signer(token)).not_to be
|
89
89
|
end
|
90
90
|
end
|
91
91
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,10 +1,6 @@
|
|
1
1
|
require "simplecov"
|
2
2
|
SimpleCov.start
|
3
3
|
|
4
|
-
RSpec.configure do |c|
|
5
|
-
c.treat_symbols_as_metadata_keys_with_true_values = true
|
6
|
-
end
|
7
|
-
|
8
4
|
require 'slosilo'
|
9
5
|
|
10
6
|
shared_context "with mock adapter" do
|
@@ -80,20 +76,6 @@ ooQ2FuL0K6ukQfHPjuMswqi41lmVH8gIVqVC+QnImUCrGxH9WXWy
|
|
80
76
|
end
|
81
77
|
|
82
78
|
def self.mock_own_key
|
83
|
-
before { Slosilo.
|
84
|
-
end
|
85
|
-
end
|
86
|
-
|
87
|
-
class RackEnvironmentInputMatcher
|
88
|
-
def initialize expected
|
89
|
-
@expected = expected
|
79
|
+
before { allow(Slosilo).to receive(:[]).with(:own).and_return key }
|
90
80
|
end
|
91
|
-
|
92
|
-
def == env
|
93
|
-
env['rack.input'].read.should == @expected
|
94
|
-
end
|
95
|
-
end
|
96
|
-
|
97
|
-
def rack_environment_with_input expected
|
98
|
-
RackEnvironmentInputMatcher.new expected
|
99
81
|
end
|
data/spec/symmetric_spec.rb
CHANGED
@@ -8,21 +8,21 @@ describe Slosilo::Symmetric do
|
|
8
8
|
let(:ciphertext) { "\xA1\xFA#z\x16\x80R\xCC|\x0Fyc\xB7j\x17\xED\x15\xC9r\xC9\xEE\xB9\xBC5\xB7\ni\x0F\f\xC8X\x80 h\a\xF4\xA6\xE3\x15\x9D\xF1-\xE5\bs\xF6\x02Z\x0F\xCD|S\x1A\xAA\x9At\xEFT\x17\xA5lT\x8C\xF3".force_encoding("ASCII-8BIT") }
|
9
9
|
describe '#encrypt' do
|
10
10
|
it "encrypts with AES-256-CBC" do
|
11
|
-
subject.
|
12
|
-
subject.encrypt(plaintext, key: key).
|
11
|
+
allow(subject).to receive_messages random_iv: iv
|
12
|
+
expect(subject.encrypt(plaintext, key: key)).to eq(ciphertext)
|
13
13
|
end
|
14
14
|
end
|
15
15
|
|
16
16
|
describe '#decrypt' do
|
17
17
|
it "decrypts with AES-256-CBC" do
|
18
|
-
subject.decrypt(ciphertext, key: key).
|
18
|
+
expect(subject.decrypt(ciphertext, key: key)).to eq(plaintext)
|
19
19
|
end
|
20
20
|
|
21
21
|
context "when ciphertext happens to end in a zero" do
|
22
22
|
let(:ciphertext) { "\x7F\xD6\xEAb\xE56\a\xD3\xC5\xF2J\n\x8C\x8Fg\xB7-\\\x8A\fh\x18\xC8\x91\xB9 \x97\xC9\x12\xE6\xA6\xAE\xB1I\x1E\x80\xAB\xD8\xDC\xBD\xB6\xCD\x9A\xA3MH\xA8\xB0\xC7\xDA\x87\xA7c\xD75,\xD2A\xB8\x9E\xE3o\x04\x00" }
|
23
23
|
let(:key) { "4pSuk1rAQyuHA5uUYaj0X0BsiPCFb9Nc8J03XA6V5/Y" }
|
24
24
|
it "works correctly" do
|
25
|
-
subject.decrypt(ciphertext, key: key).
|
25
|
+
expect(subject.decrypt(ciphertext, key: key)).to eq("R6KNTQ4aUivojbaqhgAqj1I4PaF8h/5/YcENy4uNbfk=")
|
26
26
|
end
|
27
27
|
end
|
28
28
|
|
@@ -30,22 +30,22 @@ describe Slosilo::Symmetric do
|
|
30
30
|
let(:ciphertext) { "\xC0\xDA#\xE9\xE1\xFD\xEDJ\xADs4P\xA9\xD6\x92 \xF7\xF8_M\xF6\x16\xC2i$\x8BT^\b\xA1\xB2L&\xE9\x80\x02[]6i\x9B\xD3\xC3\xED\xA9\xD1\x94\xE8\x15\xFD\xDA\xFEUj\xC5upH*\xBF\x82\x15le" }
|
31
31
|
let(:key) { "4pSuk1rAQyuHA5uUYaj0X0BsiPCFb9Nc8J03XA6V5/Y" }
|
32
32
|
it "works correctly" do
|
33
|
-
subject.decrypt(ciphertext, key: key).
|
33
|
+
expect(subject.decrypt(ciphertext, key: key)).to eq("zGptmL3vd4obi1vqSiWHt/Ias2k+6qDtuq9vdow8jNA=")
|
34
34
|
end
|
35
35
|
end
|
36
36
|
end
|
37
37
|
|
38
38
|
describe '#random_iv' do
|
39
39
|
it "generates a random iv" do
|
40
|
-
OpenSSL::Cipher.
|
41
|
-
subject.random_iv.
|
40
|
+
expect_any_instance_of(OpenSSL::Cipher).to receive(:random_iv).and_return :iv
|
41
|
+
expect(subject.random_iv).to eq(:iv)
|
42
42
|
end
|
43
43
|
end
|
44
44
|
|
45
45
|
describe '#random_key' do
|
46
46
|
it "generates a random key" do
|
47
|
-
OpenSSL::Cipher.
|
48
|
-
subject.random_key.
|
47
|
+
expect_any_instance_of(OpenSSL::Cipher).to receive(:random_key).and_return :key
|
48
|
+
expect(subject.random_key).to eq(:key)
|
49
49
|
end
|
50
50
|
end
|
51
51
|
end
|
metadata
CHANGED
@@ -1,111 +1,111 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: slosilo
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Rafał Rzepecki
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-10-
|
11
|
+
date: 2014-10-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- -
|
17
|
+
- - '>='
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: '0'
|
20
20
|
type: :development
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- -
|
24
|
+
- - '>='
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: rspec
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- -
|
31
|
+
- - ~>
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: '
|
33
|
+
version: '3.0'
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- -
|
38
|
+
- - ~>
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: '
|
40
|
+
version: '3.0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
|
-
name:
|
42
|
+
name: ci_reporter_rspec
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- -
|
45
|
+
- - '>='
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: '
|
47
|
+
version: '0'
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- -
|
52
|
+
- - '>='
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: '
|
54
|
+
version: '0'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: simplecov
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
|
-
- -
|
59
|
+
- - '>='
|
60
60
|
- !ruby/object:Gem::Version
|
61
61
|
version: '0'
|
62
62
|
type: :development
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
|
-
- -
|
66
|
+
- - '>='
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '0'
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: io-grab
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
72
72
|
requirements:
|
73
|
-
- -
|
73
|
+
- - ~>
|
74
74
|
- !ruby/object:Gem::Version
|
75
75
|
version: 0.0.1
|
76
76
|
type: :development
|
77
77
|
prerelease: false
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
79
79
|
requirements:
|
80
|
-
- -
|
80
|
+
- - ~>
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: 0.0.1
|
83
83
|
- !ruby/object:Gem::Dependency
|
84
84
|
name: sequel
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
86
86
|
requirements:
|
87
|
-
- -
|
87
|
+
- - '>='
|
88
88
|
- !ruby/object:Gem::Version
|
89
89
|
version: '0'
|
90
90
|
type: :development
|
91
91
|
prerelease: false
|
92
92
|
version_requirements: !ruby/object:Gem::Requirement
|
93
93
|
requirements:
|
94
|
-
- -
|
94
|
+
- - '>='
|
95
95
|
- !ruby/object:Gem::Version
|
96
96
|
version: '0'
|
97
97
|
- !ruby/object:Gem::Dependency
|
98
98
|
name: sqlite3
|
99
99
|
requirement: !ruby/object:Gem::Requirement
|
100
100
|
requirements:
|
101
|
-
- -
|
101
|
+
- - '>='
|
102
102
|
- !ruby/object:Gem::Version
|
103
103
|
version: '0'
|
104
104
|
type: :development
|
105
105
|
prerelease: false
|
106
106
|
version_requirements: !ruby/object:Gem::Requirement
|
107
107
|
requirements:
|
108
|
-
- -
|
108
|
+
- - '>='
|
109
109
|
- !ruby/object:Gem::Version
|
110
110
|
version: '0'
|
111
111
|
description: This gem provides an easy way of storing and retrieving encryption keys
|
@@ -116,8 +116,8 @@ executables: []
|
|
116
116
|
extensions: []
|
117
117
|
extra_rdoc_files: []
|
118
118
|
files:
|
119
|
-
-
|
120
|
-
-
|
119
|
+
- .gitignore
|
120
|
+
- .kateproject
|
121
121
|
- Gemfile
|
122
122
|
- LICENSE
|
123
123
|
- README.md
|
@@ -156,12 +156,12 @@ require_paths:
|
|
156
156
|
- lib
|
157
157
|
required_ruby_version: !ruby/object:Gem::Requirement
|
158
158
|
requirements:
|
159
|
-
- -
|
159
|
+
- - '>='
|
160
160
|
- !ruby/object:Gem::Version
|
161
161
|
version: 1.9.3
|
162
162
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
163
163
|
requirements:
|
164
|
-
- -
|
164
|
+
- - '>='
|
165
165
|
- !ruby/object:Gem::Version
|
166
166
|
version: '0'
|
167
167
|
requirements: []
|
@@ -179,3 +179,4 @@ test_files:
|
|
179
179
|
- spec/slosilo_spec.rb
|
180
180
|
- spec/spec_helper.rb
|
181
181
|
- spec/symmetric_spec.rb
|
182
|
+
has_rdoc:
|