attr_secure 0.0.3 → 0.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 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