https://github.com/gnuboard/g7/issues/122 제보자의 추가 지적 2건(빌드가 게시본을 지움 / CLI 최초 게시 후 웹 재생성 불가)에 대응하고, 같은 근본 원인을 공유하는 결함을 전수조사로 함께 고친다. - 빌드가 자기 산출물만 교체한다: 루트 vite `emptyOutDir: false` 기본값 true 는 폴백 없는 코어 3번들과 배달된 immutable URL 의 게시본을 함께 지웠다 - 게시 트리 권한을 웹이 이어받는다: 병합 전 프리플라이트 + 부모 그룹 상속·g+w 종전 소유권 정상화는 root 축만 덮어 비-root CLI 계정은 무방비였다 - 갱신 → 생성 → 완전성 확인을 한 묶음으로: 기록 바이트 대조, .old 원자 스왑, rename 일시 거부 재시도, 프론트 JSON 파싱 검증 - 실패를 억제하고 기록한다: 버전 한정 실패 마커 + 사유별 대시보드 알림 + ext-static:status 점검 커맨드 - 파생: catch-all 제외 목록을 에셋 화이트리스트 합집합에서 파생(mjs·webp·otf 누락), 번들 디스크 쓰기 fail-soft·빈 번들 503, 활성 디렉토리 prune 회피
88 lines
2.6 KiB
PHP
88 lines
2.6 KiB
PHP
<?php
|
|
|
|
namespace App\Rules;
|
|
|
|
use Closure;
|
|
use Illuminate\Contracts\Validation\ValidationRule;
|
|
|
|
class AllowedModuleFileType implements ValidationRule
|
|
{
|
|
/**
|
|
* 허용된 파일 확장자 목록
|
|
*/
|
|
private const ALLOWED_EXTENSIONS = [
|
|
// Scripts
|
|
'js', 'mjs',
|
|
|
|
// Styles
|
|
'css',
|
|
|
|
// Data
|
|
'json',
|
|
|
|
// Images
|
|
'png', 'jpg', 'jpeg', 'svg', 'webp', 'gif', 'ico',
|
|
|
|
// Fonts
|
|
'woff', 'woff2', 'ttf', 'otf', 'eot',
|
|
];
|
|
|
|
/**
|
|
* 환경과 무관한 기본 허용 확장자 목록을 반환합니다.
|
|
*
|
|
* `getAllowedExtensions()` 는 로컬에서 소스맵(`map`)을 덧붙이는 **환경 의존** 게터라
|
|
* 라우트 패턴처럼 정의 시점에 한 번 굳어 캐시에 박히는 소비자가 쓰면 안 된다
|
|
* (캐시를 구운 환경에 따라 패턴이 달라진다). 그런 소비자는 이 게터를 쓴다.
|
|
*
|
|
* @return array<string> 기본 허용 확장자 목록
|
|
*/
|
|
public static function allowedExtensions(): array
|
|
{
|
|
return self::ALLOWED_EXTENSIONS;
|
|
}
|
|
|
|
/**
|
|
* 허용된 파일 타입인지 검증
|
|
*/
|
|
public function validate(string $attribute, mixed $value, Closure $fail): void
|
|
{
|
|
if (! is_string($value)) {
|
|
$fail(__('validation.module_path.must_be_string'));
|
|
|
|
return;
|
|
}
|
|
|
|
$extension = strtolower(pathinfo($value, PATHINFO_EXTENSION));
|
|
$allowed = self::getAllowedExtensions();
|
|
|
|
if (! in_array($extension, $allowed, true)) {
|
|
$fail(__('validation.module_path.file_type_not_allowed', [
|
|
'extension' => $extension,
|
|
'allowed' => implode(', ', $allowed),
|
|
]));
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 허용된 확장자 목록 반환
|
|
*
|
|
* 로컬 개발 환경에서만 소스맵(`map`)을 덧붙인다. dev 빌드 산출물은
|
|
* `//# sourceMappingURL` 이 개별 에셋 서빙 URL 을 가리키므로 서빙되어야
|
|
* 브라우저 콘솔에 404 가 남지 않는다. 반면 소스맵에는 원본 코드 전문
|
|
* (`sourcesContent`)이 담겨 있고 이 화이트리스트가 에셋 서빙의 유일한
|
|
* 방어선이므로, 운영 환경에서는 어떤 경우에도 서빙하지 않는다.
|
|
*
|
|
* @return array<string> 허용된 확장자 목록
|
|
*/
|
|
public static function getAllowedExtensions(): array
|
|
{
|
|
if (app()->environment('local')) {
|
|
return [...self::ALLOWED_EXTENSIONS, 'map'];
|
|
}
|
|
|
|
return self::ALLOWED_EXTENSIONS;
|
|
}
|
|
}
|