attr_secure 0.0.3 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 6587948291c3a27b3b2d8b6d4510668b5fe2d7b0
4
- data.tar.gz: 63313a924a9b32dffdc259ee965a45e4dfc20db3
3
+ metadata.gz: a9f970443168e1a32a5bdb022ef5e74acedc5803
4
+ data.tar.gz: a247cfc9a807256e6f8003346d28c08ffb4c4b5a
5
5
  SHA512:
6
- metadata.gz: ca1c7c4d1868b2d980c47dbab3cda9ec2fc9ec71101bcd591aa2f241f96acfe6fc9a95382cb120a8c0def0b8f2faa38095443fa3e3ca541f54fd557a9bd59fee
7
- data.tar.gz: 5a39de22e1ec572862abf2c4d78e70b26c372a553b36c63c760e168c007daea6636dba1a2ffabe48f0f01a8c9f69d4f61e98b085d4085f3a9ff9834d481053f4
6
+ metadata.gz: 7b204d25fcbab4c785c7993d8fb65dade0369d73b10c27cbfbf39020a97020ac3809800148b2039bd586d268c9bac113ee26c755648763728dad23a6279eb438
7
+ data.tar.gz: e9c3c0dbb2a835e38ea9e970e0d561ecb41964f8d418522de45469c38e51193c81b3e464b42c9c495fb29d2feb96df23cb76cd6cc693cce81cc46259d74e989f
data/.travis.yml CHANGED
@@ -7,5 +7,3 @@ rvm:
7
7
  matrix:
8
8
  allow_failures:
9
9
  - rvm: jruby-19mode
10
-
11
- script: rspec spec
data/README.md CHANGED
@@ -2,7 +2,8 @@
2
2
 
