Skip to content

Commit 4d9e065

Browse files
authored
Update index.html
1 parent 9d797b0 commit 4d9e065

File tree

1 file changed

+117
-14
lines changed

1 file changed

+117
-14
lines changed

main/frontend/public/index.html

Lines changed: 117 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
<head>
44
<meta charset="UTF-8">
55
<meta name="viewport" content="width=device-width, initial-scale=1.0">
6-
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self' 'nonce-{{nonce}}' https://github.com; style-src 'self' 'unsafe-inline'; connect-src 'self' wss://webxos.netlify.app https://api.github.com; img-src 'self';">
6+
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self' 'nonce-{{nonce}}' https://github.com; style-src 'self' 'unsafe-inline'; connect-src 'self' wss://webxos.netlify.app https://api.github.com; img-src 'self' data:;">
77
<meta http-equiv="X-Frame-Options" content="DENY">
88
<meta http-equiv="X-Content-Type-Options" content="nosniff">
99
<meta http-equiv="Referrer-Policy" content="strict-origin-when-cross-origin">
@@ -39,6 +39,16 @@ <h1 class="text-2xl font-bold mb-4">Vial MCP Controller</h1>
3939
<p><strong>Vial 4:</strong> <span id="vial4-status">Stopped (Balance: 0)</span></p>
4040
</div>
4141

42+
<div class="mb-4">
43+
<h2 class="text-xl font-bold mb-2">Two-Factor Authentication</h2>
44+
<div id="2fa-setup" class="bg-white p-4 rounded shadow">
45+
<img id="2fa-qr-code" class="hidden" src="" alt="2FA QR Code">
46+
<input id="2fa-code" class="w-full p-2 border rounded mb-2" placeholder="Enter 2FA code">
47+
<button id="enable-2fa-btn" class="bg-blue-500 text-white px-4 py-2 rounded" disabled>Enable 2FA</button>
48+
<button id="verify-2fa-btn" class="bg-green-500 text-white px-4 py-2 rounded" disabled>Verify 2FA</button>
49+
</div>
50+
</div>
51+
4252
<div class="mb-4">
4353
<h2 class="text-xl font-bold mb-2">Transaction History</h2>
4454
<div id="transaction-history" class="bg-white p-4 rounded shadow"></div>
@@ -57,7 +67,12 @@ <h2 class="text-xl font-bold mb-2">Security KPIs</h2>
5767
<div class="mb-4">
5868
<h2 class="text-xl font-bold mb-2">User Action History</h2>
5969
<div id="action-history" class="bg-white p-4 rounded shadow"></div>
60-
<button id="load-actions-btn" class="bg-blue-500 text-white px-4 py-2 rounded" disabled>Load Action History</button>
70+
<div class="flex space-x-2">
71+
<button id="load-actions-btn" class="bg-blue-500 text-white px-4 py-2 rounded" disabled>Load Action History</button>
72+
<button id="prev-page-btn" class="bg-gray-500 text-white px-4 py-2 rounded" disabled>Previous Page</button>
73+
<button id="next-page-btn" class="bg-gray-500 text-white px-4 py-2 rounded" disabled>Next Page</button>
74+
<span id="page-info" class="p-2">Page 1</span>
75+
</div>
6176
</div>
6277

6378
<div class="mb-4">
@@ -92,6 +107,9 @@ <h2 class="text-xl font-bold mb-2">User Action History</h2>
92107
import { updateNetworkStatus } from '/js/vial_controller.js';
93108
import { wsHandler } from '/js/websocket_handler.js';
94109

110+
let currentPage = 1;
111+
let totalPages = 1;
112+
95113
updateNetworkStatus();
96114
window.addEventListener('online', updateNetworkStatus);
97115
window.addEventListener('offline', updateNetworkStatus);
@@ -107,6 +125,59 @@ <h2 class="text-xl font-bold mb-2">User Action History</h2>
107125
document.getElementById('logout-btn').disabled = false;
108126
document.getElementById('data-erasure-btn').disabled = false;
109127
document.getElementById('load-actions-btn').disabled = false;
128+
document.getElementById('enable-2fa-btn').disabled = false;
129+
});
130+
131+
async function loadActionHistory(page) {
132+
const userId = document.getElementById('user-id').innerText;
133+
if (userId === 'Not logged in') {
134+
document.getElementById('output').innerText = 'Error: Please authenticate first';
135+
return;
136+
}
137+
try {
138+
const accessToken = localStorage.getItem('access_token');
139+
const sessionId = document.cookie.match(/session_id=([^;]+)/)?.[1];
140+
const res = await fetch('https://webxos.netlify.app/mcp/execute', {
141+
method: 'POST',
142+
headers: {
143+
'Content-Type': 'application/json',
144+
'Authorization': `Bearer ${accessToken}`,
145+
'X-Session-ID': sessionId
146+
},
147+
body: JSON.stringify({
148+
jsonrpc: '2.0',
149+
method: 'security.getUserActions',
150+
params: { user_id: userId, page, page_size: 50 },
151+
id: Math.floor(Math.random() * 1000)
152+
})
153+
});
154+
const data = await res.json();
155+
if (data.error) throw new Error(data.error.message);
156+
const actions = data.result.actions;
157+
totalPages = data.result.total_pages;
158+
currentPage = data.result.current_page;
159+
const actionHistory = document.getElementById('action-history');
160+
actionHistory.innerHTML = actions.map(action => `
161+
<div class="p-2 border-b">
162+
<p><strong>Action:</strong> ${action.action}</p>
163+
<p><strong>Details:</strong> ${JSON.stringify(action.details)}</p>
164+
<p><strong>Timestamp:</strong> ${new Date(action.created_at).toLocaleString()}</p>
165+
</div>
166+
`).join('');
167+
document.getElementById('page-info').innerText = `Page ${currentPage}`;
168+
document.getElementById('prev-page-btn').disabled = currentPage === 1;
169+
document.getElementById('next-page-btn').disabled = currentPage === totalPages;
170+
} catch (error) {
171+
document.getElementById('output').innerText = `Error loading action history: ${error.message}`;
172+
}
173+
}
174+
175+
document.getElementById('load-actions-btn').addEventListener('click', () => loadActionHistory(1));
176+
document.getElementById('prev-page-btn').addEventListener('click', () => {
177+
if (currentPage > 1) loadActionHistory(currentPage - 1);
178+
});
179+
document.getElementById('next-page-btn').addEventListener('click', () => {
180+
if (currentPage < totalPages) loadActionHistory(currentPage + 1);
110181
});
111182

