收紧输入渲染与后台配置权限
This commit is contained in:
@@ -174,18 +174,29 @@ class ChangelogController extends Controller
|
||||
*/
|
||||
private function saveChangelogNotification(DevChangelog $log): void
|
||||
{
|
||||
$typeLabel = DevChangelog::TYPE_CONFIG[$log->type]['label'] ?? '更新';
|
||||
$url = url('/changelog').'#v'.$log->version;
|
||||
// 广播文案允许保留安全链接,但标题与版本号必须先做 HTML 转义,避免系统消息被拼成恶意标签。
|
||||
$safeTypeLabel = e(DevChangelog::TYPE_CONFIG[$log->type]['label'] ?? '更新');
|
||||
$safeVersion = e((string) $log->version);
|
||||
$safeTitle = e((string) $log->title);
|
||||
$detailUrl = e($this->buildChangelogDetailUrl($log));
|
||||
|
||||
SaveMessageJob::dispatch([
|
||||
'room_id' => 1,
|
||||
'from_user' => '系统公告',
|
||||
'to_user' => '大家',
|
||||
'content' => "📢 【版本更新 {$typeLabel}】v{$log->version}《{$log->title}》— <a href=\"{$url}\" target=\"_blank\" class=\"underline\">点击查看详情</a>",
|
||||
'content' => "📢 【版本更新 {$safeTypeLabel}】v{$safeVersion}《{$safeTitle}》— <a href=\"{$detailUrl}\" target=\"_blank\" rel=\"noopener\" class=\"underline\">点击查看详情</a>",
|
||||
'is_secret' => false,
|
||||
'font_color' => '#7c3aed',
|
||||
'action' => '',
|
||||
'sent_at' => now()->toIso8601String(),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成开发日志详情链接,并对版本片段做 URL 编码,避免广播 href 被注入额外属性。
|
||||
*/
|
||||
private function buildChangelogDetailUrl(DevChangelog $log): string
|
||||
{
|
||||
return route('changelog.index').'#v'.rawurlencode((string) $log->version);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,28 +17,37 @@ use App\Models\SysParam;
|
||||
use App\Services\ChatStateService;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\View\View;
|
||||
|
||||
/**
|
||||
* 类功能:后台通用系统参数配置控制器
|
||||
* 仅允许维护低敏公共参数,站长专属敏感配置需走各自独立页面。
|
||||
*/
|
||||
class SystemController extends Controller
|
||||
{
|
||||
/**
|
||||
* 构造函数注入聊天室状态服务
|
||||
*/
|
||||
public function __construct(
|
||||
private readonly ChatStateService $chatState
|
||||
) {}
|
||||
|
||||
/**
|
||||
* 显示全局参数配置表单
|
||||
* 显示通用系统参数配置表单
|
||||
*/
|
||||
public function edit(): View
|
||||
{
|
||||
// 读取数据库中最新的参数 (剔除专属模块已接管的配置,避免重复显示)
|
||||
$params = SysParam::whereNotIn('alias', ['chatbot_enabled'])
|
||||
->where('alias', 'not like', 'smtp_%')
|
||||
->get()->pluck('body', 'alias')->toArray();
|
||||
$editableAliases = $this->editableSystemAliases();
|
||||
|
||||
// 为后台界面准备的文案对照 (可动态化或硬编码)
|
||||
$descriptions = SysParam::whereNotIn('alias', ['chatbot_enabled'])
|
||||
->where('alias', 'not like', 'smtp_%')
|
||||
->get()->pluck('guidetxt', 'alias')->toArray();
|
||||
// 通用系统页仅加载白名单字段,避免站长专属配置被普通高管查看。
|
||||
$systemParams = SysParam::query()
|
||||
->whereIn('alias', $editableAliases)
|
||||
->orderBy('id')
|
||||
->get(['alias', 'body', 'guidetxt']);
|
||||
|
||||
$params = $systemParams->pluck('body', 'alias')->all();
|
||||
$descriptions = $systemParams->pluck('guidetxt', 'alias')->all();
|
||||
|
||||
return view('admin.system.edit', compact('params', 'descriptions'));
|
||||
}
|
||||
@@ -48,16 +57,19 @@ class SystemController extends Controller
|
||||
*/
|
||||
public function update(Request $request): RedirectResponse
|
||||
{
|
||||
$data = $request->except(['_token', '_method']);
|
||||
// 只接受通用系统页白名单内的字段,忽略任何伪造提交的敏感键。
|
||||
$data = $request->only($this->editableSystemAliases());
|
||||
|
||||
foreach ($data as $alias => $body) {
|
||||
$normalizedBody = (string) $body;
|
||||
|
||||
SysParam::updateOrCreate(
|
||||
['alias' => $alias],
|
||||
['body' => $body]
|
||||
['body' => $normalizedBody]
|
||||
);
|
||||
|
||||
// 写入 Cache 保证极速读取
|
||||
$this->chatState->setSysParam($alias, $body);
|
||||
// 仅对白名单字段同步缓存,杜绝越权请求覆盖站长专属配置。
|
||||
$this->chatState->setSysParam($alias, $normalizedBody);
|
||||
|
||||
// 同时清除 Sysparam 模型的内部缓存
|
||||
SysParam::clearCache($alias);
|
||||
@@ -65,4 +77,31 @@ class SystemController extends Controller
|
||||
|
||||
return redirect()->route('admin.system.edit')->with('success', '系统参数已成功更新并生效!');
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取通用系统页允许维护的参数别名白名单
|
||||
*
|
||||
* @return array<int, string>
|
||||
*/
|
||||
private function editableSystemAliases(): array
|
||||
{
|
||||
return SysParam::query()
|
||||
->orderBy('id')
|
||||
->pluck('alias')
|
||||
->filter(fn (string $alias): bool => ! $this->isSensitiveAlias($alias))
|
||||
->values()
|
||||
->all();
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断参数是否属于站长专属敏感配置
|
||||
*/
|
||||
private function isSensitiveAlias(string $alias): bool
|
||||
{
|
||||
if (Str::startsWith($alias, ['smtp_', 'vip_payment_', 'wechat_bot_', 'chatbot_'])) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return Str::endsWith($alias, ['_password', '_secret', '_token', '_key']);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user