182 lines
6.3 KiB
PHP
182 lines
6.3 KiB
PHP
<?php
|
|
declare(strict_types=1);
|
|
|
|
/**
|
|
* Google OAuth — แลก authorization code เป็นข้อมูลผู้ใช้ แล้วสร้าง/อัปเดตบัญชี loginType=google
|
|
*
|
|
* POST JSON: { code, redirectUri, state?, mergeGuestKey? }
|
|
*/
|
|
require __DIR__ . '/_common.php';
|
|
require __DIR__ . '/_player_account.php';
|
|
|
|
if (($_SERVER['REQUEST_METHOD'] ?? 'GET') !== 'POST') {
|
|
json_response(['ok' => false, 'error' => 'Use POST'], 405);
|
|
}
|
|
|
|
$body = require_json_body();
|
|
$code = trim((string) ($body['code'] ?? ''));
|
|
$redirectUri = trim((string) ($body['redirectUri'] ?? ''));
|
|
$mergeGuestKey = trim((string) ($body['mergeGuestKey'] ?? ''));
|
|
|
|
if ($code === '') {
|
|
json_response(['ok' => false, 'error' => 'missing code'], 400);
|
|
}
|
|
|
|
$oauth = read_store()['oauth'] ?? [];
|
|
$clientId = trim((string) ($oauth['googleClientId'] ?? ''));
|
|
$clientSecret = trim((string) ($oauth['googleClientSecret'] ?? ''));
|
|
$configuredRedirect = trim((string) ($oauth['googleRedirectUri'] ?? ''));
|
|
|
|
if ($clientId === '' || $clientSecret === '') {
|
|
json_response(['ok' => false, 'error' => 'ยังไม่ได้ตั้งค่า Google OAuth ใน Admin'], 503);
|
|
}
|
|
|
|
if ($redirectUri === '') {
|
|
$redirectUri = $configuredRedirect;
|
|
}
|
|
if ($redirectUri === '') {
|
|
json_response(['ok' => false, 'error' => 'missing redirectUri'], 400);
|
|
}
|
|
|
|
if ($configuredRedirect !== '' && $redirectUri !== $configuredRedirect) {
|
|
json_response(['ok' => false, 'error' => 'redirectUri ไม่ตรงกับที่ตั้งใน Admin'], 400);
|
|
}
|
|
|
|
if (!function_exists('curl_init')) {
|
|
json_response(['ok' => false, 'error' => 'PHP cURL ไม่พร้อมใช้งาน'], 500);
|
|
}
|
|
|
|
$tokenPayload = http_build_query([
|
|
'code' => $code,
|
|
'client_id' => $clientId,
|
|
'client_secret' => $clientSecret,
|
|
'redirect_uri' => $redirectUri,
|
|
'grant_type' => 'authorization_code',
|
|
]);
|
|
|
|
$ch = curl_init('https://oauth2.googleapis.com/token');
|
|
curl_setopt_array($ch, [
|
|
CURLOPT_POST => true,
|
|
CURLOPT_POSTFIELDS => $tokenPayload,
|
|
CURLOPT_RETURNTRANSFER => true,
|
|
CURLOPT_HTTPHEADER => ['Content-Type: application/x-www-form-urlencoded'],
|
|
CURLOPT_TIMEOUT => 20,
|
|
]);
|
|
$tokenRaw = curl_exec($ch);
|
|
$tokenHttp = (int) curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
|
curl_close($ch);
|
|
|
|
$tokenJson = json_decode((string) $tokenRaw, true);
|
|
if ($tokenHttp < 200 || $tokenHttp >= 300 || !is_array($tokenJson)) {
|
|
json_response(['ok' => false, 'error' => 'แลก token จาก Google ไม่สำเร็จ', 'detail' => (string) $tokenRaw], 502);
|
|
}
|
|
|
|
$accessToken = trim((string) ($tokenJson['access_token'] ?? ''));
|
|
if ($accessToken === '') {
|
|
json_response(['ok' => false, 'error' => 'Google ไม่คืน access_token', 'detail' => $tokenJson], 502);
|
|
}
|
|
|
|
$ch2 = curl_init('https://www.googleapis.com/oauth2/v3/userinfo');
|
|
curl_setopt_array($ch2, [
|
|
CURLOPT_RETURNTRANSFER => true,
|
|
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $accessToken],
|
|
CURLOPT_TIMEOUT => 20,
|
|
]);
|
|
$userRaw = curl_exec($ch2);
|
|
$userHttp = (int) curl_getinfo($ch2, CURLINFO_HTTP_CODE);
|
|
curl_close($ch2);
|
|
|
|
$user = json_decode((string) $userRaw, true);
|
|
if ($userHttp < 200 || $userHttp >= 300 || !is_array($user)) {
|
|
json_response(['ok' => false, 'error' => 'อ่านข้อมูลผู้ใช้จาก Google ไม่สำเร็จ'], 502);
|
|
}
|
|
|
|
$googleSub = trim((string) ($user['sub'] ?? ''));
|
|
if ($googleSub === '') {
|
|
json_response(['ok' => false, 'error' => 'Google ไม่คืน sub (user id)'], 502);
|
|
}
|
|
|
|
$playerKey = google_player_key($googleSub);
|
|
if (!valid_player_key($playerKey)) {
|
|
json_response(['ok' => false, 'error' => 'playerKey จาก Google ไม่ถูกต้อง'], 500);
|
|
}
|
|
|
|
$email = trim((string) ($user['email'] ?? ''));
|
|
$name = trim((string) ($user['name'] ?? ''));
|
|
if ($name === '') {
|
|
$name = trim((string) ($user['given_name'] ?? ''));
|
|
}
|
|
if ($name === '') {
|
|
$name = $email !== '' ? preg_replace('/@.*$/', '', $email) : 'Google Player';
|
|
}
|
|
if (function_exists('mb_substr')) {
|
|
$name = mb_substr($name, 0, 32);
|
|
} else {
|
|
$name = substr($name, 0, 32);
|
|
}
|
|
|
|
$picture = trim((string) ($user['picture'] ?? ''));
|
|
$now = gmdate('c');
|
|
|
|
$store = read_store();
|
|
if (!isset($store['accounts']) || !is_array($store['accounts'])) {
|
|
$store['accounts'] = [];
|
|
}
|
|
|
|
$idx = find_account_index_by_player_key($store['accounts'], $playerKey);
|
|
$isNew = $idx < 0;
|
|
|
|
if ($idx < 0) {
|
|
$store['accounts'][] = [
|
|
'id' => new_id(),
|
|
'email' => $email,
|
|
'displayName' => $name,
|
|
'loginType' => 'google',
|
|
'providerUserId' => $playerKey,
|
|
'googleSub' => $googleSub,
|
|
'avatarUrl' => $picture,
|
|
'notes' => 'oauth: google',
|
|
'blocked' => false,
|
|
'coins' => 0,
|
|
'createdAt' => $now,
|
|
'updatedAt' => $now,
|
|
];
|
|
$idx = count($store['accounts']) - 1;
|
|
} else {
|
|
$store['accounts'][$idx]['loginType'] = 'google';
|
|
$store['accounts'][$idx]['email'] = $email !== '' ? $email : ($store['accounts'][$idx]['email'] ?? '');
|
|
if ($name !== '') {
|
|
$store['accounts'][$idx]['displayName'] = $name;
|
|
}
|
|
$store['accounts'][$idx]['googleSub'] = $googleSub;
|
|
if ($picture !== '') {
|
|
$store['accounts'][$idx]['avatarUrl'] = $picture;
|
|
}
|
|
$store['accounts'][$idx]['updatedAt'] = $now;
|
|
}
|
|
|
|
if (!empty($store['accounts'][$idx]['blocked'])) {
|
|
json_response(['ok' => false, 'error' => 'บัญชีนี้ถูกระงับ'], 403);
|
|
}
|
|
|
|
if ($isNew && $mergeGuestKey !== '') {
|
|
merge_guest_account_into($store, $idx, $mergeGuestKey);
|
|
}
|
|
|
|
if (!write_store($store)) {
|
|
json_response(['ok' => false, 'error' => 'บันทึกบัญชีไม่สำเร็จ'], 500);
|
|
}
|
|
|
|
$acc = $store['accounts'][$idx] ?? [];
|
|
json_response([
|
|
'ok' => true,
|
|
'playerKey' => $playerKey,
|
|
'loginType' => 'google',
|
|
'displayName' => (string) ($acc['displayName'] ?? $name),
|
|
'email' => (string) ($acc['email'] ?? $email),
|
|
'avatarUrl' => (string) ($acc['avatarUrl'] ?? $picture),
|
|
'coins' => max(0, (int) ($acc['coins'] ?? 0)),
|
|
'accountId' => (string) ($acc['id'] ?? ''),
|
|
'isNew' => $isNew,
|
|
]);
|