Background

Huddler is a company that provided free hosting for web forums for a cut of advertising revenue. They were acquired by Wikia who apparently didn't want anything to do with the web forum business and started ending their contracts with forum owners. A colleague contacted me for assistance in a migration of his forum and here some technical notes and experiences on the task. Huddler was generally courteous about the whole seperation process and gave forum owners time to find new hosts and prepare a migration plan. Full migrations were quite a chore as the Huddler DB schema was undocumented and the style markup of forum posts was a mash of BBCode and HTML that had changed through time.

Migration Goals

  • Priority
    • Users: Name, Email, Password, Profile Images / Information / Questions, Stats (Reputation, Post Counts)
    • Threads:
      • Thread name (and ID) shouldn't change to best preserve Google Juice.
      • Thread posts: poster, post information and content (whole section on this one later).
      • Polls: Question, Answers and Votes.
  • Private Messages
  • Registration IPs
  • Poster IPs

Huddler Provided Data

  • PostgreSQL 9.4 Database Dump
  • Tarball of static images from Huddler's CDN.

Huddler / IPS Database Comparison

Users

User table entries had a 1-1 migration. Profile images were normalized to a table external_store_objects which had a list of all the static images in the CDN.

HuddlerIPB
users core_members
perms_group_membership Field on core_members
Forums

Forums, Threads / Topics and Post entries had a 1-1 migration.

HuddlerIPB
forums forums_forums
forum_threads forums_topics
forum_posts forums_posts
Polls

Huddler's poll table has a 1-1 relationship with the core_polls table, but Huddler broke out all the possible answers for a poll into a separate poll_options table. IPS stores the available answers as a JSON on the core_polls table. Additionally, the Huddler association of a poll to a thread was stored in yet another table.

HuddlerIPB
poll core_polls
poll_options Field on core_polls containing JSON
poll_attach Field on core_polls
Private Messages

Also a pretty close 1-1 relationship. Migrating the user relationships with the messages was a bit trickier. To keep things simple, we didn't migrate draft or system messages (users were given a heads-up to save their drafts if they had any).

HuddlerIPB
message_thread core_message_topics
message core_message_posts
message_recipient core_message_topic_user_map

Password Hashing

Huddler used several different password hashing techniques, the only appeared to upgrade a users hash when the users changed their passwords (password hashes can also be upgraded when a user logs in). I found at least three: bcrypt ($2y$12$) and two 32 character hashes, one with a salt field and one with a blank salt field. The first one md5( md5(password) + salt) (a holdover from before Huddler when the system was VBulletin) and a third one that Huddler wouldn't divulge the mechanism. I tried about about two dozen combinations of md4 and md5 but was never succesfull in determining what hash mechanism they were using.

I extended the IPS Internal Login Handler (system/Login/Internal.php) to authenticate and rehash the passwords using the bcrypt $2a$13$ when the users logged in. Users from the last group where the hash was unusable just had to reset their password.

Continued...