crypt_keeper 0.0.1

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/.gitignore ADDED
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ spec/debug.log
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format progress
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in lee_loo.gemspec
4
+ gemspec
data/Guardfile ADDED
@@ -0,0 +1,19 @@
1
+ # A sample Guardfile
2
+ # More info at https://github.com/guard/guard#readme
3
+
4
+ guard 'rspec', version: 2, fail_fast: true, all_on_start: false, all_after_pass: false do
5
+ watch(%r{^spec/.+_spec\.rb$})
6
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
7
+ watch('spec/spec_helper.rb') { "spec" }
8
+
9
+ # Rails example
10
+ watch(%r{^app/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
11
+ watch(%r{^app/(.*)(\.erb|\.haml)$}) { |m| "spec/#{m[1]}#{m[2]}_spec.rb" }
12
+ watch(%r{^app/controllers/(.+)_(controller)\.rb$}) { |m| ["spec/routing/#{m[1]}_routing_spec.rb", "spec/#{m[2]}s/#{m[1]}_#{m[2]}_spec.rb", "spec/acceptance/#{m[1]}_spec.rb"] }
13
+ watch(%r{^spec/support/(.+)\.rb$}) { "spec" }
14
+ watch('config/routes.rb') { "spec/routing" }
15
+ watch('app/controllers/application_controller.rb') { "spec/controllers" }
16
+ # Capybara request specs
17
+ watch(%r{^app/views/(.+)/.*\.(erb|haml)$}) { |m| "spec/requests/#{m[1]}_spec.rb" }
18
+ end
19
+
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Justin Mazzi
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,57 @@
1
+ # CryptKeeper
2
+
3
+ Provides transparent encryption for ActiveRecord. It is encryption agnostic.
4
+ You can guard your data with any encryption algorithm you want. All you need
5
+ is a simple class that does 3 things.
6
+
7
+ 1. Takes a hash argument for `initialize`
8
+ 2. Provides an `encrypt` method that returns the encrypted string
9
+ 3. Provides a `decrypt` method that returns the plaintext
10
+
11
+ Use can see an AES example here [here](https://github.com/jmazzi/crypt_keeper_providers/blob/master/lib/crypt_keeper_providers/aes.rb)
12
+
13
+ ## Why?
14
+
15
+ The options available were either too complicated under the hood or had weird
16
+ edge cases that made the library hard to use. I wanted to write something
17
+ simple that *just works*.
18
+
19
+ ## Usage
20
+
21
+ ```ruby
22
+
23
+ class MyModel < ActiveRecord::Base
24
+ crypt_keeper :field, :other_field, encryptor: Aes, passphrase: 'super_good_password'
25
+ end
26
+
27
+ model = MyModel.new(field: 'sometext')
28
+ model.save! #=> Your data is now encrypted
29
+ model.field #=> 'sometext'
30
+
31
+ ```
32
+
33
+ It works with all persistences methods: `update_attribute`, `update_attributes`,
34
+ and save.
35
+
36
+ ## Installation
37
+
38
+ Add this line to your application's Gemfile:
39
+
40
+ gem 'crypt_keeper'
41
+
42
+ And then execute:
43
+
44
+ $ bundle
45
+
46
+ Or install it yourself as:
47
+
48
+ $ gem install crypt_keeper
49
+
50
+
51
+ ## Contributing
52
+
53
+ 1. Fork it
54
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
55
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
56
+ 4. Push to the branch (`git push origin my-new-feature`)
57
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
3
+ require 'rspec/core/rake_task'
4
+
5
+ RSpec::Core::RakeTask.new :spec
6
+ Bundler::GemHelper.install_tasks
7
+
8
+ task :default => [:spec]
@@ -0,0 +1,31 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/crypt_keeper/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.authors = ["Justin Mazzi"]
6
+ gem.email = ["jmazzi@gmail.com"]
7
+ gem.description = %q{Transparent encryption for ActiveRecord that isn't over-engineered}
8
+ gem.summary = gem.description
9
+ gem.homepage = ""
10
+
11
+ gem.files = `git ls-files`.split($\)
12
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
13
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
14
+ gem.name = "crypt_keeper"
15
+ gem.require_paths = ["lib"]
16
+ gem.version = CryptKeeper::VERSION
17
+
18
+ gem.add_runtime_dependency 'activerecord', '>= 3.0'
19
+ gem.add_runtime_dependency 'activesupport', '>= 3.0'
20
+ gem.add_runtime_dependency 'crypt_keeper_providers', '~> 0.0.1'
21
+
22
+ gem.add_development_dependency 'rspec', '~> 2.10.0'
23
+ gem.add_development_dependency 'guard', '~> 1.2.0'
24
+ gem.add_development_dependency 'guard-rspec', '~> 1.1.0'
25
+ gem.add_development_dependency 'sqlite3'
26
+ gem.add_development_dependency 'rake', '~> 0.9.2.2'
27
+ if RUBY_PLATFORM == 'java'
28
+ gem.add_development_dependency 'jruby-openssl', '~> 0.7.7'
29
+ gem.add_development_dependency 'activerecord-jdbcsqlite3-adapter'
30
+ end
31
+ end
@@ -0,0 +1,95 @@
1
+ require 'active_support/concern'
2
+ require 'active_support/core_ext/array/extract_options'
3
+
4
+ module CryptKeeper
5
+ module Model
6
+ extend ActiveSupport::Concern
7
+
8
+ private
9
+
10
+ # Private: Encrypt each crypt_keeper_fields
11
+ def before_save_encrypt
12
+ crypt_keeper_fields.each do |field|
13
+ self[field] = self.class.encrypt read_attribute(field)
14
+ end
15
+ end
16
+
17
+ # Private: Decrypt each crypt_keeper_fields
18
+ def after_save_decrypt
19
+ crypt_keeper_fields.each do |field|
20
+ self[field] = self.class.decrypt read_attribute(field)
21
+ end
22
+ end
23
+
24
+ module ClassMethods
25
+ # Public: Setup fields for encryption
26
+ #
27
+ # args - An array of fields to encrypt. The last argument should be
28
+ # a hash of options. Note, an :encryptor is required. This should be
29
+ # a class that takes a hash for initialize and provides an encrypt
30
+ # and decrypt method.
31
+ #
32
+ # Example
33
+ #
34
+ # class MyModel < ActiveRecord::Base
35
+ # crypt_keeper :field, :other_field, encryptor: Aes, passphrase: 'super_good_password'
36
+ # end
37
+ #
38
+ def crypt_keeper(*args)
39
+ class_attribute :crypt_keeper_options
40
+ class_attribute :crypt_keeper_fields
41
+ class_attribute :crypt_keeper_encryptor
42
+
43
+ self.crypt_keeper_options = args.extract_options!
44
+ self.crypt_keeper_encryptor = crypt_keeper_options.delete(:encryptor)
45
+ self.crypt_keeper_fields = args
46
+
47
+ ensure_valid_encryptor!
48
+ define_crypt_keeper_callbacks
49
+ end
50
+
51
+ # Public: Encrypts a string with the encryptor
52
+ def encrypt(value)
53
+ encryptor.encrypt value
54
+ end
55
+
56
+ # Public: Decrypts a string with the encryptor
57
+ def decrypt(value)
58
+ encryptor.decrypt value
59
+ end
60
+
61
+ private
62
+
63
+ # Private: An instance of the encryptor class
64
+ def encryptor
65
+ crypt_keeper_encryptor.new(crypt_keeper_options)
66
+ end
67
+
68
+ # Private: Ensure that the encryptor responds to new
69
+ def ensure_valid_encryptor!
70
+ unless crypt_keeper_encryptor.respond_to?(:new)
71
+ raise "You must specify an encryption class `crypt_keeper encryptor: EncryptionClass`"
72
+ end
73
+ end
74
+
75
+ # Private: Define callbacks for encryption
76
+ def define_crypt_keeper_callbacks
77
+ after_save :after_save_decrypt
78
+ after_find :after_save_decrypt
79
+ before_save :before_save_encrypt
80
+
81
+ crypt_keeper_fields.each do |field|
82
+ ensure_field_is_encryptable! field
83
+ end
84
+ end
85
+
86
+ # Private: Ensures that each field is of type text. This prevents
87
+ # encrypted data from being truncated
88
+ def ensure_field_is_encryptable!(field)
89
+ unless columns_hash["#{field}"].type == :text
90
+ raise ArgumentError, ":#{field} must be of type 'text' to be used for encryption"
91
+ end
92
+ end
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,3 @@
1
+ module CryptKeeper
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,10 @@
1
+ require 'crypt_keeper/version'
2
+ require 'crypt_keeper/model'
3
+ require 'active_record'
4
+
5
+ module CryptKeeper
6
+ end
7
+
8
+ ActiveSupport.on_load(:active_record) do
9
+ include CryptKeeper::Model
10
+ end
@@ -0,0 +1,86 @@
1
+ require 'spec_helper'
2
+
3
+ module CryptKeeper
4
+ describe Model do
5
+ subject { SensitiveData }
6
+ let(:encryptor) do
7
+ mock('Encryptor').tap do |m|
8
+ m.stub :new
9
+ end
10
+ end
11
+
12
+ describe "#crypt_keeper" do
13
+ context "Fields" do
14
+ it "should set the fields" do
15
+ subject.crypt_keeper :storage, :secret, encryptor: encryptor
16
+ subject.crypt_keeper_fields.should == [:storage, :secret]
17
+ end
18
+
19
+ it "should raise an exception with wrong field type" do
20
+ msg = ":name must be of type 'text' to be used for encryption"
21
+ expect { subject.crypt_keeper :name, encryptor: encryptor }.to raise_error(ArgumentError, msg)
22
+ end
23
+ end
24
+
25
+ context "Options" do
26
+ it "should set the options" do
27
+ subject.crypt_keeper :storage, :secret, key1: 1, key2: 2, encryptor: encryptor
28
+ subject.crypt_keeper_options.should == { key1: 1, key2: 2 }
29
+ end
30
+ end
31
+ end
32
+
33
+ context "Encryption" do
34
+ let(:encryptor) do
35
+ Class.new do
36
+ def initialize(options = {})
37
+ @passphrase = options[:passphrase]
38
+ end
39
+
40
+ def encrypt(data)
41
+ @passphrase + data.reverse
42
+ end
43
+
44
+ def decrypt(data)
45
+ data.sub(/^#{@passphrase}/, '').reverse
46
+ end
47
+ end
48
+ end
49
+
50
+ let(:plain_text) { 'plain_text' }
51
+ let(:cipher_text) { 'tooltxet_nialp' }
52
+
53
+ before do
54
+ SensitiveData.crypt_keeper :storage, passphrase: 'tool', encryptor: encryptor
55
+ end
56
+
57
+ subject { SensitiveData.new }
58
+
59
+ describe "#encrypt" do
60
+ it "should encrypt the data" do
61
+ subject.storage = plain_text
62
+ subject.stub :after_save_decrypt
63
+ subject.save!
64
+ subject.storage.should == cipher_text
65
+ end
66
+ end
67
+
68
+ describe "#decrypt" do
69
+ it "should decrypt the data" do
70
+ subject.storage = cipher_text
71
+ subject.stub :before_save_encrypt
72
+ subject.save!
73
+ subject.storage.should == plain_text
74
+ end
75
+ end
76
+
77
+ describe "Encrypt & Decrypt" do
78
+ it "should encrypt and decrypt the data" do
79
+ subject.storage = plain_text
80
+ subject.save!
81
+ subject.storage.should == plain_text
82
+ end
83
+ end
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,10 @@
1
+ require 'crypt_keeper'
2
+
3
+ SPEC_ROOT = Pathname.new File.expand_path File.dirname __FILE__
4
+ Dir[SPEC_ROOT.join('support/*.rb')].each{|f| require f }
5
+
6
+ RSpec.configure do |config|
7
+ config.treat_symbols_as_metadata_keys_with_true_values = true
8
+ config.run_all_when_everything_filtered = true
9
+ config.filter_run :focus
10
+ end
@@ -0,0 +1,16 @@
1
+ require 'active_record'
2
+ require 'logger'
3
+
4
+ ActiveRecord::Base.establish_connection(:adapter => 'sqlite3', :database => ':memory:')
5
+ ActiveRecord::Base.logger = Logger.new SPEC_ROOT.join('debug.log').to_s
6
+ ActiveRecord::Migration.verbose = false
7
+
8
+ ActiveRecord::Schema.define do
9
+ create_table :sensitive_data, :force => true do |t|
10
+ t.column :name, :string
11
+ t.column :storage, :text
12
+ t.column :secret, :text
13
+ end
14
+ end
15
+
16
+ class SensitiveData < ActiveRecord::Base; end
metadata ADDED
@@ -0,0 +1,156 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: crypt_keeper
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Justin Mazzi
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-07-27 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: activerecord
16
+ requirement: &21832080 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '3.0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *21832080
25
+ - !ruby/object:Gem::Dependency
26
+ name: activesupport
27
+ requirement: &21831560 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '3.0'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: *21831560
36
+ - !ruby/object:Gem::Dependency
37
+ name: crypt_keeper_providers
38
+ requirement: &21830520 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ~>
42
+ - !ruby/object:Gem::Version
43
+ version: 0.0.1
44
+ type: :runtime
45
+ prerelease: false
46
+ version_requirements: *21830520
47
+ - !ruby/object:Gem::Dependency
48
+ name: rspec
49
+ requirement: &21829560 !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: 2.10.0
55
+ type: :development
56
+ prerelease: false
57
+ version_requirements: *21829560
58
+ - !ruby/object:Gem::Dependency
59
+ name: guard
60
+ requirement: &21828940 !ruby/object:Gem::Requirement
61
+ none: false
62
+ requirements:
63
+ - - ~>
64
+ - !ruby/object:Gem::Version
65
+ version: 1.2.0
66
+ type: :development
67
+ prerelease: false
68
+ version_requirements: *21828940
69
+ - !ruby/object:Gem::Dependency
70
+ name: guard-rspec
71
+ requirement: &21828360 !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - ~>
75
+ - !ruby/object:Gem::Version
76
+ version: 1.1.0
77
+ type: :development
78
+ prerelease: false
79
+ version_requirements: *21828360
80
+ - !ruby/object:Gem::Dependency
81
+ name: sqlite3
82
+ requirement: &21827660 !ruby/object:Gem::Requirement
83
+ none: false
84
+ requirements:
85
+ - - ! '>='
86
+ - !ruby/object:Gem::Version
87
+ version: '0'
88
+ type: :development
89
+ prerelease: false
90
+ version_requirements: *21827660
91
+ - !ruby/object:Gem::Dependency
92
+ name: rake
93
+ requirement: &21826720 !ruby/object:Gem::Requirement
94
+ none: false
95
+ requirements:
96
+ - - ~>
97
+ - !ruby/object:Gem::Version
98
+ version: 0.9.2.2
99
+ type: :development
100
+ prerelease: false
101
+ version_requirements: *21826720
102
+ description: Transparent encryption for ActiveRecord that isn't over-engineered
103
+ email:
104
+ - jmazzi@gmail.com
105
+ executables: []
106
+ extensions: []
107
+ extra_rdoc_files: []
108
+ files:
109
+ - .gitignore
110
+ - .rspec
111
+ - Gemfile
112
+ - Guardfile
113
+ - LICENSE
114
+ - README.md
115
+ - Rakefile
116
+ - crypt_keeper.gemspec
117
+ - lib/crypt_keeper.rb
118
+ - lib/crypt_keeper/model.rb
119
+ - lib/crypt_keeper/version.rb
120
+ - spec/model_spec.rb
121
+ - spec/spec_helper.rb
122
+ - spec/support/active_record.rb
123
+ homepage: ''
124
+ licenses: []
125
+ post_install_message:
126
+ rdoc_options: []
127
+ require_paths:
128
+ - lib
129
+ required_ruby_version: !ruby/object:Gem::Requirement
130
+ none: false
131
+ requirements:
132
+ - - ! '>='
133
+ - !ruby/object:Gem::Version
134
+ version: '0'
135
+ segments:
136
+ - 0
137
+ hash: -2444194484857167545
138
+ required_rubygems_version: !ruby/object:Gem::Requirement
139
+ none: false
140
+ requirements:
141
+ - - ! '>='
142
+ - !ruby/object:Gem::Version
143
+ version: '0'
144
+ segments:
145
+ - 0
146
+ hash: -2444194484857167545
147
+ requirements: []
148
+ rubyforge_project:
149
+ rubygems_version: 1.8.11
150
+ signing_key:
151
+ specification_version: 3
152
+ summary: Transparent encryption for ActiveRecord that isn't over-engineered
153
+ test_files:
154
+ - spec/model_spec.rb
155
+ - spec/spec_helper.rb
156
+ - spec/support/active_record.rb