Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 0 additions & 32 deletions src/pages/Report/ReportPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import AppHeader from '@/shared/ui/app-header';

import { resolveRiskDetectionContent } from './constants/riskDetectionCatalog';
import { useReportPage } from './hooks/useReportPage';
import { resolveAnalysisFailureNotice } from './lib/analysisFailureNotice';
import * as styles from './styles/reportPage.css';

import type { ReportStatusTone } from './types/reportPage.types';
Expand Down Expand Up @@ -96,7 +95,6 @@ export default function ReportPage() {
...resolveRiskDetectionContent(riskType, reportPageData.riskLevel),
key: `${riskType}-${index}`,
}));
const analysisFailureNotice = resolveAnalysisFailureNotice(reportPageData.detectedRiskTypes);

const toneKey = reportPageData.riskLevel;

Expand Down Expand Up @@ -157,36 +155,6 @@ export default function ReportPage() {
/>
</section>

{analysisFailureNotice.hasFailureAlert ? (
<section className={styles.analysisFailureNotice} role="alert">
<div className={styles.analysisFailureNoticeHeader}>
<span aria-hidden className={styles.analysisFailureNoticeIcon}>
!
</span>
<div className={styles.analysisFailureNoticeTitleBlock}>
<h2 className={styles.analysisFailureNoticeTitle}>
{analysisFailureNotice.isOnlyAnalysisFailures
? '분석 결과가 제한되었습니다'
: '일부 분석이 제한되었습니다'}
</h2>
<p className={styles.analysisFailureNoticeSummary}>
{analysisFailureNotice.isOnlyAnalysisFailures
? '여러 검사 모듈이 정상적으로 완료되지 않아, 이 결과를 안전하다는 의미로 해석하면 안 됩니다.'
: '일부 검사 모듈이 정상적으로 완료되지 않아, 아래 결과에는 확인하지 못한 영역이 남아 있습니다.'}
</p>
</div>
</div>

<p className={styles.analysisFailureNoticeText}>
실패한 검사: {analysisFailureNotice.labels.join(', ')}
</p>
<p className={styles.analysisFailureNoticeText}>
공식 사이트인지 직접 확인하기 전에는 로그인, 결제, 개인정보 입력, 파일 다운로드를
진행하지 마세요.
</p>
</section>
) : null}

<section className={`${styles.sectionCard} ${styles.sectionCardTone[toneKey]}`}>
<div className={styles.sectionHeader}>
<div className={styles.sectionTitleGroup}>
Expand Down
18 changes: 18 additions & 0 deletions src/pages/Report/constants/riskDetectionCatalog.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@ const backendThreatCodes = [
'XGB_FAILED',
'ML_FAILED',
'SCORING_FAILED',
'XGB_SUSPICIOUS_URL_FEATURES',
'XGB_HIGH_RISK_URL',
'CHARCNN_SUSPICIOUS_URL_PATTERN',
] as const;

describe('resolveRiskDetectionContent', () => {
Expand Down Expand Up @@ -115,6 +118,21 @@ describe('resolveRiskDetectionContent', () => {
});
});

it('maps newly added ML model risk signals to user-facing descriptions', () => {
expect(resolveRiskDetectionContent('XGB_SUSPICIOUS_URL_FEATURES', 'warning')).toMatchObject({
englishLabel: 'XGB SUSPICIOUS URL FEATURES',
title: 'XGB URL 특징 의심 신호 감지',
});
expect(resolveRiskDetectionContent('XGB_HIGH_RISK_URL', 'critical')).toMatchObject({
englishLabel: 'XGB HIGH RISK URL',
title: 'XGB 고위험 URL 감지',
});
expect(resolveRiskDetectionContent('CHARCNN_SUSPICIOUS_URL_PATTERN', 'warning')).toMatchObject({
englishLabel: 'CHARCNN SUSPICIOUS URL PATTERN',
title: 'CharCNN URL 패턴 의심 신호 감지',
});
});

it('uses user-facing copy for unknown threat fallbacks', () => {
const content = resolveRiskDetectionContent('NEW_BACKEND_SIGNAL', 'critical');

Expand Down
32 changes: 32 additions & 0 deletions src/pages/Report/constants/threatText.ts
Original file line number Diff line number Diff line change
Expand Up @@ -524,6 +524,38 @@ export const threatTextCatalog: RiskDetectionCatalogItem[] = [
risk: '최종 위험도 산정이 제한되어 실제 위험 수준이 과소 또는 과대 표시될 수 있습니다.',
title: '위험 점수 산정 실패 감지',
},
{
description:
'XGBoost 모델이 URL 길이, 특수문자 사용, 숫자와 영문 조합, 경로 구성 같은 특징에서 의심스러운 패턴을 확인했습니다.',
englishLabel: 'XGB SUSPICIOUS URL FEATURES',
names: [
'XGB_SUSPICIOUS_URL_FEATURES',
'xgb_suspicious_url_features',
'xgboost_suspicious_url_features',
],
risk: '정상 사이트에서도 일부 특징이 겹칠 수 있지만, 피싱이나 악성 URL은 주소를 복잡하게 만들거나 사용자를 속이는 문자열 조합을 자주 사용합니다. 공식 주소인지 다시 확인해야 합니다.',
title: 'XGB URL 특징 의심 신호 감지',
},
{
description:
'XGBoost 모델이 URL의 여러 특징을 종합했을 때 고위험 주소일 가능성이 높다고 판단했습니다.',
englishLabel: 'XGB HIGH RISK URL',
names: ['XGB_HIGH_RISK_URL', 'xgb_high_risk_url', 'xgboost_high_risk_url'],
risk: '주소 구조와 패턴이 위험 사이트와 유사하게 나타난 상태입니다. 로그인, 결제, 개인정보 입력, 파일 다운로드를 진행하지 말고 공식 경로로 다시 접속하는 것이 안전합니다.',
title: 'XGB 고위험 URL 감지',
},
{
description:
'CharCNN 모델이 URL 문자열 자체의 글자 배열에서 피싱이나 악성 주소에서 자주 보이는 의심 패턴을 확인했습니다.',
englishLabel: 'CHARCNN SUSPICIOUS URL PATTERN',
names: [
'CHARCNN_SUSPICIOUS_URL_PATTERN',
'charcnn_suspicious_url_pattern',
'char_cnn_suspicious_url_pattern',
],
risk: '사람이 보기에는 정상 주소처럼 보여도 글자 단위 패턴이 위장 도메인, 난독화 주소, 유사 도메인과 닮아 있을 수 있습니다. 민감한 정보를 입력하기 전에 반드시 공식 주소와 비교해야 합니다.',
title: 'CharCNN URL 패턴 의심 신호 감지',
},
{
description: 'URL에서 접속 대상 호스트명을 확인하지 못했거나 DNS 해석에 실패한 신호입니다.',
englishLabel: 'HOSTNAME MISSING',
Expand Down
29 changes: 0 additions & 29 deletions src/pages/Report/lib/analysisFailureNotice.test.ts

This file was deleted.

48 changes: 0 additions & 48 deletions src/pages/Report/lib/analysisFailureNotice.ts

This file was deleted.

66 changes: 0 additions & 66 deletions src/pages/Report/styles/reportPage.css.ts
Original file line number Diff line number Diff line change
Expand Up @@ -223,72 +223,6 @@ export const metricsGrid = style({
},
});

export const analysisFailureNotice = style({
borderRadius: vars.radius.lg,
border: '1px solid #F4C56E',
backgroundColor: '#FFF8E8',
padding: vars.spacing.lg,
display: 'grid',
gap: vars.spacing.sm,
boxShadow: '0 8px 18px rgba(138, 89, 0, 0.08)',
'@media': {
print: {
breakInside: 'avoid',
boxShadow: 'none',
},
},
});

export const analysisFailureNoticeHeader = style({
display: 'flex',
alignItems: 'flex-start',
gap: vars.spacing.sm,
});

export const analysisFailureNoticeIcon = style({
width: '30px',
height: '30px',
borderRadius: '999px',
backgroundColor: '#D97706',
color: vars.colors.white,
display: 'inline-flex',
alignItems: 'center',
justifyContent: 'center',
flexShrink: 0,
fontSize: vars.font.size.md,
fontWeight: vars.font.weight.bold,
lineHeight: 1,
});

export const analysisFailureNoticeTitleBlock = style({
display: 'grid',
gap: '4px',
});

export const analysisFailureNoticeTitle = style({
margin: 0,
color: '#7C3F00',
fontSize: vars.font.size.xl,
fontWeight: vars.font.weight.bold,
lineHeight: 1.35,
});

export const analysisFailureNoticeSummary = style({
margin: 0,
color: '#8A5A12',
fontSize: vars.font.size.sm,
fontWeight: vars.font.weight.semibold,
lineHeight: 1.6,
});

export const analysisFailureNoticeText = style({
margin: 0,
color: '#5F4824',
fontSize: vars.font.size.sm,
fontWeight: vars.font.weight.medium,
lineHeight: 1.65,
});

export const sectionCard = style({
borderRadius: vars.radius.lg,
border: '1px solid #F0E4BE',
Expand Down
Loading