From d3e81a1b00836566c698e9dd74875615e81f9ee5 Mon Sep 17 00:00:00 2001 From: ryosuke Date: Sat, 5 Mar 2022 22:31:52 +0800 Subject: [PATCH 1/2] add coinbase --- app/Payments/Coinbase.php | 129 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 129 insertions(+) create mode 100644 app/Payments/Coinbase.php diff --git a/app/Payments/Coinbase.php b/app/Payments/Coinbase.php new file mode 100644 index 00000000..ed6fba33 --- /dev/null +++ b/app/Payments/Coinbase.php @@ -0,0 +1,129 @@ +config = $config; + } + + public function form() + { + return [ + 'coinbase_url' => [ + 'label' => '接口地址', + 'description' => '', + 'type' => 'input', + ], + 'coinbase_api_key' => [ + 'label' => 'API KEY', + 'description' => '', + 'type' => 'input', + ], + 'coinbase_webhook_key' => [ + 'label' => 'WEBHOOK KEY', + 'description' => '', + 'type' => 'input', + ], + ]; + } + + public function pay($order) { + + $params = [ + 'name' => '订阅套餐', + 'description' => '订单号 ' . $order['trade_no'], + 'pricing_type' => 'fixed_price', + 'local_price' => [ + 'amount' => sprintf('%.2f', $order['total_amount'] / 100), + 'currency' => 'CNY' + ], + 'metadata' => [ + "outTradeNo" => $order['trade_no'], + ], + ]; + + $params_string = http_build_query($params); + + $ret_raw = self::_curlPost($this->config['coinbase_url'], $params_string); + + $ret = @json_decode($ret_raw, true); + + if(empty($ret['data']['hosted_url'])) { + abort(500, "error!"); + } + return [ + 'type' => 1, + 'data' => $ret['data']['hosted_url'], + ]; + } + + public function notify($params) { + + $payload = trim(file_get_contents('php://input')); + $json_param = json_decode($payload, true); + + + $headerName = 'X-Cc-Webhook-Signature'; + $headers = getallheaders(); + $signatureHeader = isset($headers[$headerName]) ? $headers[$headerName] : ''; + $computedSignature = \hash_hmac('sha256', $payload, $this->config['coinbase_webhook_key']); + + if (!self::hashEqual($signatureHeader, $computedSignature)) { + abort(400, 'HMAC signature does not match'); + } + + $out_trade_no = $json_param['event']['data']['metadata']['outTradeNo']; + $pay_trade_no=$json_param['event']['id']; + return [ + 'trade_no' => $out_trade_no, + 'callback_no' => $pay_trade_no + ]; + http_response_code(200); + die('success'); + } + + + private function _curlPost($url,$params=false){ + + $ch = curl_init(); + curl_setopt($ch, CURLOPT_URL, $url); + curl_setopt($ch, CURLOPT_HEADER, 0); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); + curl_setopt($ch, CURLOPT_TIMEOUT, 300); + curl_setopt($ch, CURLOPT_POSTFIELDS, $params); + curl_setopt( + $ch, CURLOPT_HTTPHEADER, array('X-CC-Api-Key:' .$this->config['coinbase_api_key'], 'X-CC-Version: 2018-03-22') + ); + $result = curl_exec($ch); + curl_close($ch); + return $result; + } + + + /** + * @param string $str1 + * @param string $str2 + * @return bool + */ + public function hashEqual($str1, $str2) + { + if (function_exists('hash_equals')) { + return \hash_equals($str1, $str2); + } + + if (strlen($str1) != strlen($str2)) { + return false; + } else { + $res = $str1 ^ $str2; + $ret = 0; + + for ($i = strlen($res) - 1; $i >= 0; $i--) { + $ret |= ord($res[$i]); + } + return !$ret; + } + } + +} + From 828a4ffe3920ef3b26a5f84f6e0585d8f2f0d91c Mon Sep 17 00:00:00 2001 From: ryosuke Date: Sun, 6 Mar 2022 15:29:08 +0800 Subject: [PATCH 2/2] add btcpay --- app/Payments/BTCPay.php | 148 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 148 insertions(+) create mode 100644 app/Payments/BTCPay.php diff --git a/app/Payments/BTCPay.php b/app/Payments/BTCPay.php new file mode 100644 index 00000000..e9d62127 --- /dev/null +++ b/app/Payments/BTCPay.php @@ -0,0 +1,148 @@ +config = $config; + } + + public function form() + { + return [ + 'btcpay_url' => [ + 'label' => 'API接口所在网址(包含最后的斜杠)', + 'description' => '', + 'type' => 'input', + ], + 'btcpay_storeId' => [ + 'label' => 'storeId', + 'description' => '', + 'type' => 'input', + ], + 'btcpay_api_key' => [ + 'label' => 'API KEY', + 'description' => '个人设置中的API KEY(非商店设置中的)', + 'type' => 'input', + ], + 'btcpay_webhook_key' => [ + 'label' => 'WEBHOOK KEY', + 'description' => '', + 'type' => 'input', + ], + ]; + } + + public function pay($order) { + + $params = [ + 'jsonResponse' => true, + 'amount' => sprintf('%.2f', $order['total_amount'] / 100), + 'currency' => 'CNY', + 'metadata' => [ + 'orderId' => $order['trade_no'] + ] + ]; + + $params_string = @json_encode($params); + + $ret_raw = self::_curlPost($this->config['btcpay_url'] . 'api/v1/stores/' . $this->config['btcpay_storeId'] . '/invoices', $params_string); + + $ret = @json_decode($ret_raw, true); + + if(empty($ret['checkoutLink'])) { + abort(500, "error!"); + } + return [ + 'type' => 1, // Redirect to url + 'data' => $ret['checkoutLink'], + ]; + } + + public function notify($params) { + $payload = trim(file_get_contents('php://input')); + + $headers = getallheaders(); + + //IS Btcpay-Sig + //NOT BTCPay-Sig + //API doc is WRONG! + $headerName = 'Btcpay-Sig'; + $signraturHeader = isset($headers[$headerName]) ? $headers[$headerName] : ''; + $json_param = json_decode($payload, true); + + $computedSignature = "sha256=" . \hash_hmac('sha256', $payload, $this->config['btcpay_webhook_key']); + + if (!self::hashEqual($signraturHeader, $computedSignature)) { + abort(400, 'HMAC signature does not match'); + return false; + } + + //get order id store in metadata + $context = stream_context_create(array( + 'http' => array( + 'method' => 'GET', + 'header' => "Authorization:" . "token " . $this->config['btcpay_api_key'] . "\r\n" + ) + )); + + $invoiceDetail = file_get_contents($this->config['btcpay_url'] . 'api/v1/stores/' . $this->config['btcpay_storeId'] . '/invoices/' . $json_param['invoiceId'], false, $context); + $invoiceDetail = json_decode($invoiceDetail, true); + + + $out_trade_no = $invoiceDetail['metadata']["orderId"]; + $pay_trade_no=$json_param['invoiceId']; + return [ + 'trade_no' => $out_trade_no, + 'callback_no' => $pay_trade_no + ]; + http_response_code(200); + die('success'); + } + + + private function _curlPost($url,$params=false){ + + $ch = curl_init(); + curl_setopt($ch, CURLOPT_URL, $url); + curl_setopt($ch, CURLOPT_HEADER, 0); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); + curl_setopt($ch, CURLOPT_TIMEOUT, 300); + curl_setopt($ch, CURLOPT_POSTFIELDS, $params); + curl_setopt( + $ch, CURLOPT_HTTPHEADER, array('Authorization:' .'token '.$this->config['btcpay_api_key'], 'Content-Type: application/json') + ); + $result = curl_exec($ch); + curl_close($ch); + return $result; + } + + + /** + * @param string $str1 + * @param string $str2 + * @return bool + */ + private function hashEqual($str1, $str2) + { + + if (function_exists('hash_equals')) { + return \hash_equals($str1, $str2); + } + + if (strlen($str1) != strlen($str2)) { + return false; + } else { + $res = $str1 ^ $str2; + $ret = 0; + + for ($i = strlen($res) - 1; $i >= 0; $i--) { + $ret |= ord($res[$i]); + } + return !$ret; + } + } + +} +