diff --git a/README-EN.md b/README-EN.md index e9a38687..03282a5b 100644 --- a/README-EN.md +++ b/README-EN.md @@ -42,7 +42,7 @@ Welcome to participate in internationalization work, click [here](https://github ## System Requirements - PHP: 8.2|8.3|8.4, must have extensions: bcmath, ctype, curl, fileinfo, json, mbstring, openssl, pdo_mysql, tokenizer, xml, mysqli, gd, redis, pcntl, sockets, posix, gmp, zend opcache, zip, intl, pdo_sqlite, sqlite3 - Mysql: 5.7 latest version or above -- Redis:2.6.12 or above +- Redis:4.0.0 or above - Others: supervisor, rsync ## Quick Start diff --git a/README.md b/README.md index 61a5211c..4d6e8335 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,7 @@ ## 系统要求 - PHP: 8.2|8.3|8.4,必须扩展:bcmath, ctype, curl, fileinfo, json, mbstring, openssl, pdo_mysql, tokenizer, xml, mysqli, gd, redis, pcntl, sockets, posix, gmp, zend opcache, zip, intl, pdo_sqlite, sqlite3 - Mysql: 5.7 最新版或以上版本 -- Redis:2.6.12 或以上版本 +- Redis:4.0.0 或以上版本 - 其他:supervisor, rsync ## 快速开始 diff --git a/app/Console/Kernel.php b/app/Console/Kernel.php index 1f2d1ab2..277ad9e6 100644 --- a/app/Console/Kernel.php +++ b/app/Console/Kernel.php @@ -6,6 +6,7 @@ use App\Jobs\CheckCleanup; use App\Jobs\CheckQueueFailedJobs; use App\Jobs\MaintainPluginState; use App\Jobs\ManagePlugin; +use App\Jobs\SaveIpLogCacheToDB; use App\Jobs\UpdateIsSeedBoxFromUserRecordsCache; use App\Utils\ThirdPartyJob; use Carbon\Carbon; @@ -48,10 +49,10 @@ class Kernel extends ConsoleKernel $schedule->command('meilisearch:import')->weeklyOn(1, "03:00"); $schedule->command('torrent:load_pieces_hash')->dailyAt("01:00"); $schedule->job(new CheckQueueFailedJobs())->everySixHours(); -// $schedule->job(new ThirdPartyJob())->everyMinute(); $schedule->job(new MaintainPluginState())->everyMinute(); $schedule->job(new UpdateIsSeedBoxFromUserRecordsCache())->everySixHours(); $schedule->job(new CheckCleanup())->everyFifteenMinutes(); + $schedule->job(new SaveIpLogCacheToDB())->hourly(); } diff --git a/app/Filament/Resources/System/IpLogs/IpLogResource.php b/app/Filament/Resources/System/IpLogs/IpLogResource.php new file mode 100644 index 00000000..0f807b0c --- /dev/null +++ b/app/Filament/Resources/System/IpLogs/IpLogResource.php @@ -0,0 +1,139 @@ +components([ + // + ]); + } + + public static function table(Table $table): Table + { + return $table + ->columns([ + TextColumn::make('userid') + ->label('UID') + , + TextColumn::make('usernameForAdmin') + ->label(__('label.username')) + , + TextColumn::make('ip') + ->label('IP') + , + TextColumn::make('ipLocation') + ->label(__('ip-log.ip_location')) + , + TextColumn::make('uri') + ->label(__('ip-log.uri')) + , + TextColumn::make('count') + ->label(__('ip-log.count')) + , + TextColumn::make('access') + ->label(__('ip-log.access')) + ->tooltip(__('ip-log.access_tooltip')) + , + ]) + ->defaultSort('id', 'desc') + ->filters([ + Filter::make('uid') + ->schema([ + TextInput::make('uid')->label('UID'), + ]) + ->query(function (Builder $query, array $data) { + return $query + ->when( + $data['uid'], + fn (Builder $query, $value): Builder => $query->where('userid', $value), + ); + }), + Filter::make('ip') + ->schema([ + TextInput::make('ip')->label('IP'), + ]) + ->query(function (Builder $query, array $data) { + return $query + ->when( + $data['ip'], + fn (Builder $query, $value): Builder => $query->where('ip', $value), + ); + }), + Filter::make('access_begin') + ->schema([ + DateTimePicker::make('access_begin')->label(__('ip-log.access_begin')), + ]) + ->query(function (Builder $query, array $data) { + return $query + ->when( + $data['access_begin'], + fn (Builder $query, $value): Builder => $query->where('access', '>=', $value), + ); + }), + Filter::make('access_end') + ->schema([ + DateTimePicker::make('access_end')->label(__('ip-log.access_end')), + ]) + ->query(function (Builder $query, array $data) { + return $query + ->when( + $data['access_end'], + fn (Builder $query, $value): Builder => $query->where('access', '<=', $value), + ); + }), + ]) + ->recordActions([ +// ViewAction::make(), +// EditAction::make(), +// DeleteAction::make(), + ]) + ->toolbarActions([ + BulkActionGroup::make([ +// DeleteBulkAction::make(), + ]), + ]); + } + + public static function getPages(): array + { + return [ + 'index' => ManageIpLogs::route('/'), + ]; + } +} diff --git a/app/Filament/Resources/System/IpLogs/Pages/ManageIpLogs.php b/app/Filament/Resources/System/IpLogs/Pages/ManageIpLogs.php new file mode 100644 index 00000000..f96a9de5 --- /dev/null +++ b/app/Filament/Resources/System/IpLogs/Pages/ManageIpLogs.php @@ -0,0 +1,20 @@ + [ 'throttle:api', \Illuminate\Routing\Middleware\SubstituteBindings::class, -// \App\Http\Middleware\Platform::class, ], 'filament' => [ \Illuminate\Session\Middleware\StartSession::class, @@ -73,8 +73,6 @@ class Kernel extends HttpKernel 'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class, 'throttle' => \Illuminate\Routing\Middleware\ThrottleRequestsWithRedis::class, 'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class, - 'permission' => \App\Http\Middleware\Permission::class, - 'admin' => \App\Http\Middleware\Admin::class, 'locale' => \App\Http\Middleware\Locale::class, 'checkUserStatus' => \App\Http\Middleware\CheckUserStatus::class, ]; diff --git a/app/Http/Middleware/Admin.php b/app/Http/Middleware/Admin.php deleted file mode 100644 index 422efa94..00000000 --- a/app/Http/Middleware/Admin.php +++ /dev/null @@ -1,30 +0,0 @@ -user(); - if (!$user || !$user->canAccessAdmin()) { - do_log("denied!"); - throw new UnauthorizedException('Unauthorized!'); - } - do_log("allow!"); - return $next($request); - } -} diff --git a/app/Http/Middleware/BootNexus.php b/app/Http/Middleware/BootNexus.php index 42710b07..3d4dfe5b 100644 --- a/app/Http/Middleware/BootNexus.php +++ b/app/Http/Middleware/BootNexus.php @@ -2,6 +2,7 @@ namespace App\Http\Middleware; +use App\Repositories\IpLogRepository; use Closure; use Illuminate\Http\Request; use Nexus\Nexus; diff --git a/app/Http/Middleware/LogUserIp.php b/app/Http/Middleware/LogUserIp.php new file mode 100644 index 00000000..de77f20a --- /dev/null +++ b/app/Http/Middleware/LogUserIp.php @@ -0,0 +1,26 @@ +user(); + if ($user) { + IpLogRepository::saveToCache($user->id); + } + return $response; + } +} diff --git a/app/Http/Middleware/Permission.php b/app/Http/Middleware/Permission.php deleted file mode 100644 index e6c6a7fc..00000000 --- a/app/Http/Middleware/Permission.php +++ /dev/null @@ -1,30 +0,0 @@ -user(); - if (!$user || (nexus()->isPlatformAdmin() && !$user->canAccessAdmin())) { - do_log("denied!"); - throw new UnauthorizedException('Unauthorized!'); - } - do_log("allow!"); - return $next($request); - } -} diff --git a/app/Http/Middleware/Platform.php b/app/Http/Middleware/Platform.php deleted file mode 100644 index 43417cf3..00000000 --- a/app/Http/Middleware/Platform.php +++ /dev/null @@ -1,29 +0,0 @@ -getPlatform(); - if (empty($platform)) { - throw new \InvalidArgumentException("Require platform header."); - } - if (!nexus()->isPlatformValid()) { - throw new \InvalidArgumentException("Invalid platform: " . $platform); - } - return $next($request); - } -} diff --git a/app/Jobs/CalculateUserSeedBonus.php b/app/Jobs/CalculateUserSeedBonus.php index b26d1fcd..afdf998b 100644 --- a/app/Jobs/CalculateUserSeedBonus.php +++ b/app/Jobs/CalculateUserSeedBonus.php @@ -3,8 +3,10 @@ namespace App\Jobs; use App\Models\BonusLogs; +use App\Models\IpLog; use App\Models\Setting; use App\Models\User; +use App\Repositories\IpLogRepository; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldBeUnique; use Illuminate\Contracts\Queue\ShouldQueue; @@ -238,7 +240,7 @@ class CalculateUserSeedBonus implements ShouldQueue $client = app(\ClickHouseDB\Client::class); $fields = ['business_type', 'uid', 'old_total_value', 'value', 'new_total_value', 'comment', 'created_at']; $client->insert("bonus_logs", $bonusLogInsert, $fields); - do_log("insertIntoClickHouseBulk done, created_at: {$bonusLogInsert[0]['created_at']}"); + do_log("insertIntoClickHouseBulk done, created_at: {$bonusLogInsert[0]['created_at']}, count: " . count($bonusLogInsert)); } catch (\Exception $e) { do_log($e->getMessage(), 'error'); } diff --git a/app/Jobs/SaveIpLogCacheToDB.php b/app/Jobs/SaveIpLogCacheToDB.php new file mode 100644 index 00000000..bb7a140b --- /dev/null +++ b/app/Jobs/SaveIpLogCacheToDB.php @@ -0,0 +1,31 @@ + $this->getIpLocation($attributes['ip']) + ); + } + + private function getIpLocation(string $ip) + { + $result = get_ip_location_from_geoip($ip); + $out = $result['name']; + $suffix = []; + if (!empty($result['city_en'])) { + $suffix[] = $result['city_en']; + } + if (!empty($result['country_en'])) { + $suffix[] = $result['country_en']; + } + if (!empty($result['continent_en'])) { + $suffix[] = $result['continent_en']; + } + if (!empty($suffix)) { + $out .= " " . implode(', ', $suffix); + } + return $out; + } +} diff --git a/app/Models/NexusModel.php b/app/Models/NexusModel.php index 7ab1fce9..3786dd73 100644 --- a/app/Models/NexusModel.php +++ b/app/Models/NexusModel.php @@ -2,6 +2,7 @@ namespace App\Models; +use Illuminate\Database\Eloquent\Casts\Attribute; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; use Nexus\Database\NexusDB; @@ -16,6 +17,13 @@ class NexusModel extends Model protected $connection = NexusDB::ELOQUENT_CONNECTION_NAME; + protected function usernameForAdmin(): Attribute + { + return Attribute::make( + get: fn (mixed $value, array $attributes) => username_for_admin($attributes['uid'] ?? $attributes['userid'] ?? $attributes['user_id']) + ); + } + /** * * @param \DateTimeInterface $date diff --git a/app/Models/Setting.php b/app/Models/Setting.php index 4ac33ee4..1490cfdb 100644 --- a/app/Models/Setting.php +++ b/app/Models/Setting.php @@ -108,7 +108,7 @@ class Setting extends NexusModel { $redis = NexusDB::redis(); $key = self::USER_TOKEN_PERMISSION_ALLOWED_CACHE_KRY; - $redis->del($key); + $redis->unlink($key); //must not use cache if (empty($allowed)) { $allowed = self::getFromDb("permission.user_token_allowed"); diff --git a/app/Models/TrackerUrl.php b/app/Models/TrackerUrl.php index 8d9a5f0c..0992bf39 100644 --- a/app/Models/TrackerUrl.php +++ b/app/Models/TrackerUrl.php @@ -35,7 +35,7 @@ class TrackerUrl extends NexusModel { //添加 id 与 URL 映射 $redis = NexusDB::redis(); - $redis->del(self::TRACKER_URL_CACHE_KEY); + $redis->unlink(self::TRACKER_URL_CACHE_KEY); $list = self::listAll(); $first = $list->first(); $hasDefault = false; diff --git a/app/Providers/RouteServiceProvider.php b/app/Providers/RouteServiceProvider.php index 00399302..5dccda00 100644 --- a/app/Providers/RouteServiceProvider.php +++ b/app/Providers/RouteServiceProvider.php @@ -40,11 +40,11 @@ class RouteServiceProvider extends ServiceProvider $this->routes(function () { Route::prefix('api/v1') - ->middleware('api') + ->middleware(['api', 'locale']) ->namespace($this->namespace) ->group(base_path('routes/api.php')); - Route::middleware('web') + Route::middleware(['web', 'locale']) ->namespace($this->namespace) ->group(base_path('routes/web.php')); diff --git a/app/Repositories/CleanupRepository.php b/app/Repositories/CleanupRepository.php index 3222c11b..3f7b075a 100644 --- a/app/Repositories/CleanupRepository.php +++ b/app/Repositories/CleanupRepository.php @@ -132,7 +132,7 @@ class CleanupRepository extends BaseRepository //remove this batch if ($batchKey != self::USER_SEED_BONUS_BATCH_KEY) { - $redis->del($batch); + $redis->unlink($batch); } $endTimestamp = time(); do_log(sprintf("$logPrefix, [DONE], batch: $batch, count: $count, cost time: %d seconds", $endTimestamp - $beginTimestamp)); diff --git a/app/Repositories/IpLogRepository.php b/app/Repositories/IpLogRepository.php new file mode 100644 index 00000000..b89d8d9f --- /dev/null +++ b/app/Repositories/IpLogRepository.php @@ -0,0 +1,87 @@ +hincrby($key, $field, 1); + do_log("success hincrby $key $field, result: $result", "debug"); + if ($result === 1) { + $redis->expire($key, self::CACHE_TIME); + } + } + } + + public static function saveToDB(): void + { + $beginTimestamp = microtime(true); + $redis = NexusDB::redis(); + $begin = Carbon::now()->subSeconds(self::CACHE_TIME); + $end = Carbon::now()->subHours(1); + $interval =\DateInterval::createFromDateString("1 hour"); + $period = new \DatePeriod($begin->clone(), $interval, $end); + $size = 2000; + do_log(sprintf("begin: %s, end: %s, size: %s", $begin->toDateTimeString(), $end->toDateTimeString(), $size)); + $redis->setOption(\Redis::OPT_SCAN, \Redis::SCAN_RETRY); + foreach ($period as $dt) { + $key = sprintf("%s:%s", self::CACHE_KEY_PREFIX, $dt->format('Y-m-d-H')); + if (!$redis->exists($key)) { + do_log("key: $key not found", "debug"); + continue; + } + if ($redis->hlen($key) == 0) { + do_log("key: $key length = 0", "debug"); + $redis->unlink($key); + } + do_log("handing key: $key"); + //遍历hash + $it = NULL; + while($arr_keys = $redis->hScan($key, $it, "*", $size)) { + $insert = []; + foreach ($arr_keys as $field => $value) { + list($userId, $ip, $uri) = explode("|", $field); + $insert[] = [ + 'userid' => $userId, + 'ip' => $ip, + 'uri' => $uri, + 'access' => date("Y-m-d H:i:s"), + 'count' => intval($value), + ]; + } + if (!empty($insert)) { + IpLog::query()->insert($insert); + } + do_log("key: $key, it: $it, count: " . count($insert)); + } + $redis->unlink($key); + do_log("handle key: $key done!"); + } + do_log(sprintf("all done! cost time: %.3f sec.", microtime(true) - $beginTimestamp)); + } + +} diff --git a/app/Repositories/RequireSeedTorrentRepository.php b/app/Repositories/RequireSeedTorrentRepository.php index f51539eb..0401bfd8 100644 --- a/app/Repositories/RequireSeedTorrentRepository.php +++ b/app/Repositories/RequireSeedTorrentRepository.php @@ -104,7 +104,7 @@ class RequireSeedTorrentRepository extends BaseRepository //remove torrent from list $redis->hDel(self::getTorrentCacheKey(), $torrent->id); //remove all users under torrent - $redis->del(self::getTorrentUserCacheKey($torrent->id)); + $redis->unlink(self::getTorrentUserCacheKey($torrent->id)); } RequireSeedTorrent::query()->whereIn('torrent_id', $idArr)->delete(); UserRequireSeedTorrent::query()->whereIn('torrent_id', $idArr)->delete(); diff --git a/app/Repositories/TorrentRepository.php b/app/Repositories/TorrentRepository.php index 7c6abc79..c446bb24 100644 --- a/app/Repositories/TorrentRepository.php +++ b/app/Repositories/TorrentRepository.php @@ -221,9 +221,7 @@ class TorrentRepository extends BaseRepository } if ($apiQueryBuilder->hasIncludeField('description') && $apiQueryBuilder->hasInclude('extra')) { - do_log("before format_description of torrent: {$torrent->id}"); $descriptionArr = format_description($torrent->extra->descr ?? ''); - do_log("after format_description of torrent: {$torrent->id}"); $torrent->description = $descriptionArr; $torrent->images = get_image_from_description($descriptionArr); } diff --git a/app/Utils/ApiQueryBuilder.php b/app/Utils/ApiQueryBuilder.php index 9759296d..22fb96eb 100644 --- a/app/Utils/ApiQueryBuilder.php +++ b/app/Utils/ApiQueryBuilder.php @@ -101,10 +101,10 @@ class ApiQueryBuilder { $includeCounts = explode(',', $this->request->query(self::PARAM_NAME_INCLUDE_COUNTS, '')); $valid = array_intersect($this->allowedIncludeCounts, $includeCounts); - do_log(sprintf( - "includeCounts: %s, allow: %s, valid: %s", - json_encode($includeCounts), json_encode($this->allowedIncludeCounts), json_encode($valid) - )); +// do_log(sprintf( +// "includeCounts: %s, allow: %s, valid: %s", +// json_encode($includeCounts), json_encode($this->allowedIncludeCounts), json_encode($valid) +// )); $this->query->withCount($valid); } diff --git a/database/migrations/2025_10_12_052151_add_uri_and_count_field_to_iplog_table.php b/database/migrations/2025_10_12_052151_add_uri_and_count_field_to_iplog_table.php new file mode 100644 index 00000000..fe334610 --- /dev/null +++ b/database/migrations/2025_10_12_052151_add_uri_and_count_field_to_iplog_table.php @@ -0,0 +1,30 @@ +string('uri')->nullable(); + $table->integer('count')->default(0); + $table->index('ip'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('iplog', function (Blueprint $table) { + $table->dropColumn(['uri', 'count']); + }); + } +}; diff --git a/include/functions.php b/include/functions.php index 27641fae..75c3174c 100644 --- a/include/functions.php +++ b/include/functions.php @@ -2498,10 +2498,12 @@ function stdhead($title = "", $msgalert = true, $script = "", $place = "") $tstart = getmicrotime(); // Start time //Insert old ip into iplog if ($CURUSER){ - if ($iplog1 == "yes") { - if (($oldip != $CURUSER["ip"]) && $CURUSER["ip"]) - sql_query("INSERT INTO iplog (ip, userid, access) VALUES (" . sqlesc($CURUSER['ip']) . ", " . $CURUSER['id'] . ", '" . $CURUSER['last_access'] . "')"); - } +// if ($iplog1 == "yes") { +// if (($oldip != $CURUSER["ip"]) && $CURUSER["ip"]) +// sql_query("INSERT INTO iplog (ip, userid, access) VALUES (" . sqlesc($CURUSER['ip']) . ", " . $CURUSER['id'] . ", '" . $CURUSER['last_access'] . "')"); +// } + //record always + \App\Repositories\IpLogRepository::saveToCache($CURUSER['id']); $USERUPDATESET[] = "last_access = ".sqlesc(date("Y-m-d H:i:s")); $USERUPDATESET[] = "ip = ".sqlesc($CURUSER['ip']); } @@ -2966,8 +2968,10 @@ function stdfoot() { echo "
".$footerad[0]."
"; } print("
"); - if ($CURUSER && count($USERUPDATESET)){ - sql_query("UPDATE users SET " . join(",", $USERUPDATESET) . " WHERE id = ".$CURUSER['id']); + if ($CURUSER) { + if (count($USERUPDATESET)) { + sql_query("UPDATE users SET " . join(",", $USERUPDATESET) . " WHERE id = ".$CURUSER['id']); + } } // Variables for End Time $tend = microtime(true); @@ -6099,9 +6103,9 @@ function calculate_seed_bonus($uid, $torrentIdArr = null): array $torrentIdArr = [-1]; } $idStr = implode(',', \Illuminate\Support\Arr::wrap($torrentIdArr)); - $sql = "select torrents.id, torrents.added, torrents.size, torrents.seeders, 'NO_PEER_ID' as peerID, '' as last_action from torrents WHERE id in ($idStr) and size >= $minSize"; + $sql = "select torrents.id, torrents.added, torrents.size, torrents.seeders, 'NO_PEER_ID' as peerID, '' as last_action, '' as ip from torrents WHERE id in ($idStr) and size >= $minSize"; } else { - $sql = "select torrents.id, torrents.added, torrents.size, torrents.seeders, peers.id as peerID, peers.last_action from torrents LEFT JOIN peers ON peers.torrent = torrents.id WHERE peers.userid = $uid AND peers.seeder ='yes' and torrents.size > $minSize group by peers.torrent, peers.peer_id"; + $sql = "select torrents.id, torrents.added, torrents.size, torrents.seeders, peers.id as peerID, peers.last_action, peers.ip from torrents LEFT JOIN peers ON peers.torrent = torrents.id WHERE peers.userid = $uid AND peers.seeder ='yes' and torrents.size > $minSize group by peers.torrent, peers.peer_id"; } $tagGrouped = []; $torrentResult = \Nexus\Database\NexusDB::select($sql); @@ -6120,11 +6124,15 @@ function calculate_seed_bonus($uid, $torrentIdArr = null): array $medalAdditionalFactor = floatval($userMedalResult[0]['factor'] ?? 0); do_log("$logPrefix, sql: $sql, count: " . count($torrentResult) . ", officialTag: $officialTag, officialAdditionalFactor: $officialAdditionalFactor, zeroBonusTag: $zeroBonusTag, zeroBonusFactor: $zeroBonusFactor, medalAdditionalFactor: $medalAdditionalFactor"); $last_action = ""; + $ip_arr = []; foreach ($torrentResult as $torrent) { if ($torrent['last_action'] > $last_action) { $last_action = $torrent['last_action']; } + if (!empty($torrent['ip']) && !isset($ip_arr[$torrent['ip']])) { + $ip_arr[$torrent['ip']] = $torrent['ip']; + } $size = bcadd($size, $torrent['size']); $weeks_alive = ($timenow - strtotime($torrent['added'])) / $sectoweek; $gb_size = $gb_size_raw = $torrent['size'] / 1073741824; @@ -6155,11 +6163,12 @@ function calculate_seed_bonus($uid, $torrentIdArr = null): array $medal_bonus = $valuetwo * atan($A / $l_bonus); $result = compact( 'seed_points','seed_bonus', 'A', 'count', 'torrent_peer_count', 'size', 'last_action', - 'official_bonus', 'official_a', 'official_torrent_peer_count', 'official_size', 'medal_bonus' + 'official_bonus', 'official_a', 'official_torrent_peer_count', 'official_size', 'medal_bonus', ); $result['donor_times'] = $donortimes_bonus; $result['official_additional_factor'] = $officialAdditionalFactor; $result['medal_additional_factor'] = $medalAdditionalFactor; + $result['ip_arr'] = array_keys($ip_arr); do_log("$logPrefix, result: " . json_encode($result)); return $result; } @@ -6514,6 +6523,9 @@ function torrent_name_for_admin(\App\Models\Torrent|null $torrent, $withTags = f function username_for_admin(int $id) { + if (empty($id)) { + return ''; + } return new HtmlString(get_username($id, false, true, true, true)); } diff --git a/include/functions_announce.php b/include/functions_announce.php index 323d9530..624cffe6 100644 --- a/include/functions_announce.php +++ b/include/functions_announce.php @@ -53,13 +53,7 @@ function benc_resp($d) function benc_resp_raw($x) { header("Content-Type: text/plain; charset=utf-8"); header("Pragma: no-cache"); - - if (isset($_SERVER["HTTP_ACCEPT_ENCODING"]) && $_SERVER["HTTP_ACCEPT_ENCODING"] == "gzip" && function_exists('gzencode')) { - header("Content-Encoding: gzip"); - echo gzencode($x, 9, FORCE_GZIP); - } - else - echo $x; + echo $x; } /** diff --git a/nexus/Install/Install.php b/nexus/Install/Install.php index 61836f40..3e752dcd 100644 --- a/nexus/Install/Install.php +++ b/nexus/Install/Install.php @@ -731,7 +731,7 @@ class Install $redis = NexusDB::redis(); $result = $redis->info(); $version = $result['redis_version']; - $minVersion = '2.6.12'; + $minVersion = '4.0.0'; $match = version_compare($version, $minVersion, '>='); return compact('version', 'match', 'minVersion'); } diff --git a/public/announce.php b/public/announce.php index b5287dcb..4f717667 100644 --- a/public/announce.php +++ b/public/announce.php @@ -657,6 +657,7 @@ if(count($USERUPDATESET) && $userid) $lockKey = sprintf("record_batch_lock:%s:%s", $userid, $torrentid); if ($redis->set($lockKey, TIMENOW, ['nx', 'ex' => $autoclean_interval_one])) { \App\Repositories\CleanupRepository::recordBatch($redis, $userid, $torrentid); + \App\Repositories\IpLogRepository::saveToCache($userid, null, [$ip]); } if (\App\Repositories\RequireSeedTorrentRepository::shouldRecordUser($redis, $userid, $torrentid)) { if (!isset($snatchInfo)) { diff --git a/public/download.php b/public/download.php index b963f14e..83abc5cf 100644 --- a/public/download.php +++ b/public/download.php @@ -62,10 +62,11 @@ if (!empty($_REQUEST['downhash'])) { } } //User may choose to download torrent from RSS. So log ip changes when downloading torrents. -if ($iplog1 == "yes") { - if (($oldip != $CURUSER["ip"]) && $CURUSER["ip"]) - sql_query("INSERT INTO iplog (ip, userid, access) VALUES (" . sqlesc($CURUSER['ip']) . ", " . $CURUSER['id'] . ", '" . $CURUSER['last_access'] . "')"); -} +//if ($iplog1 == "yes") { +// if (($oldip != $CURUSER["ip"]) && $CURUSER["ip"]) +// sql_query("INSERT INTO iplog (ip, userid, access) VALUES (" . sqlesc($CURUSER['ip']) . ", " . $CURUSER['id'] . ", '" . $CURUSER['last_access'] . "')"); +//} +\App\Repositories\IpLogRepository::saveToCache($CURUSER['id']); //User may choose to download torrent from RSS. So update his last_access and ip when downloading torrents. sql_query("UPDATE users SET last_access = ".sqlesc(date("Y-m-d H:i:s")).", ip = ".sqlesc($CURUSER['ip'])." WHERE id = ".sqlesc($CURUSER['id'])); diff --git a/public/scrape.php b/public/scrape.php index 1d18ed20..99bd01fb 100644 --- a/public/scrape.php +++ b/public/scrape.php @@ -6,6 +6,33 @@ dbconn_announce(); // BLOCK ACCESS WITH WEB BROWSERS AND CHEATS! block_browser(); +$passkey = $_GET['passkey'] ?? ''; +if (empty($passkey)) { + err('require passkey'); +} +$redis = $Cache->getRedis(); +$passkeyInvalidKey = "passkey_invalid"; +// check passkey +if (!$az = $Cache->get_value('user_passkey_'.$passkey.'_content')){ + $res = sql_query("SELECT id, username, downloadpos, enabled, uploaded, downloaded, class, parked, clientselect, showclienterror, passkey, donor, donoruntil, seedbonus, tracker_url_id FROM users WHERE passkey=". sqlesc($passkey)." LIMIT 1"); + $az = mysql_fetch_array($res); + do_log("[check passkey], currentUser: " . nexus_json_encode($az)); + $Cache->cache_value('user_passkey_'.$passkey.'_content', $az, 3600); +} +if (!$az) { + $redis->set("$passkeyInvalidKey:$passkey", TIMENOW, ['ex' => 24*3600]); + err("Invalid passkey! Re-download the .torrent from $BASEURL"); +} +if ($az["enabled"] == "no") + err("Your account is disabled!", 300); +elseif ($az["parked"] == "yes") + err("Your account is parked! (Read the FAQ)", 300); +elseif ($az["downloadpos"] == "no") + err("Your downloading privileges have been disabled! (Read the rules)", 300); + +$userid = intval($az['id'] ?? 0); +unset($GLOBALS['CURUSER']); +$CURUSER = $GLOBALS["CURUSER"] = $az; preg_match_all('/info_hash=([^&]*)/i', $_SERVER["QUERY_STRING"], $info_hash_array); $fields = "info_hash, times_completed, seeders, leechers"; diff --git a/public/settings.php b/public/settings.php index 8a3815bf..f77c0346 100644 --- a/public/settings.php +++ b/public/settings.php @@ -310,7 +310,7 @@ elseif ($action == 'tweaksettings') // tweak settings print ($notice); print ("
"); yesorno($lang_settings['row_save_user_location'], 'where', $TWEAK["where"], $lang_settings['text_save_user_location_note']); - yesorno($lang_settings['row_log_user_ips'], 'iplog1', $TWEAK["iplog1"], $lang_settings['text_store_user_ips_note']); +// yesorno($lang_settings['row_log_user_ips'], 'iplog1', $TWEAK["iplog1"], $lang_settings['text_store_user_ips_note']); tr($lang_settings['row_kps_enabled'],"
".$lang_settings['text_kps_note'], 1); yesorno($lang_settings['row_enable_location'], 'enablelocation', $TWEAK["enablelocation"], $lang_settings['text_enable_location_note']); yesorno($lang_settings['row_enable_tooltip'], 'enabletooltip', $TWEAK["enabletooltip"], $lang_settings['text_enable_tooltip_note']); diff --git a/resources/lang/en/ip-log.php b/resources/lang/en/ip-log.php new file mode 100644 index 00000000..702aeab1 --- /dev/null +++ b/resources/lang/en/ip-log.php @@ -0,0 +1,12 @@ + 'IP History', + 'access' => 'Access time', + 'access_begin' => 'Access time begin', + 'access_end' => 'Access time end', + 'access_tooltip' => 'The actual time was within one hour prior to this.', + 'uri' => 'URI', + 'count' => 'Count', + 'ip_location' => 'Location', +]; diff --git a/resources/lang/zh_CN/ip-log.php b/resources/lang/zh_CN/ip-log.php new file mode 100644 index 00000000..d61bf22d --- /dev/null +++ b/resources/lang/zh_CN/ip-log.php @@ -0,0 +1,12 @@ + 'IP 历史', + 'access' => '访问时间', + 'access_begin' => '访问时间开始', + 'access_end' => '访问时间结束', + 'access_tooltip' => '实际时间在此之前 1 小时内', + 'uri' => '访问路径', + 'count' => '访问次数', + 'ip_location' => '地理位置', +]; diff --git a/resources/lang/zh_TW/ip-log.php b/resources/lang/zh_TW/ip-log.php new file mode 100644 index 00000000..f4ef1269 --- /dev/null +++ b/resources/lang/zh_TW/ip-log.php @@ -0,0 +1,12 @@ + 'IP 歷史', + 'access' => '訪問時間', + 'access_begin' => '訪問時間開始', + 'access_end' => '訪問時間結束', + 'access_tooltip' => '實際時間在此之前 1 小時內', + 'uri' => '訪問路徑', + 'count' => '訪問次數', + 'ip_location' => '地理位置', +];