서버가 외부 입력으로 목적지가 제어되는 outbound HTTP 요청을 보내는 지점을 전수 조사해, 내부망(사설 IP·루프백·링크로컬·메타데이터)과 host 위조를 차단한다. KVE-2026-1546(이니시스 인증 URL 접두사 매칭 우회)과 동일 클래스의 지점(언어팩 URL 설치, 스케줄 URL 호출, 배송비 계산 API, GitHub URL 판정)을 코어 공용 유틸 App\Support\OutboundUrlValidator 로 수렴시켰다. - 접두사 매칭을 host 완전일치로 교체 — userinfo(@) 위장과 접미사 확장 도메인 우회 벡터 차단. - 사내 서버 호출이 정당한 관리자 지점(스케줄·외부 API)은 신규 설정 security.allow_internal_outbound_urls(기본 off)로 옵트인. - 언어팩 URL 설치는 원격 코드 다운로드라 옵트인과 무관하게 내부 주소 항상 차단. - 웹소켓 연결 테스트는 localhost·사설 IP 가 정상 구성이므로 구조적 위조만 차단. 각 지점에 red 재현 → 수정 → green 회귀 테스트 + 실브라우저 E2E 로 검증. 수기 API 문서가 자동 재생성으로 소실되는 사고를 막는 PreToolUse 훅을 함께 추가한다.
65 lines
5.1 KiB
PHP
65 lines
5.1 KiB
PHP
<?php
|
|
|
|
return [
|
|
'fetch_success' => '언어팩 목록을 조회했습니다.',
|
|
'fetch_failed' => '언어팩 목록을 불러오지 못했습니다: :error',
|
|
'not_found' => '언어팩을 찾을 수 없습니다.',
|
|
'install_success' => '언어팩을 설치했습니다.',
|
|
'install_failed' => '언어팩 설치에 실패했습니다: :error',
|
|
'activate_success' => '언어팩을 활성화했습니다.',
|
|
'activate_failed' => '언어팩 활성화에 실패했습니다: :error',
|
|
'deactivate_success' => '언어팩을 비활성화했습니다.',
|
|
'deactivate_failed' => '언어팩 비활성화에 실패했습니다: :error',
|
|
'uninstall_success' => '언어팩을 제거했습니다.',
|
|
'uninstall_failed' => '언어팩 제거에 실패했습니다: :error',
|
|
'manifest_invalid' => 'language-pack.json 검증에 실패했습니다.',
|
|
'check_updates_success' => '업데이트 확인을 완료했습니다.',
|
|
'check_updates_failed' => '업데이트 확인에 실패했습니다: :error',
|
|
'update_success' => '언어팩을 업데이트했습니다.',
|
|
'update_failed' => '언어팩 업데이트에 실패했습니다: :error',
|
|
'refresh_cache_success' => '언어팩 캐시를 갱신했습니다.',
|
|
'refresh_cache_failed' => '언어팩 캐시 갱신에 실패했습니다: :error',
|
|
'preview_success' => 'manifest 미리보기를 완료했습니다.',
|
|
'preview_failed' => 'manifest 미리보기에 실패했습니다: :error',
|
|
|
|
'errors' => [
|
|
'manifest_not_found' => 'ZIP 안에서 language-pack.json 파일을 찾을 수 없습니다.',
|
|
'manifest_invalid_json' => 'language-pack.json 의 JSON 형식이 올바르지 않습니다.',
|
|
'php_outside_backend' => 'backend/ 디렉토리 외에 PHP 파일이 포함되어 있습니다 (:file).',
|
|
'unsafe_php_pattern' => 'PHP 파일에 허용되지 않는 코드 패턴이 포함되어 있습니다 (:file).',
|
|
'core_locale_missing' => '코어 언어팩(:locale)이 먼저 활성화되어야 합니다.',
|
|
'target_not_installed' => '대상 :scope (:target)이 설치되어 있지 않습니다.',
|
|
'target_inactive' => '대상 :scope (:target)이 비활성 상태입니다. 먼저 활성화해야 합니다.',
|
|
'target_version_too_old' => '대상 :scope (:target) 버전이 요구 조건(:constraint)을 충족하지 않습니다.',
|
|
'downgrade_blocked' => '다운그레이드가 차단되었습니다 (:from → :to).',
|
|
'protected_pack' => '보호된 언어팩은 비활성화/제거할 수 없습니다.',
|
|
'download_failed' => 'URL(:url) 에서 언어팩을 다운로드하지 못했습니다: :error',
|
|
'download_url_not_public' => '내부 네트워크 주소(사설 IP·localhost 등)에서는 언어팩을 내려받을 수 없습니다. 외부에서 접속 가능한 https 주소를 사용해주세요.',
|
|
'checksum_mismatch' => '체크섬이 일치하지 않습니다.',
|
|
'update_no_source' => '업데이트 소스 정보가 없습니다 (GitHub 소스 언어팩만 업데이트 가능).',
|
|
'update_already_latest' => '이미 최신 버전입니다.',
|
|
'preview_invalid_manifest' => 'manifest 파일이 유효하지 않아 미리보기에 실패했습니다.',
|
|
'operation_in_progress' => '언어팩(:identifier) 에서 다른 작업이 진행 중입니다. 완료 후 다시 시도해주세요.',
|
|
'bundled_not_found' => '번들 디렉토리(lang-packs/_bundled/:identifier) 가 존재하지 않습니다.',
|
|
'slot_conflict' => '같은 슬롯에 이미 활성 언어팩(:current)이 있습니다. (:target)으로 교체하려면 확인이 필요합니다.',
|
|
'directory_not_writable' => '언어팩 설치 디렉토리(:path) 에 쓰기 권한이 없습니다. 웹 서버 사용자(예: www-data) 에게 쓰기 권한을 부여하세요. (예: sudo chgrp www-data :path && sudo chmod g+w :path)',
|
|
'identifier_not_found' => '언어팩을 찾을 수 없습니다 (:identifier).',
|
|
'unsupported_source' => '지원하지 않는 소스 (:source) — bundled, github, url 중 하나를 사용하세요.',
|
|
],
|
|
|
|
'validation' => [
|
|
'file_required' => '언어팩 ZIP 파일을 업로드하세요.',
|
|
'file_invalid' => '업로드된 파일이 유효하지 않습니다.',
|
|
'file_too_large' => '파일 크기는 10MB 를 초과할 수 없습니다.',
|
|
'file_not_zip' => 'ZIP 형식의 파일만 업로드할 수 있습니다.',
|
|
'github_url_required' => 'GitHub URL 을 입력하세요.',
|
|
'github_url_invalid' => '올바른 URL 을 입력하세요.',
|
|
'github_url_format' => 'GitHub 저장소 URL 형식이어야 합니다 (예: https://github.com/owner/repo).',
|
|
'url_required' => '다운로드 URL 을 입력하세요.',
|
|
'url_invalid' => '올바른 URL 을 입력하세요.',
|
|
'checksum_invalid' => 'SHA-256 체크섬은 64자 16진수여야 합니다.',
|
|
'identifier_required' => '언어팩 식별자를 입력하세요.',
|
|
'identifier_invalid' => '식별자는 영문/숫자/점/언더스코어/하이픈만 허용됩니다.',
|
|
],
|
|
];
|