Petit intermède technique

10May07

UPDATE : nous discutons actuellement de ce code sur le groupe de discussions railsfrance (il contient des suggestions intéressants d’amélioration du code que je n’ai pas encore eu le temps d’intégrer)

Comme j’ai eu récemment affaire au paiement électronique du Crédit Mutuel/CIC et qu’ils ne fournissent pas d’implémentation de référence pour Ruby/Ruby on Rails, mais qu’ils fournissent par contre un certain nombre d’implémentations de référence (PHP, Python, Java, C++, etc), qu’on peut d’ailleurs retrouver ici, j’ai du re-implémenter ce qu’il me manquait pour Rails. Voici donc le code que j’ai écrit.

Disclaimer habituel :

// 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.

Code utilisé dans le controller (code à insérer par exemple dans votre application.rb) :

  def show
    @tpe = "608..."# numéro de TPE du comerçant
    @date = Time.now.strftime("%d/%m/%Y:%H:%M:%S")

    @montant = "345.25EUR"
    @reference = "PIPO"
    @texte_libre = ""

    @version = "1.2open"
    @lgue = "FR"
    @societe = "nomsociete"

    @data = @tpe + "*" + @date + "*" + @montant + "*" + @reference + "*" + @texte_libre + "*" + @version + "*" + @lgue + "*" + @societe + "*"

    @mac = hmac(@data)
  end

  def confirm

    @tpe = params[:TPE]
    @date = params[:date]

    @montant = params[:montant]
    @reference = params[:reference]

    @mac = params[:MAC]
    @texte_libre = params['texte-libre']

    @code_retour = params['code-retour']
    @retour_plus = params['retourPLUS']

    @mac = params[:MAC]

    @data  = "#{@retour_plus}"

    @data += "#{@tpe}+"
    @data += "#{@date}+"
    @data += "#{@montant}+"

    @data += "#{@reference}+"
    @data += "#{@texte_libre}+"
    @data += "1.2open+"

    @data += "#{@code_retour}+"

    if @mac.downcase == hmac(@data)

      @result = @code_retour + @retour_plus

      @receipt = "OK"
    else
      @result  = 'None'

      @receipt = "Document Falsifie"
    end
    render :text => "Version:1\n#{@receipt}\n#{Time.now.strftime("%d/%m/%Y:%H:%M:%S")}"

  end

  protected

  require 'digest/sha1'
  require 'openssl'

  
  def hmac(data)
    pass = "";
    k1 = [Digest::SHA1.hexdigest(pass)].pack("H*");

    l1 = k1.length
    key = "b9..." # clé extraite grâce à extract2HmacSha1.html fourni par le Crédit Mutuel

    k2 = [key].pack("H*")
    l2 = k2.length

    #if (l1 > l2)
    #  k2 = k2.ljust(l1, chr(0x00))
    #elsif (l2 > l1)
    #  k1 = k1.ljust(l2, chr(0x00))
    #end

    xor_res = k1 ^ k2
    hmac_sha1(xor_res, data).downcase

  end

  def hmac_sha1(key, data)
    OpenSSL::HMAC.hexdigest(OpenSSL::Digest::Digest.new("sha1"), key, data)

  end

La méthode “show” va afficher le formulaire de paiement, tandis que la méthode “confirm” est l’url de confirmation de paiement (utilisée par le serveur de la banque).

Vous remarquerez que j’utilise l’opérateur ^ entre deux chaînes de caractères (xor entre deux chaînes). Celui-ci n’existe pas de base dans Ruby mais voici une petite implémentation :

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

Finalement, la vue correspondant à la méthode “show” ressemblerait à ceci :

  <% form_tag "https://ssl.paiement.cic-banques.fr/test/paiement.cgi" do -%>
    <%= hidden_field_tag 'version', @version %>
    <%= hidden_field_tag 'TPE', @tpe %>

    <%= hidden_field_tag 'date', @date %>
    <%= hidden_field_tag 'montant', @montant %>

    <%= hidden_field_tag 'reference', @reference %>
    <%= hidden_field_tag 'MAC', @mac %>

    <%= hidden_field_tag 'url_retour', "http://www.google.fr" %>
    <%= hidden_field_tag 'url_retour_ok', "http://www.google.fr" %>
    <%= hidden_field_tag 'url_retour_err', "http://www.google.fr" %>

    <%= hidden_field_tag 'lgue', @lgue %>
    <%= hidden_field_tag 'societe', @societe %>
    <%= hidden_field_tag 'text-libre', @texte_libre %>

    <%= submit_tag 'payer' %>
  <% end -%>

J’attends vos éventuels commentaires et suggestions.



No Responses Yet to “Petit intermède technique”

  1. Leave a Comment

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s


%d bloggers like this: