wsapi cleanup: factor out checkCSRF()
wsapi cleanup: flatten control flow a little bit
wsapi.authenticateSession: async-ify, combine args into a single 'options'

This includes an error-handling argument to the callback.
authenticate_user: factor out updateHash code

After the user is authenticated, we might update the hashed password if
the bcrypt work factor has been changed. To simplify the code in
preparation for later changes, this patch extracts the updateHash() code
out to a separate function.

Note that this function must run *after* the `res.json()` call for two
reasons. The first is to avoid slowing down the client (send answer
first, do work later). The second is to get the right session cookie
into the POST that we send to ourselves (to /wsapi/update_password) that
does the actual hash updated. The session is updated in
wsapi.authenticateSession, but the cookie isn't regenerated until the
call to `res.json()`, and the POST is sneakily grabbing the cookie out
of the response's Set-Cookie header to copy into the request-to-self.
enhance test/lib/wsapi.js to accept alternate contexts

This makes it possible to test two distinct sessions at the same time,
needed to exercise expiring one session when the password is changed in
a second session.
add checkExpiredSession check, set session.superSessionToken, add DB methods

With this change, existing session cookies are invalidated when the user
changes their password. This will also support a "log me out of
everywhere" button, which merely needs to update the superSessionToken
as if the password was changed.

This adds .superSessionToken to all sessions in
wsapi.authenticateSession, and checks it against the database row in
during a new checkExpiredSession() call (run for all /wsapi requests,
both GETs and POSTs).

All database methods which create an account or modify the password were
changed to also set .superSessionToken (to the current time).
updatePassword() added an 'invalidateSessions' argument so passwords can
be rehashed (when the bcrypt work factor changes) *without* invalidating
sessions. Finally, the database added a new method named
superSessionToken() to retrieve the current value, for comparison in
checkExpiredSession().

wsapi/update_password.js is changed to add a call to authenticateSession
after changing the password, to update the cookie with the new
.superSessionToken. This ensures that the user's new session works on
the next call after update_password.

Database rows that don't have a superSessionToken (created before the
code was upgraded to include this change) will not enforce
session-checking, so user sessions will not be spontaneously expired
when the server is upgraded past this revision.
update stalled-mysql tests to match new behavior

All wsapi operations now require the database (to update+check the
superSessionToken), so some tests that previously expected operations to
succeed without a database now expect them to fail (generally 503).

wsapi_client.js was changed to pass HTTP errors during
/wsapi/session_context back to the caller, so their response code can be
checked, rather than throwing an error (and preventing any other
assertions from being made).
test that all sessions are expired when the password is changed
rename superSessionToken to lastPasswordReset, easier to understand
mysql.js: update picture to match new type of lastPasswordReset
wsapi.js: don't check lastPasswordReset for not-yet-authenticated sessions

Specifically this should reduce the work needed by the
'authenticate_user' call by one DB read.
wsapi.js: if the DB doesn't have a token, don't enforce equality

This honors the preceding comment about not gratuitously expiring
innocent sessions. Somehow this clause got lost as I was
merging/rebasing this function.
fix stalled-mysql-test to handle not checking DB for unauthed sessions
mysql schema: use TIMESTAMP for lastPasswordReset, not BIGINT

Since MySQL TIMESTAMP is quantized to whole seconds, also change tests
to add a 2s stall before changing the password, to make sure
lastPasswordReset gets a new value.