Skip to content

Commit

Permalink
add cryptomus gateway
Browse files Browse the repository at this point in the history
  • Loading branch information
webcreative24 committed Feb 19, 2025
1 parent f18d5d4 commit 4a2f0d1
Show file tree
Hide file tree
Showing 8 changed files with 578 additions and 0 deletions.
45 changes: 45 additions & 0 deletions config/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -1582,5 +1582,50 @@
"type": "int",
"default": "2023020100",
"mark": "当前数据库版本"
},
{
"item": "cryptomus_api_key",
"value": "",
"class": "billing",
"is_public": 1,
"type": "string",
"default": "",
"mark": "cryptomus_api_key"
},
{
"item": "cryptomus_uuid",
"value": "",
"class": "billing",
"is_public": 1,
"type": "string",
"default": "",
"mark": "cryptomus_uuid"
},
{
"item": "cryptomus_subtract",
"value": "",
"class": "billing",
"is_public": 1,
"type": "string",
"default": "",
"mark": "cryptomus_subtract"
},
{
"item": "cryptomus_lifetime",
"value": "3600",
"class": "billing",
"is_public": 1,
"type": "string",
"default": "",
"mark": "cryptomus_lifetime"
},
{
"item": "cryptomus_currency",
"value": "CNY",
"class": "billing",
"is_public": 1,
"type": "string",
"default": "",
"mark": "cryptomus_currency"
}
]
46 changes: 46 additions & 0 deletions resources/views/tabler/admin/setting/billing.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@
<li class="nav-item">
<a href="#smogate" class="nav-link" data-bs-toggle="tab">Smogate</a>
</li>
<li class="nav-item">
<a href="#cryptomus" class="nav-link" data-bs-toggle="tab">Cryptomus</a>
</li>
</ul>
</div>
<div class="card-body">
Expand Down Expand Up @@ -325,6 +328,49 @@
</div>
</div>
</div>
<div class="tab-pane" id="cryptomus">
<div class="card-body">
<div class="form-group mb-3 row">
<label class="form-label col-3 col-form-label">Api key</label>
<div class="col">
<input id="cryptomus_api_key" type="password" class="form-control"
value="{$settings['cryptomus_api_key']}">
<span>You can find the API key in the settings of your personal account.</span>
</div>
</div>
<div class="form-group mb-3 row">
<label class="form-label col-3 col-form-label">UUID</label>
<div class="col">
<input id="cryptomus_uuid" type="text" class="form-control"
value="{$settings['cryptomus_uuid']}">
<span>You can find the UUID in the settings of your personal account.</span>
</div>
</div>
<div class="form-group mb-3 row">
<label class="form-label col-3 col-form-label">Subtract</label>
<div class="col">
<input id="cryptomus_subtract" type="number" class="form-control"
value="{$settings['cryptomus_subtract']}">
<span>How much commission does the client pay (0-100%)</span>
</div>
</div>
<div class="form-group mb-3 row">
<label class="form-label col-3 col-form-label">Lifetime</label>
<div class="col">
<input id="cryptomus_lifetime" type="number" class="form-control"
value="{$settings['cryptomus_lifetime']}">
<span>The lifespan of the issued invoice.(In seconds)</span>
</div>
</div>
{* <div class="form-group mb-3 row">*}
{* <label class="form-label col-3 col-form-label">Currency</label>*}
{* <div class="col">*}
{* <input id="cryptomus_currency" type="text" class="form-control"*}
{* value="{$settings['cryptomus_currency']}">*}
{* </div>*}
{* </div>*}
</div>
</div>
</div>
</div>
</div>
Expand Down
18 changes: 18 additions & 0 deletions resources/views/tabler/gateway/cryptomus.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<div class="card-inner">
<h4>
Cryptomus
</h4>
<p class="card-heading"></p>
<form class="cryptomus" name="cryptomus" method="post">
<button class="btn btn-flat waves-attach"
hx-post="/user/payment/purchase/cryptomus" hx-swap="none"
hx-vals='js:{
price: {$invoice->price},
invoice_id: {$invoice->id},
type: "cryptomus",
redir: window.location.href
}'>
<span>Pay</span>
</button>
</form>
</div>
6 changes: 6 additions & 0 deletions src/Controllers/Admin/Setting/BillingController.php
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,12 @@ final class BillingController extends BaseController
// Smogate
'smogate_app_id',
'smogate_app_secret',
// Cryptomus
'cryptomus_api_key',
'cryptomus_uuid',
'cryptomus_subtract',
'cryptomus_lifetime',
'cryptomus_currency',
];

/**
Expand Down
209 changes: 209 additions & 0 deletions src/Services/Gateway/Cryptomus.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
<?php
declare(strict_types=1);

namespace App\Services\Gateway;

use App\Models\Config;
use App\Models\Paylist;
use App\Services\Auth;
use App\Services\View;
use Exception;
use Psr\Http\Message\ResponseInterface;
use Slim\Http\Response;
use Slim\Http\ServerRequest;
use voku\helper\AntiXSS;
use function json_decode;
use function trim;
use App\Services\Gateway\Cryptomus\Payment as CryptomusPayment;

final class Cryptomus extends Base
{
/**
* @var array
*/
protected array $cryptomus = [];

/**
*
*/
public function __construct()
{
$this->antiXss = new AntiXSS();

$this->cryptomus['cryptomus_api_key'] = Config::obtain('cryptomus_api_key');
$this->cryptomus['cryptomus_uuid'] = Config::obtain('cryptomus_uuid');
$this->cryptomus['cryptomus_subtract'] = Config::obtain('cryptomus_subtract');
$this->cryptomus['cryptomus_lifetime'] = Config::obtain('cryptomus_lifetime');
$this->cryptomus['cryptomus_currency'] = Config::obtain('cryptomus_currency');
}

/**
* @return string
*/
public static function _name(): string
{
return 'cryptomus';
}

/**
* @return bool
*/
public static function _enable(): bool
{
return self::getActiveGateway('cryptomus');
}

/**
* @return string
*/
public static function _readableName(): string
{
return 'Cryptomus';
}

/**
* @param ServerRequest $request
* @param Response $response
* @param array $args
* @return ResponseInterface
* @throws Exception
*/
public function purchase(ServerRequest $request, Response $response, array $args): ResponseInterface
{
$price = $this->antiXss->xss_clean($request->getParam('price'));
$invoiceId = $this->antiXss->xss_clean($request->getParam('invoice_id'));

$type = $this->antiXss->xss_clean($request->getParam('type'));
$redir = $this->antiXss->xss_clean($request->getParam('redir'));

if ($price <= 0) {
return $response->withJson([
'ret' => 0,
'msg' => '非法的金额',
]);
}

$user = Auth::getUser();
$pl = new Paylist();

$tradeNumber = self::generateGuid();

$pl->userid = $user->id;
$pl->total = $price;
$pl->invoice_id = $invoiceId ;
$pl->tradeno = $tradeNumber;
$pl->gateway = self::_readableName();

$pl->save();

$paymentData = [
'amount' => $price,
'currency' => $this->cryptomus['cryptomus_currency'] ?? 'CNY',
'order_id' => 'sspanel_' . $invoiceId ,
'url_return' => $redir,
'url_callback' => self::getCallbackUrl(),
'lifetime' => $this->cryptomus['cryptomus_lifetime'] ?? '3600',
'subtract' => $config['cryptomus_subtract'] ?? '0',
'plugin_name' => 'sspanel:2024.1',
'additional_data' => json_encode(['tradeno' => $tradeNumber])
];

$paymentInstance = $this->getPayment();

try {
$payment = $paymentInstance->create($paymentData);
} catch (\Exception $exception) {
return $response->withJson([
'ret' => 0,
'msg' => '请求支付失败: ' . $exception->getMessage(),
]);
}

return $response->withHeader('HX-Redirect', $payment['url'])->withJson([
'ret' => 1,
'msg' => '订单发起成功,正在跳转到支付页面...',
]);
}


/**
* @param $request
* @param $response
* @param $args
* @return ResponseInterface
*/
public function notify($request, $response, $args): ResponseInterface
{
$payload = trim(file_get_contents('php://input'));
$data = json_decode($payload, true);
$additionalData = json_decode($data['additional_data'], true);

if (!$this->hashEqual($data)) {
return $response->withJson(['state' => 'fail', 'msg' => 'Sign is not valid']);
}

$success = !empty($data['is_final']) && ($data['status'] === 'paid' || $data['status'] === 'paid_over' || $data['status'] === 'wrong_amount');
if ($success) {
// $orderId = preg_replace('/^sspanel(?:_upd)?_/', '', $data['order_id'] ?? '');
$this->postPayment($additionalData['tradeno']);

return $response->withJson([
'ret' => 1,
'msg' => '支付成功',
]);
}

return $response->withJson(['state' => 'fail', 'msg' => 'Payment failed']);
}

/**
* @throws Exception
*/
public static function getPurchaseHTML(): string
{
return View::getSmarty()->fetch('gateway/cryptomus.tpl');
}

/**
* @return CryptomusPayment
* @throws \Exception
*/
private function getPayment(): CryptomusPayment
{
$merchantUuid = trim($this->cryptomus['cryptomus_uuid']);
$paymentKey = trim($this->cryptomus['cryptomus_api_key']);

if (!$merchantUuid && !$paymentKey) {
throw new Exception("Please fill UUID and API key");
}

return new CryptomusPayment($paymentKey, $merchantUuid);
}

/**
* @param $data
* @return bool
*/
private function hashEqual($data): bool
{
$paymentKey = trim($this->cryptomus['cryptomus_api_key']);

if (!$paymentKey) {
return false;
}

$signature = $data['sign'];
if (!$signature) {
return false;
}

unset($data['sign']);

$hash = md5(base64_encode(json_encode($data, JSON_UNESCAPED_UNICODE)) . $paymentKey);
if (!hash_equals($hash, $signature)) {
return false;
}

return true;
}
}
Loading

0 comments on commit 4a2f0d1

Please sign in to comment.