Skip to content
This repository has been archived by the owner on Nov 2, 2020. It is now read-only.

Commit

Permalink
style(Redis): rewrite namespace of cache keys
Browse files Browse the repository at this point in the history
  • Loading branch information
Rhilip committed Aug 14, 2019
1 parent da1d9a7 commit 0c4e1a2
Show file tree
Hide file tree
Showing 11 changed files with 54 additions and 110 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
### Refactor
- **Auth/JWT:** Better for auth by JWT (36f49a0)
- **Auth/Middleware:** merge Old Auth{ByCookies, ByPasskey}Middleware (71cd7d7)
- **Config:** Add define of config key type and can add runtime config (d57aede)
- **Config:** Remove params `$throw` in Config()->get() (706cc9a)
- **RateLimit:** Change last param of isRateLimitHit and rate limit store Namespace (4dd571d)
- **Site:** Simple Category Detail get function (ffa6855)
Expand Down
2 changes: 1 addition & 1 deletion apps/components/Site.php
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,6 @@ public function rulePinnedTags(): array

public static function fetchUserCount(): int
{
return app()->pdo->createCommand("SELECT COUNT(`id`) FROM `users`")->queryScalar();
return app()->pdo->createCommand('SELECT COUNT(`id`) FROM `users`')->queryScalar();
}
}
2 changes: 1 addition & 1 deletion apps/config/http_base.php
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@
// 类路径
'class' => Rid\Http\Session::class,
// 保存的Key前缀
'saveKeyPrefix' => 'SESSION:',
'saveKeyPrefix' => 'Session:',
// 生存时间
'maxLifetime' => 7200,
// session键名
Expand Down
2 changes: 1 addition & 1 deletion apps/controllers/AuthController.php
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ public function actionRecover()

