위임 관리자(부관리자)가 권한·역할·표현식·비밀 콘텐츠 경계를 우회하던 결함군을 계층 대칭성 원칙으로 전건 차단한다. 약한 경로가 정상 응답을 내보내는 것이 유일한 증상이라, 게이트를 생산 지점 한 곳(SSoT)에 두고 같은 데이터를 내보내는 소비 경로 전부가 그 게이트를 경유하도록 맞췄다. - 등급 상한(rank ceiling): 슈퍼관리자 보호·역할/사용자 역할 배정(추가·제거 대칭)·일괄 상태변경·순서변경을 상세 경로와 동일 강도로 재적용. 가드는 DB 쓰기에 선행하여 거부 시 상태 불변. - 레이아웃 표현식: new Function/with 실행을 AST 화이트리스트 평가기로 교체. 비-문자열 computed 키 정규화(normalizeKey)·Object facade(리플렉션 static 제거)·legacy 접근자 차단. 저장측 검증·정적 검사와 3계층 동형. - secret 게이트: 비밀글의 댓글·첨부·문의 독립 경로 재적용, hash 파일서빙 소유권·비밀·발행 상태 검사 통일. - 신뢰 스크립트 호스트: 확장 선언 기반 + same-origin 브라우저 정규화를 런타임·저장측·정적검사 3층 동형화. - 회귀 감지: 단위·Feature·E2E·시나리오 매니페스트 전축 + audit 룰 4종 신설.
132 lines
5.2 KiB
PHP
132 lines
5.2 KiB
PHP
<?php
|
|
|
|
namespace App\Http\View\Composers;
|
|
|
|
use App\Exceptions\TemplateNotFoundException;
|
|
use App\Extension\ModuleManager;
|
|
use App\Extension\PluginManager;
|
|
use App\Extension\TemplateManager;
|
|
use App\Extension\Traits\ClearsTemplateCaches;
|
|
use App\Http\View\Composers\Traits\CollectsActiveExtensionMeta;
|
|
use App\Http\View\Composers\Traits\CollectsExtensionAssets;
|
|
use App\Http\View\Composers\Traits\CollectsTemplateExternals;
|
|
use App\Services\ModuleSettingsService;
|
|
use App\Services\PluginSettingsService;
|
|
use App\Services\SettingsService;
|
|
use App\Services\TemplateService;
|
|
use App\Support\TrustedScriptHosts;
|
|
use Illuminate\View\View;
|
|
|
|
/**
|
|
* 사용자 템플릿 View Composer
|
|
*
|
|
* app.blade.php 뷰에 사용자 템플릿 관련 데이터를 바인딩합니다.
|
|
*/
|
|
class UserTemplateComposer
|
|
{
|
|
use CollectsActiveExtensionMeta;
|
|
use CollectsExtensionAssets;
|
|
use CollectsTemplateExternals;
|
|
|
|
/**
|
|
* 서비스 주입
|
|
*
|
|
* @param TemplateService $templateService 템플릿 서비스
|
|
* @param SettingsService $settingsService 코어 설정 서비스
|
|
* @param ModuleSettingsService $moduleSettingsService 모듈 설정 서비스
|
|
* @param PluginSettingsService $pluginSettingsService 플러그인 설정 서비스
|
|
* @param ModuleManager $moduleManager 모듈 매니저
|
|
* @param PluginManager $pluginManager 플러그인 매니저
|
|
* @param TemplateManager $templateManager 템플릿 매니저
|
|
*/
|
|
public function __construct(
|
|
private TemplateService $templateService,
|
|
private SettingsService $settingsService,
|
|
private ModuleSettingsService $moduleSettingsService,
|
|
private PluginSettingsService $pluginSettingsService,
|
|
private ModuleManager $moduleManager,
|
|
private PluginManager $pluginManager,
|
|
private TemplateManager $templateManager
|
|
) {}
|
|
|
|
/**
|
|
* 뷰에 데이터 바인딩
|
|
*
|
|
* @param View $view 뷰 인스턴스
|
|
*/
|
|
public function compose(View $view): void
|
|
{
|
|
try {
|
|
$activeTemplate = $this->templateService->getActiveTemplateIdentifier('user');
|
|
} catch (TemplateNotFoundException $e) {
|
|
$activeTemplate = null;
|
|
}
|
|
|
|
// 프론트엔드 전역 변수로 사용할 설정 조회
|
|
try {
|
|
$frontendSettings = $this->settingsService->getFrontendSettings();
|
|
} catch (\Exception $e) {
|
|
$frontendSettings = [];
|
|
}
|
|
|
|
// 활성화된 플러그인 설정 조회
|
|
try {
|
|
$pluginSettings = $this->pluginSettingsService->getAllActiveSettings();
|
|
} catch (\Exception $e) {
|
|
$pluginSettings = [];
|
|
}
|
|
|
|
// 활성화된 모듈 설정 조회 (frontend_schema 기반 필터링 적용)
|
|
try {
|
|
$moduleSettings = $this->moduleSettingsService->getAllActiveSettings();
|
|
} catch (\Exception $e) {
|
|
$moduleSettings = [];
|
|
}
|
|
|
|
// 활성화된 모듈의 프론트엔드 에셋 정보 수집
|
|
$moduleAssets = $this->collectModuleAssets();
|
|
|
|
// 활성화된 플러그인의 프론트엔드 에셋 정보 수집
|
|
$pluginAssets = $this->collectPluginAssets();
|
|
|
|
// 활성 확장(모듈/플러그인) 메타 — 레이아웃 편집기 SSoT
|
|
// 기존 modules/plugins 키는 hasSettings() 필터로 활성 전수가 아님
|
|
$activeModulesMeta = $this->collectActiveModulesMeta();
|
|
$activePluginsMeta = $this->collectActivePluginsMeta();
|
|
|
|
// 프론트엔드에 노출할 앱 config 값 조회
|
|
try {
|
|
$appConfig = $this->settingsService->getAppConfigForFrontend();
|
|
} catch (\Exception $e) {
|
|
$appConfig = [];
|
|
}
|
|
|
|
// 템플릿의 외부 리소스 정보 수집
|
|
$templateExternals = $this->collectTemplateExternals($activeTemplate);
|
|
|
|
// 확장 기능 캐시 버전 (브라우저 캐시 무효화용)
|
|
$extensionCacheVersion = ClearsTemplateCaches::getExtensionCacheVersion();
|
|
|
|
// 확장 프론트엔드 병합 번들 URL (상시 ON — 활성 에셋이 없으면 null)
|
|
$bundleUrls = $this->buildExtensionBundleUrls($moduleAssets, $pluginAssets, $extensionCacheVersion);
|
|
|
|
// 신뢰 외부 스크립트 호스트 — 레이아웃 scripts[].src same-origin 예외 허용목록
|
|
// (KVE-2026-1915: 확장이 manifest 로 선언한 CDN 호스트만 런타임 로더가 허용)
|
|
$trustedScriptHosts = TrustedScriptHosts::hosts();
|
|
|
|
$view->with('activeUserTemplate', $activeTemplate);
|
|
$view->with('extensionCacheVersion', $extensionCacheVersion);
|
|
$view->with('frontendSettings', $frontendSettings);
|
|
$view->with('pluginSettings', $pluginSettings);
|
|
$view->with('moduleSettings', $moduleSettings);
|
|
$view->with('moduleAssets', $moduleAssets);
|
|
$view->with('pluginAssets', $pluginAssets);
|
|
$view->with('bundleUrls', $bundleUrls);
|
|
$view->with('activeModulesMeta', $activeModulesMeta);
|
|
$view->with('activePluginsMeta', $activePluginsMeta);
|
|
$view->with('appConfig', $appConfig);
|
|
$view->with('templateExternals', $templateExternals);
|
|
$view->with('trustedScriptHosts', $trustedScriptHosts);
|
|
}
|
|
}
|