Prototypal inheritance of SSJS across the whole server in XPages

A friend asked me the other day how would I determine where a string lay within a JavaScript Array. I of course answered – “it depends! If you are using newer IE or a non-crappy implementation of the JavaScript engine then use Array.indexOf – it has been around for years…..”

var arr = ["simon", "marky", "david"]
return arr.indexOf("marky") // 1.0

Well – turns out the friend was asking about SSJS in XPages and it turns out that apparently XPages has one of those crappy JavaScript engines of which I spoke and Array.indexOf is not supported (facepalm). (*really??*)

<xp:text escape="true" id="computedField1">
	<xp:this.value><![CDATA[#{javascript:
		var arr = ["simon", "marky", "david"]
		return arr.indexOf("marky")
	}]]></xp:this.value>
</xp:text>

arr1

Polyfill

OK so there is a simple polyfill for the indexOf, which has also been around for years as this article written in 2007 demonstrates…..

if(!Array.indexOf){
    Array.prototype.indexOf = function(obj){
        for(var i=0; i<this.length; i++){
            if(this[i]==obj){
                return i;
            }
        }
        return -1;
    }
}

And if we add this to our XPages sample code we get the answer we are expecting….

<xp:text escape="true" id="computedField1">
	<xp:this.value><![CDATA[#{javascript:
		if(!Array.indexOf){
		    Array.prototype.indexOf = function(obj){
		        for(var i=0; i<this.length; i++){
		            if(this[i]==obj){
		                return i;
		            }
		        }
		        return -1;
		    }
		}

		var arr = ["simon", "marky", "david"]
		return arr.indexOf("marky")
	}]]></xp:this.value>
</xp:text>

arr2

Yay !

Prototyping in JavaScript

For a better explanation that I can give, check out this StackOverflow answer on what is prototyping – suffice to say that every JavaScript object has a prototype property and this is the basis for prototypal (as opposed to class based) inheritance in the JavaScript language.

What we did in the polyfill above is: we simply said if Array.indexOf method does not exist, then we created one.

So what does this have to do with XPages?

In JavaScript when you prototype a function, the scope is on the page you are looking at. As soon as you leave the page the prototype is gone. In XPages it seems to be a little broader than that…..

I (unintentionally) discovered that once you prototype the Array.indexOf, not only does it become available on the same page, it is permanently on the same page. You run the prototype code once….then take it away, and it still works. The scope would appear to be at the application level…..

Well so then I asked some people who are way smarter than I and Nathan Freeman pointed me to his article about XPages Performance Pro Tips and told me he expected that the prototype would actually be at the server level and he was right….

I included the URL of the test database in the picture above to demonstrate that when I move the simple code to another database – it still works (after the prototype code has been run once)

rr3

And just to be sure – in another browser !!

arr4

Once the Array.prototype.indexOf was created, it became available in all applications on the server, instantly.

Killing the prototype

  • Restarting HTTP *DOES NOT* stop this.
  • Killing all browsers and starting again does not stop this

As far as I can tell you have modified the way the SSJS works on the server until you kill it. So far I have run a test over 24 hours later and it is still working……

This is COOL right?

Well for one it means that you can seriously enhance all your JavaScript on the server in ways which make custom libraries look like a waste of time. We could truly add all the corporate libraries to SSJS once when the server loads and they would always be available to all developers at all times.

arr5

And the even more awesome (depending on perspective…..)

arr7

Well yeah but…….

You can also serious screw up perfectly good code across the server

arr6

Conclusion

Prototypal inheritance is at the root of JavaScript programming language and is very powerful. What we can see here though is that we are able to affect code across the entire server with a few lines of code. This is *very* cool and *very scary* at the same time.

So with this knowledge comes great responsibility – use it at your own risk and make sure you have very good server side code review if you are going to go down this path.

11 thoughts on “Prototypal inheritance of SSJS across the whole server in XPages

  1. First, great post! I need to look into this a bit more but this smacks of serious security issues. If I can overload/overwrite server functions and drop my nsf on another server I could have access to all sorts of things, right?

      • Indeed – once you’re running arbitrary code on a server, most bets are off. This is just one of the funner ways to do it.

        I suppose there’s technically a privilege-escalation problem here. If you override a common method in a prototype with a function that uses sessionAsSigner, it’ll end up executing with the permissions of the signer of some other app, which could have more rights than you. That’s probably a pretty uncommon case in real-life Domino dev, though.

  2. This is one of the evil things with SSJS, and it is why I always tell all my customers not to use SSJS in their prodcution environment. It is nice to have a easy non-transistent serverscope variable, but you have the problem that you cannot trust your own code anymore. A third party app could have changed/infected a function used by my application, and then do something while a user of my application clicks on a SSJS button. This is the worst case, I know, but just overwriting existing functionality could damage my application.
    While you can load code runtime (f.e. with eval) it is impossible to check existing applications for a overwriting code segment.

    Especially now, since you have bloggen about this “Feature” it will sooner or later happen that a “brilliant” dev uses it in his app.

    • I think a more measured approach would be that if you are concerned about 3rd party apps then don’t use them.

      Like I said to Rich above, if you have the rights to run code on a server then you have to be a trusted individual. There are many ways to break your own server and having developer access to the server allows you to do all sorts of bad things. If you can’t trust our own developers that is a different issue.

      Using Java you can blow up the server with bad coding practices, so I do not agree with the “don’t use SSJS” sentiment any more than “don’t let bad developers on your server”.

      I am a firm believer in knowledge protects you rather than knowledge hurts you.

      • It is not that easy, because as a freelancer who develops applications for my customers, I have no decision about the other applications used on the server. The problem is, that code of another application can directly affect my application. Just imagine what will happen if another developer is overwriting the String.charAt() in his application, because of -INSERT REASON HERE-. If I am using this function, it could affect the stability of my application. And it is impossible to find the origin when my customers sends me a bug report. After I have found the SJSS-prototyping problem a while ago, it was clear to me to drop any SSJS development if possible. It was the last “coffin nail” for using SSJS in my eyes.

        Btw. Most time I have no access rights to the productive environment of my customers. In over 99% percent there is a strict move-to-production process, with code reviews etc.

  3. We’ll yes, if you have that much access then of course you can run what you want. I was thinking more along the lines of Sven’s situation.
    If I told an admin ‘hey, to run this app you’ll need to replace your JVM with my custom one’ – erm… Good luck with that – alarm bells should ring😉 which is effectively what is occurring here.
    I think Devs should use whatever languages they want/need but the system (Domino in this case) should have tighter control than this. Code analysis tools can easily flag up things like the nefarious eval() but this type of thing would throw too many false positives – I guess checking for ‘prototype’ would be the closest thing and then having a manual review.
    As I said, I want to do some testing on this (not on a prod server :-)) but it seems that this would have been better implemented at application level rather than Server level. Just my 2c worth.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s