-
Notifications
You must be signed in to change notification settings - Fork 101
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #130 from jmazzi/refactor/rspec-filenames
Spec tweaks
- Loading branch information
Showing
14 changed files
with
540 additions
and
562 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
require 'spec_helper' | ||
|
||
describe CryptKeeper::LogSubscriber::MysqlAes do | ||
before do | ||
CryptKeeper.silence_logs = false | ||
end | ||
|
||
use_mysql | ||
|
||
context "AES encryption" do | ||
# Fire the ActiveSupport.on_load | ||
before do | ||
CryptKeeper::Provider::MysqlAesNew.new key: 'secret', salt: 'salt' | ||
end | ||
|
||
let(:input_query) do | ||
"SELECT aes_encrypt('encrypt_value', 'encrypt_key'), aes_decrypt('decrypt_value', 'decrypt_key') FROM DUAL;" | ||
end | ||
|
||
let(:output_query) do | ||
"SELECT aes_encrypt([FILTERED]) FROM DUAL;" | ||
end | ||
|
||
let(:input_search_query) do | ||
"SELECT \"sensitive_data\".* FROM \"sensitive_data\" WHERE ((aes_decrypt('f'), 'tool') = 'blah')) AND secret = 'testing'" | ||
end | ||
|
||
let(:output_search_query) do | ||
"SELECT \"sensitive_data\".* FROM \"sensitive_data\" WHERE ((aes_decrypt([FILTERED]) AND secret = 'testing'" | ||
end | ||
|
||
it "filters aes functions" do | ||
should_log_scrubbed_query(input: input_query, output: output_query) | ||
end | ||
|
||
it "filters aes functions in lowercase" do | ||
should_log_scrubbed_query(input: input_query.downcase, output: output_query.downcase.gsub(/filtered/, 'FILTERED')) | ||
end | ||
|
||
it "filters aes functions when searching" do | ||
should_log_scrubbed_query(input: input_search_query, output: output_search_query) | ||
end | ||
|
||
it "forces string encodings" do | ||
input_query = "SELECT aes_encrypt('hi \255', 'test') FROM DUAL;" | ||
|
||
should_log_scrubbed_query(input: input_query, output: output_query) | ||
end | ||
|
||
it "skips logging if CryptKeeper.silence_logs is set" do | ||
CryptKeeper.silence_logs = true | ||
|
||
should_not_log_query(input_query) | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
require 'spec_helper' | ||
|
||
describe CryptKeeper::LogSubscriber::PostgresPgp do | ||
before do | ||
CryptKeeper.silence_logs = false | ||
end | ||
|
||
use_postgres | ||
|
||
context "Symmetric encryption" do | ||
# Fire the ActiveSupport.on_load | ||
before do | ||
CryptKeeper::Provider::PostgresPgp.new key: 'secret' | ||
end | ||
|
||
let(:input_query) do | ||
"SELECT pgp_sym_encrypt('encrypt_value', 'encrypt_key'), pgp_sym_decrypt('decrypt_value', 'decrypt_key') FROM DUAL;" | ||
end | ||
|
||
let(:output_query) do | ||
"SELECT encrypt([FILTERED]) FROM DUAL;" | ||
end | ||
|
||
let(:input_search_query) do | ||
"SELECT \"sensitive_data\".* FROM \"sensitive_data\" WHERE ((pgp_sym_decrypt('f'), 'tool') = 'blah')) AND secret = 'testing'" | ||
end | ||
|
||
let(:output_search_query) do | ||
"SELECT \"sensitive_data\".* FROM \"sensitive_data\" WHERE decrypt([FILTERED]) AND secret = 'testing'" | ||
end | ||
|
||
it "filters pgp functions" do | ||
should_log_scrubbed_query(input: input_query, output: output_query) | ||
end | ||
|
||
it "filters pgp functions in lowercase" do | ||
should_log_scrubbed_query(input: input_query.downcase, output: output_query.downcase.gsub(/filtered/, 'FILTERED')) | ||
end | ||
|
||
it "filters pgp functions when searching" do | ||
should_log_scrubbed_query(input: input_search_query, output: output_search_query) | ||
end | ||
|
||
it "forces string encodings" do | ||
input_query = "SELECT pgp_sym_encrypt('hi \255', 'test') FROM DUAL;" | ||
|
||
should_log_scrubbed_query(input: input_query, output: output_query) | ||
end | ||
|
||
it "skips logging if CryptKeeper.silence_logs is set" do | ||
CryptKeeper.silence_logs = true | ||
|
||
should_not_log_query(input_query) | ||
end | ||
end | ||
|
||
context "Public key encryption" do | ||
let(:public_key) do | ||
IO.read(File.join(SPEC_ROOT, 'fixtures', 'public.asc')) | ||
end | ||
|
||
let(:private_key) do | ||
IO.read(File.join(SPEC_ROOT, 'fixtures', 'private.asc')) | ||
end | ||
|
||
# Fire the ActiveSupport.on_load | ||
before do | ||
CryptKeeper::Provider::PostgresPgpPublicKey.new key: 'secret', public_key: public_key, private_key: private_key | ||
end | ||
|
||
let(:input_query) do | ||
"SELECT pgp_pub_encrypt('test', dearmor('#{public_key} | ||
'))" | ||
end | ||
|
||
let(:output_query) do | ||
"SELECT encrypt([FILTERED])" | ||
end | ||
|
||
it "filters pgp functions" do | ||
should_log_scrubbed_query(input: input_query, output: output_query) | ||
end | ||
|
||
it "filters pgp functions in lowercase" do | ||
should_log_scrubbed_query(input: input_query.downcase, output: output_query.downcase.gsub(/filtered/, 'FILTERED')) | ||
end | ||
|
||
it "skips logging if CryptKeeper.silence_logs is set" do | ||
CryptKeeper.silence_logs = true | ||
|
||
should_not_log_query(input_query) | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,167 @@ | ||
# encoding: utf-8 | ||
|
||
require 'spec_helper' | ||
|
||
describe CryptKeeper::Model do | ||
use_sqlite | ||
|
||
subject { create_model } | ||
|
||
after do | ||
CryptKeeper.stub_encryption = false | ||
end | ||
|
||
describe "#crypt_keeper" do | ||
context "Fields" do | ||
it "enables encryption for the given fields" do | ||
subject.crypt_keeper :storage, :secret, encryptor: :fake_encryptor | ||
expect(subject.crypt_keeper_fields).to eq([:storage, :secret]) | ||
end | ||
|
||
it "raises an exception for missing field" do | ||
msg = "Column :none does not exist" | ||
subject.crypt_keeper :none, encryptor: :fake_encryptor | ||
expect { subject.new.save }.to raise_error(ArgumentError, msg) | ||
end | ||
|
||
it "raises an exception for non text fields" do | ||
msg = "Column :name must be of type 'text' to be used for encryption" | ||
subject.crypt_keeper :name, encryptor: :fake_encryptor | ||
expect { subject.new.save }.to raise_error(ArgumentError, msg) | ||
end | ||
end | ||
|
||
context "Options" do | ||
it "accepts the class name as a string" do | ||
subject.crypt_keeper :storage, :secret, key1: 1, key2: 2, encryptor: "FakeEncryptor" | ||
expect(subject.send(:encryptor_klass)).to eq(CryptKeeper::Provider::FakeEncryptor) | ||
end | ||
|
||
it "raises an error on missing encryptor" do | ||
expect { subject.crypt_keeper :storage, :secret }. | ||
to raise_error(RuntimeError, /You must specify a valid encryptor/) | ||
end | ||
end | ||
end | ||
|
||
context "Encryption and Decryption" do | ||
let(:plain_text) { 'plain_text' } | ||
let(:cipher_text) { 'tooltxet_nialp' } | ||
|
||
subject { create_encrypted_model :storage, passphrase: 'tool', encryptor: :encryptor } | ||
|
||
it "encrypts the data" do | ||
expect_any_instance_of(CryptKeeper::Provider::Encryptor).to receive(:encrypt).with('testing') | ||
subject.create!(storage: 'testing') | ||
end | ||
|
||
it "decrypts the data" do | ||
record = subject.create!(storage: 'testing') | ||
expect_any_instance_of(CryptKeeper::Provider::Encryptor).to receive(:decrypt).at_least(1).times.with('toolgnitset') | ||
subject.find(record.id).storage | ||
end | ||
|
||
it "returns the plaintext on decrypt" do | ||
record = subject.create!(storage: 'testing') | ||
expect(subject.find(record.id).storage).to eq('testing') | ||
end | ||
|
||
it "does not encrypt or decrypt nil" do | ||
data = subject.create!(storage: nil) | ||
expect(data.storage).to be_nil | ||
end | ||
|
||
it "does not encrypt or decrypt empty strings" do | ||
data = subject.create!(storage: "") | ||
expect(data.storage).to be_empty | ||
end | ||
|
||
it "converts numbers to strings" do | ||
data = subject.create!(storage: 1) | ||
expect(data.reload.storage).to eq("1") | ||
end | ||
|
||
it "does not decrypt when stubbing is enabled" do | ||
CryptKeeper.stub_encryption = true | ||
record = subject.create!(storage: "testing") | ||
expect_any_instance_of(CryptKeeper::Provider::Encryptor).to_not receive(:decrypt) | ||
subject.find(record.id).storage | ||
end | ||
|
||
it "does not decrypt when stubbing is enabled after model is created" do | ||
record = subject.create!(storage: "testing") | ||
CryptKeeper.stub_encryption = true | ||
expect_any_instance_of(CryptKeeper::Provider::Encryptor).to_not receive(:decrypt) | ||
subject.find(record.id).storage | ||
end | ||
end | ||
|
||
context "Search" do | ||
subject { create_encrypted_model :storage, passphrase: 'tool', encryptor: :search_encryptor } | ||
|
||
it "searches if supported" do | ||
expect { subject.search_by_plaintext(:storage, 'test1') }.to_not raise_error | ||
end | ||
|
||
it "complains about bad columns" do | ||
expect { subject.search_by_plaintext(:what, 'test1') }.to raise_error(/what is not a crypt_keeper field/) | ||
end | ||
end | ||
|
||
context "Encodings" do | ||
subject { create_encrypted_model :storage, key: 'tool', salt: 'salt', encryptor: :aes_new, encoding: 'utf-8' } | ||
|
||
it "forces the encoding on decrypt" do | ||
record = subject.create!(storage: 'Tromsø') | ||
record.reload | ||
expect(record.storage).to eql('Tromsø') | ||
end | ||
|
||
it "converts from other encodings" do | ||
plaintext = "\xC2\xA92011 AACR".force_encoding('ASCII-8BIT') | ||
record = subject.create!(storage: plaintext) | ||
record.reload | ||
expect(record.storage.encoding.name).to eql('UTF-8') | ||
end | ||
end | ||
|
||
context "Initial Table Encryption" do | ||
subject { create_encrypted_model :storage, key: 'tool', salt: 'salt', encryptor: :aes_new } | ||
|
||
before do | ||
subject.delete_all | ||
c = create_model | ||
5.times { |i| c.create! storage: "testing#{i}" } | ||
end | ||
|
||
it "encrypts the table" do | ||
expect { subject.first(5).map(&:storage) }.to raise_error(OpenSSL::Cipher::CipherError) | ||
subject.encrypt_table! | ||
expect { subject.first(5).map(&:storage) }.not_to raise_error | ||
end | ||
end | ||
|
||
context "Table Decryption (Reverse of Initial Table Encryption)" do | ||
subject { create_encrypted_model :storage, key: 'tool', salt: 'salt', encryptor: :aes_new } | ||
let!(:storage_entries) { 5.times.map { |i| "testing#{i}" } } | ||
|
||
before do | ||
subject.delete_all | ||
storage_entries.each { |entry| subject.create! storage: entry} | ||
end | ||
|
||
it "decrypts the table" do | ||
subject.decrypt_table! | ||
expect( create_model.first(5).map(&:storage) ).to eq( storage_entries ) | ||
end | ||
end | ||
|
||
context "Missing Attributes" do | ||
subject { create_encrypted_model :storage, key: 'tool', salt: 'salt', encryptor: :aes_new, encoding: 'utf-8' } | ||
|
||
it "doesn't attempt decryption of missing attributes" do | ||
subject.create!(storage: 'blah') | ||
expect { subject.select(:id).first }.to_not raise_error | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
require 'spec_helper' | ||
|
||
describe CryptKeeper::Provider::AesNew do | ||
subject { described_class.new(key: 'cake', salt: 'salt') } | ||
|
||
describe "#initialize" do | ||
let(:digested_key) do | ||
::Armor.digest('cake', 'salt') | ||
end | ||
|
||
specify { expect(subject.key).to eq(digested_key) } | ||
specify { expect { described_class.new }.to raise_error(ArgumentError, "Missing :key") } | ||
end | ||
|
||
describe "#encrypt" do | ||
let(:encrypted) do | ||
subject.encrypt 'string' | ||
end | ||
|
||
specify { expect(encrypted).to_not eq('string') } | ||
specify { expect(encrypted).to_not be_blank } | ||
end | ||
|
||
describe "#decrypt" do | ||
let(:decrypted) do | ||
subject.decrypt "V02ebRU2wLk25AizasROVg==$kE+IpRaUNdBfYqR+WjMqvA==" | ||
end | ||
|
||
specify { expect(decrypted).to eq('string') } | ||
end | ||
|
||
describe "#search" do | ||
let(:records) do | ||
[{ name: 'Bob' }, { name: 'Tim' }] | ||
end | ||
|
||
it "finds the matching record" do | ||
expect(subject.search(records, :name, 'Bob')).to eql([records.first]) | ||
end | ||
end | ||
end |
Oops, something went wrong.