edsaga commited on
Commit
89ba830
·
verified ·
1 Parent(s): 6e9678a

You need to *uniformly follow all of the design instructions and apply them across the entire design. There should not be random big pictures of polenta, and this project should now be called "GRIDLAND." You also need to implement the Draggabilly library so that the windows can be draggable.

Browse files
Files changed (4) hide show
  1. components/window.js +59 -0
  2. index.html +16 -756
  3. script.js +23 -0
  4. style.css +9 -6
components/window.js ADDED
@@ -0,0 +1,59 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ class GridlandWindow extends HTMLElement {
2
+ connectedCallback() {
3
+ this.attachShadow({ mode: 'open' });
4
+ this.shadowRoot.innerHTML = `
5
+ <style>
6
+ .window {
7
+ background: white;
8
+ box-shadow:
9
+ inset -1px -1px 0 0px #0a0a0a,
10
+ inset 1px 1px 0 0px #dfdfdf,
11
+ inset -2px -2px 0 0px #808080,
12
+ inset 2px 2px 0 0px #ffffff;
13
+ position: absolute;
14
+ z-index: 10;
15
+ cursor: move;
16
+ width: 300px;
17
+ }
18
+ .window-title {
19
+ background: linear-gradient(to right, #000080, #1084d0);
20
+ color: white;
21
+ padding: 4px 8px;
22
+ font-weight: bold;
23
+ display: flex;
24
+ justify-content: space-between;
25
+ align-items: center;
26
+ }
27
+ .window-content {
28
+ padding: 8px;
29
+ }
30
+ .close-btn {
31
+ background: white;
32
+ color: black;
33
+ border: 1px solid black;
34
+ width: 16px;
35
+ height: 16px;
36
+ display: flex;
37
+ align-items: center;
38
+ justify-content: center;
39
+ cursor: pointer;
40
+ }
41
+ </style>
42
+ <div class="window">
43
+ <div class="window-title">
44
+ <span>${this.getAttribute('title') || 'Window'}</span>
45
+ <button class="close-btn">×</button>
46
+ </div>
47
+ <div class="window-content">
48
+ <slot></slot>
49
+ </div>
50
+ </div>
51
+ `;
52
+
53
+ this.shadowRoot.querySelector('.close-btn').addEventListener('click', () => {
54
+ this.remove();
55
+ });
56
+ }
57
+ }
58
+
59
+ customElements.define('gridland-window', GridlandWindow);
index.html CHANGED
@@ -1,763 +1,23 @@
1
-
2
  <!DOCTYPE html>
3
  <html lang="en">
4
  <head>
