Skip to content

Commit

Permalink
Optionally allow disabling of Lock#ensure_required_columns.
Browse files Browse the repository at this point in the history
  • Loading branch information
Jason Whittle committed Jan 12, 2011
1 parent 746530e commit 850bd70
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 23 deletions.
17 changes: 9 additions & 8 deletions lib/strongbox.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,26 +11,27 @@ module Strongbox
RSA_SSLV23_PADDING = OpenSSL::PKey::RSA::SSLV23_PADDING
RSA_NO_PADDING = OpenSSL::PKey::RSA::NO_PADDING
RSA_PKCS1_OAEP_PADDING = OpenSSL::PKey::RSA::PKCS1_OAEP_PADDING

class << self
# Provides for setting the default options for Strongbox
def options
@options ||= {
:base64 => false,
:symmetric => :always,
:padding => RSA_PKCS1_PADDING,
:symmetric_cipher => 'aes-256-cbc'
:symmetric_cipher => 'aes-256-cbc',
:ensure_required_columns => true
}
end

def included base #:nodoc:
base.extend ClassMethods
end
end

class StrongboxError < StandardError #:nodoc:
end

module ClassMethods
# +encrypt_with_public_key+ gives the class it is called on an attribute that
# when assigned is automatically encrypted using a public key. This allows the
Expand All @@ -49,18 +50,18 @@ def encrypt_with_public_key(name, options = {})


lock_options[name] = options.symbolize_keys.reverse_merge Strongbox.options

define_method name do
lock_for(name)
end

define_method "#{name}=" do | plaintext |
lock_for(name).encrypt plaintext
end

end
end

module InstanceMethods
def lock_for name
@_locks ||= {}
Expand Down
31 changes: 16 additions & 15 deletions lib/strongbox/lock.rb
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
module Strongbox
# The Lock class encrypts and decrypts the protected attribute. It
# The Lock class encrypts and decrypts the protected attribute. It
# automatically encrypts the data when set and decrypts it when the private
# key password is provided.
class Lock

def initialize name, instance, options = {}
@name = name
@instance = instance

@size = nil

options = Strongbox.options.merge(options)

@base64 = options[:base64]
@public_key = options[:public_key] || options[:key_pair]
@private_key = options[:private_key] || options[:key_pair]
Expand All @@ -20,10 +20,11 @@ def initialize name, instance, options = {}
@symmetric_cipher = options[:symmetric_cipher]
@symmetric_key = options[:symmetric_key] || "#{name}_key"
@symmetric_iv = options[:symmetric_iv] || "#{name}_iv"
@ensure_required_columns = options[:ensure_required_columns]
end

def encrypt plaintext
ensure_required_columns
ensure_required_columns if @ensure_required_columns
unless @public_key
raise StrongboxError.new("#{@instance.class} model does not have public key_file")
end
Expand Down Expand Up @@ -55,22 +56,22 @@ def encrypt plaintext
@instance[@name] = ciphertext
end
end

# Given the private key password decrypts the attribute. Will raise
# OpenSSL::PKey::RSAError if the password is wrong.

def decrypt password = nil
# Given a private key and a nil password OpenSSL::PKey::RSA.new() will
# *prompt* for a password, we default to an empty string to avoid that.
ciphertext = @instance[@name]
return nil if ciphertext.nil?
return "" if ciphertext.empty?

return "*encrypted*" if password.nil?
unless @private_key
raise StrongboxError.new("#{@instance.class} model does not have private key_file")
end

if ciphertext
ciphertext = Base64.decode64(ciphertext) if @base64
private_key = get_rsa_key(@private_key,password)
Expand All @@ -94,20 +95,20 @@ def decrypt password = nil
nil
end
end

def to_s
decrypt
end

# Needed for validations
def blank?
@instance[@name].blank?
end

def nil?
@instance[@name].nil?
end

def size
@size
end
Expand Down
25 changes: 25 additions & 0 deletions test/missing_attributes_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -49,4 +49,29 @@ class MissingAttribuesTest < Test::Unit::TestCase
rebuild_model
end
end

context 'A Class with a secured field without a matching database column told not to check columns' do
setup do
ActiveRecord::Base.connection.create_table :dummies, :force => true do |table|
table.string :in_the_clear
end
rebuild_class {}
end

should 'not raise' do
assert_nothing_raised do
Dummy.class_eval do
encrypt_with_public_key(:secret,
:key_pair => File.join(FIXTURES_DIR,'keypair.pem'),
:ensure_required_columns => false)
end
@dummy = Dummy.new
@dummy.secret = 'Shhhh'
end
end

teardown do
rebuild_model
end
end
end

0 comments on commit 850bd70

Please sign in to comment.