La Vita è Bella

Thursday, November 24, 2016


This is an open source project I started 5 years ago, and just "finished" recently.

Back in 2011, my friend tension7 released a Chrome extension called One Password. It has a simple idea: using HMAC-MD5 to generate unique passwords for different sites.

I thought that was a good idea, and started to use it myself. (The idea is actually called "deterministic password manager/generator", and there are some discussions about it recently. I agree that it doesn't make your password stronger, but it do works better in certain cases. I use it on some sites myself, but not all of them.) I wrote a python version of it so that when I can use it easily while I'm not on Chrome.

And I also started writing an Android app for it. This is the Android app.

The sad thing is just that there're too many distractions in life, so I never found time to finish it. I made it "usable" at some point of 2013 or 2014, put it on my phone, and just put it away.

But I suddenly had some time due to various reasons recently, so I finally finished it. By "finish it" I mean I did a 1.0 release and listed it on Google Play, 5 years after I started the project.

There are still some TODOs, for example I would like to add the feature to save the master password with fingerprint, but I didn't figure out a good way to design the UI to make it work. But it's mostly feature complete, with highlights:

On the technical side, I chose Buck as the building system for this project, because it was the build system used by my day job project, and it worked great. I also tried to move it from Buck to Bazel, but Android's incompatible with Java8 is causing a lot of problems. I will probably switch to Bazel after that is sorted out.

Anyway, if you found the idea of deterministic password generator appealing to you (at least in certain cases), please give it a try. I hope you enjoy it.

tags: , , ,

21:54:18 by fishy - opensource - Permanent Link

no comments yet - no trackbacks yet - karma: -2 [+/-]

Friday, December 11, 2015

Let's Encrypt!

Thanks to Let's Encrypt, this blog is now serving via https (and https only):

Screenshot of https certificate

In the process of enabling https, I also switched my host from Dreamhost to Google Cloud, and switched to nginx as httpd. (And Dreamhost announced Let's Encrypt support after I made the switch)

The only problem with Let's Encrypt is that the certificate is only valid for 90 days (ok no support of wildcard domain might also be a problem, but I don't feel it), which means I need to renew my certificates often. Luckily that can be done via a monthly (or bi-monthly) cron job.

This is the code snippet of my nginx configuration to make both https only and Let's Encrypt ACME verification work:

server {
        listen 80;
        listen [::]:80;


        location /.well-known/acme-challenge/ {
                alias /var/www/challenges/.well-known/acme-challenge/;
                try_files $uri =404;

        location / {
                return 301 https://$host$request_uri;

And this is the script to be put into crontab (I use the official client from Debian experimental):

/usr/bin/letsencrypt certonly --renew-by-default --webroot -w /var/www/challenges -d -d -d

That's it! Please consider donating to Let's Encrypt!

tags: , , , ,

23:26:36 by fishy - linux - Permanent Link

no comments yet - no trackbacks yet - karma: 9 [+/-]

Thursday, November 10, 2011

I tried to migrate from Aperture to Lightroom but rolled back

UPDATE: with Aperture 4 Beta released with geotag support, I finally migrated to Lightroom (4), and will buy it on Day 1!

I bought my first "RAW camera" at the end of 2009, and found that iPhoto is not enough for me. So I purchased Apple Aperture 3 at February 2010, almost immediately after it's released. One reason is that I was used to iPhoto and Aperture carried on most of the things, another reason is that Adobe Photoshop Lightroom 3 is on its way but still about half year away at that time.

I'm just an amateur photographer, snap some photos for my life record and show them on Flickr. I don't sell my photos for life (but will be glad if you're interested :P). So I don't need something extremely professional to process my photos. Generally I just use the "Auto Enhance" in Aperture to tune my photos, and custom white balance sometimes. I rarely use other tunes in Aperture. So generally I'm happy with Aperture.

But there're still something drive me crazy, like the slowness, and some bugs. I was upset about some of the bugs, so serious considered to migrate to Lightroom. I downloaded Lightroom trial and borrowed a USB HD to move my photos (~80GB) from Aperture library into Lightroom, and seriously used it for a couple of days.

But, there's always a "but", Lightroom is not perfect and there're still something I don't like. And I found out that the "bugs" drive me crazy is actually something wrong with my Mac, not Aperture. So I finally decided to cool down and not to invest another $150 on Lightroom, and keep on Aperture, at least for now.

Here're some of my comparisons.

What Lightroom did great?

First I'd like to talk about some of Lightroom's advantages, and of course, they are Aperture's disadvantages:

What Aperture did great?

There're still something Aperture did better than Lightroom. Most of them are just useless to professionals, but they are good for amateurs:

Between speed and geotag, I chose geotag. But I do hope Apple can match Lightroom's speed, or Adobe can add native geotag support to Lightroom. I just hate Aperture's slowness, and Lightroom's lack of geotag support. For now, I can only suffer the slow.

tags: , , ,

15:01:42 by fishy - mac - Permanent Link

no comments yet - no trackbacks yet - karma: 146 [+/-]

Saturday, January 22, 2011

Fix epubs

The wonderful epub reader for Android, Aldiko, released a major update recently. Besides some great new features/improvements, it also broke something: all Chinese characters in Pro Git Chinese version can't be displayed. But it didn't simply broke Chinese epubs at all. My other Chinese epubs are just fine.

I contacted Aldiko for help, they just replied claiming that I need to embed Chinese font into epub for them to display, and Adobe Digital Edition have the same problem. I tried my epubs with Adobe Digital Edition and it's really the same. But after I looked into my good and broken epubs (they are simply zip archives with metadata, html, css and pictures inside), I can't find embedded Chinese font (in the good ones, of course) at all.

Instead, I found something else interesting: all my good epubs have an "xml:lang" parameter set to "zh-CN" in every html tag, and the broken one didn't.

So I add that parameter to every html file in progit-zh.epub, and repack the file, now it works (in both Aldiko and Adobe Digital Edition)!

To simplify this work, I wrote a python script to do that automatically. It will unpack the epub file into a temp directory, add "xml:lang" parameter to every html file if didn't present, and then pack the epub back again. It will also output the replaced lines into stderr, like:

<html xmlns="">
<html xmlns="" xml:lang="zh-CN">

Get it from my script repo on GitHub, and change the LANG constant if needed.

If you have other ideas about it, please let me know.

tags: , , ,

21:28:08 by fishy - i18n.zh - Permanent Link

no comments yet - no trackbacks yet - karma: 22 [+/-]

Monday, January 10, 2011

Purge Strikes Back to Android!

A Little Bit History

Back in 2005, after graduation from college, I got my first job at TrendMicro. After I got paid for enough money, I went to the store and brought a Palm Treo 650 home. That's the dream phone of that time. It have good hardware spec and more important, PalmOS.

My Treo 650 was broken at 2007. The radio module is died. So I can't use it as a phone, but can still use it as a PDA. I've made a nature choice: bought a Treo 680 to replace it. The reason is quite simple: it have PalmOS inside.

But the bad thing is I lost my Treo 680 at the end of 2007, left it on a table of a restaurant and never got it back again. This time I didn't buy Centro (but I recommended it to my then roommate :P). I decided to try something new. So I bought a Symbian phone (Nokia E51), Symbian looks like something comes from Stone Age compare to Palm OS. Then I bought a Windows Mobile phone (Sony Ericsson Xperia X1), but realized later that I do hate Windows Mobile. I bought a Samsung Galaxy (not to be confused with Samsung Galaxy S) at 2009, as I thought Android was mature enough to use. And I do love Android! But the lack of support and upgrade from Samsung makes me unhappy.

Finally, Google released Nexus One and I ordered one at the first time. This becomes the first phone after Treo 680 that I'm still happy after using it for half year, and I'm still happy with it while it's nearly a whole year already for now.


But there's still something I missed from Palm, like "Purge":


(I dug out my broken Treo 650 today, blow away the dusts, insert the battery, and it still works! so comes this photo.)

"Purge" is a simple feature to do the cleanup work: delete all old messages older than N days. Yes Android is much more powerful compare to Palm OS in the old days, and it can keep "almost everything" (actually for SMS, it will keep only the recent 200 messages per conversation and automatically delete old ones by default). But I don't like to keep too many meaningless "everything", I prefer the old Palm way.

So I took the last weekend to make Purge Strikes Back!

Purge Strikes Back!


Something I must mention is that for SMS deletion, I used some undocumented API. What did this mean? It means that this app may or may NOT work for you. It may or may NOT work as you expected. It may DELETE ALL YOUR SMS even you didn't mean to. It works on my Nexus One with Froyo and system Message app, it may not work with other phones, Android versions or Message apps. And it may break anytime even it works fine for you now. You take it totally on your own risk.

The call log deletion is implemented with system API, which should works fine, but I took no responsibility for your unexpected data loss, either.

So you'd better BACKUP YOUR SMS BEFORE TRYING IT. Personally I'm using SMS Backup + to do this for me and it works fine (it also backups call logs, too). There may be better ones but this is a choice you can consider.


How to Get It

Download it from its GitHub repo. It's free. You can also get the source code there, licensed under GPL v3.

I'll publish it to the Android Market in the coming days.

What to Expect in the Future


Some UI elements took from another awesome open source Android app Financisto, which is licensed under GPL v2.


project homepage

tags: , , ,

23:53:07 by fishy - opensource - Permanent Link

no comments yet - no trackbacks yet - karma: 34 [+/-]

Wednesday, October 13, 2010

Say "Goodbye and Thank you" to POPFile

POPFile is an awesome mail classifier works as a local POP3 proxy. It's written in Perl and use a web UI so it can run on any platform.

I started using it back from about 2004. First I use it to filter spams, later to filter work mail, personal mail and important mails apart. Time moves on, as I stop using POP3 on Gmail, the main job for POPFile became to picking not-so-important script generated reports from other work mails (combined with Thunderbird filter based on "X-Text-Classification" header).

As I also use Gmail for work mail now at Google, I have only a few POP3 accounts that rarely get some non-spam mails. So it's finally the time to say goodbye to POPFile. As a record, here's the final statistics for my POPFile history, since Jul. 2007, the last time I reset the stats:

Messages classified: 135,631,
Classification errors: 910,
Accuracy: 99.32%

That's very impressive result. Thank you POPFile for so many years of service. If you are still using POP3 account, you should try it right now!

BTW, I always hope Gmail can auto label my mails, just like POPFile. Finally we got priority inbox, but that's not enough for me.

tags: , , ,

22:54:43 by fishy - opensource - Permanent Link

no comments yet - no trackbacks yet - karma: 29 [+/-]

Tuesday, March 02, 2010

More tips about my projtags.vim

I wrote a vim plugin named projtags, initially for loading tags file for projects. But as I can "set tags+=tags;" in my vimrc, it's not that useful on the tags file way. I expanded its feature to support commands for per projects, and this is much more useful :P Here are some examples:

Case 1: different coding styles

I did some squid hacking before. My coding style is as below:

set cindent
set autoindent
set smartindent
set tabstop=8
set softtabstop=8
set shiftwidth=8
set noexpandtab
set smarttab
set cino=:0,g0,t0

But squid coding style is different. They use 4 for shiftwidth. As hacking some project, you should always follow the original coding style. But add vim modeline into every file is also unacceptable. So I use projtags.vim to do this job:

let g:ProjTags += [["~/work/squid", ":set sw=4"]]

So that every time I'm editing a file within squid, vim will use 4 instead of 8 for shiftwidth, now I'm happy with both my own codes and squid codes.

Case 2: use ant as makeprg for java projects

First, I use a autocmd to set ant as makeprg for java files:

autocmd BufNewFile,BufRead *.java :setlocal makeprg=ant\ -s\ build.xml

It works well for java files. But as I did some Android development these days, I also have lots of xml files to edit (and then make to see the result). I can't use such a autocmd for xml's, as not all xml's are in a java project. So projtags.vim is again the answer:

let g:ProjTags += [["~/work/pmats", ":set mp=ant\\ -s\\ build.xml"]]

So I can always use ":make" for ant under my Android project now, no matter it's .java or .xml.

My vimrc segment for tags and projtags

set tags+=/usr/local/include/tags
set tags+=/usr/include/tags
set tags+=/opt/local/include/tags
set tags+=tags;

let g:ProjTags = []
let g:ProjTags += [["~/work/squid", ":set sw=4"]]
let g:ProjTags += [["~/work/pmats", ":set mp=ant\\ -s\\ build.xml"]]

Patches for projtags.vim (e.g. Windows support, I haven't tested it but I guess it won't work under Windows now) are welcomed :D You can get the code from the git repo for my various scripts.

tags: , , ,

19:58:01 by fishy - dev - Permanent Link

6 comments - no trackbacks yet - karma: 29 [+/-]

Sunday, October 11, 2009

Modified Pwitter to support 3rd party twitter API

Pwitter is a good open source Twitter client for Mac. I just added supporting for 3rd party twitter API to it to make it better.

You can get my patch here or my build here.

There's no GUI for setting 3rd party twitter API address. Instead, you need to change the configuration file. You can use either Property List Editor or the Terminal "defaults write" way. Here's an example:

$ defaults write com.aki.Pwitter twitter_https -bool NO
$ defaults write com.aki.Pwitter twitter_base ""

To restore the default settings ( https and "" ), you can just delete the custom settings by:

$ defaults delete com.aki.Pwitter twitter_https
$ defaults delete com.aki.Pwitter twitter_base

It's useful when you can't connect to directly, like me in China. Enjoy it.

tags: , , , ,

22:06:13 by fishy - opensource - Permanent Link

no comments yet - no trackbacks yet - karma: 55 [+/-]

Tuesday, April 28, 2009

A script for Columbus V-900 GPS

Columbus V-900 is so far the GPS that best fit my requirements: it can log, it can take waypoints while logging, and it (can) have a big storage for logging (via TF card). I got one from WC, a friend to give it a try.

It log GPS tracks to CSV format, WC wrote a script to convert it to the GPX format, but without waypoints. So I rewrote a Python script (as I'm not so familiar with perl), to add the waypoints to the GPX file.

Get the script here, it will use the voice record filename as the name of the waypoint if available, or otherwise just "Waypoint #N". You may want to edit the converted GPX file to rename the waypoints.

tags: , , , , ,

11:47:57 by fishy - dev - Permanent Link

no comments yet - 1 trackback - karma: 61 [+/-]

Thursday, April 02, 2009

Python script to convert from IP range to IP mask

This script will convert a line contains start and end IP separated by space like:

Into IP mask format (with comment) like:

# -

The script is:

 1 #!/usr/bin/env python
 3 import sys
 4 import re
 6 def ip2int(ip) :
 7         ret = 0
 8         match = re.match("(\d*)\.(\d*)\.(\d*)\.(\d*)", ip)
 9         if not match : return 0
10         for i in xrange(4) : ret = (ret << 8) + int(match.groups()[i])
11         return ret
13 def int2ip(ipnum) :
14         ip1 = ipnum >> 24
15         ip2 = ipnum >> 16 & 0xFF
16         ip3 = ipnum >> 8 & 0xFF
17         ip4 = ipnum & 0xFF
18         return "%d.%d.%d.%d" % (ip1, ip2, ip3, ip4)
20 def printrange(startip, endip) :
21         bits = 1
22         mask = 1
23         while bits < 32 :
24                 newip = startip | mask
25                 if (newip>endip) or (((startip>>bits) << bits) != startip) :
26                         bits = bits - 1
27                         mask = mask >> 1
28                         break
29                 bits = bits + 1
30                 mask = (mask<<1) + 1
31         newip = startip | mask
32         bits = 32 - bits
33         print "%s/%d" % (int2ip(startip), bits)
34         if newip < endip :
35                 printrange(newip + 1, endip)
37 while 1 :
38         line = sys.stdin.readline().strip()
39         if not line : break
40         chars = line.split(" ")
41         print "#%s - %s" % (chars[0], chars[1])
42         ip1 = ip2int(chars[0])
43         ip2 = ip2int(chars[1])
44         printrange(ip1, ip2)

tags: , , , ,

18:57:10 by fishy - dev - Permanent Link

no comments yet - no trackbacks yet - karma: 25 [+/-]

May the Force be with you. RAmen