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 "";
} catch (\Exception $e) {
Util::WriteLog('luckystreak_error', $e->getMessage());
return "";
}
}
/**
* 根据游戏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()];
}
}
}