README.md in blind_index-0.3.2 vs README.md in blind_index-0.3.3
- old
+ new
@@ -2,11 +2,11 @@
Securely search encrypted database fields
Designed for use with [attr_encrypted](https://github.com/attr-encrypted/attr_encrypted)
-Here’s a [full example](https://shorts.dokkuapp.com/securing-user-emails-in-rails/) of how to use it with Devise
+Here’s a [full example](https://ankane.org/securing-user-emails-in-rails) of how to use it with Devise
[![Build Status](https://travis-ci.org/ankane/blind_index.svg?branch=master)](https://travis-ci.org/ankane/blind_index)
## How It Works
@@ -40,11 +40,11 @@
attr_encrypted :email, key: [ENV["EMAIL_ENCRYPTION_KEY"]].pack("H*")
blind_index :email, key: [ENV["EMAIL_BLIND_INDEX_KEY"]].pack("H*")
end
```
-We use environment variables to store the keys as hex-encoded strings ([dotenv](https://github.com/bkeepers/dotenv) is great for this). *Do not commit them to source control.* Generate one key for encryption and one key for hashing. You can generate keys in the Rails console with:
+We use environment variables to store the keys as hex-encoded strings ([dotenv](https://github.com/bkeepers/dotenv) is great for this). [Here’s an explanation](https://ankane.org/encryption-keys) of why `pack` is used. *Do not commit them to source control.* Generate one key for encryption and one key for hashing. You can generate keys in the Rails console with:
```ruby
SecureRandom.hex(32)
```
@@ -116,16 +116,40 @@
attribute :email
blind_index :email, ...
end
```
+*Requires ActiveRecord 5.1+*
+
+## Multiple Columns
+
+You can also use virtual attributes to index data from multiple columns:
+
+```ruby
+class User < ApplicationRecord
+ attribute :initials
+
+ # must come before blind_index method
+ before_validation :set_initials, if: -> { changes.key?(:first_name) || changes.key?(:last_name) }
+ blind_index :initials, ...
+
+ def set_initials
+ self.initials = "#{first_name[0]}#{last_name[0]}"
+ end
+end
+```
+
+*Requires ActiveRecord 5.1+*
+
## Fixtures
-You can use blind indexes in fixtures with:
+You can use encrypted attributes and blind indexes in fixtures with:
```yml
test_user:
+ encrypted_email: <%= User.encrypt_email("test@example.org", iv: Base64.decode64("0000000000000000")) %>
+ encrypted_email_iv: "0000000000000000"
encrypted_email_bidx: <%= User.compute_email_bidx("test@example.org").inspect %>
```
Be sure to include the `inspect` at the end, or it won’t be encoded properly in YAML.
@@ -176,9 +200,49 @@
```ruby
class User < ApplicationRecord
blind_index :email, algorithm: :argon2, cost: {t: 3, m: 12}, ...
end
```
+
+## Key Rotation
+
+To rotate keys without downtime, add a new column:
+
+```ruby
+add_column :users, :encrypted_email_v2_bidx, :string
+add_index :users, :encrypted_email_v2_bidx
+```
+
+And add to your model
+
+```ruby
+class User < ApplicationRecord
+ blind_index :email, key: [ENV["EMAIL_BLIND_INDEX_KEY"]].pack("H*")
+ blind_index :email_v2, attribute: :email, key: [ENV["EMAIL_V2_BLIND_INDEX_KEY"]].pack("H*")
+end
+```
+
+Backfill the data
+
+```ruby
+User.find_each do |user|
+ user.compute_email_v2_bidx
+ user.save!
+end
+```
+
+Then update your model
+
+```ruby
+class User < ApplicationRecord
+ blind_index :email, bidx_attribute: :encrypted_email_v2_bidx, key: [ENV["EMAIL_V2_BLIND_INDEX_KEY"]].pack("H*")
+
+ # remove this line after dropping column
+ self.ignored_columns = ["encrypted_email_bidx"]
+end
+```
+
+Finally, drop the old column.
## Reference
By default, blind indexes are encoded in Base64. Set a different encoding with: