Compare commits
2 commits
cc92d67c05
...
d95d78f5a2
| Author | SHA1 | Date | |
|---|---|---|---|
| d95d78f5a2 | |||
| 0393ab8b89 |
7 changed files with 96 additions and 22 deletions
16
.idea/php.xml
generated
16
.idea/php.xml
generated
|
|
@ -1,5 +1,15 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="MessDetectorOptionsConfiguration">
|
||||
<option name="transferred" value="true" />
|
||||
</component>
|
||||
<component name="PHPCSFixerOptionsConfiguration">
|
||||
<option name="transferred" value="true" />
|
||||
</component>
|
||||
<component name="PHPCodeSnifferOptionsConfiguration">
|
||||
<option name="highlightLevel" value="WARNING" />
|
||||
<option name="transferred" value="true" />
|
||||
</component>
|
||||
<component name="PhpIncludePathManager">
|
||||
<include_path>
|
||||
<path value="$PROJECT_DIR$/vendor/composer" />
|
||||
|
|
@ -17,9 +27,15 @@
|
|||
</include_path>
|
||||
</component>
|
||||
<component name="PhpProjectSharedConfiguration" php_language_level="8.1" />
|
||||
<component name="PhpStanOptionsConfiguration">
|
||||
<option name="transferred" value="true" />
|
||||
</component>
|
||||
<component name="PhpUnit">
|
||||
<phpunit_settings>
|
||||
<PhpUnitSettings custom_loader_path="$PROJECT_DIR$/vendor/autoload.php" />
|
||||
</phpunit_settings>
|
||||
</component>
|
||||
<component name="PsalmOptionsConfiguration">
|
||||
<option name="transferred" value="true" />
|
||||
</component>
|
||||
</project>
|
||||
38
app/App.php
38
app/App.php
|
|
@ -21,14 +21,14 @@ class App
|
|||
public static function getTemplate(): Engine
|
||||
{
|
||||
static $templates = new Engine(__DIR__ . '/../templates');
|
||||
$me = self::me();
|
||||
$isLogin = self::checkU();
|
||||
$me = static::me();
|
||||
$isLogin = static::checkU();
|
||||
$templates->addData([
|
||||
'me' => $me,
|
||||
'whoami' => "$me->username#$me->userDiscriminator",
|
||||
'noStatus' => false,
|
||||
'isLogin' => $isLogin,
|
||||
'isAllowed' => $isLogin && $me !== null && self::isAllowed($me->userId),
|
||||
'isAllowed' => $isLogin && $me !== null && static::isAllowed($me->userId),
|
||||
]);
|
||||
return $templates;
|
||||
}
|
||||
|
|
@ -40,10 +40,10 @@ class App
|
|||
|
||||
public static function checkU(): bool
|
||||
{
|
||||
$token = self::getU();
|
||||
$token = static::getU();
|
||||
if ($token === null) return false;
|
||||
if ($token->timestamp + $token->expires_in < time()) return false;
|
||||
return self::me() !== null;
|
||||
return static::me() !== null;
|
||||
}
|
||||
|
||||
public static function setU(Token $token): void
|
||||
|
|
@ -80,7 +80,7 @@ class App
|
|||
|
||||
public static function requireAuth(): void
|
||||
{
|
||||
if (!self::checkU()) {
|
||||
if (!static::checkU()) {
|
||||
header('location: /login.php');
|
||||
http_response_code(302);
|
||||
exit;
|
||||
|
|
@ -89,7 +89,7 @@ class App
|
|||
|
||||
public static function requireNonAuth(): void
|
||||
{
|
||||
if (self::checkU()) {
|
||||
if (static::checkU()) {
|
||||
header('location: /');
|
||||
http_response_code(302);
|
||||
exit;
|
||||
|
|
@ -98,10 +98,10 @@ class App
|
|||
|
||||
public static function requireAllowed(): void
|
||||
{
|
||||
self::requireAuth();
|
||||
$me = self::me();
|
||||
if ($me === null || !self::isAllowed($me->userId)) {
|
||||
self::template([
|
||||
static::requireAuth();
|
||||
$me = static::me();
|
||||
if ($me === null || !static::isAllowed($me->userId)) {
|
||||
static::template([
|
||||
'title' => '您無權限使用本系統',
|
||||
'body' => <<<HTML
|
||||
<div class="mt-5">
|
||||
|
|
@ -117,7 +117,7 @@ HTML,
|
|||
{
|
||||
try {
|
||||
$token = Auth::getTokenByCode($code);
|
||||
if ($token !== null) self::setU($token);
|
||||
if ($token !== null) static::setU($token);
|
||||
} catch (Exception) {
|
||||
error_log('Failed to getTokenByCode.');
|
||||
}
|
||||
|
|
@ -126,9 +126,11 @@ HTML,
|
|||
public static function me(): ?Me
|
||||
{
|
||||
try {
|
||||
$u = self::getU();
|
||||
$u = static::getU();
|
||||
if ($u === null) return null;
|
||||
return Auth::getMe($u);
|
||||
$cachedMe = Redis::getCachedMe($_COOKIE['u']);
|
||||
if ($cachedMe === null) return Redis::cacheMe($_COOKIE['u'], Auth::getMe($u));
|
||||
return $cachedMe;
|
||||
} catch (Exception) {
|
||||
error_log('Failed to getMe.');
|
||||
return null;
|
||||
|
|
@ -139,8 +141,8 @@ HTML,
|
|||
public static function template(array $params): void
|
||||
{
|
||||
$status = '';
|
||||
if (self::checkU() && !$params['no_status']) {
|
||||
$me = self::me();
|
||||
if (static::checkU() && !$params['no_status']) {
|
||||
$me = static::me();
|
||||
$status = <<<HTML
|
||||
<div>您已使用 <code>$me->username#$me->userDiscriminator</code> 登入,點選此處以<a href="/logout.php">登出系統</a>。</div>
|
||||
HTML;
|
||||
|
|
@ -181,13 +183,13 @@ HTML;
|
|||
|
||||
public static function isAllowed(string $userId): bool
|
||||
{
|
||||
return in_array($userId, self::allowedUsers);
|
||||
return in_array($userId, static::allowedUsers);
|
||||
}
|
||||
|
||||
#[NoReturn]
|
||||
public static function render(string $name, array $data = []): void
|
||||
{
|
||||
$html = self::getTemplate()->render($name, $data);
|
||||
$html = static::getTemplate()->render($name, $data);
|
||||
|
||||
header('Content-Type: text/html; charset=utf-8');
|
||||
header('Content-Length: ' . strlen($html));
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ class Auth
|
|||
{
|
||||
$query_string = http_build_query([
|
||||
'client_id' => $_ENV['DISCORD_CLIENT_ID'],
|
||||
'redirect_uri' => self::DISCORD_REDIRECT_URI,
|
||||
'redirect_uri' => static::DISCORD_REDIRECT_URI,
|
||||
'response_type' => 'code',
|
||||
'scope' => 'identify',
|
||||
]);
|
||||
|
|
@ -60,7 +60,7 @@ class Auth
|
|||
'client_secret' => $_ENV['DISCORD_CLIENT_SECRET'],
|
||||
'grant_type' => 'authorization_code',
|
||||
'code' => $code,
|
||||
'redirect_uri' => self::DISCORD_REDIRECT_URI,
|
||||
'redirect_uri' => static::DISCORD_REDIRECT_URI,
|
||||
]),
|
||||
],
|
||||
])));
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ abstract class FileViewer
|
|||
$directory = static::directory();
|
||||
$filename = "$directory/$file";
|
||||
|
||||
if (!in_array($file, self::list()) || !file_exists($filename) || !is_file($filename)) return null;
|
||||
if (!in_array($file, static::list()) || !file_exists($filename) || !is_file($filename)) return null;
|
||||
|
||||
$extension = pathinfo($filename, PATHINFO_EXTENSION);
|
||||
$content = file_get_contents($filename);
|
||||
|
|
|
|||
54
app/Redis.php
Normal file
54
app/Redis.php
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
<?php
|
||||
|
||||
namespace MingTsay\Akanyan;
|
||||
|
||||
use MingTsay\Akanyan\Discord\Me;
|
||||
|
||||
require_once __DIR__ . '/../env.php';
|
||||
|
||||
class Redis
|
||||
{
|
||||
public const PREFIX = 'akanyan:discord:me:';
|
||||
public const TTL = 600; // 10 minutes
|
||||
protected static ?\Redis $redis = null;
|
||||
|
||||
/**
|
||||
* @throws \RedisException
|
||||
*/
|
||||
protected static function connect(): \Redis
|
||||
{
|
||||
if (static::$redis === null) {
|
||||
static::$redis = new \Redis();
|
||||
static::$redis->connect('127.0.0.1');
|
||||
}
|
||||
return static::$redis;
|
||||
}
|
||||
|
||||
protected static function getKey(string $u): string
|
||||
{
|
||||
return static::PREFIX . md5($u);
|
||||
}
|
||||
|
||||
public static function getCachedMe(string $u): ?Me
|
||||
{
|
||||
try {
|
||||
$redis = static::connect();
|
||||
return unserialize($redis->get(static::getKey($u))) ?: null;
|
||||
} catch (\RedisException $e) {
|
||||
trigger_error($e->getMessage());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static function cacheMe(string $u, ?Me $me): ?Me
|
||||
{
|
||||
try {
|
||||
$redis = static::connect();
|
||||
$redis->setEx(static::getKey($u), static::TTL, serialize($me));
|
||||
return $me;
|
||||
} catch (\RedisException $e) {
|
||||
trigger_error($e->getMessage());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -11,6 +11,7 @@
|
|||
],
|
||||
"require": {
|
||||
"ext-iconv": "*",
|
||||
"ext-redis": "*",
|
||||
"ext-sodium": "*",
|
||||
"ext-zlib": "*",
|
||||
"components/font-awesome": "^6.1",
|
||||
|
|
|
|||
3
composer.lock
generated
3
composer.lock
generated
|
|
@ -4,7 +4,7 @@
|
|||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "528c716c3d44b77191eaef0461fe108d",
|
||||
"content-hash": "94e36763cae319a07395535f9c2373eb",
|
||||
"packages": [
|
||||
{
|
||||
"name": "components/font-awesome",
|
||||
|
|
@ -734,6 +734,7 @@
|
|||
"prefer-lowest": false,
|
||||
"platform": {
|
||||
"ext-iconv": "*",
|
||||
"ext-redis": "*",
|
||||
"ext-sodium": "*",
|
||||
"ext-zlib": "*"
|
||||
},
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue