Rest your ghost blog admin password without email.

Password managers are great, and I use a helpful browser plugin to simplify using mine, but sometimes they get it wrong (or is it my fault?).
I've been logged in to this blog on my desktop since I deployed it (blog post coming soon), so when I tried to login from my laptop I was alarmed to find the password I had stored in my password manager didn't work, and of course, the Mailgun integration didn't work for reasons, so I was kinda screwed, what now?
Google of course. The top hit is a forum post from 2018 where egg suggests putting together a simple script that uses the same password.js library to has a new password, then login to your database and update the password hash manually. Nice one, let's try.
My first thought was "I don't want to have to check out the Ghost source when I've already got it" so I logged into the VM hosting this blog and connected to the docker container:

After browsing round the Ghost installation for a few moments it became obvious that password.js wasn't at the path that egg had suggested. At this point the forum post is 7 years old, so it's not a surprise that the codebase has changed, so my original, lazy plan had failed.
Hashing my new password
Next I cloned Ghost repo and searched for "function hash" and ".hash" and couldn't find anything. I remembered the file we're trying to import was in lib/security
so I figured I'd search for that and sure enough I found a dependency in package.json to @tryghost/security
. Next I found that package on npmjs.com and followed the link to the framework git repo on github, where you can find password.js, so I and cloned that repo and we're ready to roll.
Now we can add the make-password.js
from eggs original comment.
// make-password.js
require('/path/to/ghost/core/server/lib/security/password')
.hash(process.argv[2])
.then(console.log);
Thanks egg
and now we're ready to run it, it looks like Ghost uses yarn for package management so yarn install
and then node ./make-password.js i-wont-forget-this-one
.
Changing the password
With the hard work done, I headed back to my hosting VM and attach to the mysql container. docker exec -it 7fc30477dd67 bash
and then connect to MySQL mysql -p
and finally, harking back to the early days of my web development career,
SHOW DATABASES;
USE ghost;
SELECT * FROM users;
UPDATE users SET password = 'your-new-password-hash' WHERE id = 1;
I won't be doing that again. Probably.