package II5117351e1a4f1d07d1c88690b7a75168::mod_bitpay; use strict; use JSON::PP; use LWP::UserAgent; use HTTP::Request; use MIME::Base64 qw/encode_base64/; use IIedc3417b3b246250508c70cb08344002; use Digest::SHA qw(hmac_sha256_hex); sub checkPGateSettings { my $class = shift; my $settings = shift; my @errors; push @errors, 'check.empty_api_credentials' unless $settings->{api_key}; eval { local $SIG{__DIE__} = 'DEFAULT'; require Crypt::SSLeay; }; push @errors, ['check.no_mod', 'Crypt::SSLeay'] if $@ && $ENV{HTTP_HOST} ne 'localhost'; @errors; } sub checkProductSettings { my $class = shift; my ($product) = @_; my @errors; @errors; } sub go { my $class = shift; my $pgtxn = shift; my $settings = $pgtxn->getPGateSettings; my $request = Zen->getRequest; my $in = $request->getInput; return ['go.no_bulk_payment'] unless $pgtxn->{sale_id}; my $pgate = $pgtxn->getPGate; my $sale = $pgtxn->getSale; my $order = $sale->getOrder; my $amount = int($sale->{amount}); my $data = { price => $amount, currency => $pgtxn->getCurrencyCode, notificationURL => $pgtxn->getFeedbackURL('notify', 'txn'), redirectURL => $pgtxn->getFeedbackURL('return', 'txn'), orderID => $order->{id}, buyerName => $order->{user_name}, buyerEmail => $order->{user_email}, buyerPhone => $order->{user_phone} }; my ($response, $error) = _send_request('API_SALE', $pgate, $sale, 'invoice', $data); use Data::Dumper; _debug_log(Dumper($response . " / " . $error)); return [$response->{error}{message} . " Message: " . Dumper($response->{error}{messages})] if $response->{error}; if ($error) { if ($error->[0] eq 'go.internal_processing_error') { return; } else { return (undef, $error->[1]); } } $pgtxn->getSaleOrFirstSaleInBulk->txnWaitingInit; $request->redirect($response->{url}); } sub feedbackReturnTxn { my ($class, $pgtxn) = @_; my $in = Zen->getRequest->getInput; $pgtxn->logg('RET', $in); $pgtxn->redirectToReturnPage; } sub feedbackNotifyTxn { my ($class, $pgtxn) = @_; my $in = Zen->getRequest->getInput; $pgtxn->logg('NOTIF', $in); Zen->getRequest->printHeader; print '200 OK'; my $order_status; my $order_code; if (ref($in) eq 'HASH') { while (my ($k, $v) = each %$in) { $order_status = $1 if $k =~ /"status":\s+"(.+)",/; $order_code = $1 if $k =~ /"id":\s+"(.+)",/; } } print $order_status; print $order_code; my $paymentGood = $order_status eq 'paid' ? 1 : 0; $pgtxn->txnPayment("BitPay-" . $order_code) if $paymentGood; $pgtxn->getSaleOrFirstSaleInBulk->txnWaitingClose; return; } sub _send_request { my ($paylog_label, $pgate, $sale, $command, $data) = @_; my $settings = $pgate->getPGateSettings; my $api_url = $settings->{api_url} . "$command"; my $formdata = _convert_to_formdata($data); $pgate->paylog($paylog_label . '_REQ', $sale, _prepare_paylog($formdata)); my $ua = LWP::UserAgent->new; $ua->timeout(180); $ua->env_proxy; use Data::Dumper; my $cb_req_body = encode_json($data); my $req = HTTP::Request->new('POST', $api_url); $req->header( Authorization => "Basic " . encode_base64($settings->{api_key} . ':')); $req->content_type('application/json'); $req->content($cb_req_body); my $res = $ua->request($req); _debug_log(Dumper($res)); if ($res->code == 200) { my $respdata = decode_json($res->content); return ($respdata); } elsif ($res->code == 500) { my $errmsg = $res->status_line . " - " . $res->content; $pgate->paylog($paylog_label . '_INTERR', $sale, $errmsg); return (undef, ['go.internal_processing_error', $errmsg]); } my @return = eval { my $hash = decode_json($res->content); return (undef, ['go.payment_failed', $hash->{error}{message}]); }; if ($@) { my $error = "Could not decode HTTP response: $@"; return (undef, ['go.internal_processing_error', "Could not decode HTTP response: $@"]); }; @return; } sub _convert_to_formdata { my $struct = shift; my $data = {}; my $process_value; $process_value = sub { my ($key, $value) = @_; if (ref($value) eq 'HASH') { while (my ($k, $v) = each %$value) { my $new_key = $key ? $key . "[$k]" : $k; &$process_value($new_key, $v); } } elsif (ref($value) eq 'ARRAY') { for (my $i = 0; $i < @$value; $i++) { &$process_value($key . "[$i]", $value->[$i]); } } else { $data->{$key} = $value; } }; &$process_value('', $struct); return $data; } sub _prepare_paylog { my $orig_data = shift; my $data = {%$orig_data}; for ("card[number]") { if (exists $data->{$_}) { $data->{$_} = ('*' x 12) . substr($data->{$_}, 12, 4); } } for ("card[cvc]") { if (exists $data->{$_}) { $data->{$_} = ('*' x (length($data->{$_}))); } } return $data; } sub _debug_log { my $orig_data = shift; my $dt = II8dae0e141ee45f5daba6a74e4a7c3b6f::IlIIIIIIIlllIlII($II8dae0e141ee45f5daba6a74e4a7c3b6f::IlIIlIIIIIIlIIII{$II8dae0e141ee45f5daba6a74e4a7c3b6f::IlIllIIlIllIlIIl},1010,$II8dae0e141ee45f5daba6a74e4a7c3b6f::IlIIlIIIIIIlIIII{$II720d6e18aa34327713eb014408fc9144::lIIIlIIIllIlllII})->new; if (open F, '>>' . Zen->getSitebox . 'logs/coinbase.pay.' . $dt->format('%Y-%m-%d') . '.log') { print F "[" . scalar(localtime) . "]\n"; print F "$orig_data\n"; close F; } } 1; 