modifications to support version 3

3.0
Toutie 2009-12-21 11:24:45 +01:00
parent 8cb1aff141
commit d9c53853ed
4 changed files with 155 additions and 56 deletions

View File

@ -18,3 +18,66 @@ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#==============================================================================
#
# "Open source" kit for P@iement CM-CIC(TM).
# Integration sample in a merchant site for Ruby
#
# Author : Euro-Information/e-Commerce (contact: centrecom@e-i.com)
# Version : 1.0
# Date : 01/01/2009
#
# Copyright: (c) 2009 Euro-Information. All rights reserved.
#
#==============================================================================
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
- Redistributions of source code must retain the above copyright
notice and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright
notice and the following disclaimer in the documentation and/or
other materials provided with the distribution.
- Neither the name of Euro-Information nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Note: Euro-Information does not provide person-to-person technical
support for tryout of CM-CIC P@iement examples. We do however
welcome your feedback which can be sent to <centrecom@e-i.com>.
#------------------------------------------------------------------------------
This software uses RSA Data Security, Inc. MD5 Message-Digest Algorithm.
License to copy and use this software is granted provided that it is
identified as the "RSA Data Security, Inc. MD5 Message-Digest
Algorithm" in all material mentioning or referencing this software or
this function.
License is also granted to make and use derivative works provided that
such works are identified as "derived from the RSA Data Security,
Inc. MD5 Message-Digest Algorithm" in all material mentioning or
referencing the derived work.
RSA Data Security, Inc. makes no representations concerning either the
merchantability of this software or the suitability of this software
for any particular purpose. It is provided "as is" without express or
implied warranty of any kind.
These notices must be retained in any copies of any part of this
documentation and/or software.
#==============================================================================

View File

@ -1,6 +1,6 @@
# Paiement CIC # Paiement CIC
Paiement CIC is a plugin to ease credit card payment with the CIC / Crédit Mutuel banks system. Paiement CIC is a plugin to ease credit card payment with the CIC / Crédit Mutuel banks system version 3.0.
It's a Ruby on Rails port of the connexion kits published by the bank. It's a Ruby on Rails port of the connexion kits published by the bank.
* The Plugin [site](http://github.com/novelys/cicpayment) * The Plugin [site](http://github.com/novelys/cicpayment)
@ -24,11 +24,11 @@ script/plugin install git://github.com/novelys/paiementcic.git
### in development.rb : ### in development.rb :
PaiementCic.target_url = "https://ssl.paiement.cic-banques.fr/test/paiement.cgi" PaiementCic.target_url = "https://ssl.paiement.cic-banques.fr/test/paiement.cgi" # or https://paiement.creditmutuel.fr/test/paiement.cgi
### in production.rb : ### in production.rb :
PaiementCic.target_url = "https://ssl.paiement.cic-banques.fr/paiement.cgi" PaiementCic.target_url = "https://ssl.paiement.cic-banques.fr/paiement.cgi" # or https://paiement.creditmutuel.fr/paiement.cgi
### in order controller : ### in order controller :
@ -71,15 +71,15 @@ script/plugin install git://github.com/novelys/paiementcic.git
order_transaction.update_attribute :success, true order_transaction.update_attribute :success, true
receipt = "OK" receipt = "0"
else else
order.transaction_declined! order.transaction_declined!
order.update_attribute :description, "Document Falsifie." order.update_attribute :description, "Document Falsifie."
order_transaction.update_attribute :success, false order_transaction.update_attribute :success, false
receipt = "Document Falsifie" receipt = "1\n#{PaiementCic.mac_string}"
end end
render :text => "Version: 1\n#{receipt}\n" render :text => "Pragma: no-cache\nContent-type: text/plain\n\nversion=2\ncdr=#{receipt}"
end end
def bank_ok def bank_ok

View File

@ -14,10 +14,13 @@ class String
end end
class PaiementCic class PaiementCic
@@version = "3.0" # clé extraite grâce à extract2HmacSha1.html fourni par le Crédit Mutuel
cattr_accessor :version
@@hmac_key = "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ" # clé extraite grâce à extract2HmacSha1.html fourni par le Crédit Mutuel @@hmac_key = "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ" # clé extraite grâce à extract2HmacSha1.html fourni par le Crédit Mutuel
cattr_accessor :hmac_key cattr_accessor :hmac_key
@@target_url = "https://ssl.paiement.cic-banques.fr/test/paiement.cgi" # "https://ssl.paiement.cic-banques.fr/paiement.cgi" @@target_url = "https://paiement.creditmutuel.fr/test/paiement.cgi" # "https://ssl.paiement.cic-banques.fr/paiement.cgi"
cattr_accessor :target_url cattr_accessor :target_url
@@tpe = "123456" @@tpe = "123456"
@ -26,61 +29,84 @@ class PaiementCic
@@societe = "masociete" @@societe = "masociete"
cattr_accessor :societe cattr_accessor :societe
@@url_ok = ""
cattr_accessor :url_ok
def self.date_format def self.date_format
"%d/%m/%Y:%H:%M:%S" "%d/%m/%Y:%H:%M:%S"
end end
def self.config(amount_in_cents, reference) def self.config(amount_in_cents, reference)
oa = ActiveSupport::OrderedHash.new oa = ActiveSupport::OrderedHash.new
oa["version"] = "3.0"
oa["TPE"] = tpe oa["TPE"] = tpe
oa["date"] = Time.now.strftime(date_format) oa["date"] = Time.now.strftime(date_format)
oa["montant"] = ("%.2f" % (amount_in_cents/100.0)) + "EUR" oa["montant"] = ("%.2f" % amount_in_cents) + "EUR"
oa["reference"] = reference oa["reference"] = reference
oa["texte-libre"] = "" oa["texte-libre"] = ""
oa["version"] = "1.2open"
oa["lgue"] = "FR" oa["lgue"] = "FR"
oa["societe"] = societe oa["societe"] = societe
oa["mail"] = ""
oa oa
end end
def self.calculate_hmac(ordered_hash) def self.mac_string params
data = ordered_hash.values.join("*") + "*" hmac_key = PaiementCic.new
hmac(data) mac_string = [hmac_key.tpe, params["date"], params['montant'], params['reference'], params['texte-libre'], hmac_key.version, params['code-retour'], params['cvx'], params['vld'], params['brand'], params['status3ds'], params['numauto'], params['motifrefus'], params['originecb'], params['bincb'], params['hpancb'], params['ipclient'], params['originetr'], params['veres'], params['pares']].join('*') + "*"
end end
def self.verify_hmac params def self.verify_hmac params
tpe = params[:TPE] hmac_key = PaiementCic.new
date = params[:date] mac_string = [hmac_key.tpe, params["date"], params['montant'], params['reference'], params['texte-libre'], hmac_key.version, params['code-retour'], params['cvx'], params['vld'], params['brand'], params['status3ds'], params['numauto'], params['motifrefus'], params['originecb'], params['bincb'], params['hpancb'], params['ipclient'], params['originetr'], params['veres'], params['pares']].join('*') + "*"
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("+") + "+" hmac_key.valid_hmac?(mac_string, params['MAC'])
mac == hmac(data)
end end
def self.hmac(data) # Check if the HMAC matches the HMAC of the data string
pass = ""; def valid_hmac?(mac_string, sent_mac)
k1 = [Digest::SHA1.hexdigest(pass)].pack("H*"); computeHMACSHA1(mac_string) == sent_mac.downcase
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 end
def self.hmac_sha1(key, data) # Return the HMAC for a data string
def computeHMACSHA1(data)
hmac_sha1(usable_key(self), data).downcase
end
def hmac_sha1(key, data)
length = 64
if (key.length > length)
key = [Digest::SHA1.hexdigest(key)].pack("H*")
end
key = key.ljust(length, 0.chr)
ipad = ''.ljust(length, 54.chr)
opad = ''.ljust(length, 92.chr)
k_ipad = key ^ ipad
k_opad = key ^ opad
#Digest::SHA1.hexdigest(k_opad + [Digest::SHA1.hexdigest(k_ipad + sData)].pack("H*"))
OpenSSL::HMAC.hexdigest(OpenSSL::Digest::Digest.new("sha1"), key, data) OpenSSL::HMAC.hexdigest(OpenSSL::Digest::Digest.new("sha1"), key, data)
end end
private
# Return the key to be used in the hmac function
def usable_key(payement)
hex_string_key = payement.hmac_key[0..37]
hex_final = payement.hmac_key[38..40] + "00";
cca0 = hex_final[0]
if cca0 > 70 && cca0 < 97
hex_string_key += (cca0 - 23).chr + hex_final[1..2]
elsif hex_final[1..2] == "M"
hex_string_key += hex_final[0..1] + "0"
else
hex_string_key += hex_final[0..2]
end
[hex_string_key].pack("H*")
end
end end

View File

@ -1,17 +1,27 @@
## refactor this
module PaiementCicHelper module PaiementCicHelper
def paiement_cic_hidden_fields(order, order_transaction, options = {}) def paiement_cic_hidden_fields(order, price, order_transaction, options = {})
oa = PaiementCic.config(order.amount, order_transaction.reference) oa = PaiementCic.config(price, order_transaction.reference)
hsh = oa.dup oMac = PaiementCic.new
hsh["url_retour"] = options[:url_retour] || edit_order_url(order) sDate = Time.now.strftime("%d/%m/%Y:%H:%M:%S")
hsh["url_retour_ok"] = options[:url_retour_ok] || bank_ok_order_transaction_url(order_transaction) chaine = [oMac.tpe, sDate, oa["montant"], oa["reference"].to_s, oa["texte-libre"], oMac.version, "FR", oMac.societe, "", "", "", "", "", "", "", "", "", "", ""].join("*")
hsh["url_retour_err"] = options[:url_retour_err] || bank_err_order_transaction_url(order_transaction) chaineMAC = oMac.computeHMACSHA1(chaine)
hsh["MAC"] = PaiementCic.calculate_hmac(oa)
res = "\n" html = '
hsh.each{|key, value| <input type="hidden" name="version" id="version" value="' + oa["version"] + '" />
res << hidden_field_tag(key, value) << "\n" <input type="hidden" name="TPE" id="TPE" value="' + oa["TPE"] + '" />
} <input type="hidden" name="date" id="date" value="' + oa["date"] + '" />
res <input type="hidden" name="montant" id="montant" value="' + oa["montant"] + '" />
<input type="hidden" name="reference" id="reference" value="' + oa["reference"].to_s + '" />
<input type="hidden" name="MAC" id="MAC" value="' + chaineMAC + '" />
<input type="hidden" name="url_retour" id="url_retour" value="' + bank_callback_order_transactions_url + '" />
<input type="hidden" name="url_retour_ok" id="url_retour_ok" value="' + bank_ok_order_transaction_url(order) + '" />
<input type="hidden" name="url_retour_err" id="url_retour_err" value="' + bank_err_order_transaction_url(order) + '" />
<input type="hidden" name="lgue" id="lgue" value="' + oa["lgue"] + '" />
<input type="hidden" name="societe" id="societe" value="' + oa["societe"] + '" />
<input type="hidden" name="texte-libre" id="texte-libre" value="' + oa["texte-libre"] + '" />
<input type="hidden" name="mail" id="mail" value="''" />'
html
end end
end end