# module Veritrans::Tercerog::Mdk::MdkMerchantUtility

MdkMerchantUtility モジュール

### Public Class Methods

analyze_merchant_data(merchant_data) click to toggle source

### マーチャントデータ（MD）をユーザ定義のキーと値に戻します。¶ ↑

@param

  merchant_data マーチャントデータ

@return

  ユーザ定義のキーと値 検証エラー時は、nil

    # File tgMdk/lib/tg_mdk/mdk_merchant_utility.rb, line 171
    def analyze_merchant_data(merchant_data)
      unless merchant_data.is_a? String
        raise ArgumentError
      end

      dec_md = merchant_data.unpack('m').first  # Base64 decode
      matchdata = dec_md.match(/(^.+?)&(.*$)/).to_a  # 最初の'&'で分割する
      org_digest = matchdata[1]
      source = matchdata[2] ? matchdata[2] : ""

      # 検証
      merchant_secret_key = Veritrans::Tercerog::Mdk::MdkConfig.instance.merchant_secret_key
      unless verify_sign(source, merchant_secret_key, org_digest)
        return nil
      end

      # 戻りのHashを生成
      source.split('&').inject({}) do |result, kv|
        key, value = kv.split('=')
        next if key.empty?

        key = CGI.unescape(key)
        value = CGI.unescape(value)

        key = key[1, key.size-1].intern if key[0].chr == ':'
        result[key] = value
        result
      end
    end

calc_hmac(merchant_secret_key, message_body) click to toggle source

### 設定ファイルの秘密鍵を用いてメッセージのダイジェストを取得します。¶ ↑

@param

  merchant_secret_key マーチャント認証鍵

@param

  message_body メッセージ

@return

  ダイジェスト

    # File tgMdk/lib/tg_mdk/mdk_merchant_utility.rb, line 90
    def calc_hmac(merchant_secret_key, message_body)
      key = [merchant_secret_key].pack("H*")
      OpenSSL::HMAC::hexdigest(OpenSSL::Digest::SHA256.new, key, message_body)
    end

check_message?(message_body, content_hmac) click to toggle source

### 署名を検証します。¶ ↑

@param

  message_body メッセージ

@param

  content_hmac 検証用に利用する署名

@return

  true: 検証成功、 false： 検証失敗

    # File tgMdk/lib/tg_mdk/mdk_merchant_utility.rb, line 43
    def check_message?(message_body, content_hmac)
      merchant_secret_key = Veritrans::Tercerog::Mdk::MdkConfig.instance.merchant_secret_key
      return self::check_message_by_secret_key?(merchant_secret_key, message_body, content_hmac)
    end

check_message_by_secret_key?(merchant_secret_key, message_body, content_hmac) click to toggle source

### 署名を検証します。¶ ↑

@param

  merchant_secret_key マーチャント認証鍵

@param

  message_body メッセージ

@param

  content_hmac 検証用に利用する署名

@return

  true: 検証成功、 false： 検証失敗

    # File tgMdk/lib/tg_mdk/mdk_merchant_utility.rb, line 56
    def check_message_by_secret_key?(merchant_secret_key, message_body, content_hmac)

      if merchant_secret_key.nil? || merchant_secret_key.empty?
        return false
      end

      if message_body.nil? || message_body.empty?
        return false
      end

      if content_hmac.nil? || content_hmac.empty?
        return false
      end

      param_hmac = content_hmac.split(";v=")[1]
      unless param_hmac
        return false
      end

      hmac = self::calc_hmac(merchant_secret_key, message_body)
      unless hmac
        return false
      end

      hmac == param_hmac
    end

create_merchant_data(user_hash_data={}) click to toggle source

### マーチャントデータ（MD）を生成します。¶ ↑

@param

  user_hash_data マーチャントデータ生成用のユーザ定義のキーと値

@return

  マーチャントデータ

    # File tgMdk/lib/tg_mdk/mdk_merchant_utility.rb, line 141
    def create_merchant_data(user_hash_data={})
      unless user_hash_data.is_a? Hash
        raise ArgumentError
      end

      str_md = user_hash_data.reject {|key, value|
        key.nil? || key.to_s.empty?

      }.inject([]) {|amd, (key, value)|
        key = ":" + key.to_s if key.is_a? Symbol
        amd << [CGI.escape(key), CGI.escape(value ? value : "")].join('=')

      }.join('&')

      merchant_secret_key = Veritrans::Tercerog::Mdk::MdkConfig.instance.merchant_secret_key
      digest = self::sign(str_md, merchant_secret_key)

      str_md = str_md.empty? ? digest : [digest, str_md].join('&')

      [str_md].pack('m').gsub(/\n/, '')
    end

