From e4f8502a6e7c90db7bf6981244010109fdf4e81a Mon Sep 17 00:00:00 2001 From: deepak20001 Date: Sat, 8 Nov 2025 01:54:41 +0530 Subject: [PATCH] Handle relative URLs in auth method display icons Fixes #1969 - Resolve relative displayIcon URLs against realmUrl before passing to Image.network() - Add unit test to verify relative URL resolution - Maintain backward compatibility with absolute URLs The fix checks if displayIcon starts with http:// or https://. If not, it resolves the relative URL using Uri.resolve(), matching the pattern used for loginUrl resolution. --- lib/widgets/login.dart | 7 ++++++- test/widgets/login_test.dart | 28 ++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/lib/widgets/login.dart b/lib/widgets/login.dart index 664a24509a..16edfdd6cb 100644 --- a/lib/widgets/login.dart +++ b/lib/widgets/login.dart @@ -462,7 +462,12 @@ class _LoginPageState extends State { if (externalAuthenticationMethods.isNotEmpty) ...[ const OrDivider(), ...externalAuthenticationMethods.map((method) { - final icon = method.displayIcon; + final iconUrl = method.displayIcon; + final icon = (iconUrl != null) + ? (iconUrl.startsWith('http://') || iconUrl.startsWith('https://')) + ? iconUrl + : widget.serverSettings.realmUrl.resolve(iconUrl).toString() + : null; return OutlinedButton.icon( style: ButtonStyle( backgroundColor: WidgetStatePropertyAll(colorScheme.secondaryContainer), diff --git a/test/widgets/login_test.dart b/test/widgets/login_test.dart index c77647fdb7..6121b9390e 100644 --- a/test/widgets/login_test.dart +++ b/test/widgets/login_test.dart @@ -408,6 +408,34 @@ void main() { debugNetworkImageHttpClientProvider = null; }); + testWidgets('relative displayIcon URL is resolved correctly', (tester) async { + final method = ExternalAuthenticationMethod( + name: 'github', + displayName: 'GitHub', + displayIcon: '/static/images/authentication_backends/github-icon.png', // Relative URL + loginUrl: '/accounts/login/social/github', + signupUrl: '/accounts/register/social/github', + ); + final serverSettings = eg.serverSettings( + externalAuthenticationMethods: [method]); + prepareBoringImageHttpClient(); // icon on social-auth button + await prepare(tester, serverSettings); + takeStartingRoutes(); + check(pushedRoutes).isEmpty(); + check(testBinding.globalStore.accounts).isEmpty(); + + // Verify the button exists + tester.widget(find.textContaining('GitHub')); + + // Verify the Image.network widget receives the resolved absolute URL + final imageWidget = tester.widget(find.byType(Image)); + final networkImage = imageWidget.image as NetworkImage; + final expectedResolvedUrl = eg.realmUrl.resolve(method.displayIcon!).toString(); + check(networkImage.url).equals(expectedResolvedUrl); + + debugNetworkImageHttpClientProvider = null; + }); + // TODO failures, such as: invalid loginUrl; URL can't be launched; // WebAuthPayload.realm doesn't match the realm the UI is about });