Plain Text Obfuscation

The Code Behind the Harry Potter Theory Post

As regular readers will know, I’m spending a lot of my time at the moment writing a gripping adventure book ‘Ajax in Action’, in which our hero, a young half-ancient greek, half-dutch football player combats the forces of darkness armed only with a bottle of cleaning fluid. Oh, hang on, it’s about web programming, isn’t it? Wrong Ajax, sorry,…

Well, anyway, being along-time Harry Potter fan, I’ve been rather distracted this week, and wanted to post a few musings about the new book here on the blog. At the same time, I didn’t want to give away any plot spoilers to the casual eye. One sees on many movie and book review sites the dire warning Plot Spoilers ahead. Wel, I decided to go one better, by obfuscating my post to the casual reader, so that nothing of any note could accidentally be read. On pressing the ‘reveal’ button, the random words are replaced by their real, significant counterparts, which are also highlighted. Enough explanation, give it a try now.

So how does it work?

Well, I’ve defined a simple javascript object with it’s own cod-Latin Potter-esque name. The Scrutio operates on a paragraph, taking a list of secret words and replacing them with other words randomly drawn from a list of substitutes. (’scrute’ is to see or discern, as in the word ‘inscrutable’.) For example:

var  myScrute=new  Scrutio(’potterology’,
   [’horcrux’,'amulet’,'replacement’,
  ’soul’,'ring’,'burnt’,'pensieve’,
  ’scar’,'parselmouth’,'prophesy’,
  ’numerical index’,'hand’],
   [’bat’,'toothbrush’,'wig’,
  ’goggle-eyed  goose’,'monkey’,'dork’,
  ’goddamn  robot  camel  jockey’,'doofus’]
);

Any of the words in the second argument will be replaced by one randomly selected from the third argument list.

The first element is the id of the document element to operate upon. The main text of the blog entry is wrapped in a div tag:

<div id=’potterology’>

which the Scrutio object picks up in its constructor:

function  Scrutio(el,secrets,subs){
   this.el=document.getElementById(el);
   this.secrets=secrets;
   this.subs=subs;
   this.hiddens=new  Array();
   this.cloak();
}

It then obfuscates the contents of the paragraph by calling it’s cloak() method, which replaces the innerHTML of the target element

Scrutio.prototype.cloak=function(){
   var  origTxt=this.el.innerHTML;
   var  upper=this.subs.length-1;
   for(var  i=0;i<this.secrets.length;i++){
       var  secret=this.secrets[i];
       var  rex=new  RegExp(secret,”gi”);
       var  randx=Math.floor(Math.random()*upper);
       var  rand=this.subs[randx];
       origTxt=origTxt.replace(rex,
      ”<span  realVal=’”+this.secrets[i]
      +”‘>”+rand+”</span>”);
   }
   this.el.innerHTML=origTxt;
}

First, I use Javascript Regular Expressions to search out all instances of the ’secret’ words in the text, and then wrap them up in SPAN tags, which display a randomly-selected word from the replacements list. So, for example:

Let’s review the horcruxes first

becomes:

Let’s review the <span realVal=’horcruxes’>goggle-eyed goosees</span>

once the Scrutio has finished with it. (Note that it isn’t clever enough to deal with plurals). The text that the browser displays is now harmless, but the real, secret text is stored in the attribute ‘realVal’.

We pass through the entire innerHTML string this way, and then simply replace it. In this case, its simpler than DOM manipulation, because we’re taking what was a few lengthy text nodes and breaking them up into a mix of smaller text nodes and SPANs.

When we call Scrutio.reveal(), however, to show the hidden meaning of the text, we use DOM methods to traverse the SPAN nodes, replacing their inner content with the hidden realVal attribute that we tucked in there earlier:

Scrutio.prototype.reveal=function(){
   var  hiddens=this.el.getElementsByTagName(”span”);
   for(var  i=0;i<hiddens.length;i++){
       var  hidden=hiddens[i];
       var  realVal=
           hidden.attributes.getNamedItem(”realVal”).value;
       if  (realVal){
           hidden.innerHTML=realVal;
           hidden.className=’revealed’;
       }
   }
}

realVal is a non-standard attribute, and so is unlikely to interfere with any bona-fide SPAN tags that may be inside the targetted element.

To put it together for the blog entry, I wanted the obfuscated text to make some sort of sense, rather than just completely random words, so I create three Scrutio objects, and pass them over the blog entry in turn, transforming proper names, nouns and verbs with suitably silly substitutes.

var  scrutes=null;
window.onload=function(){
   scrutes={
       properNames:new  Scrutio(’potterology’,
           [’Nagini’,'Borgin’,'Dumbledore’,'Burke’,
              ’Tom’,'Riddle’,'Voldemort’,'September’,
              ’July’,'RAB’],
           [’bat’,'toothbrush’,'wig’,
              ’goggle-eyed  goose’,'monkey’]
       ),
       nouns:new  Scrutio(’potterology’,
           [’horcrux’,'amulet’,'replacement’,’soul’,
              ’ring’,'burnt’,'pensieve’,’scar’,
              ’parselmouth’,'prophesy’,'numerical  index’,
              ’hand’],
           [’bat’,'toothbrush’,'wig’,
              ’goggle-eyed  goose’,'monkey’,'dork’,
              ’goddamn  robot  camel  jockey’,
              ’doofus’]
       ),
       verbs:new  Scrutio(’potterology’,
           [’burnt’,'tried  to  kill’,'get  rid  of’,
              ’colecting’,’seventh’,’stole’,'born’],
           [’collywobbled’,
              ’calmly  explained  in  quiet  tomes  so  as  not  to  frighten’,
              ’whupped’,'freaked  out’,'jellified’,
              ’organically  farmed’,
              ’instantiated’,'hog-wrassled’]
       )
   };
}

function  reveal(){
   for  (i  in  scrutes){
       scrutes[i].reveal();
   }
}

So, if you want to read my real thoughts about the new Harry Potter book, hit the reveal button. If you like reading semi-random gobbledegook, then keep refreshing the page, and you’ll get served up with a fresh plate of the stuff every time!

Comments are closed.