commit 1fd972c74f4ccc94f334a998ac78b36e175d2434 Author: David Bourguignon Date: Mon Aug 17 10:37:35 2009 +0200 initial commit diff --git a/MIT-LICENSE b/MIT-LICENSE new file mode 100644 index 0000000..48c13ea --- /dev/null +++ b/MIT-LICENSE @@ -0,0 +1,20 @@ +Copyright (c) 2009 Novelys + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/README b/README new file mode 100644 index 0000000..42803a2 --- /dev/null +++ b/README @@ -0,0 +1,101 @@ +# Paiement CIC + +Paiement CIC is a plugin to ease credit card payment with the CIC / Crédit Mutuel banks system. +It's a Ruby on Rails port of the connexion kits published by the bank. + +* The Plugin [site](http://github.com/novelys/cicpayment) +* The banks payment [site](http://www.cmcicpaiement.fr) + + +## INSTALL + +script/plugin install git://github.com/novelys/paiementcic.git + +## USAGE + +### in environment.rb : + + # here the hmac key calculated with the js calculator given by CIC + PaiementCic.hmac_key = "########################################" + # Here the TPE number + PaiementCic.tpe = "#######" + # Here the Merchant name + PaiementCic.societe = "xxxxxxxxxxxxx" + +### in development.rb : + + PaiementCic.target_url = "https://ssl.paiement.cic-banques.fr/test/paiement.cgi" + +### in production.rb : + + PaiementCic.target_url = "https://ssl.paiement.cic-banques.fr/paiement.cgi" + +### in order controller : + + helper :paiement_cic + +### in the payment by card view : + + - form_tag PaiementCic.target_url do + = paiement_cic_hidden_fields(@order, @order_transaction) + = submit_tag "Accéder au site de la banque", :style => "font-weight: bold;" + = image_tag "reassuring_pictograms.jpg", :alt => "Pictogrammes rassurants", :style => "width: 157px;" + +### in a controller for call back from the bank : + + class OrderTransactionsController < ApplicationController + + protect_from_forgery :except => [:bank_callback] + + def bank_callback + if PaiementCic.verify_hmac(params) + order_transaction = OrderTransaction.find_by_reference params[:reference], :last + order = order_transaction.order + + code_retour = params['code-retour'] + + if code_retour == "Annulation" + order.cancel! + order.update_attribute :description, "Paiement refusé par la banque." + + elsif code_retour == "payetest" + order.pay! + order.update_attribute :description, "TEST accepté par la banque." + order_transaction.update_attribute :test, true + + elsif code_retour == "paiement" + order.pay! + order.update_attribute :description, "Paiement accepté par la banque." + order_transaction.update_attribute :test, false + end + + order_transaction.update_attribute :success, true + + receipt = "OK" + else + order.transaction_declined! + order.update_attribute :description, "Document Falsifie." + order_transaction.update_attribute :success, false + + receipt = "Document Falsifie" + end + render :text => "Version: 1\n#{receipt}\n" + end + + def bank_ok + @order_transaction = OrderTransaction.find params[:id] + @order = @order_transaction.order + @order.pay! + end + + def bank_err + order_transaction = OrderTransaction.find params[:id] + order = order_transaction.order + order.cancel! + end + end + + + +## License +Copyright (c) 2008-2009 Novelys Team, released under the MIT license diff --git a/init.rb b/init.rb new file mode 100644 index 0000000..a4d18c5 --- /dev/null +++ b/init.rb @@ -0,0 +1,2 @@ +require "paiement_cic" +require "paiement_cic_helper" diff --git a/lib/paiement_cic.rb b/lib/paiement_cic.rb new file mode 100644 index 0000000..8d1a898 --- /dev/null +++ b/lib/paiement_cic.rb @@ -0,0 +1,86 @@ +require 'digest/sha1' +require 'openssl' + +class String + + def ^(other) + raise ArgumentError, "Can't bitwise-XOR a String with a non-String" \ + unless other.kind_of? String + raise ArgumentError, "Can't bitwise-XOR strings of different length" \ + unless self.length == other.length + result = (0..self.length-1).collect { |i| self[i] ^ other[i] } + result.pack("C*") + end +end + +class PaiementCic + @@hmac_key = "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ" # clé extraite grâce à extract2HmacSha1.html fourni par le Crédit Mutuel + cattr_accessor :hmac_key + + @@target_url = "https://ssl.paiement.cic-banques.fr/test/paiement.cgi" # "https://ssl.paiement.cic-banques.fr/paiement.cgi" + cattr_accessor :target_url + + @@tpe = "123456" + cattr_accessor :tpe + + @@societe = "masociete" + cattr_accessor :societe + + def self.date_format + "%d/%m/%Y:%H:%M:%S" + end + + def self.config(amount_in_cents, reference) + oa = ActiveSupport::OrderedHash.new + oa["TPE"] = tpe + oa["date"] = Time.now.strftime(date_format) + oa["montant"] = ("%.2f" % (amount_in_cents/100.0)) + "EUR" + oa["reference"] = reference + oa["texte-libre"] = "" + oa["version"] = "1.2open" + oa["lgue"] = "FR" + oa["societe"] = societe + oa + end + + def self.calculate_hmac(ordered_hash) + data = ordered_hash.values.join("*") + "*" + hmac(data) + end + + def self.verify_hmac params + tpe = params[:TPE] + date = params[:date] + montant = params[:montant] + reference = params[:reference] + mac = params[:MAC].downcase + texte_libre = params['texte-libre'] + code_retour = params['code-retour'] + retour_plus = params['retourPLUS'] + version = "1.2open" + + data = retour_plus + [tpe, date, montant, reference, texte_libre, version, code_retour].join("+") + "+" + + mac == hmac(data) + end + + def self.hmac(data) + pass = ""; + k1 = [Digest::SHA1.hexdigest(pass)].pack("H*"); + l1 = k1.length + + k2 = [hmac_key].pack("H*") + l2 = k2.length + if (l1 > l2) + k2 = k2.ljust(l1, 0.chr) + elsif (l2 > l1) + k1 = k1.ljust(l2, 0.chr) + end + xor_res = k1 ^ k2 + hmac_sha1(xor_res, data).downcase + end + + def self.hmac_sha1(key, data) + OpenSSL::HMAC.hexdigest(OpenSSL::Digest::Digest.new("sha1"), key, data) + end +end \ No newline at end of file diff --git a/lib/paiement_cic_helper.rb b/lib/paiement_cic_helper.rb new file mode 100644 index 0000000..31d140f --- /dev/null +++ b/lib/paiement_cic_helper.rb @@ -0,0 +1,17 @@ +module PaiementCicHelper + def paiement_cic_hidden_fields(order, order_transaction) + oa = PaiementCic.config(order.amount, order_transaction.reference) + + hsh = oa.dup + hsh["url_retour"] = edit_account_order_url(order) + hsh["url_retour_ok"] = bank_ok_order_transaction_url(order_transaction) + hsh["url_retour_err"] = bank_err_order_transaction_url(order_transaction) + hsh["MAC"] = PaiementCic.calculate_hmac(oa) + + res = "\n" + hsh.each{|key, value| + res << hidden_field_tag(key, value) << "\n" + } + res + end +end