From 57654c147d9a23702bfb0b62c2091361dadb89a6 Mon Sep 17 00:00:00 2001 From: Dmitry Andriyanov Date: Fri, 1 Nov 2024 00:18:24 +0500 Subject: [PATCH] fix: EWM-362 (#608) * EWM-352. user agent * EWM-352. Add check url with http and without www * EWM-352. after analyze --- .../browser_tab_view/browser_tab_view.dart | 76 ++++++++++++------- .../browser/browser_user_agent_utils.dart | 48 ++++++++++++ .../account_asset_tab/account_asset_tab.dart | 2 +- .../account_asset_tab_cubit.dart | 7 +- pubspec.lock | 24 ++++++ pubspec.yaml | 1 + 6 files changed, 127 insertions(+), 31 deletions(-) create mode 100644 lib/feature/browser/browser_user_agent_utils.dart diff --git a/lib/feature/browser/browser_tab_view/browser_tab_view.dart b/lib/feature/browser/browser_tab_view/browser_tab_view.dart index 0ebb4c35..f534b17e 100644 --- a/lib/feature/browser/browser_tab_view/browser_tab_view.dart +++ b/lib/feature/browser/browser_tab_view/browser_tab_view.dart @@ -8,6 +8,7 @@ import 'package:app/di/di.dart'; import 'package:app/feature/browser/browser.dart'; import 'package:app/feature/browser/browser_tab_view/browser_error_view.dart'; import 'package:app/feature/browser/browser_tab_view/browser_view_events_listener/browser_view_events_listener_cubit.dart'; +import 'package:app/feature/browser/browser_user_agent_utils.dart'; import 'package:elementary_helper/elementary_helper.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; @@ -63,6 +64,10 @@ class _BrowserTabViewState extends State with ContextMixin { 'about', ]; + static const Duration _scrollTimerDelay = Duration(milliseconds: 100); + + static final _log = Logger('BrowserTabView'); + // Last SANE Y position (i.e. not overscrolled) int? _lastScrollY; @@ -76,10 +81,10 @@ class _BrowserTabViewState extends State with ContextMixin { final List _delayedScrollEvents = []; // How long to wait before considering scroll event as not overscroll - static const Duration _scrollTimerDelay = Duration(milliseconds: 100); InAppWebViewController? _webViewController; PullToRefreshController? _pullToRefreshController; + late final _inpageProvider = InpageProvider( tabId: widget.tab.id, approvalsService: inject(), @@ -93,13 +98,14 @@ class _BrowserTabViewState extends State with ContextMixin { Timer? _screenshotTimer; - static final _log = Logger('BrowserTabView'); + final _userAgentState = StateNotifier(); @override void initState() { super.initState(); _setBrowserTabCallbacks(); + _setUserAgent(); } @override @@ -177,29 +183,37 @@ class _BrowserTabViewState extends State with ContextMixin { loadingBuilder: (_, __) => const SizedBox.shrink(), errorBuilder: (_, __, ___) => const SizedBox.shrink(), builder: (_, String? jsStr) { - return InAppWebView( - key: ValueKey(widget.tab.id), - pullToRefreshController: _pullToRefreshController, - initialSettings: initialSettings, - initialUserScripts: UnmodifiableListView([ - if (jsStr != null) - UserScript( - source: jsStr, - injectionTime: - UserScriptInjectionTime.AT_DOCUMENT_START, - ), - ]), - onOverScrolled: _onOverScrolled, - onScrollChanged: _onScrollChanged, - onWebViewCreated: (c) => _onWebViewCreated(c, context), - onLoadStart: _onLoadStart, - onLoadStop: _onLoadStop, - onLoadResource: _onLoadResource, - onReceivedError: _onReceivedError, - onReceivedHttpError: _onReceivedHttpError, - onTitleChanged: _onTitleChanged, - onReceivedHttpAuthRequest: _onReceivedHttpAuthRequest, - shouldOverrideUrlLoading: _shouldOverrideUrlLoading, + return StateNotifierBuilder( + listenableState: _userAgentState, + builder: (_, String? userAgent) { + if (userAgent == null) { + return const SizedBox.shrink(); + } + return InAppWebView( + key: ValueKey(widget.tab.id), + pullToRefreshController: _pullToRefreshController, + initialSettings: initialSettings..userAgent = userAgent, + initialUserScripts: UnmodifiableListView([ + if (jsStr != null) + UserScript( + source: jsStr, + injectionTime: + UserScriptInjectionTime.AT_DOCUMENT_START, + ), + ]), + onOverScrolled: _onOverScrolled, + onScrollChanged: _onScrollChanged, + onWebViewCreated: (c) => _onWebViewCreated(c, context), + onLoadStart: _onLoadStart, + onLoadStop: _onLoadStop, + onLoadResource: _onLoadResource, + onReceivedError: _onReceivedError, + onReceivedHttpError: _onReceivedHttpError, + onTitleChanged: _onTitleChanged, + onReceivedHttpAuthRequest: _onReceivedHttpAuthRequest, + shouldOverrideUrlLoading: _shouldOverrideUrlLoading, + ); + }, ); }, ); @@ -223,6 +237,7 @@ class _BrowserTabViewState extends State with ContextMixin { _screenshotTimer?.cancel(); + _userAgentState.dispose(); super.dispose(); } @@ -522,6 +537,10 @@ class _BrowserTabViewState extends State with ContextMixin { ); } + Future _setUserAgent() async { + _userAgentState.accept(await platformUserAgent); + } + Future _saveScreenshot({bool force = false}) async { if ((_screenshotTimer?.isActive ?? false) && !force) { return; @@ -612,7 +631,8 @@ class _BrowserTabViewState extends State with ContextMixin { final scheme = navigationAction.request.url?.scheme; - if (!_allowSchemes.contains(scheme) && await canLaunchUrl(url)) { + if ((!_allowSchemes.contains(scheme) || _checkIsCustomAppLink(url)) && + await canLaunchUrl(url)) { await launchUrl(url); return NavigationActionPolicy.CANCEL; @@ -620,6 +640,10 @@ class _BrowserTabViewState extends State with ContextMixin { return NavigationActionPolicy.ALLOW; } + + bool _checkIsCustomAppLink(Uri url) { + return url.origin.startsWith('http') && !url.origin.contains('www'); + } } // Delayed scroll event dataclass diff --git a/lib/feature/browser/browser_user_agent_utils.dart b/lib/feature/browser/browser_user_agent_utils.dart new file mode 100644 index 00000000..56028400 --- /dev/null +++ b/lib/feature/browser/browser_user_agent_utils.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:device_info_plus/device_info_plus.dart'; + +Future platformUserAgent = (() async => + Platform.isIOS ? await _iOSUserAgent : await _androidUserAgent)(); + +Future get _androidUserAgent async { + String? androidVersion; + String? deviceModel; + String? buildId; + + try { + final deviceInfo = DeviceInfoPlugin(); + final androidInfo = await deviceInfo.androidInfo; + androidVersion = androidInfo.version.release; + deviceModel = '; ${androidInfo.model}'; + buildId = ' Build/${androidInfo.id}'; + } catch (_) { + androidVersion = '12'; + } + + return 'Mozilla/5.0 ' + '(Linux; ' + 'Android $androidVersion$deviceModel$buildId) ' + 'AppleWebKit/537.36 (KHTML, like Gecko) ' + 'Chrome/117.0.0.0 Mobile Safari/537.36'; +} + +Future get _iOSUserAgent async { + String? iosVersion; + String? deviceModel; + + try { + final deviceInfo = DeviceInfoPlugin(); + final iosInfo = await deviceInfo.iosInfo; + iosVersion = iosInfo.systemVersion; + deviceModel = iosInfo.utsname.machine; + } catch (_) { + deviceModel = 'iPhone'; + iosVersion = '15_0'; + } + + return 'Mozilla/5.0 ($deviceModel; ' + 'CPU iPhone OS $iosVersion like Mac OS X) ' + 'AppleWebKit/605.1.15 (KHTML, like Gecko) ' + 'Version/$iosVersion Mobile/15E148 Safari/604.1'; +} diff --git a/lib/feature/wallet/widgets/account_asset_tab/account_asset_tab.dart b/lib/feature/wallet/widgets/account_asset_tab/account_asset_tab.dart index caa3ccec..b3c44c44 100644 --- a/lib/feature/wallet/widgets/account_asset_tab/account_asset_tab.dart +++ b/lib/feature/wallet/widgets/account_asset_tab/account_asset_tab.dart @@ -32,9 +32,9 @@ class AccountAssetsTab extends StatelessWidget { return BlocProvider( create: (_) => AccountAssetTabCubit( account, - isFirstEntering, inject(), inject(), + isFirstEntering: isFirstEntering, ), child: BlocBuilder( builder: (context, state) { diff --git a/lib/feature/wallet/widgets/account_asset_tab/account_asset_tab_cubit.dart b/lib/feature/wallet/widgets/account_asset_tab/account_asset_tab_cubit.dart index 6f6cc373..5617ed2e 100644 --- a/lib/feature/wallet/widgets/account_asset_tab/account_asset_tab_cubit.dart +++ b/lib/feature/wallet/widgets/account_asset_tab/account_asset_tab_cubit.dart @@ -16,11 +16,10 @@ part 'account_asset_tab_state.dart'; class AccountAssetTabCubit extends Cubit { AccountAssetTabCubit( KeyAccount account, - // ignore: avoid_positional_boolean_parameters - this.isFirstEntering, this.tokenWalletsService, - this.assetsService, - ) : tonWallet = account.account.tonWallet, + this.assetsService, { + required this.isFirstEntering, + }) : tonWallet = account.account.tonWallet, super( AccountAssetTabState.accounts(account.account.tonWallet, null, 0), ) { diff --git a/pubspec.lock b/pubspec.lock index 8210cdc1..f6a62d0e 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -487,6 +487,22 @@ packages: url: "https://pub.dev" source: hosted version: "2.3.3" + device_info_plus: + dependency: "direct main" + description: + name: device_info_plus + sha256: c4af09051b4f0508f6c1dc0a5c085bf014d5c9a4a0678ce1799c2b4d716387a0 + url: "https://pub.dev" + source: hosted + version: "11.1.0" + device_info_plus_platform_interface: + dependency: transitive + description: + name: device_info_plus_platform_interface + sha256: "282d3cf731045a2feb66abfe61bbc40870ae50a3ed10a4d3d217556c35c8c2ba" + url: "https://pub.dev" + source: hosted + version: "7.0.1" diff_match_patch: dependency: transitive description: @@ -2367,6 +2383,14 @@ packages: url: "https://pub.dev" source: hosted version: "5.5.4" + win32_registry: + dependency: transitive + description: + name: win32_registry + sha256: "21ec76dfc731550fd3e2ce7a33a9ea90b828fdf19a5c3bcf556fa992cfa99852" + url: "https://pub.dev" + source: hosted + version: "1.1.5" xdg_directories: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index f9d0bb84..1af05d72 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -21,6 +21,7 @@ dependencies: clock: 1.1.1 collection: 1.18.0 crypto: 3.0.5 + device_info_plus: ^11.1.0 dio: ^5.7.0 dotted_border: 2.1.0 easy_localization: 3.0.6