메일 인증 대신 휴대폰 본인확인을 쓸 수 있게 하는 플러그인을 추가한다. 가입·비밀번호 재설정·성인인증 등 코어 IDV 가 강제하는 모든 지점에서 동작하며, 테스트 모드로 계약 없이 전 흐름을 확인할 수 있다. 구현·검수 과정에서 드러난 저장소 전역 결함을 함께 처리했다. - 외래키 컬럼의 한국어 comment 가 방출되지 않던 문제 (소스 38건 교정 + 기설치본 백필 업그레이드 스텝 7종). ->comment 를 ->constrained 뒤에 체인하면 예외 없이 통과하면서 comment 가 조용히 사라진다 - 로케일 전환 후 확장 액션 핸들러가 소실되던 문제 (플러그인 3종에 재등록 진입점 노출) - 본인인증 상태 폴링 응답이 누적 시도 횟수를 함께 내보내던 문제 - 인증 안내 문구와 실제 진행 방식의 폭 경계 불일치 (768~1023px). 엔진과 같은 값을 같은 방법으로 읽도록 교정 - transition_overlay_target 이 replace 없이 무효이던 관리자 목록 40곳. 로딩 표시가 나오지 않아도 경고가 남지 않아 화면을 봐야만 알 수 있었다 두 인증 플러그인의 코어 최소 요구 버전을 7.0.6 으로 올린다. 운영 모드 자격증명 필수 검사가 7.0.6 의 설정 저장 검증 표면에 의존하며, 그보다 낮은 코어에서는 그 검사가 조용히 통과해 빈 자격증명으로 저장할 수 있었다. 재발 차단으로 정적 검사 룰 4종을 신설하고, 검사 도구가 미커밋 신규 확장을 "검사 파일 0" 으로 통과시키던 사각을 함께 막았다.
150 lines
5.0 KiB
PHP
150 lines
5.0 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Requests\Admin;
|
|
|
|
use App\Extension\HookManager;
|
|
use App\Extension\PluginManager;
|
|
use Illuminate\Foundation\Http\FormRequest;
|
|
|
|
/**
|
|
* 플러그인 설정 업데이트 요청 검증
|
|
*
|
|
* 플러그인의 설정 스키마를 기반으로 동적으로 유효성 검사 규칙을 생성합니다.
|
|
*/
|
|
class UpdatePluginSettingsRequest extends FormRequest
|
|
{
|
|
/**
|
|
* 사용자가 이 요청을 수행할 권한이 있는지 확인합니다.
|
|
*
|
|
* 권한 체크는 라우트의 permission 미들웨어에서 수행됩니다.
|
|
*
|
|
* @return bool 항상 true
|
|
*/
|
|
public function authorize(): bool
|
|
{
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* 요청에 적용할 검증 규칙을 반환합니다.
|
|
*
|
|
* 플러그인의 설정 스키마를 기반으로 동적으로 규칙을 생성합니다.
|
|
*
|
|
* @return array 검증 규칙 배열
|
|
*/
|
|
public function rules(): array
|
|
{
|
|
$identifier = $this->route('identifier');
|
|
$pluginManager = app(PluginManager::class);
|
|
$plugin = $pluginManager->getPlugin($identifier);
|
|
|
|
if (! $plugin) {
|
|
return [];
|
|
}
|
|
|
|
$schema = $plugin->getSettingsSchema();
|
|
$rules = [];
|
|
|
|
foreach ($schema as $field => $config) {
|
|
$fieldRules = [];
|
|
|
|
// 필수 여부
|
|
if ($config['required'] ?? false) {
|
|
$fieldRules[] = 'required';
|
|
} else {
|
|
$fieldRules[] = 'nullable';
|
|
}
|
|
|
|
// 타입별 규칙 추가
|
|
$type = $config['type'] ?? 'string';
|
|
|
|
switch ($type) {
|
|
case 'string':
|
|
$fieldRules[] = 'string';
|
|
if (isset($config['max'])) {
|
|
$fieldRules[] = 'max:'.$config['max'];
|
|
}
|
|
if (isset($config['min'])) {
|
|
$fieldRules[] = 'min:'.$config['min'];
|
|
}
|
|
break;
|
|
|
|
case 'integer':
|
|
$fieldRules[] = 'integer';
|
|
if (isset($config['min'])) {
|
|
$fieldRules[] = 'min:'.$config['min'];
|
|
}
|
|
if (isset($config['max'])) {
|
|
$fieldRules[] = 'max:'.$config['max'];
|
|
}
|
|
break;
|
|
|
|
case 'boolean':
|
|
$fieldRules[] = 'boolean';
|
|
break;
|
|
|
|
case 'enum':
|
|
$options = $config['options'] ?? [];
|
|
if (! empty($options)) {
|
|
$fieldRules[] = 'in:'.implode(',', $options);
|
|
}
|
|
break;
|
|
|
|
case 'url':
|
|
$fieldRules[] = 'url';
|
|
break;
|
|
|
|
case 'email':
|
|
$fieldRules[] = 'email';
|
|
break;
|
|
|
|
case 'array':
|
|
$fieldRules[] = 'array';
|
|
break;
|
|
}
|
|
|
|
$rules[$field] = $fieldRules;
|
|
}
|
|
|
|
// audit:allow core-formrequest-hook-filter reason: 훅 이름이 표준(`{대상}.{동작}_validation_rules`)과
|
|
// 어긋난 상태로 이미 공개되어 있다(`core.plugin_settings.update_rules`). 같은 이탈이 코어에
|
|
// 6개 더 있으며(core.auth.validate_reset_token_rules / core.auth.verify_password_rules /
|
|
// core.extension.changelog_rules / core.layout.get_validation_messages /
|
|
// core.search.validation_rules / core.user.upload_avatar_rules), 이름을 바꾸면 이 훅을
|
|
// 구독 중인 제3자 확장이 조용히 동작을 멈춘다. 일괄 개명은 PO 판단 사항이라 여기서
|
|
// 단독으로 바꾸지 않는다.
|
|
//
|
|
// 3번째 인자로 이번 요청의 입력값을 함께 넘긴다. 확장이 "현재 입력한 모드에 따라
|
|
// 다른 필드를 필수로 만드는" 조건부 규칙을 만들려면 입력값이 필요한데, 그것이 없어
|
|
// 확장이 request() 를 직접 들여다보던 것을 없애기 위함이다.
|
|
// 기존 2인자 구독자는 그대로 동작한다(초과 인자는 무시된다).
|
|
return HookManager::applyFilters(
|
|
'core.plugin_settings.update_rules',
|
|
$rules,
|
|
$identifier,
|
|
$this->all(),
|
|
);
|
|
}
|
|
|
|
/**
|
|
* 검증 에러 메시지를 반환합니다.
|
|
*
|
|
* @return array 에러 메시지 배열
|
|
*/
|
|
public function messages(): array
|
|
{
|
|
return [
|
|
'required' => __('validation.required'),
|
|
'string' => __('validation.string'),
|
|
'integer' => __('validation.integer'),
|
|
'boolean' => __('validation.boolean'),
|
|
'in' => __('validation.in'),
|
|
'url' => __('validation.url'),
|
|
'email' => __('validation.email'),
|
|
'array' => __('validation.array'),
|
|
'max' => __('validation.max'),
|
|
'min' => __('validation.min'),
|
|
];
|
|
}
|
|
}
|