improve use_can()

This commit is contained in:
xiaomlove
2022-08-24 00:19:19 +08:00
parent bb6cab0f49
commit 86dc15e79a
9 changed files with 102 additions and 36 deletions

View File

@@ -15,6 +15,10 @@ class Setting extends NexusModel
public static array $permissionMustHaveClass = ['defaultclass', 'staffmem']; public static array $permissionMustHaveClass = ['defaultclass', 'staffmem'];
const CLASS_PERMISSION_SET_KEY_PREFIX = 'nexus_class_permissions_';
const DIRECT_PERMISSION_SET_KEY_PREFIX = 'nexus_direct_permissions_';
const ROLE_PERMISSION_SET_KEY_PREFIX = 'nexus_role_permissions_';
/** /**
* get setting autoload = yes with cache * get setting autoload = yes with cache
* *

View File

@@ -9,6 +9,7 @@ use App\Models\Setting;
use App\Models\User; use App\Models\User;
use Carbon\Carbon; use Carbon\Carbon;
use Illuminate\Support\Arr; use Illuminate\Support\Arr;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Storage; use Illuminate\Support\Facades\Storage;
use Nexus\Database\NexusDB; use Nexus\Database\NexusDB;
use Nexus\Plugin\Plugin; use Nexus\Plugin\Plugin;
@@ -367,21 +368,50 @@ class ToolRepository extends BaseRepository
public static function listUserClassPermissions($uid): array public static function listUserClassPermissions($uid): array
{ {
$userInfo = get_user_row($uid); $userInfo = get_user_row($uid);
$prefix = "authority"; $settings = Setting::get('authority');
return Setting::query() $result = [];
->where("name", "like", "$prefix.%") foreach ($settings as $permission => $minClass) {
->where('value', '<=', $userInfo['class']) if ($minClass >= User::CLASS_PEASANT && $minClass <= $userInfo['class']) {
->where('value', '>=', User::CLASS_PEASANT) $result[] = $permission;
->pluck('name') }
->map(fn ($name) => str_replace("$prefix.", "", $name)) }
->toArray(); return $result;
} }
public static function listUserAllPermissions($uid): array public static function listUserAllPermissions($uid, $class = null): array
{ {
return NexusDB::remember("user_{$uid}_permissions", 600, function () use ($uid) { static $uidPermissionsCached = [];
$classPermissions = self::listUserClassPermissions($uid); if (isset($uidPermissionsCached[$uid])) {
return apply_filter('user_permissions', $classPermissions, $uid); return $uidPermissionsCached[$uid];
}); }
$log = "uid: $uid";
if ($class === null) {
$userInfo = get_user_row($uid);
$class = $userInfo['class'];
}
$redis = NexusDB::redis();
$setKeys = [];
//Class permission, use push mechanism, already prepared,see settings.php
$key = Setting::CLASS_PERMISSION_SET_KEY_PREFIX . $class;
$setKeys[] = $key;
//Role permission, use push mechanism, already prepared, see plugin role saving
$setKeys = apply_filter("role_permission_set_keys", $setKeys, $uid);
//Direct permission, use pull mechanism
$key = Setting::DIRECT_PERMISSION_SET_KEY_PREFIX . $uid;
$setKeys[] = $key;
if (!$redis->exists($key)) {
$log .= ", init direct permissions";
/** @var Collection $userPermissions */
$userPermissions = apply_filter("user_direct_permissions", $uid);
$userPermissionsArr = $userPermissions->pluck('permission')->toArray();
$redis->sAddArray($key, $userPermissionsArr);
}
$allPermissions = $redis->sUnion($setKeys);
do_log("$log, allSetKeys: " . json_encode($setKeys) . ", allPermissions: " . json_encode($allPermissions));
$result = array_combine($allPermissions, $allPermissions);
$uidPermissionsCached[$uid] = $result;
return $result;
} }
} }

View File