5
- <meta charset="UTF-8">
6
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
- <title>CamXploit Scanner v2.0.1</title>
8
- <link rel="stylesheet" href="https://unpkg.com/@sakun/system.css">
9
- <link rel="stylesheet" href="style.css">
10
- <script src="https://cdn.tailwindcss.com"></script>
11
- <style>
12
- @font-face {
13
- font-family: 'Chicago';
14
- src: url('https://unpkg.com/system-font-css@2.0.1/fonts/ChicagoFLF.ttf') format('truetype');
15
- }
16
- @font-face {
17
- font-family: 'Geneva';
18
- src: url('https://unpkg.com/system-font-css@2.0.1/fonts/GenevaFLF.ttf') format('truetype');
19
- }
20
-
21
- body {
22
- background-color: #008080;
23
- background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH4AkEEjIZJpQpWQAAAB1pVFh0Q29tbWVudAAAAAAAQ3JlYXRlZCB3aXRoIEdJTVBkLmUHAAAAJUlEQVQ4y2NgGAWjYBSMglEwCkbBKBgFgw0wDnQGRsEoGAWjYBSMglEAAKZQAf+J8jRZAAAAAElFTkSuQmCC');
24
- font-family: 'Geneva', monospace;
25
- font-size: 9pt;
26
- color: #000;
27
- margin: 0;
28
- padding: 0;
29
- height: 100vh;
30
- overflow: hidden;
31
- }
32
-
33
- .window {
34
- box-shadow: 4px 4px 0 #404040;
35
- border: 2px solid #000;
36
- background: #fff;
37
- margin: 20px auto;
38
- }
39
-
40
- .title-bar {
41
- background: linear-gradient(to right, #000 0%, #000 50%, #fff 50%, #fff 100%);
42
- background-size: 16px 100%;
43
- padding: 4px 6px;
44
- border-bottom: 2px solid #000;
45
- display: flex;
46
- align-items: center;
47
- }
48
-
49
- .title {
50
- font-family: 'Chicago', sans-serif;
51
- font-size: 12pt;
52
- margin: 0;
53
- padding: 0 8px;
54
- flex-grow: 1;
55
- text-align: center;
56
- color: #fff;
57
- mix-blend-mode: difference;
58
- white-space: nowrap;
59
- overflow: hidden;
60
- text-overflow: ellipsis;
61
- }
62
-
63
- .separator {
64
- height: 2px;
65
- background: #000;
66
- }
67
-
68
- .window-pane {
69
- background: #fff;
70
- padding: 12px;
71
- }
72
-
73
- .btn {
74
- font-family: 'Geneva', monospace;
75
- font-size: 9pt;
76
- padding: 4px 12px;
77
- border: 2px solid #000;
78
- background: #fff;
79
- cursor: pointer;
80
- outline: none;
81
- }
82
-
83
- .btn:active, .btn:focus {
84
- background: #000;
85
- color: #fff;
86
- }
87
-
88
- .btn:disabled {
89
- color: #808080;
90
- background: #fff;
91
- cursor: not-allowed;
92
- border-style: dotted;
93
- }
94
-
95
- input[type="text"] {
96
- font-family: 'Geneva', monospace;
97
- font-size: 9pt;
98
- padding: 4px;
99
- border: 2px inset #c0c0c0;
100
- outline: none;
101
- }
102
-
103
- input[type="text"]:focus {
104
- border: 2px dotted #000;
105
- }
106
-
107
- .menu-bar {
108
- background: #fff;
109
- border-bottom: 2px solid #000;
110
- padding: 4px 8px;
111
- display: flex;
112
- }
113
-
114
- .menu-bar ul {
115
- list-style: none;
116
- margin: 0;
117
- padding: 0;
118
- display: flex;
119
- }
120
-
121
- .menu-bar li {
122
- position: relative;
123
- padding: 2px 12px;
124
- cursor: default;
125
- }
126
-
127
- .menu-bar li:hover {
128
- background: #000;
129
- color: #fff;
130
- }
131
-
132
- .dropdown {
133
- display: none;
134
- position: absolute;
135
- top: 100%;
136
- left: 0;
137
- background: #fff;
138
- border: 2px solid #000;
139
- min-width: 160px;
140
- z-index: 100;
141
- padding: 4px 0;
142
- }
143
-
144
- .menu-bar li:hover .dropdown {
145
- display: block;
146
- }
147
-
148
- .dropdown li {
149
- padding: 4px 12px;
150
- white-space: nowrap;
151
- }
152
-
153
- .dropdown li.divider {
154
- border-top: 1px solid #000;
155
- margin-top: 4px;
156
- padding-top: 8px;
157
- }
158
-
159
- .dropdown a {
160
- color: inherit;
161
- text-decoration: none;
162
- display: block;
163
- }
164
-
165
- #results-output {
166
- font-family: 'Geneva', monospace;
167
- font-size: 9pt;
168
- line-height: 1.4;
169
- white-space: pre-wrap;
170
- }
171
-
172
- #results-output::-webkit-scrollbar {
173
- width: 16px;
174
- height: 16px;
175
- }
176
-
177
- #results-output::-webkit-scrollbar-track {
178
- background: #fff;
179
- border-left: 2px solid #000;
180
- }
181
-
182
- #results-output::-webkit-scrollbar-thumb {
183
- background: #000;
184
- border: 2px solid #fff;
185
- }
186
-
187
- #results-output::-webkit-scrollbar-button {
188
- background: #fff;
189
- border: 2px solid #000;
190
- height: 16px;
191
- width: 16px;
192
- }
193
-
194
- .field-row {
195
- margin-bottom: 12px;
196
- display: flex;
197
- align-items: center;
198
- }
199
-
200
- .field-row label {
201
- width: 120px;
202
- display: inline-block;
203
- }
204
-
205
- #progress-bar {
206
- height: 16px;
207
- border: 1px solid #000;
208
- background: #fff;
209
- position: relative;
210
- width: 280px;
211
- }
212
-
213
- #progress-bar-fill {
214
- height: 100%;
215
- background: #000;
216
- width: 0%;
217
- transition: width 0.3s;
218
- }
219
-
220
- #progress-text {
221
- position: absolute;
222
- top: 1px;
223
- left: 4px;
224
- font-family: 'Geneva', monospace;
225
- font-size: 8pt;
226
- color: #fff;
227
- mix-blend-mode: difference;
228
- }
229
-
230
- .stream-window {
231
- position: fixed;
232
- top: 50px;
233
- left: 50px;
234
- z-index: 999;
235
- }
236
-
237
- @media (max-width: 768px) {
238
- .window {
239
- width: 95% !important;
240
- margin: 10px auto;
241
- }
242
-
243
- .field-row {
244
- flex-direction: column;
245
- align-items: flex-start;
246
- }
247
-
248
- .field-row label {
249
- margin-bottom: 4px;
250
- width: auto;
251
- }
252
-
253
- #target-ip {
254
- width: 100% !important;
255
- }
256
-
257
- #progress-bar {
258
- width: 100% !important;
259
- }
260
- }
261
- </style>
262
  </head>