get_tripartite_auth_hash() click to toggle source

### ３者間通信用メッセージダイジェストを取得します。¶ ↑

    # File tgMdk/lib/tg_mdk/mdk_merchant_utility.rb, line 21
    def get_tripartite_auth_hash
      conf = Veritrans::Tercerog::Mdk::MdkConfig.instance

      merchant_cc_id = conf.merchant_cc_id
      gmnow = Veritrans::Tercerog::Mdk::MdkUtils::mdk_gmtime
      merchant_secret_key = conf.merchant_secret_key
      hash = Veritrans::Tercerog::Mdk::MdkUtils::mdk_digest(merchant_cc_id + gmnow + merchant_secret_key)

      [
        Veritrans::Tercerog::Mdk::MdkUtils::mdk_base64_encode(merchant_cc_id),
        Veritrans::Tercerog::Mdk::MdkUtils::mdk_base64_encode(gmnow),
        Veritrans::Tercerog::Mdk::MdkUtils::mdk_base64_encode(hash),
      ].join('-')
    end

sign(value, key) click to toggle source

### キー、値、マーチャントCC IDのダイジェストを取得します。¶ ↑

@param

  value 値

@param

  key キー

@return

  ダイジェスト

    # File tgMdk/lib/tg_mdk/mdk_merchant_utility.rb, line 103
    def sign(value, key)
      if value.nil? || value.empty?
        return nil #return false
      end

      if key.nil? || key.empty?
        return nil #return false
      end

      merchant_cc_id = Veritrans::Tercerog::Mdk::MdkConfig.instance.merchant_cc_id
      message = [merchant_cc_id, key, value].join(':')

      OpenSSL::Digest.hexdigest('sha1', message)
    end

verify_sign(value, key, original_digest) click to toggle source

### キーと値のダイジェストを検証します。¶ ↑

@param

  value 値

@param

  key キー

@param

  original_digest 取得済みダイジェスト

@return

  true: 検証成功、 false： 検証失敗

    # File tgMdk/lib/tg_mdk/mdk_merchant_utility.rb, line 126
    def verify_sign(value, key, original_digest)
      if original_digest.nil? || original_digest.empty?
        return false
      end

      digest = self::sign(value, key)
      digest == original_digest
    end

### Private Instance Methods

analyze_merchant_data(merchant_data) click to toggle source

### マーチャントデータ（MD）をユーザ定義のキーと値に戻します。¶ ↑

@param

  merchant_data マーチャントデータ

@return

  ユーザ定義のキーと値 検証エラー時は、nil

    # File tgMdk/lib/tg_mdk/mdk_merchant_utility.rb, line 171
    def analyze_merchant_data(merchant_data)
      unless merchant_data.is_a? String
        raise ArgumentError
      end

      dec_md = merchant_data.unpack('m').first  # Base64 decode
      matchdata = dec_md.match(/(^.+?)&(.*$)/).to_a  # 最初の'&'で分割する
      org_digest = matchdata[1]
      source = matchdata[2] ? matchdata[2] : ""

      # 検証
      merchant_secret_key = Veritrans::Tercerog::Mdk::MdkConfig.instance.merchant_secret_key
      unless verify_sign(source, merchant_secret_key, org_digest)
        return nil
      end

      # 戻りのHashを生成
      source.split('&').inject({}) do |result, kv|
        key, value = kv.split('=')
        next if key.empty?

        key = CGI.unescape(key)
        value = CGI.unescape(value)

        key = key[1, key.size-1].intern if key[0].chr == ':'
        result[key] = value
        result
      end
    end

calc_hmac(merchant_secret_key, message_body) click to toggle source

### 設定ファイルの秘密鍵を用いてメッセージのダイジェストを取得します。¶ ↑

@param

  merchant_secret_key マーチャント認証鍵

@param

  message_body メッセージ

@return

  ダイジェスト

    # File tgMdk/lib/tg_mdk/mdk_merchant_utility.rb, line 90
    def calc_hmac(merchant_secret_key, message_body)
      key = [merchant_secret_key].pack("H*")
      OpenSSL::HMAC::hexdigest(OpenSSL::Digest::SHA256.new, key, message_body)
    end

check_message?(message_body, content_hmac) click to toggle source

### 署名を検証します。¶ ↑

@param

  message_body メッセージ

@param

  content_hmac 検証用に利用する署名

