多维表格
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

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 &copy; 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>