서버가 외부 입력으로 목적지가 제어되는 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 훅을 함께 추가한다.
120 lines
5.0 KiB
PHP
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',
|
|
],
|
|
];
|