Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

【WIP】3DS2.0対応 #51

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions lib/gmo.rb
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,12 @@ def api(path, args = {}, verb = "post", options = {}, &error_checking_block)
# "ACS=1&ACSUrl=url" => { "ACS" => "1", ACSUrl => "url" }
key_values = result.body.to_s.split('&').map { |str| str.split('=', 2) }.flatten
response = Hash[*key_values]
# Transform the redirect_url
# "ACS=2&RedirectUrl=https://manage.tds2gw.gmopg.jp/api/v2/brw/callback?transId=6e48e31f-2940-48e1-a702- ebba2f3373ee&t=dccc8a7ed85372c9accff576bff59b3a" => { "ACS" => "2", RedirectUrl => "https://manage.tds2gw.gmopg.jp/api/v2/brw/callback?transId=6e48e31f-2940-48e1-a702- ebba2f3373ee&t=dccc8a7ed85372c9accff576bff59b3a" }
if response['RedirectUrl'].present? && response['t'].present? && response.keys.index('RedirectUrl') + 1 == response.keys.index('t')
response['RedirectUrl'] = response['RedirectUrl'] + '&t=' + response['t']
response.delete('t')
end
Comment on lines +44 to +49
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jiikko
3DS2.0の対応をさせていただいております。
specはToDoになりますが、実装方針が問題ないかを確認したいです。

レスポンスの中に &を含む値があり、そのまま使用すると &tが別のkeyと認識されてしまう問題がありましたので、上記のように手動でパースする実装を入れています。

上記の方法以外だと、idPass ではなく json でリクエストしなければならなくなりそうなのでもう少し大きな改修が必要になりそうです。
他のparse方法でも無理でした。

pry(main)> Rack::Utils.parse_nested_query("ACS=2&RedirectUrl=https://manage.tds2gw.gmopg.jp/api/v2/brw/callback?transId=6e48e31f-2940-48e1-a702-ebba2f3373ee&t=dccc8a7ed85372c9accff576bff59b3a")
=> {"ACS"=>"2", "RedirectUrl"=>"https://manage.tds2gw.gmopg.jp/api/v2/brw/callback?transId=6e48e31f-2940-48e1-a702-ebba2f3373ee", "t"=>"dccc8a7ed85372c9accff576bff59b3a"}

ご確認よろしくお願いいたします。

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jassan

返信が遅くなって申し訳ないです。

レスポンスの中に &を含む値があり、そのまま使用すると &tが別のkeyと認識されてしまう問題がありましたので、上記のように手動でパースする実装を入れています。

私は3DS2.0を使ったことがないので微妙なところですが、
テストを気持ち厚く書いて、動いているのであれば手動パースで問題ないと思います。


ドキュメントは公開されていないっぽいので頑張って手に入れてみます。

# converting to UTF-8
body = response = Hash[response.map { |k,v| [k, NKF.nkf('-w',v)] }]
# Check for errors if provided a error_checking_block
Expand Down
52 changes: 51 additions & 1 deletion lib/gmo/const.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,12 @@ module Const
:address_5 => "Address5",
:address_6 => "Address6",
:amount => "Amount",
:app_mode => "AppMode",
:bank_code => "Bank_Code",
:bank_id => "Bank_ID",
:branch_code => "Branch_Code",
:branch_code_jp => "Branch_Code_Jpbank",
:callback_type => "CallbackType",
:cancel_amount => "CancelAmount",
:cancel_tax => "CancelTax",
:card_name => "CardName",
Expand Down Expand Up @@ -112,7 +114,7 @@ module Const
:register_disp_7 => "RegisterDisp7",
:register_disp_8 => "RegisterDisp8",
:reserve_no => "ReserveNo",
:ret_url => "RetURL",
:ret_url => "RetUrl",

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

要求されるパラメータが RetURLRetUrl の2種類混在してるようですね。
3Dセキュアの場合は後者でよさそうですが、他の決済手段の場合前者を要求されるケースがあるようです。

:security_code => "SecurityCode",
:seq_mode => "SeqMode",
:service_name => "ServiceName",
Expand All @@ -128,7 +130,55 @@ module Const
:suica_add_info_4 => "SuicaAddInfo4",
:tax => "Tax",
:td_flag => "TdFlag",
:tds2_type => "Tds2Type",
:td_required => "TdRequired",
:td_tenant_name => "TdTenantName",
:tds2_ch_acc_change => "Tds2ChAccChange",
:tds2_ch_acc_date => "Tds2ChAccDate",
:tds2_ch_acc_pw_change => "Tds2ChAccPwChange",
:tds2_nb_purchase_account => "Tds2NbPurchaseAccount",
:tds2_param => "Tds2Param",
:tds2_payment_acc_age => "Tds2PaymentAccAge",
:tds2_provision_attempts_day => "Tds2ProvisionAttemptsDay",
:tds2_ship_address_usage => "Tds2ShipAddressUsage",
:tds2_ship_name_ind => "Tds2ShipNameInd",
:tds2_suspicious_acc_activity => "Tds2SuspiciousAccActivity",
:tds2_txn_activity_day => "Tds2TxnActivityDay",
:tds2_txn_activity_year => "Tds2TxnActivityYear",
:tds2_3ds_req_auth_data => "Tds2ThreeDSReqAuthData",
:tds2_3ds_req_auth_method => "Tds2ThreeDSReqAuthMethod",
:tds2_3ds_req_auth_timestamp => "Tds2ThreeDSReqAuthTimestamp",
:tds2_addr_match => "Tds2AddrMatch",
:tds2_bill_addr_city => "Tds2BillAddrCity",
:tds2_bill_addr_country => "Tds2BillAddrCountry",
:tds2_bill_addr_line1 => "Tds2BillAddrLine1",
:tds2_bill_addr_line2 => "Tds2BillAddrLine2",
:tds2_bill_addr_line3 => "Tds2BillAddrLine3",
:tds2_bill_addr_post_code => "Tds2BillAddrPostCode",
:tds2_bill_addr_state => "Tds2BillAddrState",
:tds2_email => "Tds2Email",
:tds2_home_phone_cc => "Tds2HomePhoneCC",
:tds2_home_phone_subscriber => "Tds2HomePhoneSubscriber",
:tds2_mobile_phone_cc => "Tds2MobilePhoneCC",
:tds2_mobile_phone_subscriber => "Tds2MobilePhoneSubscriber",
:tds2_work_phone_cc => "Tds2WorkPhoneCC",
:tds2_work_phone_subscriber => "Tds2WorkPhoneSubscriber",
:tds2_ship_addr_city => "Tds2ShipAddrCity",
:tds2_ship_addr_country => "Tds2ShipAddrCountry",
:tds2_ship_addr_line1 => "Tds2ShipAddrLine1",
:tds2_ship_addr_line2 => "Tds2ShipAddrLine2",
:tds2_ship_addr_line3 => "Tds2ShipAddrLine3",
:tds2_ship_addr_post_code => "Tds2ShipAddrPostCode",
:tds2_ship_addr_state => "Tds2ShipAddrState",
:tds2_delivery_email_address => "Tds2DeliveryEmailAddress",
:tds2_delivery_time_frame => "Tds2DeliveryTimeframe",
:tds2_gift_card_amount => "Tds2GiftCardAmount",
:tds2_gift_card_count => "Tds2GiftCardCount",
:tds2_gift_card_curr => "Tds2GiftCardCurr",
:tds2_pre_order_date => "Tds2PreOrderDate",
:tds2_pre_order_purchase_ind => "Tds2PreOrderPurchaseInd",
:tds2_reorder_items_ind => "Tds2ReorderItemsInd",
:tds2_ship_ind => "Tds2ShipInd",
:tel_no => "TelNo",
:token => "Token",
:token_seq => "TokenSeq",
Expand Down
33 changes: 33 additions & 0 deletions lib/gmo/shop_api.rb
Original file line number Diff line number Diff line change
Expand Up @@ -561,6 +561,39 @@ def search_trade_multi(options = {})
post_request name, options
end

###################################################
# 3DS2.0 対応
###################################################

# 4.3.1.7 3DS2.0認証実行(Tds2Auth)
# DS2.0認証を実行します。
# 3DS2.0認証初期化URL(RedirectUrl)のコールバックを受けたタイミングで本処理を実行してください。
def tds2_auth(options = {})
name = "Tds2Auth.idPass"
required = [:access_id, :access_pass, :tds2_param]
assert_required_options(required, options)
post_request name, options
end

# 4.3.1.8 3DS2.0認証結果取得(Tds2Result)
# 3DS2.0認証の最終的な認証結果を取得します。
# 3DS2.0認証チャレンジURL(ChallengeUrl)のコールバックを受けたタイミングで本処理を実行してください。
def tds2_result(options = {})
name = "Tds2Result.idPass"
required = [:access_id, :access_pass]
assert_required_options(required, options)
post_request name, options
end

# 4.3.1.12 3DS2.0認証後決済実行(SecureTran2)
# 3DS2.0サービスの結果を解析し、その情報を使用してカード会社と通信を行い決済を実施して結果を返します。
def secure_tran_2(options = {})
name = "SecureTran2.idPass"
required = [:access_id, :access_pass]
assert_required_options(required, options)
post_request name, options
end

private

def api_call(name, args = {}, verb = "post", options = {})
Expand Down