lib/active_crypto.rb in ezcrypto-0.3 vs lib/active_crypto.rb in ezcrypto-0.5

- old
+ new

@@ -1,294 +1,313 @@ -require "ezcrypto.rb" -module ActiveRecord # :nodoc: - module Crypto #:nodoc: - - def self.append_features(base) #:nodoc: - super - base.extend(ClassMethods) - end - -=begin rdoc - -Usage is very simple. You will generally only need the two class methods listed here in your ActiveRecord class model. - -== License - -ActiveCrypto and EzCrypto are released under the MIT license. - - -== Support - -To contact the author, send mail to pelleb@gmail.com - -Also see my blogs at: -http://stakeventures.com and -http://neubia.com - -This project was based on code used in my project StakeItOut, where you can securely share web services with your partners. -https://stakeitout.com - -(C) 2005 Pelle Braendgaard - -=end - module ClassMethods - @@session_keys={} - -=begin rdoc -Turn encryption on for this record. List all encrypted attributes - - class Document < ActiveRecord::Base - encrypt :title,:body - end - -Include optional option :key, to specify an external KeyHolder, which holds the key used for encrypting and decrypting: - - class Document < ActiveRecord::Base - belongs_to :user - encrypt :title,:body,:key=>:user - end - -=end - def encrypt(*attributes) - include ActiveRecord::Crypto::Encrypted - alias_method :orig_write_attribute, :write_attribute - alias_method :write_attribute,:write_encrypted_attribute - options=attributes.last.is_a?(Hash) ? attributes.pop : {} - if options and options[:key] - include ActiveRecord::Crypto::AssociationKeyHolder - - module_eval <<-"end;" - def session_key - (send :#{options[:key]} ).send :session_key - end - @@external_key=true - end; - else - include ActiveRecord::Crypto::KeyHolder - end - - self.encrypted_attributes=attributes - for enc in attributes - - module_eval <<-"end;" - def #{enc.to_s} - _decrypt(read_attribute("#{enc.to_s}")) - end - end; - end - end - -=begin rdoc -Creates support in this class for holding a key. Adds the following methods: - -* enter_password(password,salt="onetwothree") -* set_session_key(key) -* session_key - -Use it as follows: - - class User < ActiveRecord::Base - has_many :documents - keyholder - end - -=end - def keyholder() - include ActiveRecord::Crypto::AssociationKeyHolder - end - -=begin rdoc -Clears the session_key array. Generally this is handled automatically as a filter in ActionController. Only use these if you need to -do something out of the ordinary. -=end - def clear_session_keys() #:nodoc: - @@session_keys.clear - end - -=begin rdoc -Sets the session_keys array. Only use these if you need to -do something out of the ordinary, as it is handled -=end - def session_keys=(keys) #:nodoc: - @@session_keys=keys - end - - def session_keys() #:nodoc: - @@session_keys - end - end - -=begin rdoc -This module handles all standard key management features. -=end - module KeyHolder - -=begin rdoc -Creates a key for object based on given password and an optional salt. -=end - def enter_password(password,salt="onetwothree") - set_session_key(EzCrypto::Key.with_password(password, salt)) - end - -=begin rdoc -Decodes the Base64 encoded key and uses it as it's session key -=end - def set_encoded_key(enc) - set_session_key(EzCrypto::Key.decode(enc)) - end -=begin rdoc -Sets a session key for the object. This should be a EzCrypto::Key instance. -=end - def set_session_key(key) - @session_key=key - end - -=begin rdoc -Returns the session_key -=end - def session_key - @session_key - end - - end - - module AssociationKeyHolder - include KeyHolder -=begin rdoc -Sets a session key for the object. This should be a EzCrypto::Key instance. -=end - def set_session_key(key) - Base.session_keys[session_key_id]=key - end - -=begin rdoc -Returns the session_key -=end - def session_key - if session_key_id - Base.session_keys[session_key_id] - else - nil - end - end - - private - - def session_key_id - "#{self.class.to_s}:#{id}" - end - end - - module Encrypted #:nodoc: - def self.append_features(base) #:nodoc: - super - base.module_eval <<-"end;" - @@encrypted_attributes=[] - def encrypted_attributes - @@encrypted_attributes - end - - def #{base.to_s}.encrypted_attributes=(attrs) - @@encrypted_attributes=attrs - end - end; - end - - def write_encrypted_attribute(name,value) - if encrypted_attributes.include?(name.to_sym) - orig_write_attribute(name,_encrypt(value)) - else - orig_write_attribute(name,value) - end - end - end - - private - - def _decrypt(data) - if session_key.nil? - raise MissingKeyError - else - if data - session_key.decrypt(data) - else - nil - end - end - end - - def _encrypt(data) - if session_key.nil? - raise MissingKeyError - else - if data - session_key.encrypt(data) - else - nil - end - end - end - - end - - class Base # :nodoc: - include ActiveRecord::Crypto - end -end - -module ActionController # :nodoc: -=begin rdoc -This includes some basic support in the ActionController for handling session keys. It creates two filters one before the action and one after. -These do the following: - -If the users session already has a 'session_keys' value it loads it into the ActiveRecord::Base.session_keys class field. If not it -clears any existing session_keys. - -Leaving the action it stores any session_keys in the corresponding session variable. - -These filters are automatically enabled. You do not have to do anything. - -To manually clear the session keys call clear_session_keys. This should be done for example as part of a session log off action. -=end - module CryptoSupport - - def self.append_features(base) #:nodoc: - super - base.send :prepend_before_filter, :load_session_keys - base.send :prepend_after_filter, :save_session_keys - end - -=begin rdoc -Clears the session keys. Call this when a user logs of. -=end - def clear_session_keys - ActiveRecord::Base.clear_session_keys - end - - - private - def load_session_keys - if @session['session_keys'] - ActiveRecord::Base.session_keys=@session['session_keys'] - else - ActiveRecord::Base.clear_session_keys - end - end - - def save_session_keys - if ActiveRecord::Base.session_keys.size>0 - @session['session_keys']=ActiveRecord::Base.session_keys - else - @session['session_keys']=nil - end - end - - end - - class Base # :nodoc: - include CryptoSupport - end - -end - -class MissingKeyError < RuntimeError -end +require "ezcrypto.rb" +module ActiveCrypto # :nodoc: + + def self.append_features(base) #:nodoc: + super + base.extend(ClassMethods) + end + +=begin rdoc + +Usage is very simple. You will generally only need the two class methods listed here in your ActiveRecord class model. + +== License + +ActiveCrypto and EzCrypto are released under the MIT license. + + +== Support + +To contact the author, send mail to pelleb@gmail.com + +Also see my blogs at: +http://stakeventures.com and +http://neubia.com + +This project was based on code used in my project StakeItOut, where you can securely share web services with your partners. +https://stakeitout.com + +(C) 2005 Pelle Braendgaard + +=end + module ClassMethods + @@session_keys={} + +=begin rdoc +Turn encryption on for this record. List all encrypted attributes + + class Document < ActiveRecord::Base + encrypt :title,:body + end + +Include optional option :key, to specify an external KeyHolder, which holds the key used for encrypting and decrypting: + + class Document < ActiveRecord::Base + belongs_to :user + encrypt :title,:body,:key=>:user + end + +=end + def encrypt(*attributes) + include ActiveCrypto::Encrypted + before_save :encrypt_attributes + after_save :decrypt_attributes + options=attributes.last.is_a?(Hash) ? attributes.pop : {} + keyholder + if options and options[:key] + module_eval <<-"end;" + def session_key + (send :#{options[:key]} ).send :session_key + end + @@external_key=true + end; + end + self.encrypted_attributes=attributes + end + +=begin rdoc +Creates support in this class for holding a key. Adds the following methods: + +* enter_password(password,salt="onetwothree") +* set_session_key(key) +* session_key + +Use it as follows: + + class User < ActiveRecord::Base + has_many :documents + keyholder + end + +=end + def keyholder() + include ActiveCrypto::AssociationKeyHolder + after_create :save_session_key + end + +=begin rdoc +Clears the session_key array. Generally this is handled automatically as a filter in ActionController. Only use these if you need to +do something out of the ordinary. +=end + def clear_session_keys() #:nodoc: + @@session_keys.clear + end + +=begin rdoc +Sets the session_keys array. Only use these if you need to +do something out of the ordinary, as it is handled +=end + def session_keys=(keys) #:nodoc: + @@session_keys=keys + end + + def session_keys() #:nodoc: + @@session_keys + end + + end + +=begin rdoc +This module handles all standard key management features. +=end + module KeyHolder + +=begin rdoc +Creates a key for object based on given password and an optional salt. +=end + def enter_password(password,salt="onetwothree") + set_session_key(EzCrypto::Key.with_password(password, salt)) + end + +=begin rdoc +Decodes the Base64 encoded key and uses it as it's session key +=end + def set_encoded_key(enc) + set_session_key(EzCrypto::Key.decode(enc)) + end +=begin rdoc +Sets a session key for the object. This should be a EzCrypto::Key instance. +=end + def set_session_key(key) + @session_key=key + self.decrypt_attributes if self.class.include? Encrypted + end + +=begin rdoc +Returns the session_key +=end + def session_key + @session_key + end + + end + + module AssociationKeyHolder + include ActiveCrypto::KeyHolder + + + def save_session_key + ActiveRecord::Base.session_keys[session_key_id]=@session_key if @session_key + end +=begin rdoc +Sets a session key for the object. This should be a EzCrypto::Key instance. +=end + def set_session_key(key) + if self.new_record? + @session_key=key + else + ActiveRecord::Base.session_keys[session_key_id]=key + end + decrypt_attributes if self.class.include? Encrypted #if respond_to?(:decrypt_attributes) + + end + +=begin rdoc +Returns the session_key +=end + def session_key + if self.new_record? + @session_key + else + ActiveRecord::Base.session_keys[session_key_id] + end + end + + + + def session_key_id + "#{self.class.to_s}:#{id}" + end + + end + + module Encrypted #:nodoc: + def self.append_features(base) #:nodoc: + super + base.extend ClassAccessors + end + + module ClassAccessors + def encrypted_attributes + @encrypted_attributes||=[] + end + + def encrypted_attributes=(attrs) + @encrypted_attributes=attrs + end + + end + + protected + + def encrypt_attributes + if !is_encrypted? + self.class.encrypted_attributes.each do |key| + value=read_attribute(key) + write_attribute(key,_encrypt(value)) if value + end + @is_encrypted=true + end + true + end + + def decrypt_attributes + if is_encrypted? + self.class.encrypted_attributes.each do |key| + value=read_attribute(key) + write_attribute(key,_decrypt(value)) if value + end + @is_encrypted=false + end + true + end + + def after_find + @is_encrypted=true + decrypt_attributes unless session_key.nil? + end + + private + def is_encrypted? + @is_encrypted + end + + def _decrypt(data) + if session_key.nil? + raise MissingKeyError + else + if data + session_key.decrypt(data) + else + nil + end + end + end + + def _encrypt(data) + if session_key.nil? + raise MissingKeyError + else + if data + session_key.encrypt(data) + else + nil + end + end + end + + end + + +module ActionController # :nodoc: +=begin rdoc +This includes some basic support in the ActionController for handling session keys. It creates two filters one before the action and one after. +These do the following: + +If the users session already has a 'session_keys' value it loads it into the ActiveRecord::Base.session_keys class field. If not it +clears any existing session_keys. + +Leaving the action it stores any session_keys in the corresponding session variable. + +These filters are automatically enabled. You do not have to do anything. + +To manually clear the session keys call clear_session_keys. This should be done for example as part of a session log off action. +=end + def self.append_features(base) #:nodoc: + super + base.send :prepend_before_filter, :load_session_keys + base.send :prepend_after_filter, :save_session_keys + end + +=begin rdoc +Clears the session keys. Call this when a user logs of. +=end + def clear_session_keys + ActiveRecord::Base.clear_session_keys + end + + + private + def load_session_keys + if session['session_keys'] + ActiveRecord::Base.session_keys=session['session_keys'] + else + ActiveRecord::Base.clear_session_keys + end + end + + def save_session_keys + if ActiveRecord::Base.session_keys.size>0 + session['session_keys']=ActiveRecord::Base.session_keys + else + session['session_keys']=nil + end + end + + +end + +class MissingKeyError < RuntimeError +end +end +ActiveRecord::Base.send :include, ActiveCrypto +ActionController::Base.send :include, ActiveCrypto::ActionController