feat: secure storage artifact preview
This commit is contained in:
@@ -22,18 +22,19 @@ Route::group("/guest", function () {
|
||||
|
||||
|
||||
# 系统配置
|
||||
Route::group("/system", function () {
|
||||
Route::get("/user/info", [AdminUser::class, "info"])->name("AdminUser@info");
|
||||
Route::get("/user/list", [AdminUser::class, "getAdminUserList"])->name("AdminUser@getAdminUserList");
|
||||
Route::post("/user/save", [AdminUser::class, "saveAdminUser"])->name("AdminUser@saveAdminUser");
|
||||
Route::post("/user/del", [AdminUser::class, "delAdminUser"])->name("AdminUser@delAdminUser");
|
||||
|
||||
Route::group("/system", function () {
|
||||
Route::get("/user/info", [AdminUser::class, "info"])->name("AdminUser@info");
|
||||
Route::get("/user/list", [AdminUser::class, "getAdminUserList"])->name("AdminUser@getAdminUserList");
|
||||
Route::post("/user/save", [AdminUser::class, "saveAdminUser"])->name("AdminUser@saveAdminUser");
|
||||
Route::post("/user/del", [AdminUser::class, "delAdminUser"])->name("AdminUser@delAdminUser");
|
||||
|
||||
Route::get("/config/list", [SystemConfig::class, "getSystemConfigList"])->name("SystemConfig@getSystemConfigList");
|
||||
Route::post("/config/save", [SystemConfig::class, "saveSystemConfig"])->name("SystemConfig@saveSystemConfig");
|
||||
Route::post("/config/seo-ai-rules/reset", [SystemConfig::class, "resetSeoAiRules"])->name("SystemConfig@resetSeoAiRules");
|
||||
|
||||
Route::get("/cjpz/list", [SystemConfig::class, "getCaiJiPeiZhiList"])->name("SystemConfig@getCaiJiPeiZhiList");
|
||||
Route::post("/cjpz/save", [SystemConfig::class, "saveCaiJiPeiZhi"])->name("SystemConfig@saveCaiJiPeiZhi");
|
||||
Route::get("/storage/file", [SystemConfig::class, "previewStorageFile"])->name("SystemConfig@previewStorageFile");
|
||||
|
||||
Route::get("/cjpz/list", [SystemConfig::class, "getCaiJiPeiZhiList"])->name("SystemConfig@getCaiJiPeiZhiList");
|
||||
Route::post("/cjpz/save", [SystemConfig::class, "saveCaiJiPeiZhi"])->name("SystemConfig@saveCaiJiPeiZhi");
|
||||
|
||||
Route::get("/plan/list", [SystemConfig::class, "getPlanTaskList"])->name("SystemConfig@getPlanTaskList");
|
||||
Route::post("/plan/save", [SystemConfig::class, "savePlanTask"])->name("SystemConfig@savePlanTask");
|
||||
|
||||
@@ -25,6 +25,44 @@ use think\Response;
|
||||
|
||||
class SystemConfig extends BaseController
|
||||
{
|
||||
public function previewStorageFile(Request $Request, ?AdminUserModel $AdminUserModel)
|
||||
{
|
||||
$strRelativePath = trim(str_replace('\\', '/', (string)$Request->get('path', '')));
|
||||
if ($strRelativePath === '') {
|
||||
return response('storage path is required', 400, ['Content-Type' => 'text/plain; charset=UTF-8']);
|
||||
}
|
||||
|
||||
$strRelativePath = ltrim($strRelativePath, '/');
|
||||
if (str_starts_with($strRelativePath, 'storage/')) {
|
||||
$strRelativePath = substr($strRelativePath, strlen('storage/'));
|
||||
}
|
||||
|
||||
$strStorageRoot = rtrim(str_replace('\\', '/', (string)root_path()), '/') . '/storage';
|
||||
$strStorageRootReal = realpath($strStorageRoot);
|
||||
$strCandidatePath = $strStorageRoot . '/' . $strRelativePath;
|
||||
$strCandidateReal = realpath($strCandidatePath);
|
||||
|
||||
if ($strStorageRootReal === false || $strCandidateReal === false || !is_file($strCandidateReal)) {
|
||||
return response('storage file not found', 404, ['Content-Type' => 'text/plain; charset=UTF-8']);
|
||||
}
|
||||
|
||||
$strStorageRootReal = str_replace('\\', '/', $strStorageRootReal);
|
||||
$strCandidateReal = str_replace('\\', '/', $strCandidateReal);
|
||||
if (!str_starts_with($strCandidateReal, $strStorageRootReal . '/')) {
|
||||
return response('storage file is out of allowed root', 403, ['Content-Type' => 'text/plain; charset=UTF-8']);
|
||||
}
|
||||
|
||||
$strMimeType = (string)(mime_content_type($strCandidateReal) ?: 'application/octet-stream');
|
||||
$strFilename = basename($strCandidateReal);
|
||||
$strContent = (string)file_get_contents($strCandidateReal);
|
||||
|
||||
return response($strContent, 200, [
|
||||
'Content-Type' => $strMimeType,
|
||||
'Content-Disposition' => 'inline; filename="' . addslashes($strFilename) . '"',
|
||||
'X-Storage-Relative-Path' => $strRelativePath,
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 采集配置列表
|
||||
|
||||
Reference in New Issue
Block a user