@return

  true: 検証成功、 false： 検証失敗

    # File tgMdk/lib/tg_mdk/mdk_merchant_utility.rb, line 43
    def check_message?(message_body, content_hmac)
      merchant_secret_key = Veritrans::Tercerog::Mdk::MdkConfig.instance.merchant_secret_key
      return self::check_message_by_secret_key?(merchant_secret_key, message_body, content_hmac)
    end

check_message_by_secret_key?(merchant_secret_key, message_body, content_hmac) click to toggle source

### 署名を検証します。¶ ↑

@param

  merchant_secret_key マーチャント認証鍵

@param

  message_body メッセージ

@param

  content_hmac 検証用に利用する署名

@return

  true: 検証成功、 false： 検証失敗

    # File tgMdk/lib/tg_mdk/mdk_merchant_utility.rb, line 56
    def check_message_by_secret_key?(merchant_secret_key, message_body, content_hmac)

      if merchant_secret_key.nil? || merchant_secret_key.empty?
        return false
      end

      if message_body.nil? || message_body.empty?
        return false
      end

      if content_hmac.nil? || content_hmac.empty?
        return false
      end

      param_hmac = content_hmac.split(";v=")[1]
      unless param_hmac
        return false
      end

      hmac = self::calc_hmac(merchant_secret_key, message_body)
      unless hmac
        return false
      end

      hmac == param_hmac
    end

create_merchant_data(user_hash_data={}) click to toggle source

### マーチャントデータ（MD）を生成します。¶ ↑

@param

  user_hash_data マーチャントデータ生成用のユーザ定義のキーと値

@return

  マーチャントデータ

    # File tgMdk/lib/tg_mdk/mdk_merchant_utility.rb, line 141
    def create_merchant_data(user_hash_data={})
      unless user_hash_data.is_a? Hash
        raise ArgumentError
      end

      str_md = user_hash_data.reject {|key, value|
        key.nil? || key.to_s.empty?

      }.inject([]) {|amd, (key, value)|
        key = ":" + key.to_s if key.is_a? Symbol
        amd << [CGI.escape(key), CGI.escape(value ? value : "")].join('=')

      }.join('&')

      merchant_secret_key = Veritrans::Tercerog::Mdk::MdkConfig.instance.merchant_secret_key
      digest = self::sign(str_md, merchant_secret_key)

      str_md = str_md.empty? ? digest : [digest, str_md].join('&')

      [str_md].pack('m').gsub(/\n/, '')
    end

get_tripartite_auth_hash() click to toggle source

### ３者間通信用メッセージダイジェストを取得します。¶ ↑

    # File tgMdk/lib/tg_mdk/mdk_merchant_utility.rb, line 21
    def get_tripartite_auth_hash
      conf = Veritrans::Tercerog::Mdk::MdkConfig.instance

      merchant_cc_id = conf.merchant_cc_id
      gmnow = Veritrans::Tercerog::Mdk::MdkUtils::mdk_gmtime
      merchant_secret_key = conf.merchant_secret_key
      hash = Veritrans::Tercerog::Mdk::MdkUtils::mdk_digest(merchant_cc_id + gmnow + merchant_secret_key)

      [
        Veritrans::Tercerog::Mdk::MdkUtils::mdk_base64_encode(merchant_cc_id),
        Veritrans::Tercerog::Mdk::MdkUtils::mdk_base64_encode(gmnow),
        Veritrans::Tercerog::Mdk::MdkUtils::mdk_base64_encode(hash),
      ].join('-')
    end

sign(value, key) click to toggle source

### キー、値、マーチャントCC IDのダイジェストを取得します。¶ ↑

@param

  value 値

@param

  key キー

@return

  ダイジェスト

    # File tgMdk/lib/tg_mdk/mdk_merchant_utility.rb, line 103
    def sign(value, key)
      if value.nil? || value.empty?
        return nil #return false
      end

      if key.nil? || key.empty?
        return nil #return false
      end

      merchant_cc_id = Veritrans::Tercerog::Mdk::MdkConfig.instance.merchant_cc_id
      message = [merchant_cc_id, key, value].join(':')

      OpenSSL::Digest.hexdigest('sha1', message)
    end

verify_sign(value, key, original_digest) click to toggle source

### キーと値のダイジェストを検証します。¶ ↑

@param

  value 値

@param

  key キー

@param

  original_digest 取得済みダイジェスト

@return

  true: 検証成功、 false： 検証失敗

    # File tgMdk/lib/tg_mdk/mdk_merchant_utility.rb, line 126
    def verify_sign(value, key, original_digest)
      if original_digest.nil? || original_digest.empty?
        return false
      end

      digest = self::sign(value, key)
      digest == original_digest
    end