@@ -1,6 +1,6 @@
<?php <?php
defined('VERSION_NUMBER') || define('VERSION_NUMBER', '1.7.23'); defined('VERSION_NUMBER') || define('VERSION_NUMBER', '1.7.23');
defined('RELEASE_DATE') || define('RELEASE_DATE', '2022-08-22'); defined('RELEASE_DATE') || define('RELEASE_DATE', '2022-08-24');
defined('IN_TRACKER') || define('IN_TRACKER', false); defined('IN_TRACKER') || define('IN_TRACKER', false);
defined('PROJECTNAME') || define("PROJECTNAME","NexusPHP"); defined('PROJECTNAME') || define("PROJECTNAME","NexusPHP");
defined('NEXUSPHPURL') || define("NEXUSPHPURL","https://nexusphp.org"); defined('NEXUSPHPURL') || define("NEXUSPHPURL","https://nexusphp.org");

View File

@@ -2648,8 +2648,7 @@ else {
// $cacheKey = "staff_message_count_" . $CURUSER['id']; // $cacheKey = "staff_message_count_" . $CURUSER['id'];
// $totalsm = $Cache->get_value($cacheKey); // $totalsm = $Cache->get_value($cacheKey);
$totalsm = \App\Repositories\MessageRepository::getStaffMessageCountCache($CURUSER['id'], 'total'); $totalsm = \App\Repositories\MessageRepository::getStaffMessageCountCache($CURUSER['id'], 'total');
if ($totalsm === false){
if ($totalsm == ""){
$totalsm = \App\Repositories\MessageRepository::countStaffMessage($CURUSER['id']); $totalsm = \App\Repositories\MessageRepository::countStaffMessage($CURUSER['id']);
// $Cache->cache_value($cacheKey, $totalsm, 900); // $Cache->cache_value($cacheKey, $totalsm, 900);
\App\Repositories\MessageRepository::updateStaffMessageCountCache($CURUSER['id'], 'total', $totalsm); \App\Repositories\MessageRepository::updateStaffMessageCountCache($CURUSER['id'], 'total', $totalsm);
@@ -2752,7 +2751,7 @@ if ($msgalert)
// $nummessages = $Cache->get_value($cacheKey); // $nummessages = $Cache->get_value($cacheKey);
$nummessages = \App\Repositories\MessageRepository::getStaffMessageCountCache($CURUSER['id'], 'new'); $nummessages = \App\Repositories\MessageRepository::getStaffMessageCountCache($CURUSER['id'], 'new');
if ($nummessages == ""){ if ($nummessages === false){
$nummessages = \App\Repositories\MessageRepository::countStaffMessage($CURUSER['id'], 0); $nummessages = \App\Repositories\MessageRepository::countStaffMessage($CURUSER['id'], 0);
// $Cache->cache_value($cacheKey, $nummessages, 900); // $Cache->cache_value($cacheKey, $nummessages, 900);
\App\Repositories\MessageRepository::updateStaffMessageCountCache($CURUSER['id'], 'new', $nummessages); \App\Repositories\MessageRepository::updateStaffMessageCountCache($CURUSER['id'], 'new', $nummessages);
@@ -3029,6 +3028,8 @@ function deletetorrent($id) {
} }
sql_query("DELETE FROM hit_and_runs WHERE torrent_id = ".mysql_real_escape_string($id)); sql_query("DELETE FROM hit_and_runs WHERE torrent_id = ".mysql_real_escape_string($id));
sql_query("DELETE FROM claims WHERE torrent_id = ".mysql_real_escape_string($id)); sql_query("DELETE FROM claims WHERE torrent_id = ".mysql_real_escape_string($id));
do_action("delete_torrent", $id);
do_log("delete torrent: $id", "error");
unlink(getFullDirectory("$torrent_dir/$id.torrent")); unlink(getFullDirectory("$torrent_dir/$id.torrent"));
} }
@@ -3717,8 +3718,8 @@ function get_username($id, $big = false, $link = true, $bold = true, $target = f
$href = getSchemeAndHttpHost() . "/userdetails.php?id=$id"; $href = getSchemeAndHttpHost() . "/userdetails.php?id=$id";
$options = [ $options = [
'uid' => $id, // 'uid' => $id,
'with_role' => true, // 'with_role' => true,
]; ];
$username = ($link == true ? "<a ". $link_ext . " href=\"" . $href . "\"" . ($target == true ? " target=\"_blank\"" : "") . " class='". get_user_class_name($arr['class'],true, false, false, $options) . "_Name'>" . $username . "</a>" : $username) . $pics . ($withtitle == true ? " (" . ($arr['title'] == "" ? get_user_class_name($arr['class'],false,true,true, $options) : "<span class='".get_user_class_name($arr['class'],true, false, false, $options) . "_Name'><b>".htmlspecialchars($arr['title'])) . "</b></span>)" : ""); $username = ($link == true ? "<a ". $link_ext . " href=\"" . $href . "\"" . ($target == true ? " target=\"_blank\"" : "") . " class='". get_user_class_name($arr['class'],true, false, false, $options) . "_Name'>" . $username . "</a>" : $username) . $pics . ($withtitle == true ? " (" . ($arr['title'] == "" ? get_user_class_name($arr['class'],false,true,true, $options) : "<span class='".get_user_class_name($arr['class'],true, false, false, $options) . "_Name'><b>".htmlspecialchars($arr['title'])) . "</b></span>)" : "");
@@ -5086,6 +5087,7 @@ function saveSetting($prefix, $nameAndValue, $autoload = 'yes')
} }
$sql .= implode(",", $data) . " on duplicate key update value = values(value)"; $sql .= implode(",", $data) . " on duplicate key update value = values(value)";
\Nexus\Database\NexusDB::statement($sql); \Nexus\Database\NexusDB::statement($sql);
do_action("nexus_setting_update", $prefix, $nameAndValue);
} }
function getFullDirectory($dir) function getFullDirectory($dir)

