From 0eee07a6da5ebb339a4b043d39e3f38b63e5df20 Mon Sep 17 00:00:00 2001 From: Lukas Mirbt Date: Sat, 20 Jul 2024 21:51:34 +0200 Subject: [PATCH] fix(fresh_dio): add assert to prevent infinite refresh loop (#98) Co-authored-by: Felix Angelov --- packages/fresh_dio/lib/src/fresh.dart | 23 +++++++++++++++++++++++ packages/fresh_dio/test/fresh_test.dart | 24 ++++++++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/packages/fresh_dio/lib/src/fresh.dart b/packages/fresh_dio/lib/src/fresh.dart index b6285f2..832c62f 100644 --- a/packages/fresh_dio/lib/src/fresh.dart +++ b/packages/fresh_dio/lib/src/fresh.dart @@ -80,6 +80,29 @@ class Fresh extends QueuedInterceptor with FreshMixin { RequestOptions options, RequestInterceptorHandler handler, ) async { + assert( + _httpClient.interceptors.every((interceptor) => interceptor != this), + ''' +Cycle Detected! + +The Fresh instance was created using an http client +which already contains the Fresh instance as an interceptor. + +This will cause an infinite loop on token refresh. + +Example: + + ``` + final httpClient = Dio(); + final fresh = Fresh.oAuth2( + httpClient: httpClient, + ... + ); + httpClient.interceptors.add(fresh); // <-- BAD + ``` +''', + ); + final currentToken = await token; final headers = currentToken != null ? _tokenHeader(currentToken) diff --git a/packages/fresh_dio/test/fresh_test.dart b/packages/fresh_dio/test/fresh_test.dart index ee336fd..e9b36af 100644 --- a/packages/fresh_dio/test/fresh_test.dart +++ b/packages/fresh_dio/test/fresh_test.dart @@ -112,6 +112,30 @@ void main() { group('onRequest', () { const oAuth2Token = OAuth2Token(accessToken: 'accessToken'); + + test( + 'throws AssertionError when httpClient.interceptors ' + 'contains the Fresh instance as an interceptor', + () { + when(() => tokenStorage.read()).thenAnswer((_) async => oAuth2Token); + + final httpClient = Dio(); + + final fresh = Fresh.oAuth2( + tokenStorage: tokenStorage, + refreshToken: emptyRefreshToken, + httpClient: httpClient, + ); + + httpClient.interceptors.add(fresh); + + expect( + fresh.onRequest(RequestOptions(), RequestInterceptorHandler()), + throwsA(isA()), + ); + }, + ); + test( 'appends token header when token is OAuth2Token ' 'and tokenHeader is not provided', () async {