Files
Gnuboard7/resources/views/database-credential-error.blade.php
HeuJung 062a88ca04 feat(core): DB 최고권한 계정 차단 + OPcache 상태 안내
설치 단계와 코어 부팅의 정책이 엇갈려 있었다. 인스톨러는 root 를 자유롭게
허용하면서, 설치 후 부팅은 같은 값을 보고 확장 로딩 전체를 조용히 스킵했다.
설치는 성공하지만 이후 깨진 화면만 뜨고 원인은 로그 한 줄에만 남았다.

판정을 프레임워크 의존성 0 인 공용 SSoT 로 모아 인스톨러와 코어가 같은 답을
내게 하고, 설치 단계에서 서버 2경로로 차단하며, 설치 후 변경은 전용 에러
페이지로 드러낸다. 가드를 boot 가 아닌 미들웨어에 두어 artisan 이 죽지 않게
해 복구 수단을 남겼다. admin 은 일반 권한 운영 계정 오차단을 막기 위해 차단
목록에서 제외했다.

OPcache 는 상태 조회 경로 자체가 없어 성능 저하를 인지할 방법이 없었다.
설치 단계 경고(비차단)와 관리자 정보 탭 표시를 같은 판정 SSoT 로 추가했다.
확장 로드 여부만으로는 부족해 opcache.enable 지시자까지 확인하며, ini_get 이
차단된 환경은 "확인 불가"로 폴백해 경고도 차단도 하지 않는다.
2026-07-20 14:17:49 +09:00

138 lines
5.3 KiB
PHP

<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>{{ config('app.name', '그누보드7') }} - {{ __('database_credential.title') }}</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.credential-container {
display: flex;
align-items: center;
justify-content: center;
min-height: 100vh;
background-color: #f9fafb;
padding: 1rem;
}
.credential-card {
max-width: 36rem;
width: 100%;
background-color: #ffffff;
border-radius: 0.75rem;
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
padding: 3rem 2rem;
text-align: center;
}
.credential-icon {
margin-bottom: 1.5rem;
}
.credential-icon svg {
width: 4.5rem;
height: 4.5rem;
color: #f59e0b;
}
.credential-title {
font-size: 1.75rem;
font-weight: 700;
color: #111827;
margin-bottom: 0.75rem;
}
.credential-message {
font-size: 1.05rem;
color: #4b5563;
margin-bottom: 0.5rem;
line-height: 1.625;
}
.credential-description {
font-size: 0.875rem;
color: #6b7280;
line-height: 1.625;
margin-bottom: 1.5rem;
}
.credential-reason {
text-align: left;
background-color: #fffbeb;
border: 1px solid #fde68a;
border-radius: 0.5rem;
padding: 1rem 1.25rem;
font-size: 0.9rem;
color: #92400e;
line-height: 1.625;
margin-bottom: 1rem;
}
.credential-recovery {
text-align: left;
background-color: #f3f4f6;
border-radius: 0.5rem;
padding: 1rem 1.25rem;
font-size: 0.875rem;
color: #374151;
line-height: 1.625;
}
@media (prefers-color-scheme: dark) {
.credential-container {
background-color: #111827;
}
.credential-card {
background-color: #1f2937;
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.3), 0 4px 6px -2px rgba(0, 0, 0, 0.2);
}
.credential-icon svg {
color: #fbbf24;
}
.credential-title {
color: #ffffff;
}
.credential-message {
color: #9ca3af;
}
.credential-description {
color: #6b7280;
}
.credential-reason {
background-color: #78350f;
border-color: #92400e;
color: #fde68a;
}
.credential-recovery {
background-color: #374151;
color: #d1d5db;
}
}
</style>
</head>
<body>
<div class="credential-container">
<div class="credential-card">
{{-- Warning triangle icon (inline SVG - no external dependency) --}}
<div class="credential-icon">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126ZM12 15.75h.007v.008H12v-.008Z" />
</svg>
</div>
<h1 class="credential-title">{{ __('database_credential.title') }}</h1>
<p class="credential-message">{{ __('database_credential.message') }}</p>
<p class="credential-description">{{ __('database_credential.description') }}</p>
{{-- 원인 구분 안내. 현재 설정된 계정명 자체는 출력하지 않는다 --}}
{{-- (미인증 공개 페이지이므로 DB 계정명 노출은 정보 유출). --}}
<p class="credential-reason">
{{ __('database_credential.'.($reason ?? 'blocked').'_reason') }}
</p>
<p class="credential-recovery">{{ __('database_credential.recovery_guide') }}</p>
</div>
</div>
</body>
</html>