View File

@@ -710,12 +710,13 @@ function get_user_row($id)
'donoruntil', 'leechwarn', 'warned', 'title', 'downloadpos', 'parked', 'clientselect', 'showclienterror', 'donoruntil', 'leechwarn', 'warned', 'title', 'downloadpos', 'parked', 'clientselect', 'showclienterror',
); );
$cacheKey = 'user_'.$id.'_content'; $cacheKey = 'user_'.$id.'_content';
$row = \Nexus\Database\NexusDB::remember($cacheKey, 900, function () use ($id, $neededColumns) { $row = \Nexus\Database\NexusDB::remember($cacheKey, 3600, function () use ($id, $neededColumns) {
$user = \App\Models\User::query()->with(['wearing_medals'])->find($id, $neededColumns); $user = \App\Models\User::query()->with(['wearing_medals'])->find($id, $neededColumns);
if (!$user) { if (!$user) {
return null; return null;
} }
$arr = $user->toArray(); $arr = $user->toArray();
//Rainbow ID
$userRep = new \App\Repositories\UserRepository(); $userRep = new \App\Repositories\UserRepository();
$metas = $userRep->listMetas($id, \App\Models\UserMeta::META_KEY_PERSONALIZED_USERNAME); $metas = $userRep->listMetas($id, \App\Models\UserMeta::META_KEY_PERSONALIZED_USERNAME);
if ($metas->isNotEmpty()) { if ($metas->isNotEmpty()) {
@@ -723,7 +724,7 @@ function get_user_row($id)
} else { } else {
$arr['__is_rainbow'] = 0; $arr['__is_rainbow'] = 0;
} }
return $arr; return apply_filter("user_row", $arr);
}); });
// if ($CURUSER && $id == $CURUSER['id']) { // if ($CURUSER && $id == $CURUSER['id']) {
@@ -955,17 +956,19 @@ function clear_user_cache($uid, $passkey = '')
{ {
do_log("uid: $uid, passkey: $passkey"); do_log("uid: $uid, passkey: $passkey");
\Nexus\Database\NexusDB::cache_del("user_{$uid}_content"); \Nexus\Database\NexusDB::cache_del("user_{$uid}_content");
\Nexus\Database\NexusDB::cache_del("user_{$uid}_permissions");
\Nexus\Database\NexusDB::cache_del("user_{$uid}_roles"); \Nexus\Database\NexusDB::cache_del("user_{$uid}_roles");
\Nexus\Database\NexusDB::cache_del("announce_user_passkey_$uid");//announce.php
\Nexus\Database\NexusDB::cache_del(\App\Models\Setting::DIRECT_PERMISSION_SET_KEY_PREFIX . $uid);
if ($passkey) { if ($passkey) {
\Nexus\Database\NexusDB::cache_del('user_passkey_'.$passkey.'_content'); \Nexus\Database\NexusDB::cache_del('user_passkey_'.$passkey.'_content');//announce.php
} }
} }
function clear_setting_cache() function clear_setting_cache($buildPermissionCache = false)
{ {
\Nexus\Database\NexusDB::cache_del('nexus_settings_in_laravel'); \Nexus\Database\NexusDB::cache_del('nexus_settings_in_laravel');
\Nexus\Database\NexusDB::cache_del('nexus_settings_in_nexus'); \Nexus\Database\NexusDB::cache_del('nexus_settings_in_nexus');
} }
function clear_staff_message_cache() function clear_staff_message_cache()
@@ -974,7 +977,26 @@ function clear_staff_message_cache()
\App\Repositories\MessageRepository::updateStaffMessageCountCache(false); \App\Repositories\MessageRepository::updateStaffMessageCountCache(false);
} }
function user_can($permission, $fail = false, $uid = 0): bool function build_class_permission_cache()
{
$redis = \Nexus\Database\NexusDB::redis();
$results = [];
$settings = get_setting_from_db("authority");
foreach (\App\Models\User::$classes as $class => $info) {
foreach ($settings as $permission => $minClass) {
if ($class >= $minClass) {
$results[$class][] = $permission;
}
}
}
foreach ($results as $class => $permissions) {
$classKey = \App\Models\Setting::CLASS_PERMISSION_SET_KEY_PREFIX . $class;
$redis->del($classKey);
$redis->sAddArray($classKey, $permissions);
}
}
function user_can($permission, $fail = false, $uid = 0, $class = null): bool
{ {
$log = "permission: $permission, fail: $fail, user: $uid"; $log = "permission: $permission, fail: $fail, user: $uid";
static $userCanCached = []; static $userCanCached = [];
@@ -983,21 +1005,24 @@ function user_can($permission, $fail = false, $uid = 0): bool
$log .= ", set current uid: $uid"; $log .= ", set current uid: $uid";
} }
if ($uid <= 0) { if ($uid <= 0) {
do_log("$log, no uid, false"); do_log("$log, no uid, false", 'error');
return false; return false;
} }
if (!$fail && isset($userCanCached[$permission][$uid])) { if (!$fail && isset($userCanCached[$permission][$uid])) {
return $userCanCached[$permission][$uid]; return $userCanCached[$permission][$uid];
} }
$userInfo = get_user_row($uid); if ($class === null) {
$log .= ", userClass: " . $userInfo['class']; $userInfo = get_user_row($uid);
if ($userInfo['class'] == \App\Models\User::CLASS_STAFF_LEADER) { $class = $userInfo['class'];
}
$log .= ", userClass: $class";
if ($class == \App\Models\User::CLASS_STAFF_LEADER) {
do_log("$log, CLASS_STAFF_LEADER, true"); do_log("$log, CLASS_STAFF_LEADER, true");
$userCanCached[$permission][$uid] = true; $userCanCached[$permission][$uid] = true;
return true; return true;
} }
$userAllPermissions = \App\Repositories\ToolRepository::listUserAllPermissions($uid); $userAllPermissions = \App\Repositories\ToolRepository::listUserAllPermissions($uid, $class);
$result = in_array($permission, $userAllPermissions); $result = isset($userAllPermissions[$permission]);
$log .= ", userAllPermissions: " . json_encode($userAllPermissions) . ", result: $result"; $log .= ", userAllPermissions: " . json_encode($userAllPermissions) . ", result: $result";
if (!$fail || $result) { if (!$fail || $result) {
do_log($log); do_log($log);

View File

@@ -242,6 +242,11 @@ class Update extends Install
NexusDB::cache_del('nexus_rss'); NexusDB::cache_del('nexus_rss');
NexusDB::cache_del('nexus_is_ip_seed_box'); NexusDB::cache_del('nexus_is_ip_seed_box');
/**
* @since 1.7.23
*/
build_class_permission_cache();
} }
public function runExtraMigrate() public function runExtraMigrate()

View File

@@ -35,7 +35,7 @@ if (!empty($_REQUEST['authkey'])) {
if (empty($decrypted)) { if (empty($decrypted)) {
err('Invalid authkey'); err('Invalid authkey');
} }
$userInfo = \Nexus\Database\NexusDB::remember("announce_user_passkey_$uid", 600, function () use ($uid) { $userInfo = \Nexus\Database\NexusDB::remember("announce_user_passkey_$uid", 3600, function () use ($uid) {
return \App\Models\User::query()->where('id', $uid)->first(['id', 'passkey']); return \App\Models\User::query()->where('id', $uid)->first(['id', 'passkey']);
}); });
if (!$userInfo) { if (!$userInfo) {
@@ -115,7 +115,7 @@ 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 FROM users WHERE passkey=". sqlesc($passkey)." LIMIT 1"); $res = sql_query("SELECT id, username, downloadpos, enabled, uploaded, downloaded, class, parked, clientselect, showclienterror, passkey, donor, donoruntil FROM users WHERE passkey=". sqlesc($passkey)." LIMIT 1");
$az = mysql_fetch_array($res); $az = mysql_fetch_array($res);
do_log("[check passkey], currentUser: " . nexus_json_encode($az)); do_log("[check passkey], currentUser: " . nexus_json_encode($az));
$Cache->cache_value('user_passkey_'.$passkey.'_content', $az, 950); $Cache->cache_value('user_passkey_'.$passkey.'_content', $az, 3600);
} }
if (!$az) err("Invalid passkey! Re-download the .torrent from $BASEURL"); if (!$az) err("Invalid passkey! Re-download the .torrent from $BASEURL");
$userid = intval($az['id'] ?? 0); $userid = intval($az['id'] ?? 0);
@@ -173,8 +173,7 @@ if (!$torrent) {
err("torrent not registered with this tracker"); err("torrent not registered with this tracker");
} }
//Do not use user_can(), some func user_can() used is not available IN_TRACKER if (!user_can('seebanned', false, $az['id'], $az['class'])) {
if ($az['class'] < $seebanned_class) {
if ($torrent['banned'] == 'yes') { if ($torrent['banned'] == 'yes') {
err("torrent banned"); err("torrent banned");
} elseif ($torrent['approval_status'] != \App\Models\Torrent::APPROVAL_STATUS_ALLOW && get_setting('torrent.approval_status_none_visible') == 'no') { } elseif ($torrent['approval_status'] != \App\Models\Torrent::APPROVAL_STATUS_ALLOW && get_setting('torrent.approval_status_none_visible') == 'no') {

View File

@@ -237,7 +237,7 @@ elseif ($action == 'savesettings_authority') // save user authority
saveSetting('authority', $AUTHORITY); saveSetting('authority', $AUTHORITY);
$actiontime = date("F j, Y, g:i a"); $actiontime = date("F j, Y, g:i a");
write_log("Tracker USER AUTHORITY settings updated by {$CURUSER['username']}. $actiontime",'mod'); write_log("Tracker USER AUTHORITY settings updated by {$CURUSER['username']}. $actiontime",'mod');
do_action("nexus_setting_update", $AUTHORITY); build_class_permission_cache();
go_back(); go_back();
} }
elseif ($action == 'savesettings_tweak') // save tweak elseif ($action == 'savesettings_tweak') // save tweak

View File

@@ -815,6 +815,7 @@ EOD;
$to .= "&password=1"; $to .= "&password=1";
if ($privacyupdated == 1) if ($privacyupdated == 1)
$to .= "&privacy=1"; $to .= "&privacy=1";
clear_user_cache($CURUSER["id"]);
header("Location: $to"); header("Location: $to");
} }
stdhead($lang_usercp['head_control_panel'].$lang_usercp['head_security_settings']); stdhead($lang_usercp['head_control_panel'].$lang_usercp['head_security_settings']);