Issue
As explained here, I've used function constructor in order to avoid evil method. Didn't find a better way to inject the context:
function evalContext(context: Record<string, unknown>) {
const injectContext = Object.keys(context).reduce(
(acc, key) => `${acc}${key}=context.${key};`,
'',
);
return Function(`context`, `${injectContext}${script}`)(context);
}
const handleKeyDown: KeyboardEventHandler<HTMLTextAreaElement> = useEventCallback((event) => {
if (event.code === 'KeyE' && event.metaKey) {
evalContext({ a: 3, b: 4, log: console.log });
event.preventDefault();
event.stopPropagation();
}
});
Still, it works (no need to prefix the keys with this). The main question is would it be possible to "hide" browser objects (window, document, location, ...). From the aspect of security, the script used in the function constructor will be visible only to the owner of the account. Hope this is safe.
As a side question, tried to use a few code editor libs: monaco-editor, react-simple-code-editor, @uiw/react-textarea-code-editor, @patternfly/react-code-editor... Haven't managed to run any of them (broken this, broken that in the next.js context). Please could you suggest any of them that works fine in the most recent version on NJS?
Update:
Based on @kelly's suggestion:
function evalContext(context: Record<string, unknown>) {
const injectContext = Object.keys(context).reduce(
(acc, key) => `${acc}${key}=context.${key};`,
'',
);
return Function(
'context',
'window',
'document',
'location',
'localStorage',
'navigation',
'fetch',
'frames',
'history',
`(function () {${injectContext}${script}}).call({})`,
)(context);
}
Solution
I suppose you could just "override" the global names by adding parameters:
return Function(`context`, `window`, `globalThis`, `document`, ..., `${injectContext}${script}`)(context, undefined, undefined, undefined, ...);
Similar to this example:
function overridden(window) {
window.open("site");
}
overridden(undefined); // error will occur
Since not providing the parameter is basically the same as providing undefined, you can omit the undefined entirely:
return Function(`context`, `window`, `globalThis`, `document`, ..., `${injectContext}${script}`)(context);
Keep in mind that there are a lot of things in the global namespace.
Object.keys(window) will give you an idea...
Answered By - caTS


0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.