서버가 외부 입력으로 목적지가 제어되는 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
4.2 KiB
PHP
65 lines
4.2 KiB
PHP
<?php
|
|
|
|
return [
|
|
'fetch_success' => 'Language pack list retrieved.',
|
|
'fetch_failed' => 'Failed to load language pack list: :error',
|
|
'not_found' => 'Language pack not found.',
|
|
'install_success' => 'Language pack installed.',
|
|
'install_failed' => 'Failed to install language pack: :error',
|
|
'activate_success' => 'Language pack activated.',
|
|
'activate_failed' => 'Failed to activate language pack: :error',
|
|
'deactivate_success' => 'Language pack deactivated.',
|
|
'deactivate_failed' => 'Failed to deactivate language pack: :error',
|
|
'uninstall_success' => 'Language pack removed.',
|
|
'uninstall_failed' => 'Failed to remove language pack: :error',
|
|
'manifest_invalid' => 'language-pack.json validation failed.',
|
|
'check_updates_success' => 'Update check completed.',
|
|
'check_updates_failed' => 'Failed to check updates: :error',
|
|
'update_success' => 'Language pack updated.',
|
|
'update_failed' => 'Failed to update language pack: :error',
|
|
'refresh_cache_success' => 'Language pack cache refreshed.',
|
|
'refresh_cache_failed' => 'Failed to refresh language pack cache: :error',
|
|
'preview_success' => 'Manifest preview completed.',
|
|
'preview_failed' => 'Failed to preview manifest: :error',
|
|
|
|
'errors' => [
|
|
'manifest_not_found' => 'language-pack.json file not found in archive.',
|
|
'manifest_invalid_json' => 'language-pack.json contains invalid JSON.',
|
|
'php_outside_backend' => 'PHP file detected outside the backend/ directory (:file).',
|
|
'unsafe_php_pattern' => 'Disallowed code pattern detected in PHP file (:file).',
|
|
'core_locale_missing' => 'A core language pack for ":locale" must be active first.',
|
|
'target_not_installed' => 'Target :scope (":target") is not installed.',
|
|
'target_inactive' => 'Target :scope (":target") is inactive. Activate it first.',
|
|
'target_version_too_old' => 'Target :scope (":target") version does not satisfy the required constraint (:constraint).',
|
|
'downgrade_blocked' => 'Downgrade blocked (:from → :to).',
|
|
'protected_pack' => 'Protected language packs cannot be deactivated or removed.',
|
|
'download_failed' => 'Failed to download from URL: :url',
|
|
'download_url_not_public' => 'Language packs cannot be downloaded from internal network addresses (private IPs, localhost, etc.). Use a publicly reachable https address.',
|
|
'checksum_mismatch' => 'Checksum mismatch.',
|
|
'update_no_source' => 'No update source available (only GitHub-sourced packs can be updated).',
|
|
'update_already_latest' => 'Already on the latest version.',
|
|
'preview_invalid_manifest' => 'Manifest preview failed: invalid manifest file.',
|
|
'operation_in_progress' => 'Another operation is in progress for language pack (:identifier). Please try again after it completes.',
|
|
'bundled_not_found' => 'Bundled directory (lang-packs/_bundled/:identifier) does not exist.',
|
|
'slot_conflict' => 'Slot already has an active language pack (:current). Confirm replacement with :target.',
|
|
'directory_not_writable' => 'The language pack install directory (:path) is not writable. Grant write permission to the web server user (e.g. www-data). Example: sudo chgrp www-data :path && sudo chmod g+w :path',
|
|
'identifier_not_found' => 'Language pack not found (:identifier).',
|
|
'unsupported_source' => 'Unsupported source (:source) — use one of bundled, github, url.',
|
|
],
|
|
|
|
'validation' => [
|
|
'file_required' => 'Upload a language pack ZIP file.',
|
|
'file_invalid' => 'Uploaded file is not valid.',
|
|
'file_too_large' => 'File size must not exceed 10 MB.',
|
|
'file_not_zip' => 'Only ZIP archives are accepted.',
|
|
'github_url_required' => 'Enter a GitHub URL.',
|
|
'github_url_invalid' => 'Enter a valid URL.',
|
|
'github_url_format' => 'Must be a GitHub repository URL (e.g. https://github.com/owner/repo).',
|
|
'url_required' => 'Enter a download URL.',
|
|
'url_invalid' => 'Enter a valid URL.',
|
|
'checksum_invalid' => 'SHA-256 checksum must be 64 hex characters.',
|
|
'identifier_required' => 'Enter the language pack identifier.',
|
|
'identifier_invalid' => 'Identifier may contain letters, numbers, dots, underscores and hyphens only.',
|
|
],
|
|
];
|