i'm laying here in bed using my laptop and wanted to write some code, but the firefox bookmark for my development site was outdated (i switched from camping to rails the other week, so my local site moved from localhost:3301 to localhost:3000). rather than just change it, i decided to do something about synchronizing my bookmarks between my desktop and laptop.
i found google's and foxmarks' solutions but, while both were free, they required that i keep my data on their servers. while installing the foxmarks plugin, however, i noticed that you can easily change the server it synchronizes to and it can support https. so like any good programmer, i wrote my own backend so i could host my own bookmarks.
a quick tcpdump of the traffic showed that the plugin uses standard http authentication with the username and password you enter (which are normally created on foxmarks.com through the setup wizard), then does an http PUT to store an xml file and a GET to download it (just like ical; expecting to talk to a webdav server). all of the synchronization and conflict resolution is done locally in the plugin. with some simple ruby code to handle http authentication and rails' built-in RESTful handling, i had working bookmark synchronization between firefox on my two openbsd machines in not much time.
after installing the plugin and restarting firefox, just click cancel on the setup dialog. go into the plugin preferences and make up a username and password, then set the server name to yours, enable https, and make up a url (i chose "/bookmarksync/").
hook up a RESTful route in config/routes.rb:
map.resources :bookmarksync
then create the bookmarksync controller, with username and password being the values entered in the plugin preferences:
class BookmarksyncController < ApplicationController
SYNC_USER = "username"
SYNC_PASS = "password"
SYNC_REALM = "protected area"
DB_DIR = File.dirname(__FILE__) + "/../../db/"
def update
if !authenticated?
return false
end
f = File.open("#{DB_DIR}.bookmarks.xml", "w")
f.puts request.env["RAW_POST_DATA"]
f.close
File.rename("#{DB_DIR}.bookmarks.xml", "#{DB_DIR}bookmarks.xml")
render :text => "oll korrect"
end
def show
if !authenticated?
return false
end
send_file "#{DB_DIR}bookmarks.xml"
end
private
def authenticated?
[ "HTTP_AUTHORIZATION", "Authorization" ].each do |h|
if m = Regexp.new(/^Basic (.+)/).match(request.env[h].to_s)
user, pass = Base64.decode64(m[1]).split(":")
return true if user == SYNC_USER && pass == SYNC_PASS
end
end
response.headers["WWW-Authenticate"] = "Basic realm=\"#{SYNC_REALM}\""
render(:text => "Authentication required", :status => 401)
return false
end
end
this just (safely) writes the xml file into rails' db/ directory and then pulls it out again. it could do something more creative like store the data in my sqlite database and have a silly web interface to the bookmarks, but i don't really need any of that.
and now, with this code written and my bookmarks synched, i can get back to my original plan of... writing code.
