1 class CreditCard < ActiveRecord::Base
2 include ActiveMerchant::Billing::CreditCardMethods
3 include ActiveMerchant::Billing::CreditCardMethods::ClassMethods
5 attr_accessor :verification_value, :number, :passphrase
7 validates_presence_of :name, :number, :street_address, :state, :zip, :country, :number, :city
9 validate :check_for_credit_card_validity
10 validate :month_and_year_should_be_in_future
11 validate :at_least_two_words_in_name
12 validates_presence_of :passphrase
13 has_many :authorizations
16 before_validation :convert_number_to_string
17 before_create :crypt_number
18 before_create :save_last_four_digits
20 # Needed for authorize.net and active merchant
21 def verification_value?
26 super(:only => [:last_four_digits, :name, :month, :year, :card_type, :id])
30 new_record? ? save_last_four_digits : read_attribute(:last_four_digits)
33 def decrypt!(passphrase)
34 @number = decrypt_number(passphrase)
38 # Gets the first name from name
43 # Gets the last name from name
45 name.split[1..-1].join(" ") if name
50 def check_for_credit_card_validity
51 errors.add(:year, "is not a valid year") unless valid_expiry_year?(year.to_i)
52 errors.add(:month, "is not a valid month") unless valid_month?(month.to_i)
53 errors.add(:number, "is not a valid credit card number") unless valid_number?(number)
54 errors.add(:verification_value, "must be provided") unless verification_value
55 self.card_type = type?(number)
56 errors.add_to_base("We only accept Visa and MasterCard.") unless self.card_type == 'master' or self.card_type == 'visa'
59 def month_and_year_should_be_in_future
60 if (Date.new(year.to_i, month.to_i, 1) >> 1) < Date.today
61 errors.add_to_base("The expiration date must be in the future.") and return false
63 rescue ArgumentError => e
64 errors.add_to_base("Date is not valid") and return false
67 def at_least_two_words_in_name
68 errors.add(:name, "must be two words long.") and return false if name and name.split.size < 2
71 # Encrypts the credit card number
76 c.iv = self.iv = generate_iv(passphrase)
77 temp_number = c.update(@number)
78 temp_number << c.final
79 self.crypted_number = encode_into_base64(temp_number)
82 # Decrypts the credit card number
83 def decrypt_number(passphrase)
87 c.iv = generate_iv(passphrase)
88 d = c.update(decode_from_base64(self.crypted_number))
93 OpenSSL::Cipher::Cipher.new("aes-256-cbc")
97 Digest::SHA256.digest(@@CreditCardSecretKey)
100 def generate_iv(passphrase)
101 raise ArgumentError.new("be sure to set the passphrase") if passphrase.blank?
102 encode_into_base64(Digest::SHA1.hexdigest(passphrase))
105 # Chomping is necessary for postgresql
106 def encode_into_base64 string
107 Base64.encode64(string).chomp
110 def decode_from_base64 string
111 Base64.decode64(string)
114 def save_last_four_digits
115 self.last_four_digits = @number[-4..-1]
118 def convert_number_to_string
119 @passphrase = @passphrase.to_s
120 @number = @number.to_s