Ghost/core/server/api/canary/identities.js

37 lines
1004 B
JavaScript
Raw Normal View History

const settings = require('../../../shared/settings-cache');
const urlUtils = require('../../../shared/url-utils');
Implemented externally verifiable identity tokens no-issue This adds two new endpoints, one at /ghost/.well-known/jwks.json for exposing a public key, and one on the canary api /identities, which allows the Owner user to fetch a JWT. This token can then be used by external services to verify the domain * Added ghost_{public,private}_key settings This key can be used for generating tokens for communicating with external services on behalf of Ghost * Added .well-known directory to /ghost/.well-known We add a jwks.json file to the .well-known directory which exposes a public JWK which can be used to verify the signatures of JWT's created by Ghost This is added to the /ghost/ path so that it can live on the admin domain, rather than the frontend. This is because most of its uses/functions will be in relation to the admin domain. * Improved settings model tests This removes hardcoded positions in favour of testing that a particular event wasn't emitted which is less brittle and more precise about what's being tested * Fixed parent app unit tests for well-known This updates the parent app unit tests to check that the well-known route is mounted. We all change proxyquire to use `noCallThru` which ensures that the ubderlying modules are not required. This stops the initialisation logic in ./well-known erroring in tests https://github.com/thlorenz/proxyquire/issues/215 * Moved jwt signature to a separate 'token' propery This structure corresponds to other resources and allows to exptend with additional properties in future if needed
2020-01-20 14:45:58 +03:00
const jwt = require('jsonwebtoken');
const jose = require('node-jose');
const issuer = urlUtils.urlFor('admin', true);
const dangerousPrivateKey = settings.get('ghost_private_key');
const keyStore = jose.JWK.createKeyStore();
const keyStoreReady = keyStore.add(dangerousPrivateKey, 'pem');
const getKeyID = async () => {
const key = await keyStoreReady;
return key.kid;
};
const sign = async (claims, options) => {
const kid = await getKeyID();
return jwt.sign(claims, dangerousPrivateKey, Object.assign({
issuer,
expiresIn: '5m',
algorithm: 'RS256',
keyid: kid
}, options));
};
module.exports = {
docName: 'identities',
permissions: true,
read: {
permissions: true,
async query(frame) {
const token = await sign({sub: frame.user.get('email')});
return {token};
}
}
};