From 7a512f992b7bab054ecd5a22ac899163415001c4 Mon Sep 17 00:00:00 2001 From: Fabien O'Carroll Date: Thu, 10 Oct 2019 16:21:03 +0700 Subject: [PATCH] Updated to use HS256 signatures for tokens no-issue This makes the tokens a little more acceptable in plaintext emails --- ghost/magic-link/index.js | 21 +++++++++------------ ghost/magic-link/test/index.test.js | 18 +++--------------- 2 files changed, 12 insertions(+), 27 deletions(-) diff --git a/ghost/magic-link/index.js b/ghost/magic-link/index.js index 3f08b9edd3..ee620c2930 100644 --- a/ghost/magic-link/index.js +++ b/ghost/magic-link/index.js @@ -2,8 +2,7 @@ const jwt = require('jsonwebtoken'); module.exports = MagicLink; /** - * @typedef { Buffer | string } RsaPublicKey - * @typedef { Buffer | string } RsaPrivateKey + * @typedef { import('jsonwebtoken').Secret } Secret * @typedef { import('nodemailer').Transporter } MailTransporter * @typedef { import('nodemailer').SentMessageInfo } SentMessageInfo * @typedef { string } JSONWebToken @@ -61,20 +60,18 @@ function defaultGetSubject(type) { * * @param {object} options * @param {MailTransporter} options.transporter - * @param {RsaPublicKey} options.publicKey - * @param {RsaPrivateKey} options.privateKey + * @param {Secret} options.secret * @param {(token: JSONWebToken, type: string) => URL} options.getSigninURL * @param {typeof defaultGetText} [options.getText] * @param {typeof defaultGetHTML} [options.getHTML] * @param {typeof defaultGetSubject} [options.getSubject] */ function MagicLink(options) { - if (!options || !options.transporter || !options.publicKey || !options.privateKey || !options.getSigninURL) { - throw new Error('Missing options. Expects {transporter, publicKey, privateKey, getSigninURL}'); + if (!options || !options.transporter || !options.secret || !options.getSigninURL) { + throw new Error('Missing options. Expects {transporter, secret, getSigninURL}'); } this.transporter = options.transporter; - this.publicKey = options.publicKey; - this.privateKey = options.privateKey; + this.secret = options.secret; this.getSigninURL = options.getSigninURL; this.getText = options.getText || defaultGetText; this.getHTML = options.getHTML || defaultGetHTML; @@ -93,10 +90,10 @@ function MagicLink(options) { MagicLink.prototype.sendMagicLink = async function sendMagicLink(options) { const token = jwt.sign({ user: options.user - }, this.privateKey, { + }, this.secret, { audience: '@tryghost/magic-link', issuer: '@tryghost/magic-link', - algorithm: 'RS512', + algorithm: 'HS256', subject: options.email, expiresIn: '10m' }); @@ -123,10 +120,10 @@ MagicLink.prototype.sendMagicLink = async function sendMagicLink(options) { */ MagicLink.prototype.getUserFromToken = function getUserFromToken(token) { /** @type {object} */ - const claims = jwt.verify(token, this.publicKey, { + const claims = jwt.verify(token, this.secret, { audience: '@tryghost/magic-link', issuer: '@tryghost/magic-link', - algorithms: ['RS512'], + algorithms: ['HS256'], maxAge: '10m' }); return claims.user; diff --git a/ghost/magic-link/test/index.test.js b/ghost/magic-link/test/index.test.js index 828d364105..e0d28ef319 100644 --- a/ghost/magic-link/test/index.test.js +++ b/ghost/magic-link/test/index.test.js @@ -4,17 +4,7 @@ const MagicLink = require('../'); const crypto = require('crypto'); const sandbox = sinon.createSandbox(); -const {publicKey, privateKey} = crypto.generateKeyPairSync('rsa', { - modulusLength: 4096, - publicKeyEncoding: { - type: 'pkcs1', - format: 'pem' - }, - privateKeyEncoding: { - type: 'pkcs1', - format: 'pem' - } -}); +const secret = crypto.randomBytes(64); describe('MagicLink', function () { it('Exports a function', function () { @@ -24,8 +14,7 @@ describe('MagicLink', function () { describe('#sendMagicLink', function () { it('Sends an email to the user with a link generated from getSigninURL(token, type)', async function () { const options = { - publicKey, - privateKey, + secret, getSigninURL: sandbox.stub().returns('FAKEURL'), getText: sandbox.stub().returns('SOMETEXT'), getHTML: sandbox.stub().returns('SOMEHTML'), @@ -59,8 +48,7 @@ describe('MagicLink', function () { describe('#getUserFromToken', function () { it('Returns the user data which from the token that was encoded by #sendMagicLink', async function () { const options = { - publicKey, - privateKey, + secret, getSigninURL: sandbox.stub().returns('FAKEURL'), getText: sandbox.stub().returns('SOMETEXT'), getHTML: sandbox.stub().returns('SOMEHTML'),