public function actionLogin()
{
$test_attempts = app()->redis->hGet('SITE:fail_login_ip_count', app()->request->getClientIp()) ?: 0;
$test_attempts = app()->redis->hGet('Site:fail_login_ip_count', app()->request->getClientIp()) ?: 0;
$left_attempts = config('security.max_login_attempts') - $test_attempts;

if (app()->request->isPost()) {
Expand Down
60 changes: 23 additions & 37 deletions apps/controllers/TrackerController.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,18 @@

use apps\exceptions\TrackerException;

/** @noinspection PhpUnused */
class TrackerController
{
protected $timenow;

/** The Black List of Announce Port
* See more : https://www.speedguide.net/port.php or other website
/**
* The Black List of Announce Port
*
* @var array
* @see https://www.speedguide.net/port.php or other website
*/
protected $portBlacklist = [
const portBlacklist = [
22, // SSH Port
53, // DNS queries
80, 81, 8080, 8081, // Hyper Text Transfer Protocol (HTTP) - port used for web traffic
Expand Down Expand Up @@ -150,17 +152,16 @@ public function actionIndex()

protected function logException(\Exception $exception, $userInfo = null, $torrentInfo = null)
{
$raw_header = "";
$req_info = app()->request->server('query_string') . "\n\n";
foreach (app()->request->header() as $key => $value) {
$raw_header .= "$key : $value \n";
$req_info .= "$key : $value \n";
}
$req_info = app()->request->server('query_string') . "\n\n" . $raw_header;

app()->pdo->createCommand("INSERT INTO `agent_deny_log`(`tid`, `uid`, `user_agent`, `peer_id`, `req_info`,`create_at`, `msg`)
app()->pdo->createCommand('INSERT INTO `agent_deny_log`(`tid`, `uid`, `user_agent`, `peer_id`, `req_info`,`create_at`, `msg`)
VALUES (:tid,:uid,:ua,:peer_id,:req_info,CURRENT_TIMESTAMP,:msg)
ON DUPLICATE KEY UPDATE `user_agent` = VALUES(`user_agent`),`peer_id` = VALUES(`peer_id`),
`req_info` = VALUES(`req_info`),`msg` = VALUES(`msg`),
`last_action_at` = NOW();")->bindParams([
`last_action_at` = NOW();')->bindParams([
'tid' => $torrentInfo ? $torrentInfo['id'] : 0,
'uid' => $userInfo ? $userInfo['id'] : 0,
'ua' => app()->request->header('user-agent', ''),
Expand All @@ -186,6 +187,8 @@ private function blockClient()
/**
* This header check may block Non-bittorrent client `Aria2` to access tracker,
* Because they always add this header which other clients don't have.
*
* @see https://blog.rhilip.info/archives/1010/ ( in Chinese )
*/
|| app()->request->header('want-digest')

Expand All @@ -200,7 +203,7 @@ private function blockClient()
* The Cloudflare will add `__cfduid` Cookies to identify individual clients behind a shared IP address
* and apply security settings on a per-client basis.
*
* See more on : https://support.cloudflare.com/hc/en-us/articles/200170156
* @see https://support.cloudflare.com/hc/en-us/articles/200170156
*
*/
//|| app()->request->header('cookie')
Expand All @@ -214,7 +217,7 @@ private function blockClient()
throw new TrackerException(123);

// Block Browser by check it's User-Agent
if (preg_match('/(^Mozilla|Browser|AppleWebKit|^Opera|^Links|^Lynx|[Bb]ot)/', $ua)) {
if (preg_match('/(Mozilla|Browser|Chrome|Safari|AppleWebKit|Opera|Links|Lynx|[Bb]ot)/', $ua)) {
throw new TrackerException(121);
}
}
Expand All @@ -228,24 +231,10 @@ private function checkUserAgent(bool $onlyCheckUA = false)
// Start Check Client by `User-Agent` and `peer_id`
$userAgent = app()->request->header('user-agent');
$peer_id = app()->request->get('peer_id', '');

/**
* if this user-agent and peer_id already checked valid or not?
*
* By default, We use a Redis ZSet to cache the valid value of $client_identity with it score
* is expired timestamp (which ttl is 3600 - 7200 s, So it can be cleanup), to prevent too large key.
*
* However , If you enable the extra Redis Extension `Bloom Filter` : the ReBloom module
* You can manually change it to the code which is commented out to get better performance
*
*/
$client_identity = $userAgent . ($onlyCheckUA ? '' : ':' . $peer_id);

/* Check in Redis ZSet */
if (app()->redis->zScore(Constant::trackerValidClientZset, $client_identity) !== false) return;

/* Check with Redis ReBloom module */
// if (app()->redis->rawCommand('bf.exists', [Constant::trackerValidClientZset, $client_identity])) return;
// if this user-agent and peer_id already checked valid or not ?
if (app()->redis->zScore(Constant::trackerValidClientZset, $client_identity) > 0) return;

// Get Client White List From Database and cache it
if (false === $allowedFamily = app()->redis->get(Constant::trackerAllowedClientList)) {
Expand Down Expand Up @@ -355,7 +344,6 @@ private function checkUserAgent(bool $onlyCheckUA = false)
if ($onlyCheckUA) {
if (!$agentAccepted) throw new TrackerException(126, [':ua' => $userAgent]);
app()->redis->zAdd(Constant::trackerValidClientZset, time() + rand(7200, 18000), $client_identity);
// app()->redis->rawCommand('bf.add', [Constant::trackerValidClientZset, $client_identity]);
return;
}

Expand Down Expand Up @@ -395,7 +383,7 @@ private function checkPasskey(&$userInfo)
if (is_null($passkey))
throw new TrackerException(130, [':attribute' => 'passkey']);
if (strlen($passkey) != 32)
throw new TrackerException(132, [':attribute' => 'passkey', ':rule' => '32']);
throw new TrackerException(132, [':attribute' => 'passkey', ':rule' => 32]);
if (strspn(strtolower($passkey), 'abcdef0123456789') != 32)
throw new TrackerException(131, [':attribute' => 'passkey', ':reason' => 'The format of passkey isn\'t correct']);

Expand All @@ -413,7 +401,7 @@ private function checkPasskey(&$userInfo)
throw new TrackerException(140);
}

app()->redis->setex(Constant::trackerUserContentByPasskey($passkey), 3600 + rand(0, 30), $userInfo);
app()->redis->set(Constant::trackerUserContentByPasskey($passkey), $userInfo, 3600 + rand(0, 30));
}

/**
Expand All @@ -433,13 +421,11 @@ private function checkPasskey(&$userInfo)
* @return array|bool return the required field of torrent info by it's info_hash , or false when this info_hash is
* invalid (Not exist in our database or this status is 'deleted'
*/
private function getTorrentInfoByHash($hash, $scrape = false)
private function getTorrentInfoByHash($hash, bool $scrape = false)
{
$bin2hex_hash = bin2hex($hash);

/**
* If this torrent info_hash is exist in invalid set. (Worked as `Bloom Filter`
*/
// If this torrent info_hash is exist in invalid set. (Worked as `Bloom Filter`
if (app()->redis->zScore(Constant::trackerInvalidInfoHashZset, $bin2hex_hash) !== false) return false;

$cache_key = Constant::trackerTorrentContentByInfoHash($bin2hex_hash);
Expand All @@ -448,8 +434,8 @@ private function getTorrentInfoByHash($hash, $scrape = false)

$exist = app()->redis->exists($cache_key);
if ($exist === 0) { // This cache key is not exist , get it's information from db and then cache it
$torrentInfo = app()->pdo->createCommand("SELECT `id`, `info_hash`, `owner_id`, `status`, `incomplete`, `complete`, `downloaded`, `added_at` FROM `torrents` WHERE `info_hash` = :info LIMIT 1")
->bindParams(["info" => $hash])->queryOne();
$torrentInfo = app()->pdo->createCommand('SELECT `id`, `info_hash`, `owner_id`, `status`, `incomplete`, `complete`, `downloaded`, `added_at` FROM `torrents` WHERE `info_hash` = :info LIMIT 1')
->bindParams(['info' => $hash])->queryOne();
if ($torrentInfo === false || $torrentInfo['status'] == 'deleted') { // No-exist or deleted torrent
app()->redis->zAdd(Constant::trackerInvalidInfoHashZset, time() + 600, $bin2hex_hash);
return false;
Expand Down Expand Up @@ -477,7 +463,7 @@ private function checkScrapeFields(&$info_hash_array)
} else {
foreach ($info_hash_array as $item) {
if (strlen($item) != 20)
throw new TrackerException(133, [':attribute' => 'info_hash', ':rule' => strlen($item)]);
throw new TrackerException(133, [':attribute' => 'info_hash', ':rule' => 20]);
}
}
}
Expand Down Expand Up @@ -629,7 +615,7 @@ private function checkAnnounceFields(&$queries = [])
*/
private function checkPortFields($port)
{
if (!is_numeric($port) || $port < 0 || $port > 0xffff || in_array($port, $this->portBlacklist))
if (!is_numeric($port) || $port < 0 || $port > 0xffff || in_array($port, self::portBlacklist))
throw new TrackerException(135, [':port' => $port]);
}

Expand Down
38 changes: 19 additions & 19 deletions apps/libraries/Constant.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,43 +21,43 @@ class Constant
const invalidUserIdZset = 'Site:zset:invalid_user_id';

// Tracker Use
const trackerInvalidInfoHashZset = 'Tracker:zset:invalid_torrent_info_hash'; // FIXME use set instead
const trackerAllowedClientList = 'Tracker:string:allowed_client_list';
const trackerAllowedClientExceptionList = 'Tracker:string:allowed_client_exception_list';
const trackerValidClientZset = 'Tracker:zset:valid_clients';
const trackerAnnounceLockZset = 'Tracker:zset:lock:announce_flood';
const trackerAnnounceMinIntervalLockZset = 'Tracker:zset:lock:announce_min_interval';
const trackerValidPeerZset = 'Tracker:zset:valid_peers';
const trackerToDealQueue = 'Tracker:list:to_deal_queue';
const trackerBackupQueue = 'Tracker:list:backup_queue';
const trackerInvalidInfoHashZset = 'Tracker:invalid_torrent_info_hash'; // FIXME use set instead
const trackerAllowedClientList = 'Tracker:allowed_client_list';
const trackerAllowedClientExceptionList = 'Tracker:allowed_client_exception_list';
const trackerValidClientZset = 'Tracker:valid_clients';
const trackerAnnounceLockZset = 'Tracker:lock:announce_flood';
const trackerAnnounceMinIntervalLockZset = 'Tracker:lock:announce_min_interval';
const trackerValidPeerZset = 'Tracker:valid_peers';
const trackerToDealQueue = 'Tracker:queue:to_deal';
const trackerBackupQueue = 'Tracker:queue:backup';

// Site Status
const siteSubtitleSize = 'Site:string:subtitle_size';
const siteSubtitleSize = 'Site:subtitle_size'; // TODO move to app()->config

public static function userContent($uid)
public static function userContent(int $uid)
{
return 'User:hash:user_' . $uid . '_content';
return 'User:user_content:' . $uid; // Hash
}

public static function torrentContent($tid)
public static function torrentContent(int $tid)
{
return 'Torrent:hash:torrent_' . $tid . '_content';
return 'Torrent:torrent_content:' . $tid; // Hash
}

// Tracker User
public static function trackerUserContentByPasskey($passkey)
public static function trackerUserContentByPasskey(string $passkey)
{
return 'Tracker:string:user_passkey_' . $passkey . '_content'; // Used string to store hash, Because we will get all value in it
return 'Tracker:user_passkey_content:' . $passkey; // String
}

public static function trackerTorrentContentByInfoHash($bin2hex_hash)
public static function trackerTorrentContentByInfoHash(string $bin2hex_hash)
{
return 'Tracker:hash:torrent_infohash_' . $bin2hex_hash . '_content';
return 'Tracker:torrent_infohash_content:' . $bin2hex_hash; // Hash
}

public static function rateLimitPool($pool, $action)
{
return 'Rate:zset:pool_' . $pool . '_action_' . $action . '_limit';
return 'RateLimit:' . $pool . ':action_' . $action; // Zset
}

public static function getTorrentFileLoc($tid)
Expand Down
2 changes: 1 addition & 1 deletion apps/middleware/AuthMiddleware.php
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ private function authByCookies($callable, \Closure $next) {
return app()->response->redirect('/index');
} elseif ($action !== 'actionLogout') {
if ($action == 'actionLogin') { // TODO add register confirm fail ip count check
$test_count = app()->redis->hGet('SITE:fail_login_ip_count', $now_ip) ?: 0;
$test_count = app()->redis->hGet('Site:fail_login_ip_count', $now_ip) ?: 0;
if ($test_count > config('security.max_login_attempts')) {
return app()->response->setStatusCode(403);
}
Expand Down
6 changes: 3 additions & 3 deletions apps/models/form/Auth/UserLoginForm.php
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ public static function callbackRules(): array
/** @noinspection PhpUnused */
protected function isMaxLoginIpReached() // FIXME may use Trait
{
$test_count = app()->redis->hGet('SITE:fail_login_ip_count', app()->request->getClientIp()) ?: 0;
$test_count = app()->redis->hGet('Site:fail_login_ip_count', app()->request->getClientIp()) ?: 0;
if ($test_count > config('security.max_login_attempts')) {
$this->buildCallbackFailMsg('Login Attempts', 'User Max Login Attempts Archived.');
return;
Expand Down Expand Up @@ -132,8 +132,8 @@ protected function isMaxUserSessionsReached()

public function LoginFail() // FIXME
{
app()->redis->zAdd('SITE:fail_login_ip_zset', time(), app()->request->getClientIp());
app()->redis->hIncrBy('SITE:fail_login_ip_count', app()->request->getClientIp(), 1);
app()->redis->zAdd('Site:fail_login_ip_zset', time(), app()->request->getClientIp());
app()->redis->hIncrBy('Site:fail_login_ip_count', app()->request->getClientIp(), 1);
}

public function flush()
Expand Down
2 changes: 1 addition & 1 deletion framework/Http/BaseRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ public function url()
// 返回请求的完整URL
public function fullUrl()
{
return $this->url() . ($this->server('query_string') ? '?' . $this->server('query_string') : '');
return $this->url() . '?' . $this->server('query_string');
}

// 获取协议
Expand Down
44 changes: 0 additions & 44 deletions framework/Utils/ClassValueCacheUtils.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,6 @@

trait ClassValueCacheUtils
{
static $_StaticCacheValue = [];

protected static function getStaticCacheNameSpace(): string
{
return 'Cache:default_static';
}

protected function getCacheNameSpace(): string
{
Expand All @@ -36,42 +30,4 @@ final protected function getCacheValue($key, $closure)
return $this->$key;
}

// Get from redis cache, then generate closure (may database)
final protected static function getStaticCacheValue($key, $closure, $ttl = 86400)
{
$timenow = time();
if (array_key_exists($key, static::$_StaticCacheValue)) {
if ($timenow > static::$_StaticCacheValue[$key . ':expired_at']) {
static::cleanStaticCacheValue($key);
} else {
return static::$_StaticCacheValue[$key];
}
}

$value = app()->redis->get(static::getStaticCacheNameSpace() . ':' . $key);
if (false === $value) {
$value = $closure();
app()->redis->set(static::getStaticCacheNameSpace() . ':' . $key, $value, $ttl);
}

static::setStaticCacheValue($key, $value, $ttl, false);
return $value;
}

final protected static function setStaticCacheValue($key, $value, $ttl, $clean_first = true)
{
$timenow = time();
if ($clean_first) static::cleanStaticCacheValue($key);
static::$_StaticCacheValue[$key] = $value;
static::$_StaticCacheValue[$key . ':expired_at'] = $timenow + $ttl;
}

final protected static function cleanStaticCacheValue($key)
{
if (array_key_exists($key, static::$_StaticCacheValue)) {
unset(static::$_StaticCacheValue[$key]);
unset(static::$_StaticCacheValue[$key . ':expired_at']);
app()->redis->del(static::getStaticCacheNameSpace() . ':' . $key);
}
}
}
5 changes: 3 additions & 2 deletions framework/View/Conversion.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

use Decoda\Decoda;
use Decoda\Storage\RedisStorage;

use League\Plates\Engine;
use League\Plates\Extension\ExtensionInterface;

Expand Down Expand Up @@ -72,9 +73,9 @@ public function format_ubbcode($var)
\Rid::setDefault($var, ['escapeHtml' => true]);
$string = array_shift($var);

$code = new Decoda($string, $var,'Cache:post:' . md5($string));
$code = new Decoda($string, $var,'Decoda:' . md5($string));

$code->defaults(); // TODO add support of tag [mediainfo] , [nfo]
$code->defaults(); // TODO add support of tag [mediainfo]

$code->setStorage(new RedisStorage(app()->redis->getRedis()));
return $code->parse();
Expand Down

0 comments on commit 0c4e1a2

Please sign in to comment.