mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
Add support for uniqueness validations
This commit is contained in:
parent
f78a480818
commit
a61692cf41
7 changed files with 78 additions and 1 deletions
|
@ -23,6 +23,7 @@ module ActiveRecord
|
||||||
autoload :EnvelopeEncryptionKeyProvider
|
autoload :EnvelopeEncryptionKeyProvider
|
||||||
autoload :Errors
|
autoload :Errors
|
||||||
autoload :ExtendedDeterministicQueries
|
autoload :ExtendedDeterministicQueries
|
||||||
|
autoload :ExtendedDeterministicUniquenessValidator
|
||||||
autoload :Key
|
autoload :Key
|
||||||
autoload :KeyGenerator
|
autoload :KeyGenerator
|
||||||
autoload :KeyProvider
|
autoload :KeyProvider
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module ActiveRecord
|
||||||
|
module Encryption
|
||||||
|
module ExtendedDeterministicUniquenessValidator
|
||||||
|
def self.install_support
|
||||||
|
ActiveRecord::Validations::UniquenessValidator.prepend(EncryptedUniquenessValidator)
|
||||||
|
end
|
||||||
|
|
||||||
|
module EncryptedUniquenessValidator
|
||||||
|
def validate_each(record, attribute, value)
|
||||||
|
super(record, attribute, value)
|
||||||
|
|
||||||
|
klass = record.class
|
||||||
|
if klass.deterministic_encrypted_attributes&.each do |attribute_name|
|
||||||
|
encrypted_type = klass.type_for_attribute(attribute_name)
|
||||||
|
[ encrypted_type, *encrypted_type.previous_encrypted_types ].each do |type|
|
||||||
|
encrypted_value = type.serialize(value)
|
||||||
|
ActiveRecord::Encryption.without_encryption do
|
||||||
|
super(record, attribute, encrypted_value)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -291,9 +291,10 @@ To keep using the current cache store, you can turn off cache versioning entirel
|
||||||
ActiveRecord::Fixture.prepend ActiveRecord::Encryption::EncryptedFixtures
|
ActiveRecord::Fixture.prepend ActiveRecord::Encryption::EncryptedFixtures
|
||||||
end
|
end
|
||||||
|
|
||||||
# Support extended queries for deterministic attributes
|
# Support extended queries for deterministic attributes and validations
|
||||||
if ActiveRecord::Encryption.config.extend_queries
|
if ActiveRecord::Encryption.config.extend_queries
|
||||||
ActiveRecord::Encryption::ExtendedDeterministicQueries.install_support
|
ActiveRecord::Encryption::ExtendedDeterministicQueries.install_support
|
||||||
|
ActiveRecord::Encryption::ExtendedDeterministicUniquenessValidator.install_support
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require "cases/encryption/helper"
|
||||||
|
require "models/book_encrypted"
|
||||||
|
require "models/author_encrypted"
|
||||||
|
|
||||||
|
class ActiveRecord::Encryption::UniquenessValidationsTest < ActiveRecord::EncryptionTestCase
|
||||||
|
fixtures :books
|
||||||
|
|
||||||
|
test "uniqueness validations work" do
|
||||||
|
EncryptedBookWithDowncaseName.create!(name: "dune")
|
||||||
|
assert_raises ActiveRecord::RecordInvalid do
|
||||||
|
EncryptedBookWithDowncaseName.create!(name: "dune")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
test "uniqueness validations work when mixing encrypted an unencrypted data" do
|
||||||
|
ActiveRecord::Encryption.config.support_unencrypted_data = true
|
||||||
|
|
||||||
|
ActiveRecord::Encryption.without_encryption { EncryptedBookWithDowncaseName.create! name: "dune" }
|
||||||
|
|
||||||
|
assert_raises ActiveRecord::RecordInvalid do
|
||||||
|
EncryptedBookWithDowncaseName.create!(name: "dune")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
test "uniqueness validations work when using old encryption schemes" do
|
||||||
|
ActiveRecord::Encryption.config.previous = [ { downcase: true } ]
|
||||||
|
|
||||||
|
OldEncryptionBook = Class.new(Book) do
|
||||||
|
self.table_name = "books"
|
||||||
|
|
||||||
|
validates :name, uniqueness: true
|
||||||
|
encrypts :name, deterministic: true, downcase: false
|
||||||
|
end
|
||||||
|
|
||||||
|
OldEncryptionBook.create! name: "dune"
|
||||||
|
|
||||||
|
assert_raises ActiveRecord::RecordInvalid do
|
||||||
|
OldEncryptionBook.create! name: "DUNE"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -231,3 +231,4 @@ ActiveRecord::Encryption.configure \
|
||||||
key_derivation_salt: "testing key derivation salt"
|
key_derivation_salt: "testing key derivation salt"
|
||||||
|
|
||||||
ActiveRecord::Encryption::ExtendedDeterministicQueries.install_support
|
ActiveRecord::Encryption::ExtendedDeterministicQueries.install_support
|
||||||
|
ActiveRecord::Encryption::ExtendedDeterministicUniquenessValidator.install_support
|
||||||
|
|
|
@ -5,6 +5,7 @@ require "models/author"
|
||||||
class EncryptedAuthor < Author
|
class EncryptedAuthor < Author
|
||||||
self.table_name = "authors"
|
self.table_name = "authors"
|
||||||
|
|
||||||
|
validates :name, uniqueness: true
|
||||||
encrypts :name, previous: { deterministic: true }
|
encrypts :name, previous: { deterministic: true }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@ end
|
||||||
class EncryptedBookWithDowncaseName < ActiveRecord::Base
|
class EncryptedBookWithDowncaseName < ActiveRecord::Base
|
||||||
self.table_name = "books"
|
self.table_name = "books"
|
||||||
|
|
||||||
|
validates :name, uniqueness: true
|
||||||
encrypts :name, deterministic: true, downcase: true
|
encrypts :name, deterministic: true, downcase: true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue