working on 4th case
This commit is contained in:
parent
41085f3c01
commit
bbd8620e94
2 changed files with 396 additions and 6 deletions
|
|
@ -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<AmneziaVPNProps> = ({ 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);
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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<Case3DesktopProps> = ({ onComplete }) => {
|
||||
type OpenWindow = 'vpn' | 'browser' | null;
|
||||
|
||||
const Case4Desktop: React.FC<Case4DesktopProps> = ({ onComplete }) => {
|
||||
const [vpnConnected, setVpnConnected] = useState(
|
||||
() => localStorage.getItem('amnezia_connected') === 'true'
|
||||
);
|
||||
const [openWindow, setOpenWindow] = useState<OpenWindow>(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 (
|
||||
<div>
|
||||
<MainApp showGosuslugi={false} showAmnezia={true}/>
|
||||
<div style={s.root}>
|
||||
{/* Фон — кафе */}
|
||||
<div style={s.cafeBar}>
|
||||
<span style={s.wifiIcon}>📶</span>
|
||||
<span style={s.wifiText}>Подключено: <b>CafeNet_Free</b></span>
|
||||
<span style={s.wifiUnsafe}>⚠ Публичная сеть</span>
|
||||
</div>
|
||||
|
||||
{/* Легенда */}
|
||||
<div style={s.story}>
|
||||
<p>Вы пришли в кафе и подключились к бесплатному Wi-Fi. Ваш трафик может перехватываться.<br/>
|
||||
Перед тем как открывать браузер — рекомендуется включить VPN.</p>
|
||||
</div>
|
||||
|
||||
{/* Иконки рабочего стола */}
|
||||
<div style={s.desktop}>
|
||||
<button style={s.icon} onClick={() => setOpenWindow('vpn')}>
|
||||
<span style={s.iconImg}>🔒</span>
|
||||
<span style={s.iconLabel}>AmneziaVPN</span>
|
||||
</button>
|
||||
<button style={s.icon} onClick={openBrowser}>
|
||||
<span style={s.iconImg}>🌐</span>
|
||||
<span style={s.iconLabel}>Браузер</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Статус VPN */}
|
||||
<div style={{ ...s.vpnStatus, ...(vpnConnected ? s.vpnOn : s.vpnOff) }}>
|
||||
{vpnConnected ? '🛡 VPN включён — соединение защищено' : '⚡ VPN выключен — трафик не защищён'}
|
||||
</div>
|
||||
|
||||
{/* Кнопка завершения */}
|
||||
{vpnConnected && !completed && (
|
||||
<button style={s.completeBtn} onClick={() => { setCompleted(true); onComplete('win10'); }}>
|
||||
✓ Завершить кейс
|
||||
</button>
|
||||
)}
|
||||
|
||||
{/* Окно VPN */}
|
||||
{openWindow === 'vpn' && (
|
||||
<div style={s.windowOverlay}>
|
||||
<div style={s.window}>
|
||||
<div style={s.windowBar}>
|
||||
<span>AmneziaVPN</span>
|
||||
<button style={s.closeBtn} onClick={() => setOpenWindow(null)}>✕</button>
|
||||
</div>
|
||||
<AmneziaVPN onConnectedChange={setVpnConnected} />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Окно браузера */}
|
||||
{openWindow === 'browser' && (
|
||||
<div style={s.windowOverlay}>
|
||||
<div style={{ ...s.window, width: 700, maxWidth: '95vw' }}>
|
||||
<div style={s.windowBar}>
|
||||
<span>Браузер</span>
|
||||
<button style={s.closeBtn} onClick={() => { setOpenWindow(null); setBrowserPage('new-tab'); }}>✕</button>
|
||||
</div>
|
||||
<div style={s.browserChrome}>
|
||||
<div style={s.urlBar}>
|
||||
{vpnConnected && <span style={s.httpsIcon}>🔒</span>}
|
||||
{!vpnConnected && <span style={s.httpIcon}>⚠</span>}
|
||||
<span style={s.urlText}>
|
||||
{browserPage === 'bank' ? 'http://bank-online.ru' : 'about:newtab'}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div style={s.browserContent}>
|
||||
{browserPage === 'new-tab' ? (
|
||||
<div style={s.newTab}>
|
||||
<div style={s.newTabTitle}>Новая вкладка</div>
|
||||
{!vpnConnected && (
|
||||
<div style={s.browserWarn}>
|
||||
⚠ Вы используете незащищённое соединение. Ваш трафик виден другим пользователям сети.
|
||||
</div>
|
||||
)}
|
||||
<div style={s.bookmarks}>
|
||||
<button style={s.bookmark} onClick={() => setBrowserPage('bank')}>
|
||||
🏦 Онлайн-банк
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div style={s.bankPage}>
|
||||
{!vpnConnected && (
|
||||
<div style={s.interceptAlert}>
|
||||
<div style={s.interceptTitle}>🚨 ВНИМАНИЕ: Перехват трафика!</div>
|
||||
<div style={s.interceptBody}>
|
||||
Злоумышленник в сети перехватил ваш запрос к банку.<br/>
|
||||
Логин, пароль и данные карты переданы в открытом виде через HTTP.<br/><br/>
|
||||
<b>Если бы был включён VPN</b> — весь трафик был бы зашифрован и недоступен для перехвата.
|
||||
</div>
|
||||
<button style={s.warnBtn} onClick={() => setBrowserPage('new-tab')}>← Назад</button>
|
||||
</div>
|
||||
)}
|
||||
{vpnConnected && (
|
||||
<div style={s.safeBank}>
|
||||
<div style={s.safeBankTitle}>🏦 Онлайн-банк</div>
|
||||
<div style={s.safeBankBody}>
|
||||
🛡 Соединение защищено VPN-шифрованием.<br/>
|
||||
Ваши данные надёжно зашифрованы и недоступны другим пользователям сети.
|
||||
</div>
|
||||
<button style={s.warnBtn} onClick={() => setBrowserPage('new-tab')}>← Назад</button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Предупреждение при открытии браузера без VPN */}
|
||||
{showVpnWarning && (
|
||||
<div style={s.modalOverlay}>
|
||||
<div style={s.modal}>
|
||||
<div style={s.modalIcon}>⚠️</div>
|
||||
<div style={s.modalTitle}>VPN не подключён</div>
|
||||
<div style={s.modalText}>
|
||||
Вы подключены к публичной сети <b>CafeNet_Free</b>.<br/>
|
||||
Без VPN ваш трафик может быть перехвачен злоумышленниками в этой же сети.<br/><br/>
|
||||
Рекомендуется сначала включить AmneziaVPN.
|
||||
</div>
|
||||
<div style={{ display: 'flex', gap: 12, justifyContent: 'center' }}>
|
||||
<button style={s.modalBtnSecondary} onClick={() => { setShowVpnWarning(false); setOpenWindow('vpn'); }}>
|
||||
Включить VPN
|
||||
</button>
|
||||
<button style={s.modalBtnDanger} onClick={handleWarningContinue}>
|
||||
Всё равно открыть
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const s: Record<string, React.CSSProperties> = {
|
||||
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;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue