mirror of https://github.com/nocodb/nocodb
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
152 lines
4.7 KiB
152 lines
4.7 KiB
<!DOCTYPE html> |
|
<html lang="en"> |
|
<head> |
|
<meta charset="UTF-8"> |
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|
<title>Secure Script Executor</title> |
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.30.1/min/vs/loader.js"></script> |
|
<link href="https://cdn.jsdelivr.net/npm/tailwindcss@2.2.19/dist/tailwind.min.css" rel="stylesheet"> |
|
<style> |
|
body { |
|
display: flex; |
|
flex-direction: column; |
|
height: 100vh; |
|
font-family: 'Arial', sans-serif; |
|
} |
|
#editor, #output { |
|
height: calc(100vh - 7rem); |
|
} |
|
.console-line { |
|
padding: 2px 5px; |
|
border-bottom: 1px solid #e2e8f0; |
|
} |
|
.log { color: #2d3748; } |
|
.error { color: #e53e3e; } |
|
.warn { color: #d69e2e; } |
|
</style> |
|
</head> |
|
<body class="bg-gray-100"> |
|
<nav class="bg-blue-600 text-white p-4 flex justify-between items-center"> |
|
<h1 class="text-xl font-bold">Secure Script Executor</h1> |
|
<button onclick="runScript()" class="bg-green-500 hover:bg-green-600 text-white font-bold py-2 px-4 rounded transition duration-300 ease-in-out transform hover:scale-105"> |
|
Run Script |
|
</button> |
|
</nav> |
|
<div class="flex flex-1 overflow-hidden"> |
|
<div id="editor" class="w-1/2 border-r border-gray-300"></div> |
|
<div class="w-1/2 flex flex-col"> |
|
<div class="bg-gray-200 p-2 font-bold">Console Output</div> |
|
<div id="output" class="flex-1 overflow-auto bg-white p-2"></div> |
|
</div> |
|
</div> |
|
<footer class="bg-gray-200 p-2 text-center text-sm text-gray-600"> |
|
Secure Script Executor © 2023 |
|
</footer> |
|
|
|
<script> |
|
require.config({ paths: { vs: 'https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.30.1/min/vs' } }) |
|
require(['vs/editor/editor.main'], function () { |
|
window.editor = monaco.editor.create(document.getElementById('editor'), { |
|
value: 'console.log("Hello World");', |
|
language: 'javascript', |
|
theme: 'vs-dark', |
|
automaticLayout: true, |
|
minimap: { enabled: false }, |
|
}) |
|
}) |
|
|
|
let scriptWorker |
|
|
|
function createWorker() { |
|
const workerCode = ` |
|
'use strict'; |
|
// Security restrictions |
|
const restrictedGlobals = ['window', 'document', 'location', 'top', 'parent', 'frames', 'opener']; |
|
restrictedGlobals.forEach(name => { |
|
Object.defineProperty(self, name, { |
|
get: () => { |
|
throw new ReferenceError(name + ' is not defined'); |
|
}, |
|
configurable: false |
|
}); |
|
}); |
|
|
|
// Restricted access to APIs |
|
self.XMLHttpRequest = undefined; |
|
self.fetch = undefined; |
|
self.WebSocket = undefined; |
|
self.localStorage = undefined; |
|
self.sessionStorage = undefined; |
|
|
|
self.console = { |
|
log: (...args) => self.postMessage({type: 'log', message: args.join(' ')}), |
|
error: (...args) => self.postMessage({type: 'error', message: args.join(' ')}), |
|
warn: (...args) => self.postMessage({type: 'warn', message: args.join(' ')}) |
|
}; |
|
|
|
// Importing NocoDB SDK in the worker |
|
import { Api } from 'https://cdn.jsdelivr.net/npm/nocodb-sdk@0.255.2/+esm'; |
|
|
|
// Initialize NocoDB SDK in the worker |
|
const api = new Api({ |
|
baseURL: 'http://localhost:8080', |
|
axiosConfig: { |
|
headers: { |
|
'xc-auth': 'undefined', |
|
}, |
|
}, |
|
}); |
|
|
|
self.onmessage = function(event) { |
|
const script = event.data.script; |
|
try { |
|
eval(script); |
|
} catch (error) { |
|
self.console.error(error.toString()); |
|
} |
|
self.postMessage({type: 'done'}); |
|
}; |
|
` |
|
|
|
const blob = new Blob([workerCode], { type: 'application/javascript' }) |
|
return new Worker(URL.createObjectURL(blob), { type: 'module' }) |
|
} |
|
|
|
function runScript() { |
|
const script = window.editor.getValue() |
|
const output = document.getElementById('output') |
|
output.innerHTML = '' |
|
|
|
if (scriptWorker) { |
|
scriptWorker.terminate() |
|
} |
|
|
|
scriptWorker = createWorker() |
|
|
|
scriptWorker.onmessage = function (event) { |
|
const { type, message } = event.data |
|
if (type === 'done') { |
|
scriptWorker.terminate() |
|
scriptWorker = null |
|
} else { |
|
const line = document.createElement('div') |
|
line.textContent = message |
|
line.className = `console-line ${type}` |
|
output.appendChild(line) |
|
} |
|
} |
|
|
|
scriptWorker.onerror = function (error) { |
|
const line = document.createElement('div') |
|
line.textContent = `Worker error: ${error.message}` |
|
line.className = 'console-line error' |
|
output.appendChild(line) |
|
scriptWorker.terminate() |
|
scriptWorker = null |
|
} |
|
|
|
scriptWorker.postMessage({ script }) |
|
} |
|
</script> |
|
</body> |
|
</html>
|
|
|