attr_redactor 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +6 -0
- data/.travis.yml +17 -0
- data/CHANGELOG.md +3 -0
- data/Gemfile +3 -0
- data/MIT-LICENSE +20 -0
- data/README.md +259 -0
- data/Rakefile +22 -0
- data/attr_redactor.gemspec +52 -0
- data/lib/attr_redactor/adapters/active_record.rb +86 -0
- data/lib/attr_redactor/adapters/data_mapper.rb +21 -0
- data/lib/attr_redactor/version.rb +17 -0
- data/lib/attr_redactor.rb +318 -0
- data/test/active_record_test.rb +187 -0
- data/test/attr_redactor_test.rb +278 -0
- data/test/run.sh +12 -0
- data/test/test_helper.rb +36 -0
- metadata +208 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 7ef566d6a681d20457b44307df0704879c64814b
|
4
|
+
data.tar.gz: 529a1c447257ad7b692d36847f1625bbd70354b0
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: fd65f904aac0a3827d8d108c2ba1b2481d3696882c046e8b1782db61899b1b3e45e092dfe3d745758cb121fb750c5caa6eee21f1dfd550d8abf8682d4f4cc2de
|
7
|
+
data.tar.gz: 4c96ba87e0a8a90eb78c3776d53487839843829694133167630bb33c29a5b2e5ebbcd5d1395496e0b80bf77ab160eddd1fae2f20ac50e68459b9ae7c74c280dd
|
data/.gitignore
ADDED
data/.travis.yml
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
sudo: false
|
2
|
+
language: ruby
|
3
|
+
cache: bundler
|
4
|
+
rvm:
|
5
|
+
- 2.0
|
6
|
+
- 2.1
|
7
|
+
- 2.3.0
|
8
|
+
env:
|
9
|
+
- ACTIVERECORD=3.0.0
|
10
|
+
- ACTIVERECORD=3.2.0
|
11
|
+
- ACTIVERECORD=4.0.0
|
12
|
+
- ACTIVERECORD=4.2.0
|
13
|
+
matrix:
|
14
|
+
exclude:
|
15
|
+
allow_failures:
|
16
|
+
- rvm: rbx
|
17
|
+
fast_finish: true
|
data/CHANGELOG.md
ADDED
data/Gemfile
ADDED
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2008 Sean Huber - shuber@huberry.com
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,259 @@
|
|
1
|
+
[![Gem Version](https://badge.fury.io/rb/attr_redactor.svg)](https://badge.fury.io/rb/attr_redactor)
|
2
|
+
[![Build Status](https://travis-ci.org/chrisjensen/attr_redactor.svg?branch=master)](https://travis-ci.org/chrisjensen/attr_redactor)
|
3
|
+
[![Test Coverage](https://codeclimate.com/github/chrisjensen/attr_redactor/badges/coverage.svg)](https://codeclimate.com/github/chrisjensen/attr_redactor/coverage)
|
4
|
+
[![Code Climate](https://codeclimate.com/github/chrisjensen/attr_redactor/badges/gpa.svg)](https://codeclimate.com/github/chrisjensen/attr_redactor)
|
5
|
+
[![security](https://hakiri.io/github/chrisjensen/attr_redactor/master.svg)](https://hakiri.io/github/chrisjensen/attr_redactor/master)
|
6
|
+
|
7
|
+
# attr_redactor
|
8
|
+
|
9
|
+
Generates attr_accessors that transparently redact a hash attribute by removing, digesting or encrypting certain keys.
|
10
|
+
|
11
|
+
This code is based off of the [attr_encrypted/attr_encrypted](https://github.com/attr-encrypted/attr_encrypted) code base.
|
12
|
+
|
13
|
+
Helper classes for `ActiveRecord`,
|
14
|
+
|
15
|
+
`DataMapper`, and `Sequel` helpers have been retained, but have not been successfully tested.
|
16
|
+
|
17
|
+
## Installation
|
18
|
+
|
19
|
+
Add attr_redactor to your gemfile:
|
20
|
+
|
21
|
+
```ruby
|
22
|
+
gem "attr_redactor"
|
23
|
+
```
|
24
|
+
|
25
|
+
Then install the gem:
|
26
|
+
|
27
|
+
```bash
|
28
|
+
bundle install
|
29
|
+
```
|
30
|
+
|
31
|
+
## Usage
|
32
|
+
|
33
|
+
If you're using an ORM like `ActiveRecord` using attr_redactor is easy:
|
34
|
+
|
35
|
+
```ruby
|
36
|
+
class User
|
37
|
+
attr_redactor :user_data, redact: { :ssn => :remove, :email => :encrypt }
|
38
|
+
end
|
39
|
+
```
|
40
|
+
|
41
|
+
If you're using a PORO, you have to do a little bit more work by extending the class:
|
42
|
+
|
43
|
+
```ruby
|
44
|
+
class User
|
45
|
+
extend AttrRedactor
|
46
|
+
attr_accessor :name
|
47
|
+
attr_redactor :user_data, redact: { :ssn => :remove, :email => :encrypt }, encryption_key: 'YOUR ENCRYPTION KEY'
|
48
|
+
|
49
|
+
def load
|
50
|
+
# loads the stored data
|
51
|
+
end
|
52
|
+
|
53
|
+
def save
|
54
|
+
# saves the :name and :redacted_user_data attributes somewhere (e.g. filesystem, database, etc)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
user = User.new
|
59
|
+
user.user_data = { ssn: '123-45-6789', email: 'personal@email.com' }
|
60
|
+
user.redacted_data[:encrypted_email] # returns the encrypted version of :ssn
|
61
|
+
user.redacted_data.has_key?(:email) # false
|
62
|
+
user.save
|
63
|
+
|
64
|
+
user = User.load
|
65
|
+
user.data { email: 'personal@email.com' }
|
66
|
+
```
|
67
|
+
|
68
|
+
When you set a redacted attribute the data is *immediately* redacted and the attribute replaced.
|
69
|
+
This is to avoid confusion or inconsistency when passing a record around that might be freshly created or loaded from the DB.
|
70
|
+
|
71
|
+
```
|
72
|
+
user = User.new user_data: { ssn: '123-45-6789', email: 'personal@email.com' }
|
73
|
+
|
74
|
+
user.user_data[:ssn] # nil
|
75
|
+
```
|
76
|
+
|
77
|
+
### Note on Updating Data
|
78
|
+
|
79
|
+
Changes within the hash may not be saved
|
80
|
+
|
81
|
+
To ensure ActiveRecord saves changed data, you should always update the hash entirely, not keys within the hash.
|
82
|
+
|
83
|
+
```
|
84
|
+
user = User.new user_data: { ssn: '123-45-6789', email: 'personal@email.com' }
|
85
|
+
|
86
|
+
user.user_data[:email] = 'new_address@gmail.com'
|
87
|
+
user.save!
|
88
|
+
|
89
|
+
user.reload
|
90
|
+
user.user_data[:email] # 'personal@email.com'
|
91
|
+
```
|
92
|
+
|
93
|
+
### attr_redacted with database persistence
|
94
|
+
|
95
|
+
By default, `attr_redacted` stores the redacted data in `:redacted_<attribute>`.
|
96
|
+
|
97
|
+
Create or modify the table that your model uses to add a column with the `redacted_` prefix (which can be modified, see below), e.g. `redacted_ssn` via a migration like the following:
|
98
|
+
|
99
|
+
```ruby
|
100
|
+
create_table :users do |t|
|
101
|
+
t.string :name
|
102
|
+
t.jsonb :redacted_user_data
|
103
|
+
t.timestamps
|
104
|
+
end
|
105
|
+
```
|
106
|
+
|
107
|
+
### Specifying the redacted attribute name
|
108
|
+
|
109
|
+
By default, the redacted attribute name is `redacted_#{attribute}` (e.g. `attr_redacted :data` would create an attribute named `redacted_data`). So, if you're storing the redacted attribute in the database, you need to make sure the `redacted_#{attribute}` field exists in your table. You have a couple of options if you want to name your attribute or db column something else, see below for more details.
|
110
|
+
|
111
|
+
|
112
|
+
## attr_redacted options
|
113
|
+
|
114
|
+
#### Options are evaluated
|
115
|
+
All options will be evaluated at the instance level.
|
116
|
+
|
117
|
+
### Default options
|
118
|
+
|
119
|
+
The following are the default options used by `attr_redacted`:
|
120
|
+
|
121
|
+
```ruby
|
122
|
+
prefix: 'redacted_',
|
123
|
+
suffix: '',
|
124
|
+
marshal: false,
|
125
|
+
marshaler: Marshal,
|
126
|
+
dump_method: 'dump',
|
127
|
+
load_method: 'load',
|
128
|
+
```
|
129
|
+
|
130
|
+
Additionally, you can specify default options for all redacted attributes in your class. Instead of having to define your class like this:
|
131
|
+
|
132
|
+
```ruby
|
133
|
+
class User
|
134
|
+
attr_redacted :email, prefix: '', suffix: '_redacted'
|
135
|
+
attr_redacted :ssn, prefix: '', suffix: '_redacted'
|
136
|
+
attr_redacted :credit_card, prefix: '', suffix: '_redacted'
|
137
|
+
end
|
138
|
+
```
|
139
|
+
|
140
|
+
You can simply define some default options like so:
|
141
|
+
|
142
|
+
```ruby
|
143
|
+
class User
|
144
|
+
attr_redacted_options.merge!(prefix: '', :suffix => '_crypted')
|
145
|
+
attr_redacted :email
|
146
|
+
attr_redacted :ssn
|
147
|
+
attr_redacted :credit_card
|
148
|
+
end
|
149
|
+
```
|
150
|
+
|
151
|
+
This should help keep your classes clean and DRY.
|
152
|
+
|
153
|
+
### The `:attribute` option
|
154
|
+
|
155
|
+
You can simply pass the name of the redacted attribute as the `:attribute` option:
|
156
|
+
|
157
|
+
```ruby
|
158
|
+
class User
|
159
|
+
attr_redacted :data, attribute: 'obfuscated_data'
|
160
|
+
end
|
161
|
+
```
|
162
|
+
|
163
|
+
This would generate an attribute named `obfuscated_data`
|
164
|
+
|
165
|
+
|
166
|
+
### The `:prefix` and `:suffix` options
|
167
|
+
|
168
|
+
If you don't like the `redacted_#{attribute}` naming convention then you can specify your own:
|
169
|
+
|
170
|
+
```ruby
|
171
|
+
class User
|
172
|
+
attr_redacted :data, prefix: 'secret_', suffix: '_hidden'
|
173
|
+
end
|
174
|
+
```
|
175
|
+
|
176
|
+
This would generate the attribute: `secret_data_hidden`.
|
177
|
+
|
178
|
+
### The `:encryption_key` option
|
179
|
+
|
180
|
+
Specifies the encryption key to use for encrypted data in the hash.
|
181
|
+
This *must* be present if you use encryption.
|
182
|
+
|
183
|
+
### The `:digest_salt` option
|
184
|
+
|
185
|
+
Specifies a salt to use when digesting.
|
186
|
+
If not present then your data will be hashed *without* a salt which makes it less secure.
|
187
|
+
|
188
|
+
### The `:encode`, `:encode_iv`, and `:default_encoding` options
|
189
|
+
|
190
|
+
You're probably going to be storing your redacted attributes somehow (e.g. filesystem, database, etc). You can pass the `:encode` option to automatically encode/decode when encrypting/hashing/decrypting. The default behavior assumes that you're using a string column type and will base64 encode your cipher text. If you choose to use the binary column type then encoding is not required, but be sure to pass in `false` with the `:encode` option.
|
191
|
+
|
192
|
+
```ruby
|
193
|
+
class User
|
194
|
+
attr_redacted :data, encode: true, encode_iv: true
|
195
|
+
end
|
196
|
+
```
|
197
|
+
|
198
|
+
The default encoding is `m` (base64). You can change this by setting `encode: 'some encoding'`. See [`Arrary#pack`](http://ruby-doc.org/core-2.3.0/Array.html#method-i-pack) for more encoding options.
|
199
|
+
|
200
|
+
## ORMs
|
201
|
+
|
202
|
+
### ActiveRecord
|
203
|
+
|
204
|
+
If you're using this gem with `ActiveRecord`, you get a few extra features:
|
205
|
+
|
206
|
+
## Things to consider before using attr_redacted
|
207
|
+
|
208
|
+
#### Data gone immediately
|
209
|
+
Obviously, anything you decide to digest or remove, that will be done immediately and you will have no way to recover that data (except keeping a copy of the original hash)
|
210
|
+
|
211
|
+
#### Searching, joining, etc
|
212
|
+
You cannot search encrypted or hashed data (or, obviously, removed data), and because you can't search it, you can't index it either. You also can't use joins on the redacted data. Data that is securely encrypted is effectively noise.
|
213
|
+
So any operations that rely on the data not being noise will not work. If you need to do any of the aforementioned operations, please consider using database and file system encryption along with transport encryption as it moves through your stack.
|
214
|
+
Since redacting uses a hash that is comparable, you could still index digested columns
|
215
|
+
|
216
|
+
#### Data leaks
|
217
|
+
Please also consider where your data leaks. If you're using attr_redacted with Rails, it's highly likely that this data will enter your app as a request parameter. You'll want to be sure that you're filtering your request params from you logs or else your data is sitting in the clear in your logs. [Parameter Filtering in Rails](http://apidock.com/rails/ActionDispatch/Http/FilterParameters) Please also consider other possible leak points.
|
218
|
+
|
219
|
+
#### Metadata regarding your crypto implementation
|
220
|
+
It is advisable to also store metadata regarding the circumstances of your encrypted data. Namely, you should store information about the key used to encrypt your data, as well as the algorithm. Having this metadata with every record will make key rotation and migrating to a new algorithm signficantly easier. It will allow you to continue to decrypt old data using the information provided in the metadata and new data can be encrypted using your new key and algorithm of choice.
|
221
|
+
|
222
|
+
## Testing
|
223
|
+
To verify you've configured redaction properly in your tests, use `attr_redacted?` and `attr_redact_hash`
|
224
|
+
|
225
|
+
Given class:
|
226
|
+
|
227
|
+
```ruby
|
228
|
+
class User
|
229
|
+
attr_redacted :data, redact: { :ssn => :remove, :email => :encrypt }
|
230
|
+
end
|
231
|
+
```
|
232
|
+
|
233
|
+
### Minitest
|
234
|
+
```ruby
|
235
|
+
def test_should_redact_dataa
|
236
|
+
expected_hash = { :ssn => :remove, :email => :encrypt }
|
237
|
+
assert User.new.attr_redacted?(:data)
|
238
|
+
assert_equal expected_hash, User.new.data_redact_hash
|
239
|
+
end
|
240
|
+
```
|
241
|
+
|
242
|
+
### RSpec
|
243
|
+
```ruby
|
244
|
+
it "should redact data"
|
245
|
+
expect(User.new.attr_redacted?(:data)).to be_truthy
|
246
|
+
expect(User.new.data_redact_hash).to eq({ :ssn => :remove, :email => :encrypt })
|
247
|
+
end
|
248
|
+
```
|
249
|
+
|
250
|
+
|
251
|
+
|
252
|
+
## Note on Patches/Pull Requests
|
253
|
+
|
254
|
+
* Fork the project.
|
255
|
+
* Make your feature addition or bug fix.
|
256
|
+
* Add tests for it. This is important so I don't break it in a
|
257
|
+
future version unintentionally.
|
258
|
+
* Commit, do not mess with rakefile, version, changelog, or history.
|
259
|
+
* Send me a pull request. Bonus points for topic branches.
|
data/Rakefile
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'rake/testtask'
|
2
|
+
require 'rdoc/task'
|
3
|
+
require "bundler/gem_tasks"
|
4
|
+
|
5
|
+
desc 'Test the attr_redactor gem.'
|
6
|
+
Rake::TestTask.new(:test) do |t|
|
7
|
+
t.libs << 'lib'
|
8
|
+
t.pattern = 'test/**/*_test.rb'
|
9
|
+
t.verbose = true
|
10
|
+
end
|
11
|
+
|
12
|
+
desc 'Generate documentation for the attr_redactor gem.'
|
13
|
+
Rake::RDocTask.new(:rdoc) do |rdoc|
|
14
|
+
rdoc.rdoc_dir = 'rdoc'
|
15
|
+
rdoc.title = 'attr_redactor'
|
16
|
+
rdoc.options << '--line-numbers' << '--inline-source'
|
17
|
+
rdoc.rdoc_files.include('README*')
|
18
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
19
|
+
end
|
20
|
+
|
21
|
+
desc 'Default: run unit tests.'
|
22
|
+
task :default => :test
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
lib = File.expand_path('../lib/', __FILE__)
|
4
|
+
$:.unshift lib unless $:.include?(lib)
|
5
|
+
|
6
|
+
require 'attr_redactor/version'
|
7
|
+
require 'date'
|
8
|
+
|
9
|
+
Gem::Specification.new do |s|
|
10
|
+
s.name = 'attr_redactor'
|
11
|
+
s.version = AttrRedactor::Version.string
|
12
|
+
s.date = Date.today
|
13
|
+
|
14
|
+
s.summary = 'Redact JSON attributes before saving'
|
15
|
+
s.description = 'Generates attr_accessors that redact certain values in the JSON structure before saving.'
|
16
|
+
|
17
|
+
s.authors = ['Chris Jensen']
|
18
|
+
s.email = ['chris@broadthought.co']
|
19
|
+
s.homepage = 'http://github.com/chrisjensen/attr_redactor'
|
20
|
+
|
21
|
+
s.has_rdoc = false
|
22
|
+
s.rdoc_options = ['--line-numbers', '--inline-source', '--main', 'README.rdoc']
|
23
|
+
|
24
|
+
s.require_paths = ['lib']
|
25
|
+
|
26
|
+
s.files = `git ls-files`.split("\n")
|
27
|
+
s.test_files = `git ls-files -- test/*`.split("\n")
|
28
|
+
|
29
|
+
s.required_ruby_version = '>= 2.0.0'
|
30
|
+
|
31
|
+
s.add_dependency('hash_redactor', ['~> 0.2.1'])
|
32
|
+
# support for testing with specific active record version
|
33
|
+
activerecord_version = if ENV.key?('ACTIVERECORD')
|
34
|
+
"~> #{ENV['ACTIVERECORD']}"
|
35
|
+
else
|
36
|
+
'~> 3.0'
|
37
|
+
end
|
38
|
+
s.add_development_dependency('activerecord', activerecord_version)
|
39
|
+
s.add_development_dependency('actionpack', activerecord_version)
|
40
|
+
s.add_development_dependency('datamapper')
|
41
|
+
s.add_development_dependency('rake')
|
42
|
+
s.add_development_dependency('minitest')
|
43
|
+
s.add_development_dependency('sequel')
|
44
|
+
if defined?(RUBY_ENGINE) && RUBY_ENGINE.to_sym == :jruby
|
45
|
+
s.add_development_dependency('activerecord-jdbcsqlite3-adapter')
|
46
|
+
s.add_development_dependency('jdbc-sqlite3', '< 3.8.7') # 3.8.7 is nice and broke
|
47
|
+
else
|
48
|
+
s.add_development_dependency('sqlite3')
|
49
|
+
end
|
50
|
+
s.add_development_dependency('dm-sqlite-adapter')
|
51
|
+
s.add_development_dependency("codeclimate-test-reporter")
|
52
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
if defined?(ActiveRecord::Base)
|
2
|
+
module AttrRedactor
|
3
|
+
module Adapters
|
4
|
+
module ActiveRecord
|
5
|
+
def self.extended(base) # :nodoc:
|
6
|
+
base.class_eval do
|
7
|
+
|
8
|
+
# https://github.com/attr-encrypted/attr_encrypted/issues/68
|
9
|
+
alias_method :reload_without_attr_redactor, :reload
|
10
|
+
def reload(*args, &block)
|
11
|
+
result = reload_without_attr_redactor(*args, &block)
|
12
|
+
self.class.redacted_attributes.keys.each do |attribute_name|
|
13
|
+
instance_variable_set("@#{attribute_name}", nil)
|
14
|
+
end
|
15
|
+
result
|
16
|
+
end
|
17
|
+
|
18
|
+
def perform_attribute_assignment(method, new_attributes, *args)
|
19
|
+
return if new_attributes.blank?
|
20
|
+
|
21
|
+
send method, new_attributes.reject { |k, _| self.class.redacted_attributes.key?(k.to_sym) }, *args
|
22
|
+
send method, new_attributes.reject { |k, _| !self.class.redacted_attributes.key?(k.to_sym) }, *args
|
23
|
+
end
|
24
|
+
private :perform_attribute_assignment
|
25
|
+
|
26
|
+
if ::ActiveRecord::VERSION::STRING > "3.1"
|
27
|
+
alias_method :assign_attributes_without_attr_redactor, :assign_attributes
|
28
|
+
def assign_attributes(*args)
|
29
|
+
perform_attribute_assignment :assign_attributes_without_attr_redactor, *args
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
alias_method :attributes_without_attr_redactor=, :attributes=
|
34
|
+
def attributes=(*args)
|
35
|
+
perform_attribute_assignment :attributes_without_attr_redactor=, *args
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
protected
|
41
|
+
|
42
|
+
# <tt>attr_redactor</tt> method
|
43
|
+
def attr_redactor(*attrs)
|
44
|
+
super
|
45
|
+
options = attrs.extract_options!
|
46
|
+
attr = attrs.pop
|
47
|
+
options.merge! redacted_attributes[attr]
|
48
|
+
|
49
|
+
define_method("#{attr}_changed?") do
|
50
|
+
if send("#{options[:attribute]}_changed?")
|
51
|
+
send(attr) != send("#{attr}_was")
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
define_method("#{attr}_was") do
|
56
|
+
attr_was_options = { operation: :unredacting }
|
57
|
+
redacted_attributes[attr].merge!(attr_was_options)
|
58
|
+
evaluated_options = evaluated_attr_redacted_options_for(attr)
|
59
|
+
[:iv, :salt, :operation].each { |key| redacted_attributes[attr].delete(key) }
|
60
|
+
self.class.unredact(attr, send("#{options[:attribute]}_was"), evaluated_options)
|
61
|
+
end
|
62
|
+
|
63
|
+
alias_method "#{attr}_before_type_cast", attr
|
64
|
+
end
|
65
|
+
|
66
|
+
def attribute_instance_methods_as_symbols
|
67
|
+
# We add accessor methods of the db columns to the list of instance
|
68
|
+
# methods returned to let ActiveRecord define the accessor methods
|
69
|
+
# for the db columns
|
70
|
+
|
71
|
+
# Use with_connection so the connection doesn't stay pinned to the thread.
|
72
|
+
connected = ::ActiveRecord::Base.connection_pool.with_connection(&:active?) rescue false
|
73
|
+
|
74
|
+
if connected && table_exists?
|
75
|
+
columns_hash.keys.inject(super) {|instance_methods, column_name| instance_methods.concat [column_name.to_sym, :"#{column_name}="]}
|
76
|
+
else
|
77
|
+
super
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
ActiveRecord::Base.extend AttrRedactor
|
85
|
+
ActiveRecord::Base.extend AttrRedactor::Adapters::ActiveRecord
|
86
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
if defined?(DataMapper)
|
2
|
+
module AttrRedactor
|
3
|
+
module Adapters
|
4
|
+
module DataMapper
|
5
|
+
def self.extended(base) # :nodoc:
|
6
|
+
class << base
|
7
|
+
alias_method :included_without_attr_redactor, :included
|
8
|
+
alias_method :included, :included_with_attr_redactor
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def included_with_attr_redactor(base)
|
13
|
+
included_without_attr_redactor(base)
|
14
|
+
base.extend AttrRedactor
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
DataMapper::Resource.extend AttrRedactor::Adapters::DataMapper
|
21
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module AttrRedactor
|
2
|
+
# Contains information about this gem's version
|
3
|
+
module Version
|
4
|
+
MAJOR = 0
|
5
|
+
MINOR = 1
|
6
|
+
PATCH = 0
|
7
|
+
|
8
|
+
# Returns a version string by joining <tt>MAJOR</tt>, <tt>MINOR</tt>, and <tt>PATCH</tt> with <tt>'.'</tt>
|
9
|
+
#
|
10
|
+
# Example
|
11
|
+
#
|
12
|
+
# Version.string # '1.0.2'
|
13
|
+
def self.string
|
14
|
+
[MAJOR, MINOR, PATCH].join('.')
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|