mirror of
https://github.com/open-webui/open-webui
synced 2025-06-26 18:26:48 +00:00
refac/security: python code format endpoint
This commit is contained in:
parent
87e5aee106
commit
4fe45d4430
@ -33,7 +33,7 @@ class CodeForm(BaseModel):
|
|||||||
|
|
||||||
|
|
||||||
@router.post("/code/format")
|
@router.post("/code/format")
|
||||||
async def format_code(form_data: CodeForm, user=Depends(get_verified_user)):
|
async def format_code(form_data: CodeForm, user=Depends(get_admin_user)):
|
||||||
try:
|
try:
|
||||||
formatted_code = black.format_str(form_data.code, mode=black.Mode())
|
formatted_code = black.format_str(form_data.code, mode=black.Mode())
|
||||||
return {"code": formatted_code}
|
return {"code": formatted_code}
|
||||||
|
@ -12,7 +12,8 @@ const packages = [
|
|||||||
'sympy',
|
'sympy',
|
||||||
'tiktoken',
|
'tiktoken',
|
||||||
'seaborn',
|
'seaborn',
|
||||||
'pytz'
|
'pytz',
|
||||||
|
'black'
|
||||||
];
|
];
|
||||||
|
|
||||||
import { loadPyodide } from 'pyodide';
|
import { loadPyodide } from 'pyodide';
|
||||||
|
@ -13,8 +13,11 @@
|
|||||||
|
|
||||||
import { onMount, createEventDispatcher, getContext, tick } from 'svelte';
|
import { onMount, createEventDispatcher, getContext, tick } from 'svelte';
|
||||||
|
|
||||||
|
import PyodideWorker from '$lib/workers/pyodide.worker?worker';
|
||||||
|
|
||||||
import { formatPythonCode } from '$lib/apis/utils';
|
import { formatPythonCode } from '$lib/apis/utils';
|
||||||
import { toast } from 'svelte-sonner';
|
import { toast } from 'svelte-sonner';
|
||||||
|
import { user } from '$lib/stores';
|
||||||
|
|
||||||
const dispatch = createEventDispatcher();
|
const dispatch = createEventDispatcher();
|
||||||
const i18n = getContext('i18n');
|
const i18n = getContext('i18n');
|
||||||
@ -113,13 +116,82 @@
|
|||||||
return await language?.load();
|
return await language?.load();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let pyodideWorkerInstance = null;
|
||||||
|
|
||||||
|
const getPyodideWorker = () => {
|
||||||
|
if (!pyodideWorkerInstance) {
|
||||||
|
pyodideWorkerInstance = new PyodideWorker(); // Your worker constructor
|
||||||
|
}
|
||||||
|
return pyodideWorkerInstance;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Generate unique IDs for requests
|
||||||
|
let _formatReqId = 0;
|
||||||
|
|
||||||
|
const formatPythonCodePyodide = (code) => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const id = `format-${++_formatReqId}`;
|
||||||
|
let timeout;
|
||||||
|
const worker = getPyodideWorker();
|
||||||
|
|
||||||
|
const script = `
|
||||||
|
import black
|
||||||
|
print(black.format_str("""${code.replace(/\\/g, '\\\\').replace(/`/g, '\\`').replace(/"/g, '\\"')}""", mode=black.Mode()))
|
||||||
|
`;
|
||||||
|
|
||||||
|
const packages = ['black'];
|
||||||
|
|
||||||
|
function handleMessage(event) {
|
||||||
|
const { id: eventId, stdout, stderr } = event.data;
|
||||||
|
if (eventId !== id) return; // Only handle our message
|
||||||
|
clearTimeout(timeout);
|
||||||
|
worker.removeEventListener('message', handleMessage);
|
||||||
|
worker.removeEventListener('error', handleError);
|
||||||
|
|
||||||
|
if (stderr) {
|
||||||
|
reject(stderr);
|
||||||
|
} else {
|
||||||
|
const formatted = stdout && typeof stdout === 'string' ? stdout.trim() : '';
|
||||||
|
resolve({ code: formatted });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleError(event) {
|
||||||
|
clearTimeout(timeout);
|
||||||
|
worker.removeEventListener('message', handleMessage);
|
||||||
|
worker.removeEventListener('error', handleError);
|
||||||
|
reject(event.message || 'Pyodide worker error');
|
||||||
|
}
|
||||||
|
|
||||||
|
worker.addEventListener('message', handleMessage);
|
||||||
|
worker.addEventListener('error', handleError);
|
||||||
|
|
||||||
|
// Send to worker
|
||||||
|
worker.postMessage({ id, code: script, packages });
|
||||||
|
|
||||||
|
// Timeout
|
||||||
|
timeout = setTimeout(() => {
|
||||||
|
worker.removeEventListener('message', handleMessage);
|
||||||
|
worker.removeEventListener('error', handleError);
|
||||||
|
try {
|
||||||
|
worker.terminate();
|
||||||
|
} catch {}
|
||||||
|
pyodideWorkerInstance = null;
|
||||||
|
reject('Execution Time Limit Exceeded');
|
||||||
|
}, 60000);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
export const formatPythonCodeHandler = async () => {
|
export const formatPythonCodeHandler = async () => {
|
||||||
if (codeEditor) {
|
if (codeEditor) {
|
||||||
const res = await formatPythonCode(localStorage.token, _value).catch((error) => {
|
const res = await (
|
||||||
|
$user?.role === 'admin'
|
||||||
|
? formatPythonCode(localStorage.token, _value)
|
||||||
|
: formatPythonCodePyodide(_value)
|
||||||
|
).catch((error) => {
|
||||||
toast.error(`${error}`);
|
toast.error(`${error}`);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
if (res && res.code) {
|
if (res && res.code) {
|
||||||
const formattedCode = res.code;
|
const formattedCode = res.code;
|
||||||
codeEditor.dispatch({
|
codeEditor.dispatch({
|
||||||
|
Loading…
Reference in New Issue
Block a user