Closed cristiano-belloni closed 8 years ago
(please note that the plugin is submitted by users, and can have a syntax error)
Would it help, if you execute user's code in a try-catch block?
Have a look on how it's implemented in this demo and how it reacts to a syntax error in a user's provided code:
The problem is that I need to call functions on the user code / plugin . Evaluating the user block won't work.
Also, if you specify, for example function(a) { return 'a' }
in the Web Console, it returns Unexpected token (
But can you maybe call those functions in try-catch block? What would happen then?
Also, if you specify, for example function(a) { return 'a' } in the Web Console, it returns Unexpected token (
Same happens if you run that code in Chrome Dev-tools. To make it work, you can add an assignment:
b = function(a) { return 'a' }
(what I'm doing now is something like):
var log
, except
, action
, next
, parameters = {}
, staticData = {}
, initException = null
, indexedDB = null
, location = null
, navigator = null
, onerror = null
, onmessage = null
, performance = null
, self = null
, webkitIndexedDB = null
, postMessage = null
, close = null
, openDatabase = null
, openDatabaseSync = null
, webkitRequestFileSystem = null
, webkitRequestFileSystemSync = null
, webkitResolveLocalFileSystemSyncURL = null
, webkitResolveLocalFileSystemURL = null
, addEventListener = null
, dispatchEvent = null
, removeEventListener = null
, dump = null
, onoffline = null
, ononline = null
, importScripts = null
, console = null
try {
application.whenConnected(function() {
application.remote.start()
log = application.remote.log
action = application.remote.action
except = application.remote.except
next = application.remote.next
if (initException) except({type: 'init', e: stringifyException(initException)})
application.setInterface ({
callUserFunction: function(data) {
try {
onUserFunction(data)
next()
}
catch(e) {
except({type: 'runtime', e: stringifyException(e)})
}
}
})
${script}
})
}
catch(e) {
initException = e
if (except) except({type: 'init', e: stringifyException(e)})
}
var stringifyException = function(err, filter, space) {
var plainObject = {}
Object.getOwnPropertyNames(err).forEach(function(key) {
plainObject[key] = err[key]
})
return JSON.stringify(plainObject, filter, space)
}
where ${script}
contains the user code, which is like:
function onUserFunction (data) {
// do something with the data
log('did something with the data')
}
@asvd - btw, if I execute the users's code in a try catch block:
try {
${script}
}
catch (e) {
initException = e
if (except) except({type: 'init', e: stringifyException(e)}
}
It still dies with an unhandled exception
so user code is substituted into the plugin code body before creating the plugin instance?
Yep, it is.
I just can't pass it as a string and then eval it, because I need to call a callback in the user code and it needs to call callbacks in mine.
Not good, user can close the brace and break the structure of the code.
Do the following:
setUserFunction()
which will save user code as a string;callUserFunction()
invocation;next()
?).Is there any callbacks you cannot call in this way?
Should work if user's code simply calls log()
, since eval()
executes code in a current context and has everything available.
But if user-provided code is only intended to process some data, I would suggest simply to let user return the result, and then perform any respective actions on the application site. Why do you need user's code to do something additional?
See another demo concerning processing the data with user-provided code:
Because the user has to send commands to the main application based on the data. Ideally, the user would only have to write something like:
var state = {}
var initialize = function(initData) {
// This is called once
state.whatever = initData.whatever
}
var onData = function(data) {
// This is called repeatedly every time there's a new piece of data
state.whatever = state + data.whatever
log('did something with the data')
action('DO_SOMETHING', calculatedValue)
}
You can also return a string describing which respective action to perform on the application site. Or an array of them in case there might be several actions to be performed. Or a serialized object with properties containing the detailed description concerning what exactly user code wants to happen.
Your example:
var onData = function(data, oldState) {
return {
newState: oldState + data.whatever,
action : {
name: 'DO_SOMETHING',
params: [calculatedValue]
},
log : 'did something with the data'
};
}
I'll try something similar, thank you. Btw, the last demo doesn't work -- Mixed Content: The page at 'https://asvd.github.io/jailed/lib/_frame.html' was loaded over HTTPS, but requested an insecure Worker script 'blob:null/4abedc87-2d97-45be-9fc6-1c9bc351aa60'. This request has been blocked; the content must be served over HTTPS.
yep, will investigate on this. Should work if you load it by http instead of https
@asvd Can I close this or you need it open for the https issue?
We can close it. The https issue is solved on HEAD already.
I'm using
and
but, if script has a syntax error, the process dies with an unhandled exception:
Is there a way to handle this without the process dying?