Added ability to fetch member by identity token (#329)

refs https://github.com/TryGhost/Team/issues/1057

This method will validate a token, and then return the member associated
with it. Rather than exposing token validation and coupling consumers to
the structure of the token response data.
This commit is contained in:
Fabien 'egg' O'Carroll 2021-09-17 11:25:57 +02:00 committed by GitHub
parent d99e0acf1a
commit 528fd23874
3 changed files with 31 additions and 7 deletions

View File

@ -58,6 +58,12 @@ module.exports = function MembersAPI({
common.logging.setLogger(logger);
}
const tokenService = new TokenService({
privateKey,
publicKey,
issuer
});
const stripeConfig = paymentConfig && paymentConfig.stripe || {};
const stripeAPIService = new StripeAPIService({
@ -90,6 +96,7 @@ module.exports = function MembersAPI({
const memberRepository = new MemberRepository({
stripeAPIService,
logger,
tokenService,
productRepository,
Member,
MemberSubscribeEvent,
@ -128,12 +135,6 @@ module.exports = function MembersAPI({
sendEmailWithMagicLink
});
const tokenService = new TokenService({
privateKey,
publicKey,
issuer
});
const geolocationService = new GeolocationSerice();
const magicLinkService = new MagicLink({

View File

@ -12,6 +12,11 @@ const messages = {
bulkActionRequiresFilter: 'Cannot perform {action} without a filter or all=true'
};
/**
* @typedef {object} ITokenService
* @prop {(token: string) => Promise<import('jsonwebtoken').JwtPayload>} decodeToken
*/
module.exports = class MemberRepository {
/**
* @param {object} deps
@ -25,6 +30,7 @@ module.exports = class MemberRepository {
* @param {any} deps.StripeCustomerSubscription
* @param {any} deps.productRepository
* @param {import('../../services/stripe-api')} deps.stripeAPIService
* @param {ITokenService} deps.tokenService
* @param {any} deps.logger
*/
constructor({
@ -38,6 +44,7 @@ module.exports = class MemberRepository {
StripeCustomerSubscription,
stripeAPIService,
productRepository,
tokenService,
logger
}) {
this._Member = Member;
@ -50,6 +57,7 @@ module.exports = class MemberRepository {
this._StripeCustomerSubscription = StripeCustomerSubscription;
this._stripeAPIService = stripeAPIService;
this._productRepository = productRepository;
this.tokenService = tokenService;
this._logging = logger;
}
@ -76,6 +84,14 @@ module.exports = class MemberRepository {
return this._Member.findOne(data, options);
}
async getByToken(token, options) {
const data = await this.tokenService.decodeToken(token);
return this.get({
email: data.sub
}, options);
}
async create(data, options) {
const {labels} = data;

View File

@ -29,14 +29,21 @@ module.exports = class TokenService {
/**
* @param {string} token
* @returns {Promise<jwt.JwtPayload>}
*/
async decodeToken(token) {
await this._keyStoreReady;
return jwt.verify(token, this._publicKey, {
const result = jwt.verify(token, this._publicKey, {
algorithms: ['RS512'],
issuer: this._issuer
});
if (typeof result === 'string') {
return {sub: result};
}
return result;
}
async getPublicKeys() {