3
3
  [![Build Status](https://travis-ci.org/neilmiddleton/attr_secure.png?branch=master)](https://travis-ci.org/neilmiddleton/attr_secure)
4
4
 
5
- Securely stores ActiveRecord attributes for a given model/attribute and a predefined secret.
5
+ Securely stores attribute values for your Ruby objects. Also supports Active
6
+ Record and Sequel!
6
7
 
7
8
  ```
8
9
  ENV["ATTR_SECURE_SECRET"] = "MySuperSecretKeyThatCannotBeGuessed"
data/Rakefile CHANGED
@@ -1,8 +1,10 @@
1
1
  require "bundler/gem_tasks"
2
- require "rake/testtask"
2
+ require "rspec/core/rake_task"
3
3
 
4
- Rake::TestTask.new do |t|
5
- t.libs.push "lib"
6
- t.test_files = FileList['test/*_test.rb']
7
- t.verbose = true
4
+ RSpec::Core::RakeTask.new(:core) do |spec|
5
+ spec.pattern = 'spec/**/*_spec.rb'
6
+ spec.rspec_opts = ['--backtrace']
8
7
  end
8
+
9
+ task(:default).clear
10
+ task default: :core
data/attr_secure.gemspec CHANGED
@@ -19,7 +19,10 @@ Gem::Specification.new do |spec|
19
19
  spec.require_paths = ["lib"]
20
20
 
21
21
  spec.add_development_dependency "rspec"
22
+ spec.add_development_dependency "rake"
23
+ spec.add_development_dependency "activerecord"
24
+ spec.add_development_dependency "sequel"
25
+ spec.add_development_dependency "sqlite3"
22
26
 
23
27
  spec.add_dependency 'fernet'
24
- spec.add_dependency 'activerecord', ' ~> 3.2.0'
25
28
  end
data/lib/attr_secure.rb CHANGED
@@ -1,24 +1,38 @@
1
1
  require "attr_secure/version"
2
2
  require 'fernet'
3
- require 'active_record'
4
3
 
5
- require 'attr_secure/secure'
4
+ require 'attr_secure/adapters/ruby'
5
+ require 'attr_secure/adapters/active_record'
6
+ require 'attr_secure/adapters/sequel'
6
7
 
7
8
  Fernet::Configuration.run do |config|
8
9
  config.enforce_ttl = false
9
10
  end
10
11
 
11
12
  module AttrSecure
13
+ #
14
+ # All the available adapters.
15
+ # The order in this list matters, as only the first valid adapter will be used
16
+ #
17
+ ADAPTERS = [
18
+ AttrSecure::Adapters::Sequel,
19
+ AttrSecure::Adapters::ActiveRecord,
20
+ AttrSecure::Adapters::Ruby
21
+ ]
12
22
 
13
- def attr_secure(attribute)
23
+ def attr_secure(attribute, encryption_class = Secure.new)
14
24
  define_method("#{attribute}=") do |value|
15
- write_attribute(attribute, Secure.new.encrypt(value.nil? ? nil : value.to_sym))
25
+ encrypted_value = encryption_class.encrypt(value.nil? ? nil : value)
26
+ self.class.attr_secure_adapter.write_attribute self, attribute, encrypted_value
16
27
  end
17
28
 
18
29
  define_method("#{attribute}") do
19
- Secure.new.decrypt read_attribute(attribute.to_sym)
30
+ encrypted_value = self.class.attr_secure_adapter.read_attribute(self, attribute)
31
+ encryption_class.decrypt encrypted_value
20
32
  end
21
33
  end
22
- end
23
34
 
24
- ActiveRecord::Base.send(:extend, AttrSecure)
35
+ def attr_secure_adapter
36
+ ADAPTERS.find {|a| a.valid?(self) }
37
+ end
38
+ end
@@ -0,0 +1,24 @@
1
+ require 'attr_secure/secure'
2
+
3
+ module AttrSecure
4
+ module Adapters
5
+ module ActiveRecord
6
+
7
+ def self.valid?(object)
8
+ object.respond_to?(:<) && defined?(ActiveRecord) && object < ::ActiveRecord::Base
9
+ end
10
+
11
+ def self.write_attribute(object, attribute, value)
12
+ object.send :write_attribute, attribute, value
13
+ end
14
+
15
+ def self.read_attribute(object, attribute)
16
+ object.send :read_attribute, attribute.to_sym
17
+ end
18
+ end
19
+ end
20
+ end
21
+
22
+ if defined?(ActiveRecord)
23
+ ActiveRecord::Base.send(:extend, AttrSecure)
24
+ end
@@ -0,0 +1,21 @@
1
+ require 'attr_secure/secure'
2
+
3
+ module AttrSecure
4
+ module Adapters
5
+ module Ruby
6
+
7
+ def self.valid?(object)
8
+ true
9
+ end
10
+
11
+ def self.write_attribute(object, attribute, value)
12
+ object.instance_variable_set "@#{attribute}", value
13
+ end
14
+
15
+ def self.read_attribute(object, attribute)
16
+ object.instance_variable_get "@#{attribute}"
17
+ end
18
+
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,24 @@
1
+ require 'attr_secure/secure'
2
+
3
+ module AttrSecure
4
+ module Adapters
5
+ module Sequel
6
+
7
+ def self.valid?(object)
8
+ object.respond_to?(:<) && defined?(Sequel) && object < ::Sequel::Model
9
+ end
10
+
11
+ def self.write_attribute(object, attribute, value)
12
+ object[attribute] = value
13
+ end
14
+
15
+ def self.read_attribute(object, attribute)
16
+ object[attribute]
17
+ end
18
+ end
19
+ end
20
+ end
21
+
22
+ if defined?(Sequel)
23
+ Sequel::Model.send(:extend, AttrSecure)
24
+ end
@@ -1,5 +1,10 @@
1
1
  module AttrSecure
2
2
  class Secure
3
+ attr_reader :env
4
+
5
+ def initialize(env=ENV)
6
+ @env = env
7
+ end
3
8
 
4
9
  def encrypt(value)
5
10
  Fernet.generate(attr_secure_secret) do |generator|
@@ -10,12 +15,12 @@ module AttrSecure
10
15
  def decrypt(value)
11
16
  return nil if value.nil?
12
17
  verifier = Fernet.verifier(attr_secure_secret, value)
13
- verifier.data["value"] if verifier.valid?
18
+ verifier.data['value'] if verifier.valid?
14
19
  end
15
20
 
16
21
  private
17
22
  def env!(key)
18
- ENV.fetch(key) { raise("Missing ENV(#{key})") }
23
+ env.fetch(key) { raise("Missing ENV(#{key})") }
19
24
  end
20
25
 
21
26
  def attr_secure_secret
@@ -1,3 +1,3 @@
1
1
  module AttrSecure
2
- VERSION = "0.0.3"
2
+ VERSION = "0.1.0"
3
3
  end
@@ -0,0 +1,30 @@
1
+ require 'spec_helper'
2
+
3
+ describe AttrSecure::Adapters::ActiveRecord do
4
+ let(:described) { Class.new(ActiveRecord::Base) }
5
+ subject { described.new }
6
+ let(:secure_mock) { double(AttrSecure::Secure) }
7
+
8
+ before do
9
+ described.table_name = 'fake_database'
10
+ described.extend(AttrSecure)
11
+ described.attr_secure :title, secure_mock
12
+ end
13
+
14
+ it 'has active record as it\'s adapter' do
15
+ expect(described.attr_secure_adapter).to eq(AttrSecure::Adapters::ActiveRecord)
16
+ end
17
+
18
+ it 'encrypts' do
19
+ secure_mock.should_receive(:encrypt).with('hello').and_return('encrypted')
20
+ subject.title = 'hello'
21
+ expect(subject.attributes['title']).to eq('encrypted')
22
+ end
23
+
24
+ it 'decrypts' do
25
+ secure_mock.should_receive(:encrypt).with('hello').and_return('encrypted')
26
+ subject.title = 'hello'
27
+ secure_mock.should_receive(:decrypt).with('encrypted').and_return('decrypted')
28
+ expect(subject.title).to eq('decrypted')
29
+ end
30
+ end
@@ -0,0 +1,29 @@
1
+ require 'spec_helper'
2
+
3
+ describe AttrSecure::Adapters::Ruby do
4
+ let(:described) { Class.new }
5
+ subject { described.new }
6
+ let(:secure_mock) { double(AttrSecure::Secure) }
7
+
8
+ before do
9
+ described.extend(AttrSecure)
10
+ described.attr_secure :foo, secure_mock
11
+ end
12
+
13
+ it 'has ruby as it\'s adapter' do
14
+ expect(described.attr_secure_adapter).to eq(AttrSecure::Adapters::Ruby)
15
+ end
16
+
17
+ it 'encrypts' do
18
+ secure_mock.should_receive(:encrypt).with('hello').and_return('encrypted')
19
+ subject.foo = 'hello'
20
+ expect(subject.instance_variable_get(:@foo)).to eq('encrypted')
21
+ end
22
+
23
+ it 'decrypts' do
24
+ secure_mock.should_receive(:encrypt).with('hello').and_return('encrypted')
25
+ subject.foo = 'hello'
26
+ secure_mock.should_receive(:decrypt).with('encrypted').and_return('decrypted')
27
+ expect(subject.foo).to eq('decrypted')
28
+ end
29
+ end
@@ -0,0 +1,30 @@
1
+ require 'spec_helper'
2
+
3
+ describe AttrSecure::Adapters::Sequel do
4
+ let(:described) { Class.new(Sequel::Model) }
5
+ subject { described.new }
6
+ let(:secure_mock) { double(AttrSecure::Secure) }
7
+
8
+ before do
9
+ described.set_dataset(:fake_database)
10
+ described.extend(AttrSecure)
11
+ described.attr_secure :title, secure_mock
12
+ end
13
+
14
+ it 'has sequel as it\'s adapter' do
15
+ expect(described.attr_secure_adapter).to eq(AttrSecure::Adapters::Sequel)
16
+ end
17
+
18
+ it 'encrypts' do
19
+ secure_mock.should_receive(:encrypt).with('hello').and_return('encrypted')
20
+ subject.title = 'hello'
21
+ expect(subject.values[:title]).to eq('encrypted')
22
+ end
23
+
24
+ it 'decrypts' do
25
+ secure_mock.should_receive(:encrypt).with('hello').and_return('encrypted')
26
+ subject.title = 'hello'
27
+ secure_mock.should_receive(:decrypt).with('encrypted').and_return('decrypted')
28
+ expect(subject.title).to eq('decrypted')
29
+ end
30
+ end
@@ -0,0 +1,22 @@
1
+ require 'spec_helper'
2
+
3
+ describe AttrSecure::Secure do
4
+ subject { described_class.new({'ATTR_SECURE_SECRET' => token}) }
5
+ let(:token) { 'fWSvpC6Eh1/FFE1TUgXpcEzMmmGc9IZSqoexzEslzKI=' }
6
+
7
+ describe 'encrypt' do
8
+ it "should encrypt a string" do
9
+ expect(subject.encrypt('encrypted')).to be_a(String)
10
+ expect(subject.encrypt('encrypted')).to_not be_empty
11
+ expect(subject.encrypt('encrypted')).to_not eq(subject.encrypt('encrypted'))
12
+ end
13
+ end
14
+
15
+ describe 'decrypt' do
16
+ let(:encrypted_value) { subject.encrypt('decrypted') }
17
+
18
+ it "should decrypt a string" do
19
+ expect(subject.decrypt(encrypted_value)).to eq('decrypted')
20
+ end
21
+ end
22
+ end
data/spec/spec_helper.rb CHANGED
@@ -1,5 +1,7 @@
1
1
  require 'attr_secure'
2
2
 
3
+ Dir['spec/support/**/*.rb'].sort.each { |path| load File.expand_path(path) }
4
+
3
5
  RSpec.configure do |config|
4
6
  config.treat_symbols_as_metadata_keys_with_true_values = true
5
7
  config.run_all_when_everything_filtered = true
@@ -0,0 +1,11 @@
1
+ require 'active_record'
2
+ ActiveRecord::Base.establish_connection adapter: "sqlite3", database: ":memory:"
3
+
4
+ ActiveRecord::Schema.define do
5
+ self.verbose = false
6
+
7
+ create_table :fake_database, :force => true do |t|
8
+ t.string :title
9
+ t.timestamps
10
+ end
11
+ end
@@ -0,0 +1,8 @@
1
+ require 'sequel'
2
+
3
+ DB = Sequel.sqlite
4
+
5
+ DB.create_table :fake_database do
6
+ primary_key :id
7
+ column :title, :string
8
+ 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.0.3
4
+ version: 0.1.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-05-31 00:00:00.000000000 Z
11
+ date: 2013-06-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec
@@ -25,13 +25,13 @@ dependencies:
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
27
  - !ruby/object:Gem::Dependency
28
- name: fernet
28
+ name: rake
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - '>='
32
32
  - !ruby/object:Gem::Version
33
33
  version: '0'
34
- type: :runtime
34
+ type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
@@ -42,16 +42,58 @@ dependencies:
42
42
  name: activerecord
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - ~>
45
+ - - '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: sequel
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
46
67
  - !ruby/object:Gem::Version
47
- version: 3.2.0
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: sqlite3
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: fernet
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - '>='
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
48
90
  type: :runtime
49
91
  prerelease: false
50
92
  version_requirements: !ruby/object:Gem::Requirement
51
93
  requirements:
52
- - - ~>
94
+ - - '>='
53
95
  - !ruby/object:Gem::Version
54
- version: 3.2.0
96
+ version: '0'
55
97
  description: Securely stores activerecord model attributes
56
98
  email:
57
99
  - neil@neilmiddleton.com
@@ -67,10 +109,18 @@ files:
67
109
  - Rakefile
68
110
  - attr_secure.gemspec
69
111
  - lib/attr_secure.rb
112
+ - lib/attr_secure/adapters/active_record.rb
113
+ - lib/attr_secure/adapters/ruby.rb
114
+ - lib/attr_secure/adapters/sequel.rb
70
115
  - lib/attr_secure/secure.rb
71
116
  - lib/attr_secure/version.rb
72
- - spec/attr_secure_spec.rb
117
+ - spec/adapters/active_record_spec.rb
118
+ - spec/adapters/ruby_spec.rb
119
+ - spec/adapters/sequel_spec.rb
120
+ - spec/secure_spec.rb
73
121
  - spec/spec_helper.rb
122
+ - spec/support/load_active_record.rb
123
+ - spec/support/load_sequel.rb
74
124
  homepage: http://www.neilmiddleton.com
75
125
  licenses:
76
126
  - MIT
@@ -96,5 +146,10 @@ signing_key:
96
146
  specification_version: 4
97
147
  summary: Securely stores activerecord model attributes
98
148
  test_files:
99
- - spec/attr_secure_spec.rb
149
+ - spec/adapters/active_record_spec.rb
150
+ - spec/adapters/ruby_spec.rb
151
+ - spec/adapters/sequel_spec.rb
152
+ - spec/secure_spec.rb
100
153
  - spec/spec_helper.rb
154
+ - spec/support/load_active_record.rb
155
+ - spec/support/load_sequel.rb
@@ -1,52 +0,0 @@
1
- require 'spec_helper'
2
-
3
- class FakeModelWithSecureAttributes
4
- extend AttrSecure
5
- attr_accessor :attributes
6
-
7
- attr_secure :foo
8
-
9
- def initialize(attributes={})
10
- @attributes = attributes
11
- end
12
-
13
- def read_attribute(attr_name)
14
- attributes[attr_name]
15
- end
16
-
17
- def write_attribute(attr_name, value)
18
- attributes[attr_name] = value
19
- end
20
- end
21
-
22
-
23
- ENV['ATTR_SECURE_SECRET'] = 'xxx'
24
-
25
- describe AttrSecure do
26
- subject { FakeModelWithSecureAttributes.new }
27
-
28
- it 'encrypts' do
29
- encrypter = lambda { |secret|
30
- assert_equal 'xxx', secret
31
- 'world'
32
- }
33
-
34
- Fernet.stub :generate, encrypter do |f|
35
- subject.foo = 'hello'
36
- expect(subject.attributes[:foo]).to eq('world')
37
- end
38
- end
39
-
40
- it 'decrypts' do
41
- decrypter_mock = double(Object)
42
- decrypter_mock.stub(:valid?) { true }
43
- decrypter_mock.stub(:data) { {'value' => 'world'} }
44
-
45
- Fernet.stub(:generate, 'world') do
46
- Fernet.stub(:verifier, decrypter_mock) do
47
- subject.foo = 'hello'
48
- expect(subject.foo).to eq('world')
49
- end
50
- end
51
- end
52
- end