263
  <body>
264
- <custom-navbar></custom-navbar>
265
- <div class="menu-bar" role="menubar" style="margin-top: 60px;">
266
- <ul role="menu">
267
- <li role="menuitem" tabindex="0">📁 File
268
- <ul role="menu" class="dropdown">
269
- <li role="menuitem"><a href="#new">New Scan</a></li>
270
- <li role="menuitem" class="divider"><a href="#export">Export Results</a></li>
271
- <li role="menuitem"><a href="#quit">Quit</a></li>
272
- </ul>
273
- </li>
274
- <li role="menuitem" tabindex="0">⚙️ Tools
275
- <ul role="menu" class="dropdown">
276
- <li role="menuitem"><a href="#shodan">Search Shodan</a></li>
277
- <li role="menuitem"><a href="#censys">Search Censys</a></li>
278
- <li role="menuitem"><a href="#google">Google Dork</a></li>
279
- </ul>
280
- </li>
281
- <li role="menuitem" tabindex="0">❓ Help
282
- <ul role="menu" class="dropdown">
283
- <li role="menuitem"><a href="#about">About CamXploit</a></li>
284
- <li role="menuitem"><a href="#usage">Usage Guide</a></li>
285
- </ul>
286
- </li>
287
- </ul>
288
- </div>
289
-
290
- <div class="window" style="width: 680px; margin: 20px auto;">
291
- <div class="title-bar">
292
- <button aria-label="Close" class="close"></button>
293
- <h1 class="title">🎥 CamXploit Scanner v2.0.1</h1>
294
- <button aria-label="Resize" class="resize"></button>
295
- </div>
296
- <div class="separator"></div>
297
- <div class="window-pane">
298
- <div class="field-row">
299
- <label for="target-ip">🎯 Target IP:</label>
300
- <input type="text" id="target-ip" placeholder="192.168.1.1 or 192.168.1.0/24" style="width: 280px;">
301
- </div>
302
-
303
- <div class="field-row" style="margin-top: 16px;">
304
- <button class="btn" id="start-scan" style="margin-right: 8px;">🔍 Start Scan</button>
305
- <button class="btn" id="stop-scan" disabled>⏹️ Stop Scan</button>
306
- <button class="btn" id="clear-results" style="margin-left: 8px;">🗑️ Clear</button>
307
- </div>
308
-
309
- <div class="field-row" style="margin-top: 16px;">
310
- <label>📊 Status:</label>
311
- <span id="scan-status" style="font-weight: bold;">Ready to scan</span>
312
- </div>
313
-
314
- <div class="field-row" style="margin-top: 8px;">
315
- <label>⏱️ Progress:</label>
316
- <div id="progress-bar">
317
- <div id="progress-bar-fill"></div>
318
- <span id="progress-text">0%</span>
319
- </div>
320
- </div>
321
-
322
- <div class="field-row" style="margin-top: 16px; flex-direction: column;">
323
- <label style="font-weight: bold; margin-bottom: 4px;">📋 Scan Results:</label>
324
- <div id="results-output" style="width: 100%; height: 320px; border: 2px inset #c0c0c0; background: #fff; overflow-y: auto; padding: 8px;" tabindex="0">
325
- <!-- Scan results will appear here -->
326
- </div>
327
- </div>
328
- </div>
329
- </div>
330
-
331
- <script>
332
- // Global state management
333
- let scanState = {
334
- isScanning: false,
335
- currentScan: null,
336
- results: [],
337
- totalFindings: 0
338
- };
339
-
340
- // DOM element references
341
- const targetIpInput = document.getElementById('target-ip');
342
- const startScanBtn = document.getElementById('start-scan');
343
- const stopScanBtn = document.getElementById('stop-scan');
344
- const clearResultsBtn = document.getElementById('clear-results');
345
- const scanStatus = document.getElementById('scan-status');
346
- const progressBarFill = document.getElementById('progress-bar-fill');
347
- const progressText = document.getElementById('progress-text');
348
- const resultsOutput = document.getElementById('results-output');
349
-
350
- // System 6 style alert dialogs
351
- function showSystemAlert(title, message, callback) {
352
- const alertWindow = document.createElement('div');
353
- alertWindow.className = 'window';
354
- alertWindow.style.cssText = `
355
- position: fixed;
356
- top: 50%;
357
- left: 50%;
358
- transform: translate(-50%, -50%);
359
- width: 400px;
360
- z-index: 1000;
361
- `;
362
-
363
- alertWindow.innerHTML = `
364
- <div class="title-bar">
365
- <h1 class="title">⚠️ ${title}</h1>
366
- </div>
367
- <div class="separator"></div>
368
- <div class="window-pane" style="padding: 16px; text-align: center;">
369
- <p style="margin: 16px 0; font-family: Geneva; font-size: 9pt;">${message}</p>
370
- <button class="btn" onclick="this.closest('.window').remove(); ${callback ? 'callback()' : ''}"
371
- style="margin-top: 16px;">OK</button>
372
- </div>
373
- `;
374
-
375
- document.body.appendChild(alertWindow);
376
- }
377
-
378
- // IP validation with System 6 feedback
379
- function validateIP(ip) {
380
- const ipPattern = /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(?:\/[0-9]{1,2})?$/;
381
- return ipPattern.test(ip.trim());
382
- }
383
-
384
- // Format scan results with System 6 styling
385
- function formatScanResult(event) {
386
- const timestamp = new Date().toLocaleTimeString();
387
- let formattedResult = '';
388
-
389
- switch(event.type) {
390
- case 'status':
391
- formattedResult = `[${timestamp}] 📊 ${event.message}\n`;
392
- break;
393
- case 'finding':
394
- scanState.totalFindings++;
395
- if (event.url) {
396
- formattedResult = `[${timestamp}] ✅ FOUND: ${event.message}\n`;
397
- formattedResult += ` 🔗 URL: ${event.url}\n`;
398
-
399
- // Create clickable link for streams
400
- if (event.url.includes('rtsp://') || event.url.includes('http')) {
401
- const linkElement = document.createElement('a');
402
- linkElement.href = '#';
403
- linkElement.textContent = '👁️ View Stream';
404
- linkElement.style.cssText = 'color: #000; text-decoration: underline; cursor: pointer;';
405
- linkElement.onclick = () => openStreamViewer(event.url);
406
- resultsOutput.appendChild(linkElement);
407
- resultsOutput.appendChild(document.createTextNode('\n'));
408
- }
409
- } else {
410
- formattedResult = `[${timestamp}] 🔍 ${event.message}\n`;
411
- }
412
- break;
413
- case 'error':
414
- formattedResult = `[${timestamp}] ❌ ERROR: ${event.message}\n`;
415
- break;
416
- case 'complete':
417
- formattedResult = `[${timestamp}] ✅ SCAN COMPLETE\n`;
418
- formattedResult += ` 📊 Total findings: ${scanState.totalFindings}\n`;
419
- break;
420
- }
421
-
422
- return formattedResult;
423
- }
424
-
425
- // Stream viewer in System 6 style window
426
- function openStreamViewer(streamUrl) {
427
- const streamWindow = document.createElement('div');
428
- streamWindow.className = 'window stream-window';
429
- streamWindow.style.width = '640px';
430
-
431
- const b64Url = btoa(streamUrl).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
432
-
433
- streamWindow.innerHTML = `
434
- <div class="title-bar">
435
- <button aria-label="Close" class="close" onclick="this.closest('.window').remove()"></button>
436
- <h1 class="title">📺 Stream Viewer</h1>
437
- </div>
438
- <div class="separator"></div>
439
- <div class="window-pane" style="padding: 8px; height: calc(100% - 40px);">
440
- <video controls autoplay style="width: 100%; height: calc(100% - 60px); background: #000;">
441
- <source src="/stream/${b64Url}" type="application/vnd.apple.mpegurl">
442
- Your browser does not support HLS streams.
443
- </video>
444
- <div style="margin-top: 8px; font-family: Geneva; font-size: 8pt;">
445
- 🔗 ${streamUrl}
446
- </div>
447
- </div>
448
- `;
449
-
450
- document.body.appendChild(streamWindow);
451
- }
452
-
453
- // Main scan function with backend integration
454
- async function startScan() {
455
- const targetIP = targetIpInput.value.trim();
456
-
457
- if (!targetIP) {
458
- showSystemAlert('Input Error', 'Please enter a target IP address.');
459
- return;
460
- }
461
-
462
- if (!validateIP(targetIP)) {
463
- showSystemAlert('Input Error', 'Please enter a valid IP address or CIDR range.');
464
- return;
465
- }
466
-
467
- // Update UI state
468
- scanState.isScanning = true;
469
- scanState.totalFindings = 0;
470
- startScanBtn.disabled = true;
471
- stopScanBtn.disabled = false;
472
- targetIpInput.disabled = true;
473
-
474
- // Clear previous results
475
- resultsOutput.textContent = '';
476
- updateProgress(0, 'Initializing scan...');
477
-
478
- try {
479
- const response = await fetch('/scan', {
480
- method: 'POST',
481
- headers: { 'Content-Type': 'application/json' },
482
- body: JSON.stringify({ ip: targetIP })
483
- });
484
-
485
- if (!response.ok) {
486
- const errorData = await response.json().catch(() => ({}));
487
- throw new Error(errorData.error || 'Server error');
488
- }
489
-
490
- // Process streaming response
491
- const reader = response.body.getReader();
492
- const decoder = new TextDecoder();
493
- let buffer = '';
494
- let progress = 0;
495
-
496
- while (scanState.isScanning) {
497
- const { value, done } = await reader.read();
498
- if (done) break;
499
-
500
- buffer += decoder.decode(value, { stream: true });
501
- let lines = buffer.split('\n');
502
- buffer = lines.pop();
503
-
504
- for (const line of lines) {
505
- if (!line.trim()) continue;
506
-
507
- let event;
508
- try {
509
- event = JSON.parse(line);
510
- } catch (e) {
511
- continue;
512
- }
513
-
514
- // Update progress
515
- progress = Math.min(progress + 2, 95);
516
- updateProgress(progress, event.message || 'Scanning...');
517
-
518
- // Format and display result
519
- const formattedResult = formatScanResult(event);
520
- resultsOutput.textContent += formattedResult;
521
- resultsOutput.scrollTop = resultsOutput.scrollHeight;
522
-
523
- // Handle scan completion
524
- if (event.type === 'end' || event.complete) {
525
- finalizeScan();
526
- break;
527
- }
528
- }
529
- }
530
-
531
- } catch (error) {
532
- showSystemAlert('Connection Error', `Failed to connect to scanner: ${error.message}`);
533
- finalizeScan();
534
- }
535
- }
536
-
537
- // Progress update with System 6 styling
538
- function updateProgress(percentage, message) {
539
- progressBarFill.style.width = `${percentage}%`;
540
- progressText.textContent = `${Math.round(percentage)}%`;
541
- scanStatus.textContent = message;
542
- }
543
-
544
- // Finalize scan state
545
- function finalizeScan() {
546
- scanState.isScanning = false;
547
- startScanBtn.disabled = false;
548
- stopScanBtn.disabled = true;
549
- targetIpInput.disabled = false;
550
- updateProgress(100, `Scan completed - ${scanState.totalFindings} findings`);
551
- }
552
-
553
- // Stop scan function
554
- function stopScan() {
555
- if (scanState.isScanning) {
556
- scanState.isScanning = false;
557
- showSystemAlert('Scan Stopped', 'Scan has been manually stopped.');
558
- finalizeScan();
559
- }
560
- }
561
-
562
- // Clear results function
563
- function clearResults() {
564
- resultsOutput.textContent = '';
565
- scanState.results = [];
566
- scanState.totalFindings = 0;
567
- updateProgress(0, 'Ready to scan');
568
- }
569
-
570
- // Menu functions
571
- function openSearchUrl(service, ip) {
572
- const urls = {
573
- shodan: `https://www.shodan.io/search?query=${ip}`,
574
- censys: `https://search.censys.io/hosts/${ip}`,
575
- google: `https://www.google.com/search?q=site:${ip}+inurl:view/view.shtml+OR+inurl:admin.html`
576
- };
577
-
578
- if (urls[service]) {
579
- window.open(urls[service], '_blank');
580
- }
581
- }
582
-
583
- // Event listeners
584
- startScanBtn.addEventListener('click', startScan);
585
- stopScanBtn.addEventListener('click', stopScan);
586
- clearResultsBtn.addEventListener('click', clearResults);
587
-
588
- // Enter key support for IP input
589
- targetIpInput.addEventListener('keypress', (e) => {
590
- if (e.key === 'Enter' && !scanState.isScanning) {
591
- startScan();
592
- }
593
- });
594
-
595
- // Menu item handlers
596
- document.querySelectorAll('[role="menuitem"] a').forEach(link => {
597
- link.addEventListener('click', (e) => {
598
- e.preventDefault();
599
- const action = e.target.getAttribute('href').substring(1);
600
-
601
- switch(action) {
602
- case 'new':
603
- clearResults();
604
- targetIpInput.focus();
605
- break;
606
- case 'export':
607
- exportResults();
608
- break;
609
- case 'shodan':
610
- case 'censys':
611
- case 'google':
612
- const ip = targetIpInput.value.trim();
613
- if (ip) {
614
- openSearchUrl(action, ip);
615
- } else {
616
- showSystemAlert('No Target', 'Please enter an IP address first.');
617
- }
618
- break;
619
- case 'about':
620
- showAboutDialog();
621
- break;
622
- case 'usage':
623
- showUsageDialog();
624
- break;
625
- case 'quit':
626
- showSystemAlert('Quit', 'This would close the application in a real environment.');
627
- break;
628
- }
629
- });
630
- });
631
-
632
- // Export results function
633
- function exportResults() {
634
- const results = resultsOutput.textContent;
635
- if (!results.trim()) {
636
- showSystemAlert('No Results', 'No scan results to export.');
637
- return;
638
- }
639
-
640
- const blob = new Blob([results], { type: 'text/plain' });
641
- const url = URL.createObjectURL(blob);
642
- const a = document.createElement('a');
643
- a.href = url;
644
- a.download = `camxploit-scan-${new Date().toISOString().slice(0,19).replace(/:/g,'-')}.txt`;
645
- a.click();
646
- URL.revokeObjectURL(url);
647
- }
648
-
649
- // About dialog
650
- function showAboutDialog() {
651
- const aboutWindow = document.createElement('div');
652
- aboutWindow.className = 'window';
653
- aboutWindow.style.cssText = `
654
- position: fixed;
655
- top: 30%;
656
- left: 50%;
657
- transform: translate(-50%, -50%);
658
- width: 500px;
659
- z-index: 1000;
660
- `;
661
-
662
- aboutWindow.innerHTML = `
663
- <div class="title-bar">
664
- <button aria-label="Close" class="close" onclick="this.closest('.window').remove()"></button>
665
- <h1 class="title">About CamXploit</h1>
666
- </div>
667
- <div class="separator"></div>
668
- <div class="window-pane" style="padding: 16px;">
669
- <div style="text-align: center; margin-bottom: 16px;">
670
- <div style="font-size: 48px; margin-bottom: 8px;">🎥</div>
671
- <div style="font-family: Chicago; font-size: 12pt; font-weight: bold;">CamXploit Scanner</div>
672
- <div style="font-family: Geneva; font-size: 9pt;">Version 2.0.1</div>
673
- </div>
674
- <div style="font-family: Geneva; font-size: 9pt; line-height: 1.4;">
675
- <p>CamXploit is a reconnaissance tool for discovering exposed CCTV cameras and analyzing their security configurations.</p>
676
- <p><strong>Features:</strong></p>
677
- <ul style="margin-left: 20px;">
678
- <li>Comprehensive port scanning</li>
679
- <li>Camera brand detection</li>
680
- <li>Default credential testing</li>
681
- <li>Live stream discovery</li>
682
- <li>Vulnerability identification</li>
683
- </ul>
684
- <p><em>⚠️ For educational and authorized security testing only.</em></p>
685
- </div>
686
- <div style="text-align: center; margin-top: 16px;">
687
- <button class="btn" onclick="this.closest('.window').remove()">OK</button>
688
- </div>
689
- </div>
690
- `;
691
-
692
- document.body.appendChild(aboutWindow);
693
- }
694
-
695
- // Usage dialog
696
- function showUsageDialog() {
697
- const usageWindow = document.createElement('div');
698
- usageWindow.className = 'window';
699
- usageWindow.style.cssText = `
700
- position: fixed;
701
- top: 20%;
702
- left: 50%;
703
- transform: translate(-50%, -50%);
704
- width: 500px;
705
- z-index: 1000;
706
- `;
707
-
708
- usageWindow.innerHTML = `
709
- <div class="title-bar">
710
- <button aria-label="Close" class="close" onclick="this.closest('.window').remove()"></button>
711
- <h1 class="title">Usage Guide</h1>
712
- </div>
713
- <div class="separator"></div>
714
- <div class="window-pane" style="padding: 16px;">
715
- <div style="font-family: Geneva; font-size: 9pt; line-height: 1.4;">
716
- <p><strong>How to use CamXploit Scanner:</strong></p>
717
- <ol style="margin-left: 20px;">
718
- <li>Enter a target IP address or CIDR range (e.g., 192.168.1.1 or 192.168.1.0/24)</li>
719
- <li>Click "Start Scan" or press Enter</li>
720
- <li>Monitor progress in the status area</li>
721
- <li>View discovered cameras in the results panel</li>
722
- <li>Click "View Stream" links to open live feeds</li>
723
- <li>Use "Export Results" to save your findings</li>
724
- </ol>
725
- <p><strong>Keyboard Shortcuts:</strong></p>
726
- <ul style="margin-left: 20px;">
727
- <li>Enter: Start scan</li>
728
- <li>Escape: Stop scan</li>
729
- <li>Cmd/Ctrl+E: Export results</li>
730
- </ul>
731
- <p><em>Note: Always ensure you have permission to scan target networks.</em></p>
732
- </div>
733
- <div style="text-align: center; margin-top: 16px;">
734
- <button class="btn" onclick="this.closest('.window').remove()">OK</button>
735
- </div>
736
- </div>
737
- `;
738
-
739
- document.body.appendChild(usageWindow);
740
- }
741
-
742
- // Initialize application
743
- document.addEventListener('DOMContentLoaded', () => {
744
- updateProgress(0, 'Ready to scan');
745
- targetIpInput.focus();
746
-
747
- // Add keyboard shortcuts
748
- document.addEventListener('keydown', (e) => {
749
- if (e.key === 'Escape' && scanState.isScanning) {
750
- stopScan();
751
- }
752
-
753
- if ((e.ctrlKey || e.metaKey) && e.key === 'e') {
754
- exportResults();
755
- e.preventDefault();
756
- }
757
- });
758
- });
759
- </script>
760
- <script src="components/navbar.js"></script>
761
- <script src="components/footer.js"></script>
762
  </body>
