UNPKG

@piggly/fastify-chassis

Version:

An ESM/CommonJS toolkit to help you to do common operations in your back-end applications with Fastify and NodeJS.

130 lines 3.74 kB
import crypto from 'node:crypto'; import { ServiceProvider, } from '@piggly/ddd-toolkit'; /** * @file Nonce service. * @copyright Piggly Lab 2025 * @since 7.0.0 * @author Caique Araujo <caique@piggly.com.br> */ export class NonceTokenService { /** * Repository. * * @type {IStoreService} * @protected * @memberof NonceTokenService * @since 7.0.0 * @author Caique Araujo <caique@piggly.com.br> */ _repository; /** * Constructor. * * @param {IStoreService} repository * @public * @constructor * @memberof NonceTokenService * @since 7.0.0 * @author Caique Araujo <caique@piggly.com.br> */ constructor(repository) { this._repository = repository; } /** * Issue one or more nonces. * * @param {number} size * @returns {Promise<Array<string>>} * @throws {Error} If failed to issue nonce. Error may be produced by store service. * @since 7.0.0 * @author Caique Araujo <caique@piggly.com.br> */ async issue(size = 1, ttl = 3600) { const nonces = []; for (let i = 0; i < size; i++) { const nonce = NonceTokenService.generateClientSecret(32); const response = await this._repository.set(`nonce:${nonce}`, '1', ttl); if (response === false) { throw new Error('Failed to issue nonce'); } nonces.push(nonce); } return nonces; } /** * Verify a nonce. * * If will return undefined if nonce is not found * or the same nonce if found. But, if regenerate * is true, it will regenerate the nonce and return * the new nonce. * * @param {string} nonce * @param {boolean} regenerate * @param {number} ttl * @returns {Promise<TOrUndefined<string>>} * @throws {Error} If failed to verify/regenerate nonce. Error may be produced by store service. * @since 7.0.0 * @author Caique Araujo <caique@piggly.com.br> */ async verify(nonce, regenerate, ttl) { const response = await this._repository.getAndDelete(`nonce:${nonce}`); if (!response) { return undefined; } if (regenerate === false) { return nonce; } const nonces = await this.issue(1, ttl); return nonces[0]; } /** * Random generates a client secret. * * @param {number} [size=36] * @public * @static * @memberof NonceTokenService * @since 7.6.0 * @author Caique Araujo <caique@piggly.com.br> */ static generateClientSecret(size = 36) { const buffer = crypto.randomBytes(size); return buffer .toString('base64') .replace(/\//g, '_') .replace(/\+/g, '-') .replace(/=/g, ''); } /** * Register application service. * * @param {NonceTokenService} store * @public * @static * @memberof NonceTokenService * @since 7.0.0 * @author Caique Araujo <caique@piggly.com.br> */ static register(store) { if (ServiceProvider.has('NonceTokenService')) { return; } ServiceProvider.register('NonceTokenService', new NonceTokenService(store)); } /** * Resolve application service. * * @returns {NonceTokenService} * @throws {Error} If service is not registered. * @public * @static * @memberof NonceTokenService * @since 7.0.0 * @author Caique Araujo <caique@piggly.com.br> */ static resolve() { return ServiceProvider.resolve('NonceTokenService'); } } //# sourceMappingURL=NonceTokenService.js.map