112183
document.getElementById('logout-btn').addEventListener('click', async () => {
@@ -149,6 +220,8 @@ <h2 class="text-xl font-bold mb-2">User Action History</h2>
149220
document.getElementById('logout-btn').disabled = true;
150221
document.getElementById('data-erasure-btn').disabled = true;
151222
document.getElementById('load-actions-btn').disabled = true;
223+
document.getElementById('enable-2fa-btn').disabled = true;
224+
document.getElementById('verify-2fa-btn').disabled = true;
152225
} catch (error) {
153226
document.getElementById('output').innerText = `Logout error: ${error.message}`;
154227
}
@@ -192,12 +265,14 @@ <h2 class="text-xl font-bold mb-2">User Action History</h2>
192265
document.getElementById('logout-btn').disabled = true;
193266
document.getElementById('data-erasure-btn').disabled = true;
194267
document.getElementById('load-actions-btn').disabled = true;
268+
document.getElementById('enable-2fa-btn').disabled = true;
269+
document.getElementById('verify-2fa-btn').disabled = true;
195270
} catch (error) {
196271
document.getElementById('output').innerText = `Data erasure error: ${error.message}`;
197272
}
198273
});
199274

200-
document.getElementById('load-actions-btn').addEventListener('click', async () => {
275+
document.getElementById('enable-2fa-btn').addEventListener('click', async () => {
201276
const userId = document.getElementById('user-id').innerText;
202277
if (userId === 'Not logged in') {
203278
document.getElementById('output').innerText = 'Error: Please authenticate first';
@@ -215,24 +290,52 @@ <h2 class="text-xl font-bold mb-2">User Action History</h2>
215290
},
216291
body: JSON.stringify({
217292
jsonrpc: '2.0',
218-
method: 'security.getUserActions',
293+
method: 'auth.enable2FA',
219294
params: { user_id: userId },
220295
id: Math.floor(Math.random() * 1000)
221296
})
222297
});
223298
const data = await res.json();
224299
if (data.error) throw new Error(data.error.message);
225-
const actions = data.result.actions;
226-
const actionHistory = document.getElementById('action-history');
227-
actionHistory.innerHTML = actions.map(action => `
228-
<div class="p-2 border-b">
229-
<p><strong>Action:</strong> ${action.action}</p>
230-
<p><strong>Details:</strong> ${JSON.stringify(action.details)}</p>
231-
<p><strong>Timestamp:</strong> ${new Date(action.created_at).toLocaleString()}</p>
232-
</div>
233-
`).join('');
300+
document.getElementById('2fa-qr-code').src = data.result.qr_code_url;
301+
document.getElementById('2fa-qr-code').classList.remove('hidden');
302+
document.getElementById('verify-2fa-btn').disabled = false;
234303
} catch (error) {
235-
document.getElementById('output').innerText = `Error loading action history: ${error.message}`;
304+
document.getElementById('output').innerText = `2FA setup error: ${error.message}`;
305+
}
306+
});
307+
308+
document.getElementById('verify-2fa-btn').addEventListener('click', async () => {
309+
const userId = document.getElementById('user-id').innerText;
310+
const totpCode = document.getElementById('2fa-code').value;
311+
if (!totpCode) {
312+
document.getElementById('output').innerText = 'Error: Please enter 2FA code';
313+
return;
314+
}
315+
try {
316+
const accessToken = localStorage.getItem('access_token');
317+
const sessionId = document.cookie.match(/session_id=([^;]+)/)?.[1];
318+
const res = await fetch('https://webxos.netlify.app/mcp/execute', {
319+
method: 'POST',
320+
headers: {
321+
'Content-Type': 'application/json',
322+
'Authorization': `Bearer ${accessToken}`,
323+
'X-Session-ID': sessionId
324+
},
325+
body: JSON.stringify({
326+
jsonrpc: '2.0',
327+
method: 'auth.verify2FA',
328+
params: { user_id: userId, totp_code: totpCode },
329+
id: Math.floor(Math.random() * 1000)
330+
})
331+
});
332+
const data = await res.json();
333+
if (data.error) throw new Error(data.error.message);
334+
document.getElementById('output').innerText = '2FA verified successfully';
335+
document.getElementById('2fa-qr-code').classList.add('hidden');
336+
document.getElementById('verify-2fa-btn').disabled = true;
337+
} catch (error) {
338+
document.getElementById('output').innerText = `2FA verification error: ${error.message}`;
236339
}
237340
});
238341
</script>

0 commit comments

Comments
 (0)