The other day I wrote about my failure to realize that CSJS and SSJS libraries shalt not cross during my attempt to write a single library for CSJS and SSJS validation code.
Not to be out done and with some great suggestions from the wonderful Sven Hasselbach I trucked on into the next attempt.
Parameterized development
I first met this concept a few years ago. I was working on an application created by John McCann, and all the script routines for a suite of applications were sorted in notes documents. The application would look up the code it needed and then executed it as needed. This made for extremely efficient code management and the ability to make updates to code snippets without changing any “code”.
Using this design pattern I set out to create a simple document in a view with a simple JavaScript function within it – the “are the fields the same” code I used in the previous article.
I then created a Java Bean to access the notes view and get the field value.
(Yes I could have done it in SSJS – but hey this is a learning exercise as much as anything and the more Java code crosses my path (as rare as it is) the more likely I am to get familiar with it)
The bean is pretty simple and I am not going to detail the how’s and why’s and when’s of the bean – if you want to learn more about beans go see Russ Maher !!
package com.xomino.jsLookup; //load import for Domino classes import java.io.Serializable; import lotus.domino.*; import lotus.domino.local.Database; import lotus.domino.local.Document; //import for JavaServer Faces classes import javax.faces.context.FacesContext; //var marky = com.xomino.jsLookup.getValidationCode.getCode public class getValidationCode implements Serializable{ /** * */ private static final long serialVersionUID = 1L; private String theCode; public getValidationCode() { System.out.println("Starting Bean"); } // open method, this actually runs the whole App public String getCode(){ System.out.println("MARKY SSJS"); // let's add a try catch here, to grab errors near the end try { // Declare Variables, one to hold Documents/ and page through results with the other Document doc; //BEGIN DEBUG Database database = (Database) FacesContext.getCurrentInstance().getApplication() .getVariableResolver().resolveVariable(FacesContext.getCurrentInstance(), "database"); System.out.println("Database Obtained..." + database); // Find the view in question View view = database.getView("jsValidation"); System.out.println("View Obtained..." + view); //get the document doc = (Document) view.getFirstDocument(); System.out.println("Doc Obtained..." + doc); System.out.println("Loading to Xpage..."); // process the document in the View //recycle to free up mem theCode = doc.getItemValueString("js"); System.out.println("Loading to Xpage..."); doc.recycle(); } catch (Exception e) { e.printStackTrace(); System.out.println("FAIL"); } return theCode; } }
Big thanks to the Java Guru known as David Leedy for pointing out my inability to watch notesin9 videos correctly and learn how to do beans
Anyway the interesting code
The code which is stored in the notes document is just a simple JavaScript function
function checkPasswords(){ if (getComponent("Password").getSubmittedValue() != getComponent("ConfirmPassword").getSubmittedValue()){ return false; } else { return true; } }
Back in my XPage I set up two sections for code – one for SSJS and one for CSJS
The CSJS code which will run on the web page looks like this (return lookupCode.getCode())
<xp:this.resources> <xp:script clientSide="true"> <xp:this.contents> <![CDATA[${javascript: return lookupCode.getCode() }]]> </xp:this.contents> </xp:script> <xp:script src="/libValidation.js" clientSide="true"></xp:script> </xp:this.resources>
In this context the text string returned from the bean feeds directly into the contents of the script library – looks like this in the page source:
The keen eyed among you will have noticed I also included the libValidation.js function which I created in the last article which is the CSJS equivalent of the getComponent(x).getSubmittedValue()
The SSJS code is similar but with one crucial difference:
<xp:validateExpression message="Passwords Must Match"><!-- (2) --> <xp:this.expression> <![CDATA[#{javascript: var theCode = lookupCode.getCode() eval(theCode) return checkPasswords() }]]> </xp:this.expression> </xp:validateExpression>
In the SSJS I have to use “eval” to evaluate the text string which is returned from the bean. This works just fine – but eval is very very evil and I do not like this approach at all. But right now we are talking proof of concept so I am ok with it in development but would never use this in production. If the contents of the lookup document were compromised this would expose a massive hole in the security of the entire server – but that is a blog post for another day……
But the same code (lookupCode.getCode()) was used to get the code and if you notice checkPasswords() is then called in this context to test if the fields are the same.
Running this through a browser (with no CSJS yet) we can see a successful test
Then the CSJS is called from the onClick event of the submit button
<xp:button value="Submit" id="button1"> <xp:eventHandler event="onclick" submit="true" refreshMode="complete" immediate="false" save="true"> <xp:this.script> <![CDATA[ if (!checkPasswords()){ alert('passwords must match') return false } ]]> </xp:this.script> </xp:eventHandler> </xp:button>
Which looks like this
So why are we doing this again Marky?
Well the point is that CSJS alone is a better experience for the user but it is not secure – so if we can write the validation code once it can be used Client Side and Server Side with the minimum of duplication
Here is how I break the CSJS validation and bypass it – see in firefox – I can override the checkPasswords function to show a different prompt and then return true – submitting the form
Which is then validated using the SSJS – securing the application 🙂
Summary
In both cases we were able to use the checkPasswords() function which was written once and stored in the notes document So as far as I know this is the first example of using the same JavaScript code to validate a form client-side and server-side – which was the initial goal – there is some improvement to be done here though I am sure
Caveats
And there are a few…..
- For the uninitiated the eval function is evil and should not be used in production code unless you can absolutely guarantee the security of the source.
- Looking up the code in a document has an overhead and this would not scale well over many functions and many documents
- There is a lot more code written to save copying and pasting a few lines of code in this case – this did not make my life in any way shape or form easier
- There has to be a better way – and the quest has only just begun