8

Here is a simple page:

<!DOCTYPE HTML>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Test page</title>
    <script type="text/javascript">
        function foo (num) {
            alert(num);
        }
    </script>
</head>
<body>
    Hello World
    <script type="text/javascript">
        foo(2);
    </script>
</body>
</html>  

I'd like to write a Chrome extension to prevent the execute of the bottom script(foo(2)).
I tried to write a content script which removes the last script tag with:

document.body.removeChild(document.body.lastChild);  

but it does not work.

I think this may be because the content script runs after the last script line has executed. then I tried to set the run_at to document_start or document_end, but none of them work for me..

wong2
  • 34,358
  • 48
  • 134
  • 179
  • Have you tried overriding foo? `document.write('');` inside the content script at `document_start`? Edit: Nevermind, document_start is before any other scripts exec – Kai Feb 19 '12 at 09:04
  • @Wong2 My answer below will work now, as the bug has been **[marked as fixed](http://code.google.com/p/chromium/issues/detail?id=115452#hc4)**. – Rob W Mar 14 '12 at 16:03

2 Answers2

5

I faced the same problem during development of the Don't track me Google User script / extension.

#Important note The window object in a Chrome contentscript cannot be accessed directly, in any way.
I have tested many methods, and the only reliable method is injecting the code through a dynamically created script tag. Have a look at this answer, or my extension's source code for more information.

I solved it by using Object.defineProperty. With this method, you can define a property, and specify information about the getter, setter and property descriptors. In your case:

Object.defineProperty(window, 'foo', {
    value: function(){/*This function cannot be overridden*/}
});

Or, if you want to capture the variable, and use it later:

(function() {
    var originalFoo = function(){/*Default*/};
    Object.defineProperty(window, 'foo', {
        get: function(){
            if (confirm('function logic')) return function(){/*dummy*/};
            else return originalFoo;
        },
        set: function(fn){originalFoo = fn;}
    });
})();

##Bug in Chrome 17 [Bug #115452](http://code.google.com/p/chromium/issues/detail?id=115452) [Fixed!](http://code.google.com/p/chromium/issues/detail?id=115452#hc4) In Chrome 17, using V8 3.7.12.12 (but not in Chrome 16, using V8 3.6.6.19), **Function declarations override the property descriptors**.
See http://jsfiddle.net/bHUag/
Note that this bug *seems* to not be applied when the function declaration and property descriptor method are in the same block. This is false, though. The effect is not visible, because function declarations are always evaluated before the code block. So, `function foo(){}` is evaluated first, then the rest of the code.
<script>
Object.defineProperty(window, 'foo', {value: function(){return 5;} });
</script><script>
function foo(){return 1};
alert(foo()); // Shows 5 in all browsers except for Chrome v17
</script>
Zsolt Meszaros
  • 21,961
  • 19
  • 54
  • 57
Rob W
  • 341,306
  • 83
  • 791
  • 678
  • I tried something similar to this earlier and it didnt work... `Object.defineProperty (window,"foo",{ value : function(){}, writable: false });` If you try and change the value to say 0, it wont change, but if you try and redeclare it as a function it will? Now tried your versions and the same prob. Tested on http://paez.kodingen.com/blockme.html (try and block foo()) with Chrome 19.0.1041.0 and yes Im injecting the code into the page. – PAEz Feb 20 '12 at 08:28
  • @PAEz Did you add `"run_at": "document_start",` to the `content_scripts` section of your `manifest.json` file? ([link to developer's documentation](http://code.google.com/chrome/extensions/content_scripts.html)). – Rob W Feb 20 '12 at 09:48
  • Yep. I just tried something in the console that I thought was interesting.... put `Object.defineProperty (window,"food",{ value : function(){}, writable: false });` in then `food` (result, expected), then `food=3` then `food` (result, expected), now `food=function(){alert('bleh')};`, `food` (result, expected)..but now for the fun `function food(){alert('bleh')};`, `food`...result, food has changed. – PAEz Feb 20 '12 at 10:43
  • @PAEz We have discovered a bug in Chrome's JavaScript implementation (not necessary v8, because the bug doesn't occur in Node.js's REPL). – Rob W Feb 20 '12 at 15:00
  • You can report the bug for this one ;) Im sure your wording would be better than mine, Im no good at technical things. And if you do, please post it here so we can star it. Also overrides const foo=function(){} that worked in the past (apparently http://stackoverflow.com/questions/9246772/chrome-extension-run-at-doc-start/9258481). – PAEz Feb 20 '12 at 16:49
  • File a bug at http://new.crbug.com/ if you don't mind. Post the bug ID here and I'll make sure it falls into the correct queue. – Mike West Feb 20 '12 at 17:54
0

I think it's worth mentioning the relatively new metadata item // @unwrap which takes the userscript out of the sandbox that userscripts normally run in. More info:

https://wiki.greasespot.net/Metadata_Block#.40unwrap

Tom Burris
  • 380
  • 2
  • 19