attr_secure 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +7 -3
- data/attr_secure.gemspec +1 -1
- data/lib/attr_secure/adapters/active_record.rb +3 -1
- data/lib/attr_secure/adapters/sequel.rb +3 -1
- data/lib/attr_secure/secure.rb +15 -4
- data/lib/attr_secure/version.rb +1 -1
- data/spec/adapters/active_record_spec.rb +5 -0
- data/spec/adapters/sequel_spec.rb +5 -0
- data/spec/attr_secure_spec.rb +2 -2
- data/spec/secure_spec.rb +37 -13
- metadata +7 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 823b15116fee5d14b97ae231f81b48e7cb1b304e
|
4
|
+
data.tar.gz: 49b2aefa2a76a6eb4e6cd466320cba879ac88d20
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 19037e5da221dc532f23f733380f1bf0d10f18fb1b18d1877aa648d32b42262ae42622a9491173be0630979bec41d601a13e9861b778d38b933bcd69f3f7213c
|
7
|
+
data.tar.gz: fd893bd6f3858c51e74c74057fbec4a88c99d588b849d1d42228a2996ad516669e29991f3ba6179bc7eef5cca3eb5800e1b3b083b80955552027444d7b32ab87
|
data/README.md
CHANGED
@@ -42,22 +42,26 @@ To make an model attribute secure, first you need a secure key:
|
|
42
42
|
|
43
43
|
dd if=/dev/urandom bs=32 count=1 2>/dev/null | openssl base64
|
44
44
|
|
45
|
-
There's a number of ways of setting a key for a given attribute. The easiest is to default the key via the environment.
|
45
|
+
There's a number of ways of setting a key for a given attribute. The easiest is to default the key via the environment.
|
46
46
|
Setting the environment variable `ATTR_SECURE_SECRET` to a secret value will secure all attributes with the same key.
|
47
47
|
|
48
48
|
Alternatively, if you want to use different keys for different attributes you can do this too:
|
49
49
|
|
50
50
|
attr_secure :my_attribute, :secret => "EKq88AMFeRLqEx5knUcoJ4LOnrv52d7hfAFgEKMoDKzqNei4m7kbu"
|
51
|
-
|
51
|
+
|
52
52
|
If you would like your key dependent on something else, a lambda is OK too:
|
53
53
|
|
54
54
|
attr_secure :my_attribute, :secret => lambda {|record| record.user.secret }
|
55
|
-
|
55
|
+
|
56
56
|
Remember kids, it's not a good idea to hard-code secrets.
|
57
57
|
|
58
58
|
Note: You will want to set your table columns for encrypted values to :text or
|
59
59
|
similar. Encrypted values are long.
|
60
60
|
|
61
|
+
## Key rotation
|
62
|
+
|
63
|
+
You can pass a comma delimited list of keys as your secret. attr_secure will decrypt with each key in turn until it hits a verified value. Encryption always happens with the newest (leftmost) key.
|
64
|
+
|
61
65
|
## Contributing
|
62
66
|
|
63
67
|
1. Fork it
|
data/attr_secure.gemspec
CHANGED
@@ -3,7 +3,9 @@ module AttrSecure
|
|
3
3
|
module ActiveRecord
|
4
4
|
|
5
5
|
def self.valid?(object)
|
6
|
-
object.respond_to?(:<) &&
|
6
|
+
object.respond_to?(:<) && object < ::ActiveRecord::Base
|
7
|
+
rescue NameError
|
8
|
+
false
|
7
9
|
end
|
8
10
|
|
9
11
|
def self.write_attribute(object, attribute, value)
|
@@ -3,7 +3,9 @@ module AttrSecure
|
|
3
3
|
module Sequel
|
4
4
|
|
5
5
|
def self.valid?(object)
|
6
|
-
object.respond_to?(:<) &&
|
6
|
+
object.respond_to?(:<) && object < ::Sequel::Model
|
7
|
+
rescue NameError
|
8
|
+
false
|
7
9
|
end
|
8
10
|
|
9
11
|
def self.write_attribute(object, attribute, value)
|
data/lib/attr_secure/secure.rb
CHANGED
@@ -9,19 +9,30 @@ module AttrSecure
|
|
9
9
|
attr_reader :secret
|
10
10
|
|
11
11
|
def initialize(secret)
|
12
|
-
@secret = secret
|
12
|
+
@secret = secret.split(",")
|
13
|
+
end
|
14
|
+
|
15
|
+
def secret=(val)
|
16
|
+
@secret = secret.split(",")
|
13
17
|
end
|
14
18
|
|
15
19
|
def encrypt(value)
|
16
|
-
Fernet.generate(secret) do |generator|
|
20
|
+
Fernet.generate([secret].flatten.first) do |generator|
|
17
21
|
generator.data = { value: value }
|
18
22
|
end
|
19
23
|
end
|
20
24
|
|
21
25
|
def decrypt(value)
|
22
26
|
return nil if value.nil?
|
23
|
-
|
24
|
-
|
27
|
+
[secret].flatten.each do |_secret|
|
28
|
+
begin
|
29
|
+
verifier = Fernet.verifier(_secret, value)
|
30
|
+
return verifier.data['value'] if verifier.valid?
|
31
|
+
rescue
|
32
|
+
end
|
33
|
+
raise OpenSSL::Cipher::CipherError
|
34
|
+
end
|
25
35
|
end
|
36
|
+
|
26
37
|
end
|
27
38
|
end
|
data/lib/attr_secure/version.rb
CHANGED
@@ -16,6 +16,11 @@ describe AttrSecure::Adapters::ActiveRecord do
|
|
16
16
|
it "should not be valid" do
|
17
17
|
expect(described_class.valid?(String)).to be_false
|
18
18
|
end
|
19
|
+
|
20
|
+
it "should not be valid if activerecord is not loaded" do
|
21
|
+
hide_const('ActiveRecord')
|
22
|
+
expect(described_class.valid?(described)).to be_false
|
23
|
+
end
|
19
24
|
end
|
20
25
|
|
21
26
|
describe "write attribute" do
|
@@ -16,6 +16,11 @@ describe AttrSecure::Adapters::Sequel do
|
|
16
16
|
it "should not be valid" do
|
17
17
|
expect(described_class.valid?(String)).to be_false
|
18
18
|
end
|
19
|
+
|
20
|
+
it "should not be valid if sequel is not loaded" do
|
21
|
+
hide_const('Sequel')
|
22
|
+
expect(described_class.valid?(described)).to be_false
|
23
|
+
end
|
19
24
|
end
|
20
25
|
|
21
26
|
describe "write attribute" do
|
data/spec/attr_secure_spec.rb
CHANGED
@@ -6,8 +6,8 @@ describe AttrSecure do
|
|
6
6
|
let(:described) { Class.new }
|
7
7
|
let(:secure_mock) { double(AttrSecure::Secure) }
|
8
8
|
let(:secret_mock) { double(AttrSecure::Secret) }
|
9
|
-
let(:crypter) {
|
10
|
-
let(:adapter) {
|
9
|
+
let(:crypter) { double(:secure_crypter) }
|
10
|
+
let(:adapter) { double(:adapter) }
|
11
11
|
|
12
12
|
before do
|
13
13
|
described.extend(AttrSecure)
|
data/spec/secure_spec.rb
CHANGED
@@ -1,22 +1,46 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe AttrSecure::Secure do
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
4
|
+
context "with a simple key" do
|
5
|
+
|
6
|
+
subject { described_class.new(secret) }
|
7
|
+
let(:secret) { 'fWSvpC6Eh1/FFE1TUgXpcEzMmmGc9IZSqoexzEslzKI=' }
|
8
|
+
|
9
|
+
describe '#encrypt' do
|
10
|
+
it "should encrypt a string" do
|
11
|
+
expect(subject.encrypt('encrypted')).to be_a(String)
|
12
|
+
expect(subject.encrypt('encrypted')).to_not be_empty
|
13
|
+
expect(subject.encrypt('encrypted')).to_not eq(subject.encrypt('encrypted'))
|
14
|
+
end
|
12
15
|
end
|
13
|
-
end
|
14
16
|
|
15
|
-
|
16
|
-
|
17
|
+
describe '#decrypt' do
|
18
|
+
let(:encrypted_value) { subject.encrypt('decrypted') }
|
17
19
|
|
18
|
-
|
19
|
-
|
20
|
+
it "should decrypt a string" do
|
21
|
+
expect(subject.decrypt(encrypted_value)).to eq('decrypted')
|
22
|
+
end
|
20
23
|
end
|
21
24
|
end
|
25
|
+
|
26
|
+
# context "with an array of keys" do
|
27
|
+
# subject { described_class.new(secret) }
|
28
|
+
# let(:secret) { 'fWSvpC6Eh1/FFE1TUgXpcEzMmmGc9IZSqoexzEslzKI=,d9ssNmUYn7UpMoSc0eM2glVUG2DPYwXveLTDU7j8pBY=' }
|
29
|
+
|
30
|
+
# describe '#encrypt' do
|
31
|
+
# it "should encrypt a string" do
|
32
|
+
# expect(subject.encrypt('encrypted')).to be_a(String)
|
33
|
+
# expect(subject.encrypt('encrypted')).to_not be_empty
|
34
|
+
# expect(subject.encrypt('encrypted')).to_not eq(subject.encrypt('encrypted'))
|
35
|
+
# end
|
36
|
+
# end
|
37
|
+
|
38
|
+
# describe '#decrypt' do
|
39
|
+
# let(:encrypted_value) { subject.encrypt('decrypted') }
|
40
|
+
|
41
|
+
# it "should decrypt a string" do
|
42
|
+
# expect(subject.decrypt(encrypted_value)).to eq('decrypted')
|
43
|
+
# end
|
44
|
+
# end
|
45
|
+
# end
|
22
46
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: attr_secure
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Neil Middleton
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-
|
11
|
+
date: 2013-12-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rspec
|
@@ -84,16 +84,16 @@ dependencies:
|
|
84
84
|
name: fernet
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
86
86
|
requirements:
|
87
|
-
- - '
|
87
|
+
- - '='
|
88
88
|
- !ruby/object:Gem::Version
|
89
|
-
version: '
|
89
|
+
version: '1.6'
|
90
90
|
type: :runtime
|
91
91
|
prerelease: false
|
92
92
|
version_requirements: !ruby/object:Gem::Requirement
|
93
93
|
requirements:
|
94
|
-
- - '
|
94
|
+
- - '='
|
95
95
|
- !ruby/object:Gem::Version
|
96
|
-
version: '
|
96
|
+
version: '1.6'
|
97
97
|
description: Securely stores activerecord model attributes
|
98
98
|
email:
|
99
99
|
- neil@neilmiddleton.com
|
@@ -144,7 +144,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
144
144
|
version: '0'
|
145
145
|
requirements: []
|
146
146
|
rubyforge_project:
|
147
|
-
rubygems_version: 2.0.
|
147
|
+
rubygems_version: 2.0.7
|
148
148
|
signing_key:
|
149
149
|
specification_version: 4
|
150
150
|
summary: Securely stores activerecord model attributes
|