앞선 커밋이 CHANGELOG 에 주장한 "로딩 표시가 나오지 않던 문제 수정" 이 실제로 화면에 나타나는지 브라우저로 확정했다. 전달 경로부터 DOM 마운트·해제까지 측정했고, 지연·에러 응답에서도 영구 로딩이 남지 않음을 확인했다. 측정 과정에서 앞선 세션의 판단 하나가 틀렸음을 확인했다 — "오버레이 DOM 이 어느 화면에서도 관측되지 않는다" 는 관측 대상 노드를 잘못 잡은 것이었다. 스피너 방식 레이아웃은 다른 노드를 쓰며, 대조군에서도 안 보였던 이유가 이것이다. 미뤄 두었던 과제 4건을 함께 구현했다. - 인증창을 그냥 닫고 이탈하면 그 인증 요청을 서버에도 종료로 표시한다. 이전에는 브라우저만 알고 있어 인증 이력에 "보낸 뒤 소식 없는" 항목이 남았다 - 플러그인 설정 화면이 저장된 비밀값을 다시 내려받던 것을 가려서 표시한다. 그 항목을 건드리지 않고 저장하면 저장된 값이 그대로 유지된다 - 언어팩 반영 누락 검사가 버전만 비교해 "버전 같고 내용 다름" 을 놓치던 사각을 콘텐츠 비교로 닫았다 - 확장이 검증 규칙을 추가할 때 쓰는 필터 이름 6개를 표준 형태로 통일했다. 예전 이름도 함께 발행하므로 기존 확장은 수정 없이 동작한다 정적 검사 룰 2종의 오탐·사각을 함께 고쳤고, 개명으로 검사 대상에 편입된 파일의 사전 결함 8건을 해소했다. 검수용 데이터는 전량 정리했다.
81 lines
3.1 KiB
PHP
81 lines
3.1 KiB
PHP
<?php
|
|
|
|
namespace App\Support;
|
|
|
|
/**
|
|
* 민감 설정값(sensitive: true)의 응답 마스킹 규약.
|
|
*
|
|
* 관리자 설정 조회 응답은 저장된 비밀값(암호화 키, API 시크릿 등)을 평문으로 되돌려주지 않는다.
|
|
* 값이 저장되어 있다는 사실만 마스크로 알리고, 실제 값은 서버 안에만 둔다 — 화면·브라우저 개발자
|
|
* 도구·프록시 로그에 비밀값이 남지 않게 하기 위함이다.
|
|
*
|
|
* 저장 쪽과 짝을 이룬다: 운영자가 값을 건드리지 않으면 화면이 마스크를 그대로 되돌려 보내므로,
|
|
* 저장 단계에서 마스크를 걸러내 기존 값을 보존한다. 빈 문자열은 마스크가 아니라 "지우겠다" 는
|
|
* 명시적 의사로 취급한다.
|
|
*
|
|
* 내부 소비자(provider 에 자격증명을 주입하는 listener 등)는 마스킹되지 않은 값을 그대로 받는다 —
|
|
* 마스킹은 오직 관리자 API 응답 경계에서만 적용한다.
|
|
*
|
|
* @since 7.0.6
|
|
*/
|
|
final class SensitiveSettingMask
|
|
{
|
|
/**
|
|
* 저장된 비밀값을 대신하는 마스크 문자열.
|
|
*
|
|
* 실제 값으로 오인될 수 없도록 통상적인 키·시크릿 문자셋에 없는 형태를 쓴다.
|
|
*/
|
|
public const MASK = '••••••••';
|
|
|
|
/**
|
|
* 스키마의 sensitive 필드를 마스크로 치환한다.
|
|
*
|
|
* 값이 비어 있는 필드는 마스크를 씌우지 않는다 — 화면이 "아직 입력되지 않음" 을 구분해야 한다.
|
|
*
|
|
* @param array<string, mixed> $settings 설정 배열 (복호화된 상태)
|
|
* @param array<string, mixed> $schema 설정 스키마 (sensitive 플래그 보유)
|
|
* @return array<string, mixed> 마스킹된 설정 배열
|
|
*/
|
|
public static function apply(array $settings, array $schema): array
|
|
{
|
|
foreach ($schema as $field => $config) {
|
|
if (! is_array($config) || ! ($config['sensitive'] ?? false)) {
|
|
continue;
|
|
}
|
|
if (! array_key_exists($field, $settings)) {
|
|
continue;
|
|
}
|
|
if ($settings[$field] === null || $settings[$field] === '') {
|
|
continue;
|
|
}
|
|
|
|
$settings[$field] = self::MASK;
|
|
}
|
|
|
|
return $settings;
|
|
}
|
|
|
|
/**
|
|
* 저장 요청에서 마스크로 되돌아온 sensitive 필드를 제거한다.
|
|
*
|
|
* 제거된 필드는 저장 단계의 기존 설정 병합에서 종전 값이 유지된다.
|
|
*
|
|
* @param array<string, mixed> $settings 저장 요청 설정 배열
|
|
* @param array<string, mixed> $schema 설정 스키마
|
|
* @return array<string, mixed> 마스크 필드가 제거된 설정 배열
|
|
*/
|
|
public static function stripUnchanged(array $settings, array $schema): array
|
|
{
|
|
foreach ($schema as $field => $config) {
|
|
if (! is_array($config) || ! ($config['sensitive'] ?? false)) {
|
|
continue;
|
|
}
|
|
if (($settings[$field] ?? null) === self::MASK) {
|
|
unset($settings[$field]);
|
|
}
|
|
}
|
|
|
|
return $settings;
|
|
}
|
|
}
|