From bbd8620e94c8ecc67fae46ce6a540bfd209ddef1 Mon Sep 17 00:00:00 2001 From: koplenov Date: Sun, 5 Apr 2026 05:55:51 +0300 Subject: [PATCH] working on 4th case --- src/apps/amneziavpn/AmneziaVPN.tsx | 8 +- src/cases/Case4Desktop.tsx | 394 ++++++++++++++++++++++++++++- 2 files changed, 396 insertions(+), 6 deletions(-) diff --git a/src/apps/amneziavpn/AmneziaVPN.tsx b/src/apps/amneziavpn/AmneziaVPN.tsx index 11250e4..183c180 100644 --- a/src/apps/amneziavpn/AmneziaVPN.tsx +++ b/src/apps/amneziavpn/AmneziaVPN.tsx @@ -1,7 +1,11 @@ import React, { useState } from 'react'; import './AmneziaVPN.css'; -const AmneziaVPN: React.FC = () => { +interface AmneziaVPNProps { + onConnectedChange?: (connected: boolean) => void; +} + +const AmneziaVPN: React.FC = ({ onConnectedChange }) => { const [connected, setConnected] = useState(() => localStorage.getItem('amnezia_connected') === 'true'); const [connecting, setConnecting] = useState(false); @@ -9,12 +13,14 @@ const AmneziaVPN: React.FC = () => { if (connected) { setConnected(false); localStorage.setItem('amnezia_connected', 'false'); + onConnectedChange?.(false); } else { setConnecting(true); setTimeout(() => { setConnecting(false); setConnected(true); localStorage.setItem('amnezia_connected', 'true'); + onConnectedChange?.(true); }, 1500); } }; diff --git a/src/cases/Case4Desktop.tsx b/src/cases/Case4Desktop.tsx index c3c02a9..a0c80e9 100644 --- a/src/cases/Case4Desktop.tsx +++ b/src/cases/Case4Desktop.tsx @@ -1,18 +1,402 @@ import React, { useState } from 'react'; import type { WallpaperType } from '../App'; -import MainApp from '../MainApp'; +import AmneziaVPN from '../apps/amneziavpn/AmneziaVPN'; -interface Case3DesktopProps { +interface Case4DesktopProps { onComplete: (type: WallpaperType) => void; } -const Case4Desktop: React.FC = ({ onComplete }) => { +type OpenWindow = 'vpn' | 'browser' | null; + +const Case4Desktop: React.FC = ({ onComplete }) => { + const [vpnConnected, setVpnConnected] = useState( + () => localStorage.getItem('amnezia_connected') === 'true' + ); + const [openWindow, setOpenWindow] = useState(null); + const [showVpnWarning, setShowVpnWarning] = useState(false); + const [browserPage, setBrowserPage] = useState<'new-tab' | 'bank'>('new-tab'); + const [completed, setCompleted] = useState(false); + + const openBrowser = () => { + if (!vpnConnected) { + setShowVpnWarning(true); + } else { + setOpenWindow('browser'); + } + }; + + const handleWarningContinue = () => { + setShowVpnWarning(false); + setOpenWindow('browser'); + }; return ( -
- +
+ {/* Фон — кафе */} +
+ 📶 + Подключено: CafeNet_Free + ⚠ Публичная сеть +
+ + {/* Легенда */} +
+

Вы пришли в кафе и подключились к бесплатному Wi-Fi. Ваш трафик может перехватываться.
+ Перед тем как открывать браузер — рекомендуется включить VPN.

+
+ + {/* Иконки рабочего стола */} +
+ + +
+ + {/* Статус VPN */} +
+ {vpnConnected ? '🛡 VPN включён — соединение защищено' : '⚡ VPN выключен — трафик не защищён'} +
+ + {/* Кнопка завершения */} + {vpnConnected && !completed && ( + + )} + + {/* Окно VPN */} + {openWindow === 'vpn' && ( +
+
+
+ AmneziaVPN + +
+ +
+
+ )} + + {/* Окно браузера */} + {openWindow === 'browser' && ( +
+
+
+ Браузер + +
+
+
+ {vpnConnected && 🔒} + {!vpnConnected && } + + {browserPage === 'bank' ? 'http://bank-online.ru' : 'about:newtab'} + +
+
+
+ {browserPage === 'new-tab' ? ( +
+
Новая вкладка
+ {!vpnConnected && ( +
+ ⚠ Вы используете незащищённое соединение. Ваш трафик виден другим пользователям сети. +
+ )} +
+ +
+
+ ) : ( +
+ {!vpnConnected && ( +
+
🚨 ВНИМАНИЕ: Перехват трафика!
+
+ Злоумышленник в сети перехватил ваш запрос к банку.
+ Логин, пароль и данные карты переданы в открытом виде через HTTP.

+ Если бы был включён VPN — весь трафик был бы зашифрован и недоступен для перехвата. +
+ +
+ )} + {vpnConnected && ( +
+
🏦 Онлайн-банк
+
+ 🛡 Соединение защищено VPN-шифрованием.
+ Ваши данные надёжно зашифрованы и недоступны другим пользователям сети. +
+ +
+ )} +
+ )} +
+
+
+ )} + + {/* Предупреждение при открытии браузера без VPN */} + {showVpnWarning && ( +
+
+
⚠️
+
VPN не подключён
+
+ Вы подключены к публичной сети CafeNet_Free.
+ Без VPN ваш трафик может быть перехвачен злоумышленниками в этой же сети.

+ Рекомендуется сначала включить AmneziaVPN. +
+
+ + +
+
+
+ )}
); }; +const s: Record = { + root: { + minHeight: '100vh', + background: 'linear-gradient(135deg, #1a0a00 0%, #0d1117 50%, #001a1a 100%)', + color: '#ccc', + fontFamily: "'Share Tech Mono', monospace", + position: 'relative', + overflow: 'hidden', + }, + cafeBar: { + background: 'rgba(0,0,0,0.6)', + borderBottom: '1px solid rgba(0,255,255,0.15)', + padding: '10px 24px', + display: 'flex', + alignItems: 'center', + gap: 12, + fontSize: 14, + }, + wifiIcon: { fontSize: 18 }, + wifiText: { color: '#ccc' }, + wifiUnsafe: { color: '#f5a623', marginLeft: 8 }, + story: { + maxWidth: 700, + margin: '24px auto 0', + padding: '16px 24px', + background: 'rgba(0,255,255,0.04)', + border: '1px solid rgba(0,255,255,0.15)', + borderRadius: 8, + fontSize: 14, + lineHeight: 1.7, + color: '#aaa', + textAlign: 'center', + }, + desktop: { + display: 'flex', + gap: 40, + justifyContent: 'center', + marginTop: 48, + }, + icon: { + background: 'rgba(255,255,255,0.04)', + border: '1px solid rgba(255,255,255,0.1)', + borderRadius: 12, + padding: '20px 28px', + cursor: 'pointer', + display: 'flex', + flexDirection: 'column', + alignItems: 'center', + gap: 10, + transition: 'all 0.2s', + color: '#ccc', + }, + iconImg: { fontSize: 40 }, + iconLabel: { fontSize: 13, fontFamily: "'Share Tech Mono', monospace" }, + vpnStatus: { + textAlign: 'center', + marginTop: 32, + fontSize: 13, + padding: '8px 20px', + borderRadius: 6, + display: 'inline-block', + position: 'relative', + left: '50%', + transform: 'translateX(-50%)', + }, + vpnOn: { background: 'rgba(0,255,65,0.1)', border: '1px solid #00FF41', color: '#00FF41' }, + vpnOff: { background: 'rgba(245,166,35,0.1)', border: '1px solid #f5a623', color: '#f5a623' }, + completeBtn: { + display: 'block', + margin: '24px auto 0', + padding: '12px 36px', + background: '#00FF41', + border: 'none', + borderRadius: 6, + color: '#000', + fontFamily: "'Orbitron', monospace", + fontSize: 14, + fontWeight: 700, + cursor: 'pointer', + }, + windowOverlay: { + position: 'fixed', + inset: 0, + background: 'rgba(0,0,0,0.5)', + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + zIndex: 100, + }, + window: { + background: '#0d0d22', + border: '1px solid rgba(0,255,255,0.25)', + borderRadius: 10, + overflow: 'hidden', + width: 360, + boxShadow: '0 0 40px rgba(0,255,255,0.1)', + }, + windowBar: { + background: '#080818', + borderBottom: '1px solid rgba(0,255,255,0.15)', + padding: '10px 16px', + display: 'flex', + justifyContent: 'space-between', + alignItems: 'center', + fontSize: 13, + color: '#00FFFF', + fontFamily: "'Orbitron', monospace", + }, + closeBtn: { + background: 'transparent', + border: '1px solid rgba(255,0,64,0.4)', + color: '#ff6b6b', + cursor: 'pointer', + borderRadius: 4, + padding: '2px 8px', + fontSize: 12, + }, + browserChrome: { + background: '#080818', + borderBottom: '1px solid rgba(0,255,255,0.1)', + padding: '8px 12px', + }, + urlBar: { + background: '#0a0a1a', + border: '1px solid rgba(0,255,255,0.2)', + borderRadius: 4, + padding: '6px 12px', + fontSize: 13, + display: 'flex', + alignItems: 'center', + gap: 8, + }, + httpsIcon: { color: '#00FF41', fontSize: 14 }, + httpIcon: { color: '#f5a623', fontSize: 14 }, + urlText: { color: '#888', flex: 1 }, + browserContent: { minHeight: 300, background: '#0a0a0a' }, + newTab: { padding: 24 }, + newTabTitle: { color: '#555', fontSize: 13, marginBottom: 16, fontFamily: "'Orbitron', monospace" }, + browserWarn: { + background: 'rgba(245,166,35,0.1)', + border: '1px solid #f5a623', + borderRadius: 6, + padding: '10px 14px', + fontSize: 13, + color: '#f5a623', + marginBottom: 20, + }, + bookmarks: { display: 'flex', gap: 12, flexWrap: 'wrap' }, + bookmark: { + background: 'rgba(0,255,255,0.05)', + border: '1px solid rgba(0,255,255,0.2)', + borderRadius: 8, + padding: '12px 18px', + color: '#aaa', + cursor: 'pointer', + fontSize: 13, + fontFamily: "'Share Tech Mono', monospace", + }, + bankPage: { padding: 24 }, + interceptAlert: { + background: 'rgba(255,0,64,0.08)', + border: '1px solid #FF0040', + borderRadius: 8, + padding: 20, + }, + interceptTitle: { color: '#FF0040', fontFamily: "'Orbitron', monospace", fontSize: 15, marginBottom: 12, fontWeight: 700 }, + interceptBody: { color: '#ccc', fontSize: 13, lineHeight: 1.7, marginBottom: 16 }, + safeBank: { + background: 'rgba(0,255,65,0.06)', + border: '1px solid #00FF41', + borderRadius: 8, + padding: 20, + }, + safeBankTitle: { color: '#00FF41', fontFamily: "'Orbitron', monospace", fontSize: 15, marginBottom: 12, fontWeight: 700 }, + safeBankBody: { color: '#ccc', fontSize: 13, lineHeight: 1.7, marginBottom: 16 }, + warnBtn: { + background: 'transparent', + border: '1px solid rgba(0,255,255,0.3)', + color: '#888', + borderRadius: 6, + padding: '8px 16px', + cursor: 'pointer', + fontSize: 13, + fontFamily: "'Share Tech Mono', monospace", + }, + modalOverlay: { + position: 'fixed', + inset: 0, + background: 'rgba(0,0,0,0.7)', + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + zIndex: 200, + }, + modal: { + background: '#0d0d22', + border: '1px solid #f5a623', + borderRadius: 10, + padding: '32px 28px', + maxWidth: 420, + textAlign: 'center', + boxShadow: '0 0 30px rgba(245,166,35,0.2)', + }, + modalIcon: { fontSize: 40, marginBottom: 12 }, + modalTitle: { color: '#f5a623', fontFamily: "'Orbitron', monospace", fontSize: 16, marginBottom: 12, fontWeight: 700 }, + modalText: { color: '#aaa', fontSize: 13, lineHeight: 1.7, marginBottom: 24 }, + modalBtnSecondary: { + background: '#00FF41', + border: 'none', + borderRadius: 6, + padding: '10px 20px', + color: '#000', + cursor: 'pointer', + fontFamily: "'Orbitron', monospace", + fontSize: 12, + fontWeight: 700, + }, + modalBtnDanger: { + background: 'transparent', + border: '1px solid rgba(255,0,64,0.5)', + borderRadius: 6, + padding: '10px 20px', + color: '#FF0040', + cursor: 'pointer', + fontFamily: "'Share Tech Mono', monospace", + fontSize: 12, + }, +}; + export default Case4Desktop;