Chrome Extension: qiandao

12 May 2014

It’s just another chrome extension I developed in last few days. it uses content_scripts of Chrome. add hooks after visiting the related pages. and get the cookie/token to post Ajax request for signup/qiandao.

the code is available at


have fun.

RSA Encrypt in Java Decrypt in Perl: keyczar rocks

23 April 2014

I have been struggling with Java RSA decrypt for a long time last night until I meet keyczar

the case is that we developed an API login which is used in a mobile App. but it’s quite insecure to pass the plain password directly to server. so it must be encrpyted in Java (Android App) then post to the Perl API.

the Java is using something like below to encrypt the pass

Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.ENCRYPT_MODE, key);
return cipher.doFinal(data);

then decrypt with

Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.DECRYPT_MODE, key);
return cipher.doFinal(cipherData);

it was a nightware to find equivalent code in Perl. RSA+EBC+PKCS1Padding, no luck with a lots of RSA modules tried.

until I found the Crypt::Keyczar. it saves a lot. the author wrote a very good file to do the Java magic. with the make running, you got a crypt-rsa and crypt-rsa-pub created. actually it’s done by KeyczarTool

create --location=crypt-rsa --purpose=crypt --asymmetric=rsa
addkey --location=crypt-rsa --status=primary
pubkey --location=crypt-rsa --destination=crypt-rsa-pub

after that, we encrypt the string in Java with code like:

import org.keyczar.*;

