{"action":"created","issue":{"url":"https://api.github.com/repos/Fordi/BlockEvil/issues/2","repository_url":"https://api.github.com/repos/Fordi/BlockEvil","labels_url":"https://api.github.com/repos/Fordi/BlockEvil/issues/2/labels{/name}","comments_url":"https://api.github.com/repos/Fordi/BlockEvil/issues/2/comments","events_url":"https://api.github.com/repos/Fordi/BlockEvil/issues/2/events","html_url":"https://github.com/Fordi/BlockEvil/issues/2","id":390906973,"node_id":"MDU6SXNzdWUzOTA5MDY5NzM=","number":2,"title":"Circumvent using (pseudo) async call","user":{"login":"LittleFinix","id":3407997,"node_id":"MDQ6VXNlcjM0MDc5OTc=","avatar_url":"https://avatars2.githubusercontent.com/u/3407997?v=4","gravatar_id":"","url":"https://api.github.com/users/LittleFinix","html_url":"https://github.com/LittleFinix","followers_url":"https://api.github.com/users/LittleFinix/followers","following_url":"https://api.github.com/users/LittleFinix/following{/other_user}","gists_url":"https://api.github.com/users/LittleFinix/gists{/gist_id}","starred_url":"https://api.github.com/users/LittleFinix/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/LittleFinix/subscriptions","organizations_url":"https://api.github.com/users/LittleFinix/orgs","repos_url":"https://api.github.com/users/LittleFinix/repos","events_url":"https://api.github.com/users/LittleFinix/events{/privacy}","received_events_url":"https://api.github.com/users/LittleFinix/received_events","type":"User","site_admin":false},"labels":[],"state":"closed","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":0,"created_at":"2018-12-13T23:39:39Z","updated_at":"2018-12-14T02:02:11Z","closed_at":"2018-12-14T02:02:11Z","author_association":"NONE","body":"The detection can be circumvented by using `setTimeout`, as the actual call-site won't show up in the stack trace:\r\n```javascript\r\nfunction queryAsync(q, cb)\r\n{\r\n  setTimeout(() => {\r\n    let el = document.querySelector(q);\r\n    cb(el);\r\n  }, 0);\r\n}\r\n\r\neval(\"queryAsync('#test', el => el.innerHTML = 'It Works!')\");\r\n```\r\njsFiddle: https://jsfiddle.net/Littlefinix/0fymc9vs/37/\r\n\r\nI'm not sure how this can be prevented... we'll probably need to replace `setTimeout` in the userscript and use its original call-site when detecting calls to any of the 'bad' functions. Something like this:\r\n```javascript\r\nconst originalSetTimeout = setTimeout;\r\nsetTimeout = function() {\r\n  const stack = getStackTrace(); // get stack trace from somewhere\r\n  const fn = arguments[0]; // first argument should be the callback\r\n  const safeFn = function() {\r\n    setContext(stack); // <-- tell noEval to check this stack trace as well\r\n    return fn.apply(this, arguments);\r\n  };\r\n  return originalSetTimeout.apply(this, [ safeFn ].concat(arguments.slice(1)));\r\n};\r\n```\r\nAlthough, I haven't tested this.\r\n\r\nIt would need to be done for `setInterval` as well, of course.\r\n\r\nSome good news is it requires at least a bit of effort to replace all the calls to `querySelector`, etc. with async ones. However, this could be made relatively easy with `Promise`s and `async`/`await`, and possibly a precompiler like Babel or TypeScript."},"comment":{"url":"https://api.github.com/repos/Fordi/BlockEvil/issues/comments/447187240","html_url":"https://github.com/Fordi/BlockEvil/issues/2#issuecomment-447187240","issue_url":"https://api.github.com/repos/Fordi/BlockEvil/issues/2","id":447187240,"node_id":"MDEyOklzc3VlQ29tbWVudDQ0NzE4NzI0MA==","user":{"login":"Fordi","id":116676,"node_id":"MDQ6VXNlcjExNjY3Ng==","avatar_url":"https://avatars3.githubusercontent.com/u/116676?v=4","gravatar_id":"","url":"https://api.github.com/users/Fordi","html_url":"https://github.com/Fordi","followers_url":"https://api.github.com/users/Fordi/followers","following_url":"https://api.github.com/users/Fordi/following{/other_user}","gists_url":"https://api.github.com/users/Fordi/gists{/gist_id}","starred_url":"https://api.github.com/users/Fordi/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Fordi/subscriptions","organizations_url":"https://api.github.com/users/Fordi/orgs","repos_url":"https://api.github.com/users/Fordi/repos","events_url":"https://api.github.com/users/Fordi/events{/privacy}","received_events_url":"https://api.github.com/users/Fordi/received_events","type":"User","site_admin":false},"created_at":"2018-12-14T02:02:11Z","updated_at":"2018-12-14T02:02:11Z","author_association":"OWNER","body":"Solved it by making setInterval / setTimeout / requestAnimationFrame wrap the passed function in a function named `eval` if an eval stack is detected at the time the async'r is called."}}
{"actor":{"display_login":"Fordi"}}