Catalyst / admin/AirportCyberSimulator 14.8 GB / 57.8 GB 40.0 GB free
Help Sign in

admin / AirportCyberSimulator

public

Airport Cyber Attack Simulation Application

Code Issues Pull requests Pipelines Packages Security Insights Wiki Settings
AirportCyberSimulator / airport-cyber-sim / backend / static / index.html 13259 B · main
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
  <title>Airport Cyber Resilience Simulator</title>
  <!-- Vendored locally so the container needs no runtime internet access -->
  <script src="vendor/gsap.min.js"></script>
  <!-- Fonts are progressive enhancement; CSS has system fallbacks if offline -->
  <link rel="preconnect" href="https://fonts.googleapis.com" />
  <link href="https://fonts.googleapis.com/css2?family=Orbitron:wght@500;700;900&family=Rajdhani:wght@400;500;600;700&display=swap" rel="stylesheet" />
  <link rel="stylesheet" href="styles.css" />
</head>
<body>
  <!-- Kiosk stage: everything is drawn on a 1920x1080 canvas and scaled to fit -->
  <div id="stage-wrap">
    <div id="stage">

      <!-- ================= LEFT CONTROL SIDEBAR ================= -->
      <aside id="sidebar">
        <header id="brand">
          <div class="brand-mark">
            <svg viewBox="0 0 48 48" width="46" height="46"><use href="#icon-shield"/></svg>
          </div>
          <div>
            <h1>AIRPORT CYBER</h1>
            <h2>RESILIENCE SIMULATOR</h2>
          </div>
        </header>

        <section class="panel">
          <div class="panel-title"><span>ATTACK PLAYBOOKS</span><i class="dot"></i></div>
          <div id="playbook-list"><!-- populated by JS --></div>
        </section>

        <section class="panel" id="metrics-panel">
          <div class="panel-title"><span>LIVE OPERATIONAL STATE</span><i class="dot"></i></div>

          <div class="metric" data-metric="security">
            <div class="metric-head"><span>Security Integrity</span><span class="metric-val" id="m-security">100%</span></div>
            <div class="bar"><div class="bar-fill sec" id="bar-security"></div></div>
          </div>

          <div class="metric" data-metric="capacity">
            <div class="metric-head"><span>Operational Capacity</span><span class="metric-val" id="m-capacity">100%</span></div>
            <div class="bar"><div class="bar-fill cap" id="bar-capacity"></div></div>
          </div>

          <div class="metric" data-metric="financial">
            <div class="metric-head"><span>Financial / Reputational Loss</span><span class="metric-val loss" id="m-financial">£0</span></div>
            <div class="bar"><div class="bar-fill fin" id="bar-financial"></div></div>
          </div>
        </section>

        <section class="panel grow" id="log-panel">
          <div class="panel-title"><span>INCIDENT FEED</span><i class="dot"></i></div>
          <div id="event-log"></div>
        </section>

        <button id="reset-btn">
          <svg viewBox="0 0 24 24" width="26" height="26"><use href="#icon-reset"/></svg>
          RESET SIMULATION
        </button>
        <div id="conn-status"><i></i><span>CONNECTING…</span></div>
      </aside>

      <!-- ================= MAIN MAP AREA ================= -->
      <main id="map-area">
        <div id="map-header">
          <div id="scenario-title">SELECT A PLAYBOOK TO BEGIN</div>
          <div id="scenario-sub">Interactive airport infrastructure — hover or tap a node</div>
          <div id="sim-clock">T+00.0s</div>
        </div>

        <svg id="map" viewBox="0 0 1460 1080" preserveAspectRatio="xMidYMid meet">
          <defs>
            <!-- glow filters -->
            <filter id="glow-green" x="-60%" y="-60%" width="220%" height="220%">
              <feGaussianBlur stdDeviation="6" result="b"/><feMerge><feMergeNode in="b"/><feMergeNode in="SourceGraphic"/></feMerge>
            </filter>
            <filter id="glow-red" x="-80%" y="-80%" width="260%" height="260%">
              <feGaussianBlur stdDeviation="9" result="b"/><feMerge><feMergeNode in="b"/><feMergeNode in="SourceGraphic"/></feMerge>
            </filter>
            <radialGradient id="bg-grad" cx="50%" cy="35%" r="80%">
              <stop offset="0%" stop-color="#0d2033"/><stop offset="100%" stop-color="#050a12"/>
            </radialGradient>
          </defs>

          <rect x="0" y="0" width="1460" height="1080" fill="url(#bg-grad)"/>
          <g id="grid-layer"></g>
          <g id="link-layer"></g>
          <g id="particle-layer"></g>
          <g id="node-layer"></g>
          <g id="ingress-layer"></g>
        </svg>
      </main>
    </div>
  </div>

  <!-- ================= NODE / MITIGATION OVERLAY ================= -->
  <div id="node-overlay" class="overlay hidden">
    <div class="overlay-card">
      <button class="overlay-close" data-close>&times;</button>
      <div class="overlay-head">
        <div class="overlay-icon"><svg viewBox="0 0 48 48" width="40" height="40"><use id="ov-icon" href="#node-atc"/></svg></div>
        <div>
          <div id="ov-name" class="overlay-name">Node</div>
          <div id="ov-status" class="overlay-status">NORMAL</div>
        </div>
      </div>

      <div class="overlay-tabs">
        <button class="tab active" data-tab="details">Details</button>
        <button class="tab" data-tab="mitigation">Mitigation</button>
        <button class="tab" data-tab="regulatory">Regulatory Insights</button>
      </div>

      <div class="tab-body" data-body="details">
        <div class="kv"><span>Service</span><b id="ov-service"></b></div>
        <div class="kv"><span>Capacity</span><b id="ov-capacity">100%</b></div>
        <div class="kv"><span>Threat Vector</span><b id="ov-vector">None</b></div>
        <p id="ov-desc" class="overlay-desc"></p>
      </div>

      <div class="tab-body hidden" data-body="mitigation">
        <p class="mit-help">Every response carries an operational trade-off. Choose deliberately.</p>
        <button class="mit-btn iso" data-mit="ISOLATE">
          <b>A · ISOLATE NODE</b><span>Sever links, stop spread instantly. Capacity → 0%. High operational loss.</span>
        </button>
        <button class="mit-btn red" data-mit="REDUCE">
          <b>B · REDUCE TRAFFIC</b><span>Slow spread 80%. Capacity → 40%. Moderate operational loss.</span>
        </button>
        <button class="mit-btn stop" data-mit="STOP">
          <b>C · STOP ATTACK</b><span>15s patch countdown. Heavy £ penalty. Fails if the next spread beats the timer.</span>
        </button>
      </div>

      <div class="tab-body hidden" data-body="regulatory">
        <div class="reg-badge"><span id="reg-obj">CAF —</span></div>
        <div class="kv"><span>CAF Principle</span><b id="reg-principle"></b></div>
        <div class="kv col"><span>Statutory Duty</span><p id="reg-duty"></p></div>
        <div class="kv col"><span>Resilience Insight</span><p id="reg-insight"></p></div>
      </div>
    </div>
  </div>

  <!-- ================= ATTRACT LOOP ================= -->
  <div id="attract" class="hidden">
    <div class="attract-inner">
      <svg viewBox="0 0 48 48" width="90" height="90" class="attract-shield"><use href="#icon-shield"/></svg>
      <h1>AIRPORT CYBER RESILIENCE SIMULATOR</h1>
      <p>Explore how a single point of ingress cascades across critical airport infrastructure —<br/>and weigh the operational cost of every defensive decision.</p>
      <button id="attract-start">TAP TO BEGIN</button>
      <div class="attract-scroll"><span>RANSOMWARE</span><span>IoT BOTNET</span><span>SUPPLY CHAIN</span><span>ROGUE INSIDER</span><span>SIGNAL SPOOFING</span></div>
    </div>
  </div>

  <!-- ================= SVG ICON SPRITE ================= -->
  <svg width="0" height="0" style="position:absolute" aria-hidden="true">
    <defs>
      <!-- generic -->
      <g id="icon-shield"><path d="M24 3l16 6v11c0 10-7 18-16 21-9-3-16-11-16-21V9z" fill="none" stroke="currentColor" stroke-width="2.5"/><path d="M16 24l6 6 10-12" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"/></g>
      <g id="icon-reset"><path d="M4 12a8 8 0 1 1 2.3 5.6M4 12V6M4 12h6" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></g>

      <!-- node icons (24x24 viewport paths scaled inside 48) -->
      <g id="node-atc"><path d="M24 6v20M14 26h20l-3 16H17zM24 6a3 3 0 100-.1" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linejoin="round"/><circle cx="24" cy="7" r="3" fill="currentColor"/></g>
      <g id="node-runway"><path d="M20 8l8 0 6 34H14zM24 8v34M18 20h12M17 30h14" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linejoin="round"/></g>
      <g id="node-comms"><path d="M24 14a10 10 0 00-10 10M24 8a16 16 0 00-16 16M24 20a4 4 0 00-4 4" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round"/><circle cx="24" cy="24" r="3" fill="currentColor"/><path d="M24 27v13" stroke="currentColor" stroke-width="2.4"/></g>
      <g id="node-security"><path d="M24 6l14 5v9c0 9-6 15-14 18-8-3-14-9-14-18v-9z" fill="none" stroke="currentColor" stroke-width="2.4"/><circle cx="24" cy="21" r="4" fill="none" stroke="currentColor" stroke-width="2.2"/><path d="M24 25v6" stroke="currentColor" stroke-width="2.2"/></g>
      <g id="node-identity"><circle cx="24" cy="18" r="7" fill="none" stroke="currentColor" stroke-width="2.4"/><path d="M12 40c0-7 5-11 12-11s12 4 12 11" fill="none" stroke="currentColor" stroke-width="2.4"/></g>
      <g id="node-boarding"><rect x="10" y="14" width="28" height="20" rx="3" fill="none" stroke="currentColor" stroke-width="2.4"/><path d="M10 22h28M18 28h6" stroke="currentColor" stroke-width="2.2"/></g>
      <g id="node-checkin"><rect x="12" y="10" width="24" height="30" rx="2" fill="none" stroke="currentColor" stroke-width="2.4"/><path d="M18 18h12M18 24h12M18 30h8" stroke="currentColor" stroke-width="2.2" stroke-linecap="round"/></g>
      <g id="node-baggage"><rect x="14" y="16" width="20" height="24" rx="3" fill="none" stroke="currentColor" stroke-width="2.4"/><path d="M19 16v-4a3 3 0 013-3h4a3 3 0 013 3v4M22 22v12M26 22v12" stroke="currentColor" stroke-width="2.2" stroke-linecap="round"/></g>
      <g id="node-logistics"><path d="M6 30h20V16H6zM26 22h8l6 6v2H26z" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linejoin="round"/><circle cx="14" cy="34" r="3" fill="none" stroke="currentColor" stroke-width="2.2"/><circle cx="32" cy="34" r="3" fill="none" stroke="currentColor" stroke-width="2.2"/></g>
      <g id="node-hvac"><rect x="8" y="12" width="32" height="24" rx="3" fill="none" stroke="currentColor" stroke-width="2.4"/><path d="M14 20h6M28 20h6M14 28h20" stroke="currentColor" stroke-width="2.2" stroke-linecap="round"/></g>
      <g id="node-terminal"><rect x="12" y="8" width="24" height="32" rx="2" fill="none" stroke="currentColor" stroke-width="2.4"/><circle cx="30" cy="24" r="1.8" fill="currentColor"/><path d="M17 14h6" stroke="currentColor" stroke-width="2.2" stroke-linecap="round"/></g>
      <g id="node-retail"><path d="M10 16h28l-3 22H13zM16 16a8 8 0 0116 0" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linejoin="round"/></g>
      <g id="node-ticketing"><ellipse cx="24" cy="14" rx="14" ry="5" fill="none" stroke="currentColor" stroke-width="2.2"/><path d="M10 14v20c0 3 6 5 14 5s14-2 14-5V14M10 24c0 3 6 5 14 5s14-2 14-5" fill="none" stroke="currentColor" stroke-width="2.2"/></g>
      <g id="node-wifi"><path d="M8 20a24 24 0 0132 0M14 27a15 15 0 0120 0M20 34a6 6 0 018 0" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round"/><circle cx="24" cy="39" r="2.2" fill="currentColor"/></g>

      <!-- ingress method icons -->
      <g id="ing-usb_drive"><rect x="18" y="18" width="12" height="24" rx="2" fill="none" stroke="currentColor" stroke-width="2.4"/><path d="M20 18v-6h8v6M24 6v6" stroke="currentColor" stroke-width="2.4"/><path d="M22 26v8M26 26v8" stroke="currentColor" stroke-width="2"/></g>
      <g id="ing-unlocked_padlock"><rect x="12" y="22" width="24" height="18" rx="3" fill="none" stroke="currentColor" stroke-width="2.4"/><path d="M16 22v-4a8 8 0 0115-4" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round"/><circle cx="24" cy="31" r="2.5" fill="currentColor"/></g>
      <g id="ing-phishing_email"><rect x="8" y="12" width="32" height="24" rx="3" fill="none" stroke="currentColor" stroke-width="2.4"/><path d="M8 14l16 12 16-12" fill="none" stroke="currentColor" stroke-width="2.4"/><path d="M30 30l4 4m0-4l-4 4" stroke="currentColor" stroke-width="2.4" stroke-linecap="round"/></g>
      <g id="ing-rogue_smartphone"><rect x="16" y="6" width="16" height="36" rx="3" fill="none" stroke="currentColor" stroke-width="2.4"/><path d="M21 10h6" stroke="currentColor" stroke-width="2" stroke-linecap="round"/><circle cx="24" cy="36" r="1.6" fill="currentColor"/><path d="M30 16l6-6m-6 0l6 6" stroke="currentColor" stroke-width="2" stroke-linecap="round"/></g>
      <g id="ing-vpn_breach"><path d="M24 6l14 5v9c0 9-6 15-14 18-8-3-14-9-14-18v-9z" fill="none" stroke="currentColor" stroke-width="2.4"/><path d="M18 22l5 5 8-9" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round" opacity=".35"/><path d="M17 18l14 12M31 18L17 30" stroke="currentColor" stroke-width="2.2" stroke-linecap="round"/></g>
    </defs>
  </svg>

  <script src="app.js"></script>
</body>
</html>