public class demo {
    public static void main(String[] args) throws Exception {
        KeyczarFileReader reader = new KeyczarFileReader("./crypt-rsa-pub");
        try {
            Encrypter crypter = new Encrypter(reader);
            System.out.print(crypter.encrypt("hello") + "\n");

        } catch (org.keyczar.exceptions.KeyczarException e) {

sample output:

$ export CLASSPATH="log4j.jar:gson.jar:keyczar.jar:."
$ javac
$ java demo

with Perl code like:

use Crypt::Keyczar::Crypter;
use FindBin qw/$Bin/;

my $msg = "AG1jZrM2CFMhPpNegCx5jletymyJ_9-DlkIgigYo83WCiF6tkTRpotg754LRIjy8ILMSA6Q4AMTg0YD7EgiI6S2rLE1r9lwOYIc0E84tKSWJ3tw0QEBeCLPwuotZbHB92K2Dkuylp3dsP3ESG7rD_RLQylITssyUgNmzdDOGNfmLRJE9XSvJMw3jov3unvLp0iBsK5E71ntsU56kRRXGAI37-tRxo3mmcQZkkozdrS_2p0QZ4zQ08rjCYbCMlrl_xdMlOB3fd1y-HujLHzYID0lb83gW_o5pX2gurldU0-nB2bitgH21pQuPRQz1qEy5zW1TLkOkDX66uqIowHA08R-ueWKSwkm72MbdWvdUmuA-NtkY7IJ-1wRW6HWRaSqbIo3Hz3uPp3j2FfXlNsxtnfdFgV5Hhh348oIjzTE7AGhXSfBE9KB8S0lHGFIxXEc3I43ZIt4gNBbn_nNwhLjzn5hmE_OrlGPKNsoALwLMDGzFQfh7IXfGQmKISfobr5YVv-3ZDes3et8zIEQX9X4iEKLPtX4Jw1qNxFRi715kpXjim1fkya9SjNOYAvwul_Ql16Uvzr2xM0ohip4RuEXNkuqqyLxoF8pS0ISexHiBKLbD23rJy-ZjUPxJa6zXHUW4Fx8r2VPW-03xW5QCxekG1-1zqdUVL9jHti19ObZOzsSjSZ4X9w";

my $c = Crypt::Keyczar::Crypter->new("$Bin/crypt-rsa");
print $c->decrypt(Crypt::Keyczar::Util::decode($msg)) . "\n"; ## print hello

pretty neat. many thanks to the author. have fun.

Chrome Extension: Findmjob

06 January 2014

I just got my first Chrome Extension published: Findmjob: Push Jobs to You

the basic was created with Extensionizr. it’s a very useful tool.

the source is at

it’s pure javascript. use localStorage to store the options data and transfer data from background.js to browser_action.js (need JSON parse and stringify since it only accept strings.)

Notification is quite simple as below:

var notification = window.webkitNotifications.createNotification(
    '../../icons/icon48.png',            // The image.
    v.title,                       // The title.
    v.title      // The body.
notification.onclick = function() { // Open on click + v.url + '?' + REF_STRING);
// Close after 20 secs
setTimeout(function() {
}, 20 * 1000);

and Badge Text in browserAction:

    text: data.updates.length.toString()

super simple. and works great.


Play with Go Lang

28 December 2013

Well, few days ago I was a bit free and boring, I started to read a Go book online.

you know you’ll get nothing until you start coding, so I started my hack on simplest stuff. always get stroke count of a Chinese character. at last, all the code is at

The whole progress is done by keeping Googling with how to read file with Go, how to replace string, upper case etc. but I’m quite glad that the code is working finally.

the learning is interesting and there are some good points in Go that I like.

  • you can’t import a module but do not use it (well, it’s quite troublesome that I need keep enable fmt for debugging then disable it on publish anyway)
  • import functions are started with upper case. there are traditions/rules everywhere that makes Go faster.

and something I do not like at all.

  • the type system is pretty killing since I am from a Perl background. I’m good with a type system like Python but Go is really quite trouble when there are string, bytes and rune in strconv.
  • the func return is not that … you have to use , _ (to discard the extra values) even we just need one value returned.

Well, it’s from a newbie really. I just read Go for just 3 or 4 hours. so bear with it.


Mojolicious basic_auth and DBIx::Class JSON InflateColumn::Serializer

15 December 2013

Well, it’s very good that you have something to work or hack. yesterday I was working to add some new features to my toy website

I decided to add an admin interface which will use basic_auth to protect.

Mojolicious::Plugin::BasicAuth fits the need well but it does not have a good example really. I do want to put it under a whole site or certain path instead of write it everywhere. so here is the sample code

    $r = $r->under(sub {
        my $self = shift;
        unless ( $self->basic_auth( realm => sub { return 1 if "@_" eq $config->{admin}->{auth} } ) ) {
            $self->render(text => 'Permission Denied.');
            return 0;
        return 1;

another story is for DBIx:Class InflateColumn::Serializer. well, I use DBIx::Class::Schema::Loader to create the Result which means that I can’t hack the add_columns as suggested in the POD. by checking the source, I know I can do it somehow like

use DBIx::Class::InflateColumn::Serializer::JSON;
    data => {
        inflate => DBIx::Class::InflateColumn::Serializer::JSON->get_unfreezer('data'),
        deflate => DBIx::Class::InflateColumn::Serializer::JSON->get_freezer('data'),

but that’s too damn weird and not looks good. so instead, I start writing a patch for that module so that it can be also written as:

__PACKAGE__->set_serialize_column('data', 'JSON');

the patch is here. hope that it can be merged soon.

Happy Hacking.

Updated on Dec 28th

the patch is really not useful. the Author pointed out that we can do it like below:

__PACKAGE__->add_columns('+data', { serializer_class => 'JSON' });

which is much more cleaner. Thanks

evil fake voting: shuapiao

09 December 2013

Some days ago, one of my relatives asks me if I know how to do fake votings. she has a niece who wants to be a cover girl of the calendar.

Yes. I know it’s evil. but as I know, some people are also doing that. so we have no choice somehow.

for fake voting, there are two requirements. one is you need lots of IPs (Tor is not changing IP fastly and not reliable on such task). the other is you need do some decaptcha to prove you’re not a robot (actually that’s a robot).

I won’t tell you how to rent lots of IPs. but the decaptcha service, I recommend the DeathByCaptcha, it’s quite cheap and reliable on most of the time.

I published the code at github, that you can take a look

that’s a simple Perl script, nothing magic. here are few tips:

  • use WWW::UserAgent::Random to change user agent so that it looks like not from one user.
  • use Parallel::ForkManager to do the forks. +1 every minute is not fast, you can’t beat others.

otherwise, all are simple and you’re welcome to use that as a start for a new fake voting script.

have fun.

PHP Composer, Slim Middleware RequireHTTPS

05 December 2013

Well, I’m not a fan or expert of PHP. I do not use PHP a lot and I do not know PHP well.

but when I come to write a PHP website, my first pick is always Slim. it’s very lightweight and fits my needs well.

Today I got a needs to redirect all http to https for a website written by Slim, and come out as a new VERY SIMPLE middleware Slim-Middleware-RequireHTTPS.

the usage is quite simple:

$app = new \Slim\Slim();
$app->add(new \Slim\Middleware\RequireHTTPS());

and that’s all. now all http:// will be redirected to https://

Slim uses composer inside, so I think it’s better put my package as a part of composer too. I spent few minutes to check how to write composer.json (copied from slim one) and get it into the Packagist in next few minutes.

I was amazed by the progress at some points. damn, CPAN is really very old fashion (BUT it works GOOD.).

first, submit a new package is simply type a URL. and it will read all the info from remote composer.json. dead simple.

since that’s git (or other VCS), version is simply supported with –tags. you do git tag -a X.Y and with hook in github repos settings, the version will be shown up in the website immediately. and there is always dev-master which maps to the master source code.

Packagist does not need host any files. when you go composer install/update, it fetches from the remote VCS. really smart idea.

Have fun.


30 November 2013

I just got a new CPAN module released: Email::Sender::Transport::SMTPS

it’s a replacement for Email::Sender::Transport::SMTP::TLS.

the new module uses great Net::SMTPS instead of a little messy Net::SMTP::TLS::ButMaintained

here is few examples from the POD:

my $transport = Email::Sender::Transport::SMTPS->new({
  host => '',
  ssl  => 'starttls',
  sasl_username => '',
  sasl_password => 'mypassword',
my $transport = Email::Sender::Transport::SMTPS->new(
  host => '',
  ssl  => 'starttls',
  sasl_username => '',
  sasl_password => 'api_key',
  helo => '',
my $transport = Email::Sender::Transport::SMTPS->new(
  host => '',
  ssl  => 'starttls',
  sasl_username => 'xx',
  sasl_password => 'zzz',

and you’re welcome to give it a try and provide feedback!


cpan-count nodejs module

17 November 2013

It is my first npm module. it is a nodejs module to get the modules count of one CPAN author thourgh MetaCPAN API. it is quite simple because it’s almost a copy-paste from the gem-count. but at last, it’s still very interesting and fun to learn some nodejs and try npm publish

few points:

  • it takes a while for me to find out the cpan-count api call as
  • I have also contributed a pull request to the author of
  • npm register and publish is so damn simple that I haven’t imagined. sign up on the web costs less than 1 minute. npm adduser costs less than 1 minute. npm publish . costs less than 1 minute. and MY MODULE SHOWS UP AT THE WEBSITE costs less than 1 minute.
  • I like the package.json, I know Perl has META.yml or META.json but package.json has two points I like, one is you do not define version in somewhere else (Perl need write it in the main module also. that’s why dzil is so popular because it saves time.) and it contains keywords. keywords is good for search.

Have fun.

phantomjs/casperjs and qiandao

14 November 2013

Well, qiandao here means Chinese 签到。

that action is boring that you need open browser, login, then click buttons. afterwards, you get some points that you can use it somehow as a little money.

Programming is born for saving you from daily repeating/boring works. and that’s why programming is fun.

I spent few hours to write a casperjs coffeescript today to do the action for the code is quite simple and the result is very interesting. phantomjs or casperjs is born for suck work.

you can take a look of the code at, it’s quite self-explaining. open page, click button, wait until frame shows, type user/pass, then submit. afterwards, just wait until the result shows up. and print it. meanwhile, after collect few 淘金币, it also collects one 集分宝.

crontab it as casperjs /path/to/casperjs-qiandao/ –username=fayland_lam –password=secret

and that’s it. programming does the job for you and it’s reliable.

have fun.