mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-12-01 22:02:11 +03:00
7c5a3bb537
no-issue * Added SingleUseTokenProvider to members service This implements the TokenProvider interface required by members-api to generate magic links. It handles checking if the token is expired and pulls out any associated data. Future improvments may include the email in the error for expired tokens, which would make resending a token simpler. * Passed SingleUseTokenProvider to members-api This sets up the members-api module to use the new single use tokens * Installed @tryghost/members-api@0.30.0 This includes the change to allow us to pass a token provider to the members-api
68 lines
1.8 KiB
JavaScript
68 lines
1.8 KiB
JavaScript
// @ts-check
|
|
const {UnauthorizedError} = require('@tryghost/errors');
|
|
|
|
class SingleUseTokenProvider {
|
|
/**
|
|
* @param {import('../../models/base')} SingleUseTokenModel - A model for creating and retrieving tokens.
|
|
* @param {number} validity - How long a token is valid for from it's creation in milliseconds.
|
|
*/
|
|
constructor(SingleUseTokenModel, validity) {
|
|
this.model = SingleUseTokenModel;
|
|
this.validity = validity;
|
|
}
|
|
|
|
/**
|
|
* @method create
|
|
* Creates and stores a token, with the passed data associated with it.
|
|
* Returns the created token value.
|
|
*
|
|
* @param {Object<string, any>} data
|
|
*
|
|
* @returns {Promise<string>}
|
|
*/
|
|
async create(data) {
|
|
const model = await this.model.add({
|
|
data: JSON.stringify(data)
|
|
});
|
|
|
|
return model.get('token');
|
|
}
|
|
|
|
/**
|
|
* @method validate
|
|
* Validates a token, returning any parsable data associated.
|
|
* If the token is invalid the returned Promise will reject.
|
|
*
|
|
* @param {string} token
|
|
*
|
|
* @returns {Promise<Object<string, any>>}
|
|
*/
|
|
async validate(token) {
|
|
const model = await this.model.findOne({token});
|
|
|
|
if (!model) {
|
|
throw new UnauthorizedError({
|
|
message: 'Invalid token provided'
|
|
});
|
|
}
|
|
|
|
const createdAtEpoch = model.get('created_at').getTime();
|
|
|
|
const tokenLifetimeMilliseconds = Date.now() - createdAtEpoch;
|
|
|
|
if (tokenLifetimeMilliseconds > this.validity) {
|
|
throw new UnauthorizedError({
|
|
message: 'Token expired'
|
|
});
|
|
}
|
|
|
|
try {
|
|
return JSON.parse(model.get('data'));
|
|
} catch (err) {
|
|
return {};
|
|
}
|
|
}
|
|
}
|
|
|
|
module.exports = SingleUseTokenProvider;
|