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 React, { useState } from 'react';
|
||||||
import './AmneziaVPN.css';
|
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 [connected, setConnected] = useState(() => localStorage.getItem('amnezia_connected') === 'true');
|
||||||
const [connecting, setConnecting] = useState(false);
|
const [connecting, setConnecting] = useState(false);
|
||||||
|
|
||||||
|
|
@ -9,12 +13,14 @@ const AmneziaVPN: React.FC = () => {
|
||||||
if (connected) {
|
if (connected) {
|
||||||
setConnected(false);
|
setConnected(false);
|
||||||
localStorage.setItem('amnezia_connected', 'false');
|
localStorage.setItem('amnezia_connected', 'false');
|
||||||
|
onConnectedChange?.(false);
|
||||||
} else {
|
} else {
|
||||||
setConnecting(true);
|
setConnecting(true);
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
setConnecting(false);
|
setConnecting(false);
|
||||||
setConnected(true);
|
setConnected(true);
|
||||||
localStorage.setItem('amnezia_connected', 'true');
|
localStorage.setItem('amnezia_connected', 'true');
|
||||||
|
onConnectedChange?.(true);
|
||||||
}, 1500);
|
}, 1500);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,402 @@
|
||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import type { WallpaperType } from '../App';
|
import type { WallpaperType } from '../App';
|
||||||
import MainApp from '../MainApp';
|
import AmneziaVPN from '../apps/amneziavpn/AmneziaVPN';
|
||||||
|
|
||||||
interface Case3DesktopProps {
|
interface Case4DesktopProps {
|
||||||
onComplete: (type: WallpaperType) => void;
|
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 (
|
return (
|
||||||
<div>
|
<div style={s.root}>
|
||||||
<MainApp showGosuslugi={false} showAmnezia={true}/>
|
{/* Фон — кафе */}
|
||||||
|
<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>
|
</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;
|
export default Case4Desktop;
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue