Files
Gnuboard7/lang/en/schedule.php
T
HeuJung c4beb116ad fix(security): outbound URL 내부주소·host 검증 전수 강화
서버가 외부 입력으로 목적지가 제어되는 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 훅을 함께 추가한다.
2026-07-14 09:17:00 +09:00

120 lines
5.0 KiB
PHP

<?php
return [
// Messages
'fetch_success' => 'Schedules retrieved successfully.',
'fetch_failed' => 'Failed to retrieve schedules.',
'create_success' => 'Schedule created successfully.',
'create_failed' => 'Failed to create schedule.',
'update_success' => 'Schedule updated successfully.',
'update_failed' => 'Failed to update schedule.',
'delete_success' => 'Schedule deleted successfully.',
'delete_failed' => 'Failed to delete schedule.',
'run_success' => 'Schedule executed successfully.',
'run_failed' => 'Failed to execute schedule.',
'duplicate_success' => 'Schedule duplicated successfully.',
'duplicate_failed' => 'Failed to duplicate schedule.',
'bulk_status_updated' => 'Selected schedules status updated.',
'bulk_update_status_failed' => 'Failed to update schedules status.',
'bulk_delete_success' => 'Selected schedules deleted successfully.',
'bulk_delete_failed' => 'Failed to delete schedules.',
'statistics_success' => 'Schedule statistics retrieved successfully.',
'statistics_failed' => 'Failed to retrieve schedule statistics.',
'history_fetch_success' => 'Execution history retrieved successfully.',
'history_fetch_failed' => 'Failed to retrieve execution history.',
'history_delete_success' => 'Execution history deleted successfully.',
'history_delete_failed' => 'Failed to delete execution history.',
'history_not_found' => 'Execution history not found.',
'copy' => 'Copy',
'shell_command_failed' => 'Shell command execution failed.',
'http_request_failed' => 'HTTP request failed with status: :status',
'url_not_public' => 'Internal network addresses (private IPs, localhost, etc.) cannot be called. To call an address inside your network, enable "Allow internal network addresses" under Settings > Security.',
// Task types
'type' => [
'artisan' => 'Artisan Command',
'shell' => 'Shell Command',
'url' => 'URL Call',
],
// Frequencies
'frequency' => [
'everyMinute' => 'Every Minute',
'hourly' => 'Hourly',
'daily' => 'Daily',
'weekly' => 'Weekly',
'monthly' => 'Monthly',
'custom' => 'Custom',
],
// Results
'result' => [
'success' => 'Success',
'failed' => 'Failed',
'running' => 'Running',
'never' => 'Never Run',
],
// Trigger types
'trigger_type' => [
'scheduled' => 'Scheduled',
'manual' => 'Manual',
],
// Duration
'duration' => [
'seconds' => 's',
'minutes' => 'm',
],
// Validation messages
'validation' => [
'page_integer' => 'Page number must be an integer.',
'page_min' => 'Page number must be at least 1.',
'per_page_integer' => 'Items per page must be an integer.',
'per_page_min' => 'Items per page must be at least 1.',
'per_page_max' => 'Items per page must not exceed 100.',
'type_invalid' => 'Invalid task type.',
'frequency_invalid' => 'Invalid frequency.',
'status_invalid' => 'Invalid status.',
'last_result_invalid' => 'Invalid execution result.',
'history_status_invalid' => 'Invalid history status.',
'trigger_type_invalid' => 'Invalid trigger type.',
'created_from_invalid' => 'Invalid start date format.',
'created_to_invalid' => 'Invalid end date format.',
'created_to_after_from' => 'End date must be after start date.',
'started_from_invalid' => 'Invalid start date format.',
'started_to_invalid' => 'Invalid end date format.',
'started_to_after_from' => 'End date must be after start date.',
'sort_by_invalid' => 'Invalid sort field.',
'sort_order_invalid' => 'Invalid sort order.',
'name_required' => 'Task name is required.',
'name_max' => 'Task name must not exceed 255 characters.',
'type_required' => 'Task type is required.',
'command_required' => 'Command is required.',
'command_max' => 'Command must not exceed 2000 characters.',
'expression_required' => 'Cron expression is required.',
'expression_max' => 'Cron expression must not exceed 100 characters.',
'frequency_required' => 'Frequency is required.',
'timeout_integer' => 'Timeout must be an integer.',
'timeout_min' => 'Timeout must be at least 1 second.',
'timeout_max' => 'Timeout must not exceed 86400 seconds (24 hours).',
'ids_required' => 'ID list is required.',
'ids_array' => 'ID list must be an array.',
'ids_min' => 'At least 1 ID is required.',
'id_integer' => 'ID must be an integer.',
'id_exists' => 'Schedule not found.',
'is_active_required' => 'Active status is required.',
'is_active_boolean' => 'Active status must be true or false.',
],
// Permissions
'permissions' => [
'read' => 'View Schedules',
'create' => 'Create Schedules',
'update' => 'Update Schedules',
'delete' => 'Delete Schedules',
'run' => 'Run Schedules',
],
];