Just five days ago, I blogged about minting Hashcash tokens in Mutt using a Python script (make sure you check that page for any updates to the source if you're using it). Well today, I finished writing my verification script. It takes some additional changes to your ~/.muttrc, which I'll outline here, and it requires the installation of a Python script. Of course, as previous, I'm assuming that you're running at least Python 2.5 and the latest version of Hashcash. With that, let's get busy.
First, the necessary changes to your "~/.muttrc" config. The script relies on the "X-Hashcash:" header (as well as the "Hashcash:" header- I guess there was some discrepancy or something about X-headers being deprecated, or something) not being weeded out. It must be displayed if present. This way, the script can actually see the token in the header, and process the logic of checking if it's valid. If you hid the hashcash headers, then the script won't execute, and as a result, won't add anything to the token database. We use the $display_filter variable to execute the Python script, and show the results to the pager. Here's the changes you will need to make:
# file: ~/.muttrc ignore * # draconian header weed - recommended unignore from date subject to cc user-agent # standard headers unignored - recommended unignore x-hashcash hashcash # required
You will also need to set the $display_filter variable. I like having my theme consistent, so I've also added color to my theme to show the Hashcash verification at the top of the mail:
# file: ~/.muttrc set display_filter="/path/to/verify_hashcash.py" # required color body brightyellow default "^\$$!--.*Hashcash*" # recommended
Now with that set, all we need to do is install the Python script, and we're ready to go. When looking over the code, you'll notice that it's creating a database of spent tokens. I've placed the database in ~/.mutt/, seeing as though I only have Mutt working with Hashcash at the moment (and it's really the only MUA I use these days). If you have something else that uses Hashcash tokens, in an already existing database, you may want to make the necessary modifications to the Python script, so it's pointing to the right file. Also, we're only interested in keeping track of tokens minted for us personally, not all tokens we can find in the headers. Lastly, this Python script is only working for one email address. If you have multiple emails, as I do, you'll have to either use a primary email to verify the tokens against, or modify the Python script to support checking tokens under multiple accounts.
With that said, here's the script:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | #!/usr/bin/env python # Licensed under the public domain import rfc822 import StringIO import subprocess import sys # Change the DB path in COMMAND as needed, and change your email address COMMAND="hashcash -cdb '%s' -r '%s' -f /home/user/.mutt/hashcash.db '%s'" EMAILADDR="foo@bar.com" tokens = [] token_status = [] # converting a list to a file-type object for parsing rfc822 headers original = sys.stdin.read() emailmsg = StringIO.StringIO(''.join(original)) message = rfc822.Message(emailmsg) # check for the presence of "X-Hashcash" and "Hashcash" headers if message.has_key("X-Hashcash"): for hc_list in message.getheaders("X-Hashcash"): tokens.append(hc_list) if message.has_key("Hashcash"): for hc_list in message.getheaders("Hashcash"): tokens.append(hc_list) # check each token if tokens: token_status.append("[-- Begin Hashcash output --]") for hc_token in tokens: if hc_token.split(":")[3] == EMAILADDR: hc_bits = hc_token.split(":")[1] hc_resource = hc_token.split(":")[3] p = subprocess.Popen(COMMAND % (hc_bits,hc_resource,hc_token), shell=True, stderr=subprocess.PIPE, stdout=subprocess.PIPE) out = p.stderr.read().strip() token_status.append(out) else: token_status.append("No valid tokens for %s found." % EMAILADDR) token_status.append("[-- End Hashcash output --]") print >> sys.stdout, ''.join(message.headers) for status in token_status: print >> sys.stdout, ''.join(status) if tokens: print '' emailmsg.seek(message.startofbody) print >> sys.stdout, ''.join(emailmsg.readlines()) |
One thing I do find odd about the code above, is the hashcash binary, when checking tokens, prints to STDERR rather than STDOUT. I'm guessing this could change in the future, so that's something that will need to be watched out for.
So far, the Python script has been working flawless for me. I haven't noticed a single hiccup, and it's fast, which it should be. However, standard disclaimers apply, such as not coming with any warranty, blah, blah, blah, and if you find any bugs, or have any enhancements (such as supporting multiple email addresses), I'm all ears. At any rate, I hope you find it helpful, should you wish to get into Hashcash with Mutt.
{ 3 } Comments