Skip to content

Commit

Permalink
Merge pull request #130 from jmazzi/refactor/rspec-filenames
Browse files Browse the repository at this point in the history
Spec tweaks
  • Loading branch information
jmazzi authored Oct 13, 2016
2 parents a222a03 + 1472be8 commit 47a6b08
Show file tree
Hide file tree
Showing 14 changed files with 540 additions and 562 deletions.
56 changes: 56 additions & 0 deletions spec/crypt_keeper/log_subscriber/mysql_aes_spec.rb
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
94 changes: 94 additions & 0 deletions spec/crypt_keeper/log_subscriber/postgres_pgp_spec.rb
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
167 changes: 167 additions & 0 deletions spec/crypt_keeper/model_spec.rb
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
41 changes: 41 additions & 0 deletions spec/crypt_keeper/provider/aes_new_spec.rb
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
Loading

0 comments on commit 47a6b08

Please sign in to comment.