763
  </html>
 
 
1
  <!DOCTYPE html>
2
  <html lang="en">
3
  <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>GRIDLAND</title>
7
+ <link rel="stylesheet" href="style.css">
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8
  </head>
9
  <body>
10
+ <div class="container">
11
+ <gridland-window title="Welcome">
12
+ <p>Welcome to GRIDLAND. Drag windows around!</p>
13
+ </gridland-window>
14
+
15
+ <gridland-window title="Info" style="top: 100px; left: 100px;">
16
+ <p>This is a draggable window demo.</p>
17
+ </gridland-window>
18
+ </div>
19
+
20
+ <script src="components/window.js"></script>
21
+ <script src="script.js"></script>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
22
  </body>
23
  </html>
script.js ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Import Draggabilly from CDN
2
+ (function() {
3
+ function loadScript(url, callback) {
4
+ const script = document.createElement('script');
5
+ script.src = url;
6
+ script.onload = callback;
7
+ document.body.appendChild(script);
8
+ }
9
+
10
+ document.addEventListener('DOMContentLoaded', () => {
11
+ // Load Draggabilly
12
+ loadScript('https://unpkg.com/draggabilly@3.0.0/dist/draggabilly.pkgd.min.js', () => {
13
+ // Make all windows draggable
14
+ const windows = document.querySelectorAll('.window');
15
+ windows.forEach(window => {
16
+ new Draggabilly(window, {
17
+ containment: '.container',
18
+ handle: '.window-title'
19
+ });
20
+ });
21
+ });
22
+ });
23
+ })();
style.css CHANGED
@@ -5,9 +5,9 @@ body {
5
  margin: 0;
6
  padding: 0;
7
  color: #000;
8
- background-color: #C0C0C0;
9
- background-image: url('http://static.photos/retro/640x360/42');
10
- background-size: cover;
11
  background-attachment: fixed;
12
  }
13
  /* Layout */
@@ -16,18 +16,21 @@ body {
16
  max-width: 800px;
17
  margin: 2rem auto;
18
  padding: 2px;
19
- background: white;
 
20
  box-shadow:
21
  inset -1px -1px 0 0px #0a0a0a,
22
  inset 1px 1px 0 0px #dfdfdf,
23
  inset -2px -2px 0 0px #808080,
24
  inset 2px 2px 0 0px #ffffff;
25
  }
26
-
27
  .window {
28
  margin: 1rem 0;
29
  background: white;
30
- box-shadow:
 
 
 
31
  inset -1px -1px 0 0px #0a0a0a,
32
  inset 1px 1px 0 0px #dfdfdf,
33
  inset -2px -2px 0 0px #808080,
 
5
  margin: 0;
6
  padding: 0;
7
  color: #000;
8
+ background-color: #008080;
9
+ background-image: repeating-linear-gradient(45deg, rgba(255,255,255,0.1) 0px, rgba(255,255,255,0.1) 10px, transparent 10px, transparent 20px);
10
+ background-size: cover;
11
  background-attachment: fixed;
12
  }
13
  /* Layout */
 
16
  max-width: 800px;
17
  margin: 2rem auto;
18
  padding: 2px;
19
+ position: relative;
20
+ background: white;
21
  box-shadow:
22
  inset -1px -1px 0 0px #0a0a0a,
23
  inset 1px 1px 0 0px #dfdfdf,
24
  inset -2px -2px 0 0px #808080,
25
  inset 2px 2px 0 0px #ffffff;
26
  }
 
27
  .window {
28
  margin: 1rem 0;
29
  background: white;
30
+ position: absolute;
31
+ cursor: move;
32
+ z-index: 10;
33
+ box-shadow:
34
  inset -1px -1px 0 0px #0a0a0a,
35
  inset 1px 1px 0 0px #dfdfdf,
36
  inset -2px -2px 0 0px #808080,