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' 'unsafe-inline ' 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'; ">
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 ">
@@ -54,6 +54,12 @@ <h2 class="text-xl font-bold mb-2">Security KPIs</h2>
5454 </ div >
5555 </ div >
5656
57+ < div class ="mb-4 ">
58+ < h2 class ="text-xl font-bold mb-2 "> User Action History</ h2 >
59+ < 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 >
61+ </ div >
62+
5763 < div class ="mb-4 ">
5864 < textarea id ="claude-code " class ="w-full h-32 p-2 border rounded " placeholder ="Enter Claude-generated code " disabled > </ textarea >
5965 < textarea id ="wallet-import " class ="w-full h-32 p-2 border rounded " placeholder ="Paste wallet markdown to import "> </ textarea >
@@ -79,10 +85,10 @@ <h2 class="text-xl font-bold mb-2">Security KPIs</h2>
7985 < div id ="output " class ="bg-white p-4 rounded shadow "> </ div >
8086 </ div >
8187
82- < script type ="module " src ="/js/auth_handler.js "> </ script >
83- < script type ="module " src ="/js/websocket_handler.js "> </ script >
84- < script type ="module " src ="/js/vial_controller.js "> </ script >
85- < script type ="module ">
88+ < script type ="module " nonce =" {{nonce}} " src ="/js/auth_handler.js "> </ script >
89+ < script type ="module " nonce =" {{nonce}} " src ="/js/websocket_handler.js "> </ script >
90+ < script type ="module " nonce =" {{nonce}} " src ="/js/vial_controller.js "> </ script >
91+ < script type ="module " nonce =" {{nonce}} " >
8692 import { updateNetworkStatus } from '/js/vial_controller.js' ;
8793 import { wsHandler } from '/js/websocket_handler.js' ;
8894
@@ -100,6 +106,7 @@ <h2 class="text-xl font-bold mb-2">Security KPIs</h2>
100106 document . getElementById ( 'cash-out-btn' ) . disabled = ! navigator . onLine ;
101107 document . getElementById ( 'logout-btn' ) . disabled = false ;
102108 document . getElementById ( 'data-erasure-btn' ) . disabled = false ;
109+ document . getElementById ( 'load-actions-btn' ) . disabled = false ;
103110 } ) ;
104111
105112 document . getElementById ( 'logout-btn' ) . addEventListener ( 'click' , async ( ) => {
@@ -128,6 +135,7 @@ <h2 class="text-xl font-bold mb-2">Security KPIs</h2>
128135 const data = await res . json ( ) ;
129136 if ( data . error ) throw new Error ( data . error . message ) ;
130137 localStorage . removeItem ( 'access_token' ) ;
138+ localStorage . removeItem ( 'refresh_token' ) ;
131139 document . cookie = 'session_id=; Max-Age=0; path=/;' ;
132140 document . getElementById ( 'user-id' ) . innerText = 'Not logged in' ;
133141 document . getElementById ( 'output' ) . innerText = 'Logged out successfully' ;
@@ -140,6 +148,7 @@ <h2 class="text-xl font-bold mb-2">Security KPIs</h2>
140148 document . getElementById ( 'cash-out-btn' ) . disabled = true ;
141149 document . getElementById ( 'logout-btn' ) . disabled = true ;
142150 document . getElementById ( 'data-erasure-btn' ) . disabled = true ;
151+ document . getElementById ( 'load-actions-btn' ) . disabled = true ;
143152 } catch ( error ) {
144153 document . getElementById ( 'output' ) . innerText = `Logout error: ${ error . message } ` ;
145154 }
@@ -169,6 +178,7 @@ <h2 class="text-xl font-bold mb-2">Security KPIs</h2>
169178 const data = await res . json ( ) ;
170179 if ( res . status !== 200 ) throw new Error ( data . detail || 'Data erasure failed' ) ;
171180 localStorage . removeItem ( 'access_token' ) ;
181+ localStorage . removeItem ( 'refresh_token' ) ;
172182 document . cookie = 'session_id=; Max-Age=0; path=/;' ;
173183 document . getElementById ( 'user-id' ) . innerText = 'Not logged in' ;
174184 document . getElementById ( 'output' ) . innerText = 'Data erasure request successful. All data deleted.' ;
@@ -181,10 +191,50 @@ <h2 class="text-xl font-bold mb-2">Security KPIs</h2>
181191 document . getElementById ( 'cash-out-btn' ) . disabled = true ;
182192 document . getElementById ( 'logout-btn' ) . disabled = true ;
183193 document . getElementById ( 'data-erasure-btn' ) . disabled = true ;
194+ document . getElementById ( 'load-actions-btn' ) . disabled = true ;
184195 } catch ( error ) {
185196 document . getElementById ( 'output' ) . innerText = `Data erasure error: ${ error . message } ` ;
186197 }
187198 } ) ;
199+
200+ document . getElementById ( 'load-actions-btn' ) . addEventListener ( 'click' , async ( ) => {
201+ const userId = document . getElementById ( 'user-id' ) . innerText ;
202+ if ( userId === 'Not logged in' ) {
203+ document . getElementById ( 'output' ) . innerText = 'Error: Please authenticate first' ;
204+ return ;
205+ }
206+ try {
207+ const accessToken = localStorage . getItem ( 'access_token' ) ;
208+ const sessionId = document . cookie . match ( / s e s s i o n _ i d = ( [ ^ ; ] + ) / ) ?. [ 1 ] ;
209+ const res = await fetch ( 'https://webxos.netlify.app/mcp/execute' , {
210+ method : 'POST' ,
211+ headers : {
212+ 'Content-Type' : 'application/json' ,
213+ 'Authorization' : `Bearer ${ accessToken } ` ,
214+ 'X-Session-ID' : sessionId
215+ } ,
216+ body : JSON . stringify ( {
217+ jsonrpc : '2.0' ,
218+ method : 'security.getUserActions' ,
219+ params : { user_id : userId } ,
220+ id : Math . floor ( Math . random ( ) * 1000 )
221+ } )
222+ } ) ;
223+ const data = await res . json ( ) ;
224+ 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 ( '' ) ;
234+ } catch ( error ) {
235+ document . getElementById ( 'output' ) . innerText = `Error loading action history: ${ error . message } ` ;
236+ }
237+ } ) ;
188238 </ script >
189239</ body >
190240</ html >
0 commit comments