자동 로그인 구현 - login_token 테이블 - reqNonce -> loginByToken - sha512(token + nonce) Reviewed-on: https://storage.hided.net/gitea/devsam/core/pulls/196 Co-authored-by: hide_d <hided62@gmail.com> Co-committed-by: hide_d <hided62@gmail.com>
104 lines
3.8 KiB
PHP
104 lines
3.8 KiB
PHP
<?php
|
|
|
|
namespace sammo;
|
|
|
|
class APIHelper
|
|
{
|
|
private function __construct()
|
|
{
|
|
//static only
|
|
}
|
|
|
|
public static function launch(string $rootPath)
|
|
{
|
|
//TODO: path를 php://input에서 받는게 아니라 api.php?~~~~~ 로 받아오는것이 etag 캐시 측면에서 훨씬 나을 듯!
|
|
try {
|
|
$rawInput = file_get_contents('php://input');
|
|
$input = Json::decode($rawInput);
|
|
} catch (\Exception $e) {
|
|
Json::dieWithReason($e->getMessage());
|
|
}
|
|
|
|
if(!$input){
|
|
Json::dieWithReason("input이 비어있습니다. {$rawInput}");
|
|
}
|
|
|
|
if (!key_exists('path', $input)) {
|
|
Json::dieWithReason('path가 지정되지 않았습니다.');
|
|
}
|
|
|
|
if (key_exists('args', $input) && !is_array($input['args'])) {
|
|
Json::dieWithReason('args가 array가 아닙니다.' . gettype($input['args']));
|
|
}
|
|
|
|
try {
|
|
$obj = buildAPIExecutorClass($input['path'], $rootPath, $input['args'] ?? []);
|
|
$validateResult = $obj->validateArgs();
|
|
if ($validateResult !== null) {
|
|
Json::dieWithReason($validateResult);
|
|
}
|
|
|
|
$sessionMode = $obj->getRequiredSessionMode();
|
|
if ($sessionMode === BaseAPI::NO_SESSION) {
|
|
$session = Session::getInstance();//XXX: NoSession이면 진짜 NoSession이어야..?
|
|
} else {
|
|
if ($sessionMode & BaseAPI::REQ_GAME_LOGIN) {
|
|
$session = Session::requireGameLogin();
|
|
} else if ($sessionMode & BaseAPI::REQ_LOGIN) {
|
|
$session = Session::requireLogin();
|
|
} else {
|
|
Json::dieWithReason("올바르지 않은 SessionMode: {$sessionMode}");
|
|
}
|
|
|
|
if ($sessionMode & BaseAPI::REQ_READ_ONLY) {
|
|
$session->setReadOnly();
|
|
}
|
|
}
|
|
|
|
$modifiedSince = isset($_SERVER['HTTP_IF_MODIFIED_SINCE'])
|
|
? new \DateTimeImmutable($_SERVER['HTTP_IF_MODIFIED_SINCE'], new \DateTimeZone("UTC"))
|
|
: null;
|
|
$reqEtags = isset($_SERVER['HTTP_IF_NONE_MATCH']) ? trim($_SERVER['HTTP_IF_NONE_MATCH']) : null;
|
|
|
|
$result = $obj->launch($session, $modifiedSince, $reqEtags);
|
|
if (is_string($result)) {
|
|
Json::dieWithReason($result);
|
|
}
|
|
|
|
$cacheResult = $obj->tryCache();
|
|
if ($cacheResult !== null) {
|
|
/** @var \DateTimeInterface $lastModified */
|
|
[$lastModified, $etag] = $cacheResult;
|
|
|
|
if ($lastModified !== null) {
|
|
header("Last-Modified: " . gmdate("D, d M Y H:i:s", Util::toInt(TimeUtil::DateTimeToSeconds($lastModified, true))) . " GMT");
|
|
}
|
|
if ($etag !== null) {
|
|
header("Etag: $etag");
|
|
}
|
|
|
|
if ($modifiedSince !== null && $lastModified !== null && TimeUtil::DateIntervalToSeconds($modifiedSince->diff($lastModified)) == 0) {
|
|
header("HTTP/1.1 304 Not Modified");
|
|
die();
|
|
}
|
|
if ($reqEtags !== null && $reqEtags === $etag) {
|
|
header("HTTP/1.1 304 Not Modified");
|
|
die();
|
|
}
|
|
}
|
|
|
|
if ($result === null) {
|
|
Json::die([
|
|
'result' => true,
|
|
'reason' => 'success'
|
|
], $cacheResult === null ? Json::NO_CACHE : 0);
|
|
}
|
|
Json::die($result, $cacheResult === null ? Json::NO_CACHE : 0);
|
|
} catch (\Throwable $e) {
|
|
Json::dieWithReason($e->getMessage());
|
|
} catch (mixed $e) {
|
|
Json::dieWithReason(strval($e));
|
|
}
|
|
}
|
|
}
|