| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466 |
- <?php
- namespace App\Game\Services;
- use App\Game\GlobalUserInfo;
- use App\Http\helper\NumConfig;
- use App\Models\AccountsInfo;
- use App\Notification\TelegramBot;
- use App\Util;
- use GuzzleHttp\Client;
- use GuzzleHttp\Exception\RequestException;
- use Illuminate\Support\Facades\DB;
- use Illuminate\Support\Facades\Log;
- use Illuminate\Support\Facades\Redis;
- class LuckyStreakService
- {
- protected $client;
- protected $operatorId;
- protected $operatorName;
- protected $clientId;
- protected $clientSecret;
- protected $apiUrl;
- protected $currency;
- protected $hmacId;
- protected $hmacUser;
- protected $hmacKey;
- public function __construct()
- {
- $this->client = new Client();
- $this->currency = env('CONFIG_24680_CURRENCY');
- $this->operatorId = env('LUCKYSTREAK_OPERATOR_ID', '526');
- $this->operatorName = env('LUCKYSTREAK_OPERATOR_NAME', 'AEG');
- $this->clientId = env('LUCKYSTREAK_CLIENT_ID', 'AEG_operator');
- $this->clientSecret = env('LUCKYSTREAK_CLIENT_SECRET', 'X6vuibvYJI2Z9NglbzZE');
- $this->apiUrl = env('LUCKYSTREAK_API_URL', 'https://integ.livepbt.com');
- $this->hmacId = env('LUCKYSTREAK_HMAC_ID', 'AEG1');
- $this->hmacUser = env('LUCKYSTREAK_HMAC_USER', 'AEGhmac1');
- $this->hmacKey = env('LUCKYSTREAK_HMAC_KEY', 'WcVIR7szsyXNPstaY2JX');
- }
- public function callSubApi($username,$request)
- {
- Util::WriteLog('luckystreak_validate','callsubapi');
- $apiurl=ServerService::GetApiByGUID($username);
- try {
- // 获取当前请求的 GET 和 POST 数据
- // $getData = $request->query(); // 获取 GET 数据
- $postData = $request->post(); // 获取 POST 数据
- $response = $this->client->post( $apiurl . $_SERVER['REQUEST_URI'], [
- 'verify'=>false,
- // 'query' => $getData, // 传递 GET 数据
- 'form_params' => $postData, // 传递 POST 数据
- ]);
- $res=json_decode($response->getBody(),true);
- Util::WriteLog('luckystreak_validate',$res);
- return $res;
- } catch (RequestException $e) {
- return $this->handleRequestException($e);
- }
- }
- private function handleRequestException(\Exception $e)
- {
- // TelegramBot::getDefault()->sendMsgWithEnv($e->getMessage().$e->getTraceAsString());
- }
- /**
- * 获取授权令牌
- *
- * @return string|null
- */
- public function getAuthToken()
- {
- try {
- // 构建凭证字符串
- $credentialsBase = $this->operatorId . ':' . $this->clientId . ':' . $this->clientSecret;
- $credentials = base64_encode($credentialsBase);
- // 请求授权令牌
- $response = $this->client->post('https://integ-api-ids.livepbt.com/ids/connect/token', [
- 'verify' => false,
- 'headers' => [
- 'Content-Type' => 'application/x-www-form-urlencoded',
- 'Authorization'=>'Basic QUVHX29wZXJhdG9yOlg2dnVpYnZZSkkyWjlOZ2xielpF'
- ],
- 'form_params' => [
- 'grant_type' => 'operator_authorization',
- 'scope' => 'operator offline_access',
- 'operator_name' => 'AEG'
- ]
- ]);
- $result = json_decode($response->getBody(), true);
- $token = $result['access_token'] ?? null;
- if ($token) {
- // 缓存令牌一段时间以减少API调用
- $expiresIn = $result['expires_in'] ?? 3600;
- Redis::setex('luckystreak_token', $expiresIn - 60, $token);
- }
- return $token;
- } catch (\Exception $e) {
- Util::WriteLog('luckystreak_error', $e->getMessage());
- return null;
- }
- }
- /**
- * 获取缓存的令牌或请求新令牌
- *
- * @return string|null
- */
- public function getCachedAuthToken()
- {
- // 尝试从缓存获取令牌
- $token = Redis::get('luckystreak_token');
- // 如果缓存中没有令牌或令牌已过期,请求新令牌
- if (!$token) {
- $token = $this->getAuthToken();
- }
- return $token;
- }
- /**
- * 获取游戏列表
- *
- * @return array
- */
- public function getGamesList()
- {
- try {
- // 获取授权令牌
- $token = $this->getCachedAuthToken();
- if (!$token) {
- throw new \Exception("Failed to get authorization token");
- }
- // 调用游戏列表API
- $response = $this->client->post($this->apiUrl . '/lobby/api/v4/lobby/games', [
- 'verify' => false,
- 'headers' => [
- 'Authorization' => 'Bearer ' . $token,
- 'Content-Type' => 'application/json'
- ],
- 'json' => [
- 'data' => [
- 'Open' => true,
- 'GameTypes' => [],
- 'Currencies' => []
- ]
- ]
- ]);
- return json_decode($response->getBody(), true);
- } catch (\Exception $e) {
- Util::WriteLog('luckystreak_error', $e->getMessage());
- return ['error' => $e->getMessage()];
- }
- }
- public function getJackpot()
- {
- try {
- // 获取授权令牌
- $token = $this->getCachedAuthToken();
- if (!$token) {
- throw new \Exception("Failed to get authorization token");
- }
- // 调用游戏列表API
- $response = $this->client->post($this->apiUrl . '/lobby/api/v4/lobby/jackpots', [
- 'verify' => false,
- 'headers' => [
- 'Authorization' => 'Bearer ' . $token,
- 'Content-Type' => 'application/json'
- ],
- 'json' => [
- ]
- ]);
- return json_decode($response->getBody(), true);
- } catch (\Exception $e) {
- Util::WriteLog('luckystreak_error', $e->getMessage());
- return ['error' => $e->getMessage()];
- }
- }
- /**
- * 获取游戏启动URL的HTML
- *
- * @param string $gameId
- * @param string $globalUid
- * @param string $ipAddress
- * @param string $language
- * @return string
- */
- public function getLaunchURLHTML($gameId,$globalUid, $ipAddress, $language)
- {
- try {
- // 获取游戏类型(如果需要)
- $gameType = $this->getGameTypeById($gameId);
- // 使用GlobalUID作为AuthCode参数
- // 使用正确的启动URL格式
- $launchURL = "https://m.integ.livepbt.com/?PlayerName={$globalUid}&OperatorName=AEG&AuthCode={$globalUid}&GameId={$gameId}&GameType={$gameType}&LimitsGroupId=67efe1d102d4c16717303002";
- // 添加语言参数
- if ($language) {
- $launchURL .= "&language={$language}";
- }
- // 返回HTML重定向脚本
- return "<script>window.location.href='{$launchURL}';</script>";
- } catch (\Exception $e) {
- Util::WriteLog('luckystreak_error', $e->getMessage());
- return "<script>alert('System error: " . $e->getMessage() . "');</script>";
- }
- }
- /**
- * 根据游戏ID获取游戏类型
- *
- * @param string $gameId
- * @return string|null
- */
- private function getGameTypeById($gameId)
- {
- // 基本游戏类型映射
- $gameTypes = [
- '3' => 'Roulette',
- '4' => 'Blackjack',
- '2' => 'Baccarat',
- // 可以添加更多游戏类型映射
- ];
- return $gameTypes[$gameId] ?? null;
- }
- /**
- * 验证HMAC签名(用于出站请求)
- *
- * @param array $data
- * @param string $signature
- * @return bool
- */
- public function verifyHmacSignature($data, $signature)
- {
- // 根据LuckyStreak API文档实现HMAC验证逻辑
- // 按照文档附录B的规范实现
- // 1. 获取完整请求URL中的路径部分(不包含域名和查询参数)
- $path = $data['path'] ?? '';
- unset($data['path']);
- // 2. 获取请求方法
- $method = $data['method'] ?? 'POST';
- unset($data['method']);
- // 3. 获取请求时间戳
- $timestamp = $data['timestamp'] ?? '';
- if (empty($timestamp)) {
- return false;
- }
- unset($data['timestamp']);
- // 4. 获取随机nonce
- $nonce = $data['nonce'] ?? '';
- if (empty($nonce)) {
- return false;
- }
- unset($data['nonce']);
- // 获取ext和hash
- $ext = '';
- if (isset($data['ext'])) {
- $ext = $data['ext'];
- unset($data['ext']);
- }
- $hash = '';
- if (isset($data['hash'])) {
- $hash = $data['hash'];
- unset($data['hash']);
- }
- // 主机名和端口
- $host = isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : 'euapi.24680.org';
- $port = '443'; // 假设使用HTTPS
- // 5. 构建规范化请求字符串
- $normalized = "hawk.1.header\n" .
- $timestamp . "\n" .
- $nonce . "\n" .
- $method . "\n" .
- $path . "\n" .
- $host . "\n" .
- $port . "\n";
- // 6. 如果有请求体,添加请求体内容的哈希
- if (isset($data['body']) && !empty($data['body'])) {
- $body = $data['body'];
- // 如果是JSON字符串,尝试解码并重新编码,确保格式一致
- if (is_string($body) && json_decode($body) !== null) {
- $bodyObj = json_decode($body, true);
- if (is_array($bodyObj)) {
- $body = json_encode($bodyObj);
- }
- } elseif (is_array($body)) {
- $body = json_encode($body);
- }
- // 如果已提供的hash值,使用它
- if (!empty($hash)) {
- $normalized .= $hash . "\n";
- } else {
- // 否则计算body的hash
- $bodyHash = base64_encode(hash('sha256', $body, true));
- $normalized .= $bodyHash . "\n";
- }
- } else {
- $normalized .= "\n"; // 如果没有请求体,添加空行
- }
- // 7. 如果有ext,添加ext
- if (!empty($ext)) {
- $normalized .= $ext . "\n";
- } else {
- $normalized .= ''; // 如果没有ext,添加空字符串
- }
- // 8. 使用HMAC-SHA256生成签名
- $calculatedSignature = base64_encode(hash_hmac('sha256', $normalized, $this->hmacKey, true));
- // 9. 比较签名
- // Util::WriteLog('luckystreak_hmac', [
- // 'normalized' => $normalized,
- // 'calculated' => $calculatedSignature,
- // 'received' => $signature,
- // 'hmacKey' => $this->hmacKey
- // ]);
- return $signature === $calculatedSignature;
- }
- public function generateHmacSignature($data, $body = null)
- {
- // $data=['path' => '',
- // 'method' => '',
- // 'timestamp' => '',
- // 'nonce' => ''];
- // 生成时间戳(毫秒级)
- // $timestamp = (string)round(microtime(true) * 1000);
- // 生成随机nonce
- // $nonce = uniqid('', true);
- extract($data);
- // 主机名和端口
- $host = isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : 'euapi.24680.org';
- $port = '443'; // 假设使用HTTPS
- // 请求标识符 (根据文档使用hawk.1.response)
- $type = "hawk.1.response";
- // 构建规范化请求字符串
- $normalized = $type . "\n" .
- $timestamp . "\n" .
- $nonce . "\n" .
- $method . "\n" .
- $path . "\n" .
- $host . "\n" .
- $port . "\n";
- // 如果有请求体,添加请求体的哈希
- $bodyHash = '';
- if (!empty($body)&&false) {
- // 如果是JSON字符串,尝试解码并重新编码,确保格式一致
- if (is_string($body) && json_decode($body) !== null) {
- $bodyObj = json_decode($body, true);
- if (is_array($bodyObj)) {
- $body = json_encode($bodyObj);
- }
- } elseif (is_array($body)) {
- $body = json_encode($body);
- }
- $bodyHash = base64_encode(hash('sha256', $body, true));
- $normalized .= $bodyHash . "\n";
- } else {
- $normalized .= "\n"; // 如果没有请求体,添加空行
- }
- // 添加ext(根据文档使用X-Request-Header-To-Protect:secret)
- $ext = "X-Request-Header-To-Protect:secret";
- $normalized .= $ext ."\n";
- // 使用HMAC-SHA256生成签名
- $signature = base64_encode(hash_hmac('sha256', $normalized, $this->hmacKey, true));
- // Util::WriteLog('luckystreak_hmac', [
- // 'normalized' => $normalized,
- // 'signature' => $signature,
- // 'body' => $body,
- // 'bodyHash' => $bodyHash,
- // 'header'=>[ 'Server-Authorization' => 'hawk mac="' . $signature . '", ext="' . $ext . '"']
- // ]);
- // 返回Server-Authorization头(根据文档)
- return [
- 'Server-Authorization' => 'hawk mac="' . $signature . '", ext="' . $ext . '"'
- ];
- }
- /**
- * 获取第三方游戏提供商游戏列表
- *
- * @return array
- */
- public function getProviderGamesList()
- {
- try {
- // 获取授权令牌
- $token = $this->getCachedAuthToken();
- if (!$token) {
- throw new \Exception("Failed to get authorization token");
- }
- // 调用Provider游戏列表API
- $response = $this->client->post($this->apiUrl . '/lobby/api/v4/lobby/providergames', [
- 'verify' => false,
- 'headers' => [
- 'Authorization' => 'Bearer ' . $token,
- 'Content-Type' => 'application/json'
- ],
- 'json' => [
- 'data' => [
- 'Open' => true,
- 'GameTypes' => [],
- 'Currencies' => []
- ]
- ]
- ]);
- return json_decode($response->getBody(), true);
- } catch (\Exception $e) {
- Util::WriteLog('luckystreak_error', $e->getMessage());
- return ['error' => $e->getMessage()];
- }
- }
- }
|