Notice: The WebPlatform project, supported by various stewards between 2012 and 2015, has been discontinued. This site is now available on github.

Importing users from MediaWiki to Firefox Accounts

This page describes how to query MediaWiki database and run an import script to create accounts within our fork (WPD/Projects/SSO/Adapt_Firefox_Accounts_for_WebPlatform) of Firefox Accounts (“FxA”).

To have an higher level description of how we implemented it, see WPD/Projects/SSO/How_we_implemented_it.

See canonical version in this gist.github.com/WebPlatformDocs

Process

  • Requires NodeJS, NPM
  • Clone fxa-auth-server in a folder of the same name
  • Install dependencies in fxa-auth-server with npm install
  • Go a folder up, create a new one and paste the following in it

1. Export MediaWiki Users

See also REAMDE in original gist

  • Run this query from MySQL Workbench.
    SELECT
      CONVERT(user_name USING utf8),
      CONVERT(user_real_name USING utf8),
      CONVERT(user_email USING utf8),
      CONVERT(user_registration, DATETIME),
      user_id
    FROM
      user
    ORDER BY user_id
    LIMIT 40000;
  • Export the result in a file `users.csv`, it’ll be used to import
  • Make sure the output is a CSV file
    • one entry per line
    • Fields in this order: username, realname, email, creation date

Should look like…

WikiSysop,,team-webplatform-admin@w3.org,"2012-05-29 17:37:32"
NoEmailUser,"Eliot Graff",,"2012-06-26 00:17:47"

2. Create file run.js

See also run.js in original gist

/**
 * Import MediaWiki accounts file to run
 *
 * To use within fxa-auth-server deployment.
 *
 * Based on work pushed in https://github.com/mozilla/fxa-auth-server/pull/711
 *
 * See documentation at /docs/WPD/Projects/SSO/Importing_users_from_MediaWiki_to_Firefox_Accounts
 *
 * @author David Kirstein <frozenice@frozenice.de> (http://webplatform.org)
 * @author Renoir Boulanger <renoir@w3.org>
 */

var fs = require('fs');
var Q = require('q');
var csv = require('csv-streamify');
var sleep = require('sleep');
var AccountCreator = require('./accountscreator');

function doSomethingWithLine(line) {
    try {
      var payload = new AccountCreator(line);
    } catch (err) {
      return Q.reject(err);
    }

    return payload.makePromiseToCreate();
}

var fstream = fs.createReadStream('users.csv');
var csvOptions = { empty: null, objectMode: true };
var parser = csv(csvOptions);
var workItems = [], errors = [];

parser.on('readable', function() {
  var line = parser.read(); // line is an array of fields
  sleep.usleep(100 * 1000); // sleep 100 ms
  var promise = doSomethingWithLine(line);
  promise.done(function onFulfilled() {
    // Nothing
  }, function onRejected(a) {
    errors.push([line[0], a.message || a]);
  });
  workItems.push(promise);
});

fstream.pipe(parser).on('end', function() {
  waitForAllPromises();
});

function waitForAllPromises() {
  // use allSettled, all would abort if just one promise would be rejected
  Q.allSettled(workItems).done(function() {
    console.log('all done! errors:');
    console.error(errors);
  });
}

3. Create file accountscreator.js

See also accountscreator.js in original gist

/**
 * Import MediaWiki accounts
 *
 * To use within fxa-auth-server deployment.
 *
 * Based on work pushed in https://github.com/mozilla/fxa-auth-server/pull/711
 *
 * See documentation at /docs/WPD/Projects/SSO/Importing_users_from_MediaWiki_to_Firefox_Accounts
 *
 * @author Renoir Boulanger <renoir@w3.org>
 */

// Password (DO NOT USE THE SAME AS POSTED ONLINE!1)
var password = '4e9bde2d85';

    /**
     * fxa-auth-server listen IP and port
     *
     * Make sure it matches the same configuration
     * otherwise the hashing validation will fail with
     * "Bad mac" error message.
     *
     * See config/config.js in listen section.
     *
     * @type {String} FXA Auth server HTTP endpoint to make calls against
     */
var  instanceEndpoint = 'https://api.accounts.webplatform.org';

var fs = require('fs'),
    publicKey = JSON.parse(fs.readFileSync('../fxa-auth-server/config/public-key.json')),
    Client = require('../fxa-auth-server/client'),
    duration = 1000 * 60 * 60 * 24,
    client = null;

function AccountCreator(dataObject) {
  if ( dataObject[2] === null ) {
    throw 'User MUST have an email address for ' + dataObject[0];
  }
  // Use a hard to guess password to force users to ask a new one
  this.password = password;
  this.email = dataObject[2]; // See _parseUserData
  this.config = {pk: publicKey, d: duration, ep: instanceEndpoint};
  this.userData = this._parseUserData(dataObject);
}

/**
 * Format options array for overloaded signup
 *
 * userData expects 4 members:
 * - MediaWiki username
 * - Full name
 * - Email address
 * - Registration date
 *
 * @param  array  userData      data in a predetermined order
 * @return object optionsObject what we return as 3rd argument to ClientCreate call
 */
AccountCreator.prototype._parseUserData = function _parseUserData(userData) {
    var dateObject = new Date(userData[3]),
        out = {};

    out.preVerified = true;
    out.username = userData[0];
    out.fullName = userData[1] || null;
    out.forceCreatedAt = dateObject.getTime();

    return out;
};

AccountCreator.prototype.makePromiseToCreate = function makePromiseToCreate () {
  return Client.create(this.config.ep, this.email, this.password, this.userData)
          .then(function(a){
            console.log('Created ', a.email);
          });
};

module.exports = AccountCreator;

4. Create a new package.json

See original package.json gist

{
  "name": "mediawiki-to-fxa-user-importer",
  "version": "0.0.1",
  "dependencies": {
    "q": "~1.0.0",
    "csv-streamify":"~1.0.0",
    "sleep": "~1.1.5"
  }
}

Run

npm install

5. Run import script

Note that this step can take some time. With ~39 000 users, it took a bit more than an hour to run in full.

node run.js