From 84cd34646326ffa096eeaf52ebfa9038b8d36d8b Mon Sep 17 00:00:00 2001 From: Mateusz Baginski Date: Mon, 23 Dec 2024 11:51:07 +0100 Subject: [PATCH] Do not attach refresh token interval if initialization of token failed in `init()` method of `CloudServices` plugin. --- .../src/cloudservices.ts | 18 ++++++++--- .../tests/cloudservices.js | 31 ++++++++++++++++++- 2 files changed, 44 insertions(+), 5 deletions(-) diff --git a/packages/ckeditor5-cloud-services/src/cloudservices.ts b/packages/ckeditor5-cloud-services/src/cloudservices.ts index be3604e9799..f3bc9634e43 100644 --- a/packages/ckeditor5-cloud-services/src/cloudservices.ts +++ b/packages/ckeditor5-cloud-services/src/cloudservices.ts @@ -101,11 +101,21 @@ export default class CloudServices extends ContextPlugin implements CloudService return; } + // Initialization of the token may fail. By default, the token is being refreshed on the failure. + // The problem is that if this happens here, then the token refresh interval will be executed even + // after destroying the editor (as the exception was thrown from `init` method). To prevent that + // behavior we need to catch the exception and destroy the uninitialized token instance. + // See: https://github.com/ckeditor/ckeditor5/issues/17531 const cloudServicesCore: CloudServicesCore = this.context.plugins.get( 'CloudServicesCore' ); - - this.token = await cloudServicesCore.createToken( this.tokenUrl ).init(); - - this._tokens.set( this.tokenUrl, this.token ); + const uninitializedToken = cloudServicesCore.createToken( this.tokenUrl ); + + try { + this.token = await uninitializedToken.init(); + this._tokens.set( this.tokenUrl, this.token ); + } catch ( error ) { + uninitializedToken.destroy(); + throw error; + } } /** diff --git a/packages/ckeditor5-cloud-services/tests/cloudservices.js b/packages/ckeditor5-cloud-services/tests/cloudservices.js index 289eed71967..f3e26945ec2 100644 --- a/packages/ckeditor5-cloud-services/tests/cloudservices.js +++ b/packages/ckeditor5-cloud-services/tests/cloudservices.js @@ -3,7 +3,7 @@ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options */ -/* global document */ +/* global document, console */ import CloudServices from '../src/cloudservices.js'; import CloudServicesCore from '../src/cloudservicescore.js'; @@ -170,6 +170,35 @@ describe( 'CloudServices', () => { return context.destroy(); } ); } ); + + it( 'if token url crashes, then it should not create infinity loop of requests after destroy of the editor', async () => { + const clock = sinon.useFakeTimers(); + + sinon.stub( console, 'warn' ); + + const tokenUrlStub = sinon.stub().rejects( new Error( 'Token URL crashed' ) ); + + try { + await Context.create( { + plugins: [ CloudServices ], + cloudServices: { + tokenUrl: tokenUrlStub + } + } ); + + expect.fail( 'Context.create should reject' ); + } catch ( error ) { + expect( error.message ).to.equal( 'Token URL crashed' ); + } + + expect( tokenUrlStub ).to.be.calledOnce; + + clock.tick( 17000 ); + clock.restore(); + + // Editor was destroyed at this moment, so no more requests should be made. + expect( tokenUrlStub ).to.be.calledOnce; + } ); } ); describe( 'registerTokenUrl()', () => {