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.
153 lines
4.7 KiB
153 lines
4.7 KiB
2 months ago
|
<!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>
|