diff --git a/Explorer/Assets/DCL/ApplicationGuards/ApplicationBlocklistGuard/BannedNotificationHandler.cs b/Explorer/Assets/DCL/ApplicationGuards/ApplicationBlocklistGuard/BannedNotificationHandler.cs index 94e8f19dd99..c4f1bb3876f 100644 --- a/Explorer/Assets/DCL/ApplicationGuards/ApplicationBlocklistGuard/BannedNotificationHandler.cs +++ b/Explorer/Assets/DCL/ApplicationGuards/ApplicationBlocklistGuard/BannedNotificationHandler.cs @@ -20,7 +20,7 @@ public class BannedNotificationHandler : IDisposable private readonly IWeb3IdentityCache identityCache; private readonly ModerationDataProvider moderationDataProvider; private readonly IMVCManager mvcManager; - private readonly IWebBrowser webBrowser; + private readonly UnityAppWebBrowser webBrowser; private CancellationTokenSource cts = new (); @@ -30,7 +30,7 @@ public BannedNotificationHandler( IWeb3IdentityCache identityCache, ModerationDataProvider moderationDataProvider, IMVCManager mvcManager, - IWebBrowser webBrowser) + UnityAppWebBrowser webBrowser) { this.webRequestController = webRequestController; this.urlsSource = urlsSource; @@ -47,7 +47,7 @@ public void Dispose() => cts.SafeCancelAndDispose(); private void OnBanWarningNotificationClicked(object[] parameters) => - webBrowser.OpenUrl(urlsSource.Url(DecentralandUrl.SupportLink)); + webBrowser.OpenUrlMainThreadOnly(urlsSource.Url(DecentralandUrl.SupportLink)); private void OnBannedNotificationClicked(object[] parameters) { diff --git a/Explorer/Assets/DCL/ApplicationGuards/ApplicationBlocklistGuard/BlockedScreenController.cs b/Explorer/Assets/DCL/ApplicationGuards/ApplicationBlocklistGuard/BlockedScreenController.cs index 12aede9cab2..8d5f38547f0 100644 --- a/Explorer/Assets/DCL/ApplicationGuards/ApplicationBlocklistGuard/BlockedScreenController.cs +++ b/Explorer/Assets/DCL/ApplicationGuards/ApplicationBlocklistGuard/BlockedScreenController.cs @@ -14,12 +14,12 @@ public class BlockedScreenController : ControllerBase CanvasOrdering.SortingLayer.OVERLAY; - public BlockedScreenController(ViewFactoryMethod viewFactory, IWebBrowser webBrowser) : base(viewFactory) + public BlockedScreenController(ViewFactoryMethod viewFactory, UnityAppWebBrowser webBrowser) : base(viewFactory) { this.webBrowser = webBrowser; } @@ -66,7 +66,7 @@ public override void Dispose() private void OnSupportClicked() { - webBrowser.OpenUrl(DecentralandUrl.Help); + webBrowser.OpenUrlMainThreadOnly(DecentralandUrl.Help); } private static string FormatRemainingBanTime(string expiresAt) diff --git a/Explorer/Assets/DCL/ApplicationGuards/ApplicationMinimumSpecsGuard/UI/MinimumSpecsScreenController.cs b/Explorer/Assets/DCL/ApplicationGuards/ApplicationMinimumSpecsGuard/UI/MinimumSpecsScreenController.cs index aa2c942b515..874352d7c3a 100644 --- a/Explorer/Assets/DCL/ApplicationGuards/ApplicationMinimumSpecsGuard/UI/MinimumSpecsScreenController.cs +++ b/Explorer/Assets/DCL/ApplicationGuards/ApplicationMinimumSpecsGuard/UI/MinimumSpecsScreenController.cs @@ -11,7 +11,7 @@ namespace DCL.ApplicationGuards { public class MinimumSpecsScreenController : ControllerBase { - private readonly IWebBrowser webBrowser; + private readonly UnityAppWebBrowser webBrowser; private readonly IAnalyticsController analytics; private readonly IReadOnlyList specResult; public override CanvasOrdering.SortingLayer Layer => CanvasOrdering.SortingLayer.OVERLAY; @@ -20,7 +20,7 @@ public class MinimumSpecsScreenController : ControllerBase specResult) : base(viewFactory) { @@ -66,7 +66,7 @@ private void OnContinueClicked() private void OnReadMoreClicked() { - webBrowser.OpenUrl(DecentralandUrl.MinimumSpecs); + webBrowser.OpenUrlMainThreadOnly(DecentralandUrl.MinimumSpecs); } protected override UniTask WaitForCloseIntentAsync(CancellationToken ct) => diff --git a/Explorer/Assets/DCL/ApplicationGuards/ApplicationVersionGuard/ApplicationVersionGuard.cs b/Explorer/Assets/DCL/ApplicationGuards/ApplicationVersionGuard/ApplicationVersionGuard.cs index ca18d9d4e68..443110c2f54 100644 --- a/Explorer/Assets/DCL/ApplicationGuards/ApplicationVersionGuard/ApplicationVersionGuard.cs +++ b/Explorer/Assets/DCL/ApplicationGuards/ApplicationVersionGuard/ApplicationVersionGuard.cs @@ -31,9 +31,9 @@ public class ApplicationVersionGuard private const string DECENTRALAND_LEGACY_LAUNCHER_MAC_X_64_DMG = "Decentraland Outdated-mac-x64.dmg"; private readonly IWebRequestController webRequestController; - private readonly IWebBrowser webBrowser; + private readonly UnityAppWebBrowser webBrowser; - public ApplicationVersionGuard(IWebRequestController webRequestController, IWebBrowser webBrowser) + public ApplicationVersionGuard(IWebRequestController webRequestController, UnityAppWebBrowser webBrowser) { this.webRequestController = webRequestController; this.webBrowser = webBrowser; @@ -89,7 +89,7 @@ private void DownloadLauncher() string downloadUrl = $"{GetLauncherDownloadPath()}/{assetName}"; if (!string.IsNullOrEmpty(downloadUrl)) - webBrowser.OpenUrl(downloadUrl); + webBrowser.OpenUrlMainThreadOnly(downloadUrl); else ReportHub.LogError(ReportCategory.VERSION_CONTROL, "Failed to get launcher download URL."); } diff --git a/Explorer/Assets/DCL/AuthenticationScreenFlow/AuthenticationScreenController.cs b/Explorer/Assets/DCL/AuthenticationScreenFlow/AuthenticationScreenController.cs index 22f49b29d4b..35918d0b417 100644 --- a/Explorer/Assets/DCL/AuthenticationScreenFlow/AuthenticationScreenController.cs +++ b/Explorer/Assets/DCL/AuthenticationScreenFlow/AuthenticationScreenController.cs @@ -52,7 +52,7 @@ public enum AuthStatus private readonly ICompositeWeb3Provider web3Authenticator; private readonly ISelfProfile selfProfile; - private readonly IWebBrowser webBrowser; + private readonly UnityAppWebBrowser webBrowser; private readonly IWeb3IdentityCache storedIdentityProvider; private readonly ICharacterPreviewFactory characterPreviewFactory; private readonly SplashScreen splashScreen; @@ -99,7 +99,7 @@ public AuthenticationScreenController( ViewFactoryMethod viewFactory, ICompositeWeb3Provider web3Authenticator, ISelfProfile selfProfile, - IWebBrowser webBrowser, + UnityAppWebBrowser webBrowser, IWeb3IdentityCache storedIdentityProvider, ICharacterPreviewFactory characterPreviewFactory, SplashScreen splashScreen, @@ -165,7 +165,7 @@ protected override void OnViewInstantiated() new InitAuthState(viewInstance, installSource), new LoginSelectionAuthState(fsm, viewInstance, this, CurrentState, splashScreen, web3Authenticator, webBrowser, enableEmailOTP), new ProfileFetchingAuthState(fsm, viewInstance, this, CurrentState, selfProfile, storedIdentityProvider), - new IdentityVerificationDappAuthState(fsm, viewInstance, this, CurrentState, web3Authenticator), + new IdentityVerificationDappDeepLinkAuthState(fsm, viewInstance, this, CurrentState, web3Authenticator), new LobbyForExistingAccountAuthState(fsm, viewInstance, this, splashScreen, CurrentState, characterPreviewController), new LobbyForNewAccountAuthState(fsm, viewInstance, this, CurrentState, characterPreviewController, selfProfile, wearablesProvider, webBrowser, webRequestController, decentralandUrlsSource, profileChangesBus) ); @@ -212,7 +212,7 @@ private async UniTaskVoid TryAutoLoginAndProceedAsync(IWeb3Identity storedIdenti bool autoLoginSuccess = await web3Authenticator.TryAutoLoginAsync(ct); if (autoLoginSuccess) - fsm.Enter(new (storedIdentity, storedIdentity.Source != IWeb3Identity.Web3IdentitySource.TokenFile, ct)); + fsm.Enter(new (storedIdentity, storedIdentity.Source != IWeb3Identity.Web3IdentitySource.TOKEN_FILE, ct)); else { fsm.Enter(UIAnimationHashes.IN, true); @@ -289,7 +289,7 @@ async UniTaskVoid ChangeAccountAsync(CancellationToken ct) private void OpenSupportUrl() { - webBrowser.OpenUrl(DecentralandUrl.SupportLink); + webBrowser.OpenUrlMainThreadOnly(DecentralandUrl.SupportLink); DiscordButtonClicked?.Invoke(); } diff --git a/Explorer/Assets/DCL/AuthenticationScreenFlow/States/IdentityVerificationDappAuthState.cs.meta b/Explorer/Assets/DCL/AuthenticationScreenFlow/States/IdentityVerificationDappAuthState.cs.meta deleted file mode 100644 index 8198611de28..00000000000 --- a/Explorer/Assets/DCL/AuthenticationScreenFlow/States/IdentityVerificationDappAuthState.cs.meta +++ /dev/null @@ -1,3 +0,0 @@ -fileFormatVersion: 2 -guid: a598c3ba1e1c43c7bb50b4629218ecee -timeCreated: 1766517747 \ No newline at end of file diff --git a/Explorer/Assets/DCL/AuthenticationScreenFlow/States/IdentityVerificationDappAuthState.cs b/Explorer/Assets/DCL/AuthenticationScreenFlow/States/IdentityVerificationDappDeepLinkAuthState.cs similarity index 59% rename from Explorer/Assets/DCL/AuthenticationScreenFlow/States/IdentityVerificationDappAuthState.cs rename to Explorer/Assets/DCL/AuthenticationScreenFlow/States/IdentityVerificationDappDeepLinkAuthState.cs index fe8289c4c23..81ca9d02e00 100644 --- a/Explorer/Assets/DCL/AuthenticationScreenFlow/States/IdentityVerificationDappAuthState.cs +++ b/Explorer/Assets/DCL/AuthenticationScreenFlow/States/IdentityVerificationDappDeepLinkAuthState.cs @@ -1,6 +1,5 @@ using Cysharp.Threading.Tasks; using DCL.Diagnostics; -using DCL.PerformanceAndDiagnostics; using DCL.Utilities; using DCL.Web3; using DCL.Web3.Authenticators; @@ -14,17 +13,16 @@ namespace DCL.AuthenticationScreenFlow { - public class IdentityVerificationDappAuthState : AuthStateBase, IPayloadedState<(LoginMethod method, CancellationToken ct)> + public class IdentityVerificationDappDeepLinkAuthState : AuthStateBase, IPayloadedState<(LoginMethod method, CancellationToken ct)> { private readonly MVCStateMachine machine; - private readonly VerificationDappAuthView view; private readonly AuthenticationScreenController controller; private readonly ReactiveProperty currentState; private readonly ICompositeWeb3Provider compositeWeb3Provider; private Exception? loginException; - public IdentityVerificationDappAuthState( + public IdentityVerificationDappDeepLinkAuthState( MVCStateMachine machine, AuthenticationScreenView viewInstance, AuthenticationScreenController controller, @@ -32,7 +30,6 @@ public IdentityVerificationDappAuthState( ICompositeWeb3Provider compositeWeb3Provider) : base(viewInstance) { this.machine = machine; - view = viewInstance.VerificationDappAuthView; this.controller = controller; this.currentState = currentState; this.compositeWeb3Provider = compositeWeb3Provider; @@ -49,33 +46,23 @@ public void Enter((LoginMethod method, CancellationToken ct) payload) controller.CurrentRequestID = string.Empty; + currentState.Value = AuthStatus.VerificationRequested; AuthenticateAsync(payload.method, payload.ct).Forget(); } public override void Exit() { - if (loginException == null) + if (loginException != null) { - view.Hide(OUT); - - // Hide login selection view if still visible (social logins skip the verification step, - // so ShowVerification is never called and the login selection view remains active) - if (viewInstance.LoginSelectionAuthView.gameObject.activeSelf) - viewInstance.LoginSelectionAuthView.Hide(); - } - else - { - if (currentState.Value == AuthStatus.VerificationRequested) - view.Hide(SLIDE); - spanErrorInfo = loginException switch { - OperationCanceledException => new SpanErrorInfo("Login process was cancelled by user"), - SignatureExpiredException ex => new SpanErrorInfo("Web3 signature expired during authentication", ex), - Web3SignatureException ex => new SpanErrorInfo("Web3 signature validation failed", ex), - CodeVerificationException ex => new SpanErrorInfo("Code verification failed during authentication", ex), - Web3Exception ex => new SpanErrorInfo("Connection error during authentication flow", ex), - Exception ex => new SpanErrorInfo("Unexpected error during authentication flow", ex), + OperationCanceledException ex => new SpanErrorInfo("Login process was cancelled by user", ex), + TimeoutException ex => new SpanErrorInfo("Deep-link sign-in timed out waiting for the browser to deliver the signin deep link", ex), + SignatureExpiredException ex => new SpanErrorInfo("Web3 signature expired during deep-link authentication", ex), + Web3SignatureException ex => new SpanErrorInfo("Web3 signature validation failed during deep-link authentication", ex), + DeeplinkSigninRetrievalException ex => new SpanErrorInfo($"Signin identity retrieval failed: {ex.Reason}", ex), + Web3Exception ex => new SpanErrorInfo("Connection error during deep-link authentication flow", ex), + { } ex => new SpanErrorInfo("Unexpected error during deep-link authentication flow", ex), }; if (loginException is not OperationCanceledException) @@ -83,7 +70,6 @@ public override void Exit() } NativeWindowManager.ReleaseTemporaryWindowMode(); - view.BackButton.onClick.RemoveListener(controller.CancelLoginProcess); base.Exit(); } @@ -91,8 +77,8 @@ private async UniTaskVoid AuthenticateAsync(LoginMethod method, CancellationToke { try { - compositeWeb3Provider.VerificationRequired += ShowVerification; IWeb3Identity identity = await compositeWeb3Provider.LoginAsync(LoginPayload.ForDappFlow(method), ct); + viewInstance.LoginSelectionAuthView.Hide(); machine.Enter(new (identity, false, ct)); } catch (OperationCanceledException e) @@ -100,17 +86,17 @@ private async UniTaskVoid AuthenticateAsync(LoginMethod method, CancellationToke loginException = e; machine.Enter(SLIDE); } - catch (SignatureExpiredException e) + catch (TimeoutException e) { loginException = e; machine.Enter(SLIDE); } - catch (Web3SignatureException e) + catch (SignatureExpiredException e) { loginException = e; machine.Enter(SLIDE); } - catch (CodeVerificationException e) + catch (Web3SignatureException e) { loginException = e; machine.Enter(SLIDE); @@ -125,32 +111,6 @@ private async UniTaskVoid AuthenticateAsync(LoginMethod method, CancellationToke loginException = e; machine.Enter(ErrorType.CONNECTION_ERROR); } - finally - { - compositeWeb3Provider.VerificationRequired -= ShowVerification; - } - } - - private void ShowVerification((int code, DateTime expiration, string requestId) data) - { - compositeWeb3Provider.VerificationRequired -= ShowVerification; - - controller.CurrentRequestID = data.requestId; - currentState.Value = AuthStatus.VerificationRequested; - - SentryTransactionNameMapping.Instance.StartSpan(LOADING_TRANSACTION_NAME, new SpanData - { - SpanName = "CodeVerification", - SpanOperation = "auth.code_verification", - Depth = STATE_SPAN_DEPTH + 1, - }); - - // Hide non-interactable Login Screen - viewInstance.LoginSelectionAuthView.Hide(); - - // Show Verification Screen - view.Show(data.code, data.expiration); - view.BackButton.onClick.AddListener(controller.CancelLoginProcess); } } } diff --git a/Explorer/Assets/DCL/AuthenticationScreenFlow/States/IdentityVerificationDappDeepLinkAuthState.cs.meta b/Explorer/Assets/DCL/AuthenticationScreenFlow/States/IdentityVerificationDappDeepLinkAuthState.cs.meta new file mode 100644 index 00000000000..ff88a635015 --- /dev/null +++ b/Explorer/Assets/DCL/AuthenticationScreenFlow/States/IdentityVerificationDappDeepLinkAuthState.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 751b79780c1444718391d7d388ae0fff +timeCreated: 1766517747 diff --git a/Explorer/Assets/DCL/AuthenticationScreenFlow/States/LobbyForNewAccountAuthState.cs b/Explorer/Assets/DCL/AuthenticationScreenFlow/States/LobbyForNewAccountAuthState.cs index 9ffe2346679..02e25641e2d 100644 --- a/Explorer/Assets/DCL/AuthenticationScreenFlow/States/LobbyForNewAccountAuthState.cs +++ b/Explorer/Assets/DCL/AuthenticationScreenFlow/States/LobbyForNewAccountAuthState.cs @@ -33,7 +33,7 @@ public class LobbyForNewAccountAuthState : AuthStateBase, IPayloadedState<(Profi private readonly LobbyForNewAccountAuthView view; private readonly IWearablesProvider wearablesProvider; - private readonly IWebBrowser webBrowser; + private readonly UnityAppWebBrowser webBrowser; private readonly IWebRequestController webRequestController; private readonly IDecentralandUrlsSource decentralandUrlsSource; private readonly ProfileChangesBus profileChangesBus; @@ -57,7 +57,7 @@ public LobbyForNewAccountAuthState(MVCStateMachine fsm, AuthenticationScreenCharacterPreviewController characterPreviewController, ISelfProfile selfProfile, IWearablesProvider wearablesProvider, - IWebBrowser webBrowser, + UnityAppWebBrowser webBrowser, IWebRequestController webRequestController, IDecentralandUrlsSource decentralandUrlsSource, ProfileChangesBus profileChangesBus) : base(viewInstance) @@ -161,7 +161,7 @@ private void ReparentCharacterPreview() } private void OpenClickableURL(string url) => - webBrowser.OpenUrl(url); + webBrowser.OpenUrlMainThreadOnly(url); private async UniTask InitializeAvatarAsync() { diff --git a/Explorer/Assets/DCL/AuthenticationScreenFlow/States/LoginSelectionAuthState.cs b/Explorer/Assets/DCL/AuthenticationScreenFlow/States/LoginSelectionAuthState.cs index e403038f4bf..62f0a63bc78 100644 --- a/Explorer/Assets/DCL/AuthenticationScreenFlow/States/LoginSelectionAuthState.cs +++ b/Explorer/Assets/DCL/AuthenticationScreenFlow/States/LoginSelectionAuthState.cs @@ -22,13 +22,13 @@ public class LoginSelectionAuthState : AuthStateBase, IState, IPayloadedState currentState; private readonly SplashScreen splashScreen; private readonly ICompositeWeb3Provider compositeWeb3Provider; - private readonly IWebBrowser webBrowser; + private readonly UnityAppWebBrowser webBrowser; private readonly bool enableEmailOTP; public LoginSelectionAuthState(MVCStateMachine machine, AuthenticationScreenView viewInstance, AuthenticationScreenController controller, ReactiveProperty currentState, SplashScreen splashScreen, - ICompositeWeb3Provider compositeWeb3Provider, IWebBrowser webBrowser, bool enableEmailOTP) : base(viewInstance) + ICompositeWeb3Provider compositeWeb3Provider, UnityAppWebBrowser webBrowser, bool enableEmailOTP) : base(viewInstance) { view = viewInstance.LoginSelectionAuthView; @@ -174,7 +174,7 @@ private void Login(LoginMethod method) currentState.Value = AuthStatus.LoginRequested; view.SetLoadingSpinnerVisibility(true); - machine.Enter((method, controller.GetRestartedLoginToken())); + machine.Enter((method, controller.GetRestartedLoginToken())); } private void OTPLogin() @@ -202,7 +202,7 @@ private void CloseErrorPopup() => view.ErrorPopupRoot.SetActive(false); private void RequestAlphaAccess() => - webBrowser.OpenUrl(REQUEST_BETA_ACCESS_LINK); + webBrowser.OpenUrlMainThreadOnly(REQUEST_BETA_ACCESS_LINK); } public enum ErrorType diff --git a/Explorer/Assets/DCL/Backpack/AvatarSection/AvatarController.cs b/Explorer/Assets/DCL/Backpack/AvatarSection/AvatarController.cs index 54d7b5886d4..97eae67be80 100644 --- a/Explorer/Assets/DCL/Backpack/AvatarSection/AvatarController.cs +++ b/Explorer/Assets/DCL/Backpack/AvatarSection/AvatarController.cs @@ -15,7 +15,7 @@ public class AvatarController : ISection, IDisposable { private readonly AvatarView view; private readonly RectTransform rectTransform; - private readonly IWebBrowser webBrowser; + private readonly UnityAppWebBrowser webBrowser; private readonly BackpackSlotsController slotsController; private readonly CategoriesPresenter categoriesPresenter; private readonly OutfitsPresenter outfitsPresenter; @@ -28,7 +28,7 @@ public class AvatarController : ISection, IDisposable private readonly URLParameter marketplaceSourceParam = new ("utm_source", "backpack"); public AvatarController(AvatarView view, - IWebBrowser webBrowser, + UnityAppWebBrowser webBrowser, AvatarSlotView[] slotViews, NftTypeIconSO rarityBackgrounds, BackpackCommandBus backpackCommandBus, @@ -77,7 +77,7 @@ private void OnOpenMarketplace() urlBuilder.Clear(); urlBuilder.AppendDomain(URLDomain.FromString(decentralandUrlsSource.Url(DecentralandUrl.Market))); urlBuilder.AppendParameter(marketplaceSourceParam); - webBrowser.OpenUrl(urlBuilder.Build()); + webBrowser.OpenUrlMainThreadOnly(urlBuilder.Build()); } public void Dispose() diff --git a/Explorer/Assets/DCL/Backpack/AvatarSection/Outfits/OutfitsPresenter.cs b/Explorer/Assets/DCL/Backpack/AvatarSection/Outfits/OutfitsPresenter.cs index d4bc9e0c5df..253a586486d 100644 --- a/Explorer/Assets/DCL/Backpack/AvatarSection/Outfits/OutfitsPresenter.cs +++ b/Explorer/Assets/DCL/Backpack/AvatarSection/Outfits/OutfitsPresenter.cs @@ -33,7 +33,7 @@ public class OutfitsPresenter : ISection, IDisposable private readonly IEventBus eventBus; private readonly IBackpackEventBus backpackEventBus; private readonly IEquippedWearables equippedWearables; - private readonly IWebBrowser webBrowser; + private readonly UnityAppWebBrowser webBrowser; private readonly OutfitApplier outfitApplier; private readonly OutfitBannerPresenter outfitBannerPresenter; private readonly OutfitsCollection outfitsCollection; @@ -58,7 +58,7 @@ public OutfitsPresenter(OutfitsView view, IBackpackEventBus backpackEventBus, OutfitApplier outfitApplier, OutfitsCollection outfitsCollection, - IWebBrowser webBrowser, + UnityAppWebBrowser webBrowser, IEquippedWearables equippedWearables, LoadOutfitsCommand loadOutfitsCommand, SaveOutfitCommand saveOutfitCommand, @@ -519,13 +519,13 @@ private void UpdateFirstEmptySlotPrompt() private void OnLinkClicked(string url) { - webBrowser.OpenUrl(url); + webBrowser.OpenUrlMainThreadOnly(url); } private void OnGetANameClicked() { - webBrowser.OpenUrl("https://decentraland.org/marketplace/names/claim"); + webBrowser.OpenUrlMainThreadOnly("https://decentraland.org/marketplace/names/claim"); eventBus.Publish(new OutfitsEvents.ClaimExtraOutfitsEvent()); } diff --git a/Explorer/Assets/DCL/Backpack/BackpackController.cs b/Explorer/Assets/DCL/Backpack/BackpackController.cs index 305bb1a2552..8a8881b1e15 100644 --- a/Explorer/Assets/DCL/Backpack/BackpackController.cs +++ b/Explorer/Assets/DCL/Backpack/BackpackController.cs @@ -63,7 +63,7 @@ public class BackpackController : ISection, IDisposable public BackpackController( BackpackView view, ISelfProfile selfProfile, - IWebBrowser webBrowser, + UnityAppWebBrowser webBrowser, AvatarView avatarView, NftTypeIconSO rarityInfoPanelBackgrounds, BackpackCommandBus backpackCommandBus, diff --git a/Explorer/Assets/DCL/Backpack/BackpackGridController.cs b/Explorer/Assets/DCL/Backpack/BackpackGridController.cs index 50d306a43c8..1a9356edb53 100644 --- a/Explorer/Assets/DCL/Backpack/BackpackGridController.cs +++ b/Explorer/Assets/DCL/Backpack/BackpackGridController.cs @@ -43,7 +43,7 @@ public class BackpackGridController : IDisposable private readonly IObjectPool gridItemsPool; private readonly IThumbnailProvider thumbnailProvider; private readonly IWearablesProvider wearablesProvider; - private readonly IWebBrowser webBrowser; + private readonly UnityAppWebBrowser webBrowser; private readonly IWearableStorage wearableStorage; private readonly SmartWearableCache smartWearableCache; private readonly IMVCManager mvcManager; @@ -77,7 +77,7 @@ public BackpackGridController(BackpackGridView view, IObjectPool gridItemsPool, IThumbnailProvider thumbnailProvider, IWearablesProvider wearablesProvider, - IWebBrowser webBrowser, + UnityAppWebBrowser webBrowser, ColorToggleView colorToggle, ColorPresetsSO hairColors, ColorPresetsSO eyesColors, @@ -523,6 +523,6 @@ private void UpdateBodyShapeCompatibility(IReadOnlyList wearab } private void OpenMarketplaceLink(string url) => - webBrowser.OpenUrl(url); + webBrowser.OpenUrlMainThreadOnly(url); } } diff --git a/Explorer/Assets/DCL/Backpack/EmotesSection/BackpackEmoteGridController.cs b/Explorer/Assets/DCL/Backpack/EmotesSection/BackpackEmoteGridController.cs index 720fe230b76..39fa8286df8 100644 --- a/Explorer/Assets/DCL/Backpack/EmotesSection/BackpackEmoteGridController.cs +++ b/Explorer/Assets/DCL/Backpack/EmotesSection/BackpackEmoteGridController.cs @@ -47,7 +47,7 @@ public class BackpackEmoteGridController : IDisposable private readonly IObjectPool gridItemsPool; private readonly IEmoteProvider emoteProvider; private readonly IThumbnailProvider thumbnailProvider; - private readonly IWebBrowser webBrowser; + private readonly UnityAppWebBrowser webBrowser; private readonly IEmoteStorage emoteStorage; private readonly IPendingTransferService ownedNftFilter; @@ -71,7 +71,7 @@ public BackpackEmoteGridController( IObjectPool gridItemsPool, IEmoteProvider emoteProvider, IThumbnailProvider thumbnailProvider, - IWebBrowser webBrowser, + UnityAppWebBrowser webBrowser, IEmoteStorage emoteStorage, IPendingTransferService ownedNftFilter) { @@ -459,6 +459,6 @@ private void OnWearableEquipped(IWearable wearable, bool isManuallyEquipped) } private void OpenMarketplaceLink(string url) => - webBrowser.OpenUrl(url); + webBrowser.OpenUrlMainThreadOnly(url); } } diff --git a/Explorer/Assets/DCL/Backpack/Gifting/Presenters/GiftTransfer/GiftTransferController.cs b/Explorer/Assets/DCL/Backpack/Gifting/Presenters/GiftTransfer/GiftTransferController.cs index cfbbeb42263..a86f9dfcffe 100644 --- a/Explorer/Assets/DCL/Backpack/Gifting/Presenters/GiftTransfer/GiftTransferController.cs +++ b/Explorer/Assets/DCL/Backpack/Gifting/Presenters/GiftTransfer/GiftTransferController.cs @@ -30,7 +30,7 @@ private enum State { Waiting, Success, Failed } private State currentState; private readonly IEventBus eventBus; - private readonly IWebBrowser webBrowser; + private readonly UnityAppWebBrowser webBrowser; private readonly IMVCManager mvcManager; private readonly IDecentralandUrlsSource decentralandUrlsSource; private readonly GiftTransferRequestCommand giftTransferRequestCommand; @@ -41,7 +41,7 @@ private enum State { Waiting, Success, Failed } private CancellationTokenSource? delayCts; public GiftTransferController(ViewFactoryMethod viewFactory, - IWebBrowser webBrowser, + UnityAppWebBrowser webBrowser, IEventBus eventBus, IMVCManager mvcManager, IDecentralandUrlsSource decentralandUrlsSource, @@ -292,7 +292,7 @@ private async UniTask ShowErrorPopupAsync(CancellationToken ct) private void LinkCallback(string url) { - webBrowser.OpenUrl(url); + webBrowser.OpenUrlMainThreadOnly(url); } } } diff --git a/Explorer/Assets/DCL/Communities/CommunitiesBrowser/CommunitiesBrowserController.cs b/Explorer/Assets/DCL/Communities/CommunitiesBrowser/CommunitiesBrowserController.cs index 161f98a214a..0829c36ca68 100644 --- a/Explorer/Assets/DCL/Communities/CommunitiesBrowser/CommunitiesBrowserController.cs +++ b/Explorer/Assets/DCL/Communities/CommunitiesBrowser/CommunitiesBrowserController.cs @@ -63,7 +63,7 @@ public class CommunitiesBrowserController : ISection, IDisposable private readonly IAnalyticsController analytics; private readonly CommunityDataService communityDataService; private readonly ILoadingStatus loadingStatus; - private readonly IWebBrowser webBrowser; + private readonly UnityAppWebBrowser webBrowser; private readonly IDecentralandUrlsSource decentralandUrlsSource; private readonly CommunitiesBrowserMyCommunitiesPresenter myCommunitiesPresenter; @@ -101,7 +101,7 @@ public CommunitiesBrowserController( IAnalyticsController analytics, CommunityDataService communityDataService, ILoadingStatus loadingStatus, - IWebBrowser webBrowser, + UnityAppWebBrowser webBrowser, IDecentralandUrlsSource decentralandUrlsSource) { this.view = view; diff --git a/Explorer/Assets/DCL/Communities/CommunitiesCard/CommunityCardController.cs b/Explorer/Assets/DCL/Communities/CommunitiesCard/CommunityCardController.cs index e06ad205f07..061d0a30514 100644 --- a/Explorer/Assets/DCL/Communities/CommunitiesCard/CommunityCardController.cs +++ b/Explorer/Assets/DCL/Communities/CommunitiesCard/CommunityCardController.cs @@ -76,7 +76,7 @@ public class CommunityCardController : ControllerBase eventsFetchData = new (PAGE_SIZE); @@ -58,7 +58,7 @@ public EventListController(EventListView view, ThumbnailLoader thumbnailLoader, IMVCManager mvcManager, ISystemClipboard clipboard, - IWebBrowser webBrowser, + UnityAppWebBrowser webBrowser, IRealmNavigator realmNavigator, IDecentralandUrlsSource decentralandUrlsSource) : base(view, PAGE_SIZE) { @@ -101,7 +101,7 @@ public override void Dispose() } private void OnCreateEventButtonClicked() => - webBrowser.OpenUrl(string.Format(createEventFormat, communityData?.id)); + webBrowser.OpenUrlMainThreadOnly(string.Format(createEventFormat, communityData?.id)); private void OnEventCopyLinkButtonClicked(PlaceAndEventDTO eventData) { @@ -111,7 +111,7 @@ private void OnEventCopyLinkButtonClicked(PlaceAndEventDTO eventData) } private void OnEventShareButtonClicked(PlaceAndEventDTO eventData) => - webBrowser.OpenUrl($"{EventUtilities.GetEventShareLink(eventData.Event, decentralandUrlsSource)}&utm_source=explorer&utm_campaign=communities"); + webBrowser.OpenUrlMainThreadOnly($"{EventUtilities.GetEventShareLink(eventData.Event, decentralandUrlsSource)}&utm_source=explorer&utm_campaign=communities"); private void OnInterestedButtonClicked(PlaceAndEventDTO eventData, EventListItemView eventItemView) { diff --git a/Explorer/Assets/DCL/Communities/CommunitiesCard/Members/MembersListController.cs b/Explorer/Assets/DCL/Communities/CommunitiesCard/Members/MembersListController.cs index 600b2becb4b..8318b68889e 100644 --- a/Explorer/Assets/DCL/Communities/CommunitiesCard/Members/MembersListController.cs +++ b/Explorer/Assets/DCL/Communities/CommunitiesCard/Members/MembersListController.cs @@ -51,7 +51,7 @@ public class MembersListController : CommunityFetchingControllerBase> sectionsFetchData = new (); @@ -88,7 +88,7 @@ public MembersListController(MembersListView view, ChatEventBus chatEventBus, IWeb3IdentityCache web3IdentityCache, ISelfProfile selfProfile, - IWebBrowser webBrowser, + UnityAppWebBrowser webBrowser, IDecentralandUrlsSource decentralandUrlsSource) : base(view, PAGE_SIZE) { this.view = view; diff --git a/Explorer/Assets/DCL/Communities/CommunitiesCard/Places/PlacesSectionController.cs b/Explorer/Assets/DCL/Communities/CommunitiesCard/Places/PlacesSectionController.cs index 7574c6b895a..6bead89fdc9 100644 --- a/Explorer/Assets/DCL/Communities/CommunitiesCard/Places/PlacesSectionController.cs +++ b/Explorer/Assets/DCL/Communities/CommunitiesCard/Places/PlacesSectionController.cs @@ -69,7 +69,7 @@ public PlacesSectionController(PlacesSectionView view, IRealmNavigator realmNavigator, IMVCManager mvcManager, ISystemClipboard clipboard, - IWebBrowser webBrowser, + UnityAppWebBrowser webBrowser, IProfileRepository profileRepository, IDecentralandUrlsSource dclUrlSource, HomePlaceEventBus homePlaceEventBus, diff --git a/Explorer/Assets/DCL/Communities/CommunityCreation/CommunityCreationEditionController.cs b/Explorer/Assets/DCL/Communities/CommunityCreation/CommunityCreationEditionController.cs index a4d28e2bad9..9383b82f506 100644 --- a/Explorer/Assets/DCL/Communities/CommunityCreation/CommunityCreationEditionController.cs +++ b/Explorer/Assets/DCL/Communities/CommunityCreation/CommunityCreationEditionController.cs @@ -47,7 +47,7 @@ public class CommunityCreationEditionController : ControllerBase - webBrowser.OpenUrl(DecentralandUrl.MarketplaceClaimName); + webBrowser.OpenUrlMainThreadOnly(DecentralandUrl.MarketplaceClaimName); private void DisableShortcutsInput() => inputBlock.Disable(InputMapComponent.Kind.SHORTCUTS, InputMapComponent.Kind.IN_WORLD_CAMERA); @@ -615,10 +615,10 @@ private void OpenContentPolicyAndCodeOfEthicsLink(string id) switch (id) { case CONTENT_POLICY_LINK_ID: - webBrowser.OpenUrl(DecentralandUrl.ContentPolicy); + webBrowser.OpenUrlMainThreadOnly(DecentralandUrl.ContentPolicy); break; case CODE_AND_ETHICS_LINK_ID: - webBrowser.OpenUrl(DecentralandUrl.CodeOfEthics); + webBrowser.OpenUrlMainThreadOnly(DecentralandUrl.CodeOfEthics); break; } diff --git a/Explorer/Assets/DCL/Donations/UI/DonationsPanelController.cs b/Explorer/Assets/DCL/Donations/UI/DonationsPanelController.cs index 3c04706f21e..ac39fe8c206 100644 --- a/Explorer/Assets/DCL/Donations/UI/DonationsPanelController.cs +++ b/Explorer/Assets/DCL/Donations/UI/DonationsPanelController.cs @@ -35,7 +35,7 @@ public class DonationsPanelController : ControllerBase - webBrowser.OpenUrl(decentralandUrlsSource.Url(DecentralandUrl.Account)); + webBrowser.OpenUrlMainThreadOnly(decentralandUrlsSource.Url(DecentralandUrl.Account)); private void OnContactSupportRequested() => - webBrowser.OpenUrl(decentralandUrlsSource.Url(DecentralandUrl.Help)); + webBrowser.OpenUrlMainThreadOnly(decentralandUrlsSource.Url(DecentralandUrl.Help)); protected override void OnBeforeViewShow() { diff --git a/Explorer/Assets/DCL/Events/EventCardActionsController.cs b/Explorer/Assets/DCL/Events/EventCardActionsController.cs index d08366f9990..fbba43d67e7 100644 --- a/Explorer/Assets/DCL/Events/EventCardActionsController.cs +++ b/Explorer/Assets/DCL/Events/EventCardActionsController.cs @@ -29,14 +29,14 @@ public class EventCardActionsController private const string LINK_COPIED_MESSAGE = "Link copied to clipboard!"; private readonly HttpEventsApiService eventsApiService; - private readonly IWebBrowser webBrowser; + private readonly UnityAppWebBrowser webBrowser; private readonly IRealmNavigator realmNavigator; private readonly ISystemClipboard clipboard; private readonly IDecentralandUrlsSource decentralandUrlsSource; public EventCardActionsController( HttpEventsApiService eventsApiService, - IWebBrowser webBrowser, + UnityAppWebBrowser webBrowser, IRealmNavigator realmNavigator, ISystemClipboard clipboard, IDecentralandUrlsSource decentralandUrlsSource) @@ -74,13 +74,13 @@ public async UniTaskVoid SetEventAsInterestedAsync(IEventDTO eventData, EventCar public void AddEventToCalendar(IEventDTO eventData) { - webBrowser.OpenUrl($"{EventUtilities.GetEventAddToCalendarLink(eventData, decentralandUrlsSource)}&utm_source=explorer&utm_campaign=discover"); + webBrowser.OpenUrlMainThreadOnly($"{EventUtilities.GetEventAddToCalendarLink(eventData, decentralandUrlsSource)}&utm_source=explorer&utm_campaign=discover"); AddEventToCalendarClicked?.Invoke(eventData); } public void AddEventToCalendar(IEventDTO eventData, DateTime utcStart) { - webBrowser.OpenUrl($"{EventUtilities.GetEventAddToCalendarLink(eventData, utcStart, decentralandUrlsSource)}&utm_source=explorer&utm_campaign=discover"); + webBrowser.OpenUrlMainThreadOnly($"{EventUtilities.GetEventAddToCalendarLink(eventData, utcStart, decentralandUrlsSource)}&utm_source=explorer&utm_campaign=discover"); AddEventToCalendarClicked?.Invoke(eventData); } @@ -104,7 +104,7 @@ public void JumpInEvent(IEventDTO eventData, CancellationToken ct) public void ShareEvent(IEventDTO eventData) { - webBrowser.OpenUrl($"{EventUtilities.GetEventShareLink(eventData, decentralandUrlsSource)}&utm_source=explorer&utm_campaign=discover"); + webBrowser.OpenUrlMainThreadOnly($"{EventUtilities.GetEventShareLink(eventData, decentralandUrlsSource)}&utm_source=explorer&utm_campaign=discover"); EventShared?.Invoke(eventData); } diff --git a/Explorer/Assets/DCL/Events/EventDetailPanelController.cs b/Explorer/Assets/DCL/Events/EventDetailPanelController.cs index deb71fcdfa1..d32efadc3f8 100644 --- a/Explorer/Assets/DCL/Events/EventDetailPanelController.cs +++ b/Explorer/Assets/DCL/Events/EventDetailPanelController.cs @@ -1,32 +1,16 @@ using Cysharp.Threading.Tasks; using DCL.Events; using DCL.EventsApi; -using DCL.NotificationsBus; -using DCL.NotificationsBus.NotificationTypes; -using DCL.UI; -using DCL.Utilities.Extensions; -using DCL.WebRequests; using MVC; using System; using System.Threading; -using CommunicationData.URLHelpers; -using DCL.Browser; -using DCL.Clipboard; -using DCL.CommunicationData.URLHelpers; -using UnityEngine; using Utility; namespace DCL.Communities.EventInfo { public class EventDetailPanelController : ControllerBase { - private const string LINK_COPIED_MESSAGE = "Link copied to clipboard!"; - private const string INTERESTED_CHANGED_ERROR_MESSAGE = "There was an error changing your interest on the event. Please try again."; - private readonly EventCardActionsController eventCardActionsController; - private readonly ISystemClipboard clipboard; - private readonly IWebBrowser webBrowser; - private readonly HttpEventsApiService eventsApiService; public override CanvasOrdering.SortingLayer Layer => CanvasOrdering.SortingLayer.POPUP; @@ -35,19 +19,12 @@ public class EventDetailPanelController : ControllerBase public void GoToCreateEventPage(bool fromHeader) { - webBrowser.OpenUrl($"{decentralandUrlsSource.Url(DecentralandUrl.WhatsOnNewEventLink)}?utm_source=explorer&utm_campaign=discover"); + webBrowser.OpenUrlMainThreadOnly($"{decentralandUrlsSource.Url(DecentralandUrl.WhatsOnNewEventLink)}?utm_source=explorer&utm_campaign=discover"); CreateEventButtonClicked?.Invoke(fromHeader); } } diff --git a/Explorer/Assets/DCL/EventsApi/GoogleUserCalendar.cs b/Explorer/Assets/DCL/EventsApi/GoogleUserCalendar.cs index 65fd8190947..aecf3bdeb1e 100644 --- a/Explorer/Assets/DCL/EventsApi/GoogleUserCalendar.cs +++ b/Explorer/Assets/DCL/EventsApi/GoogleUserCalendar.cs @@ -13,10 +13,10 @@ public class GoogleUserCalendar private const string DATES_PARAM = "dates"; private const string DESCRIPTION_PARAM = "details"; - private readonly IWebBrowser webBrowser; + private readonly UnityAppWebBrowser webBrowser; private readonly URLBuilder urlBuilder = new (); - public GoogleUserCalendar(IWebBrowser webBrowser) + public GoogleUserCalendar(UnityAppWebBrowser webBrowser) { this.webBrowser = webBrowser; } @@ -31,7 +31,7 @@ public void Add(string title, string description, DateTime startAt, DateTime end .AppendParameter(new URLParameter(DATES_PARAM, $"{startAt:yyyyMMddTHHmmssZ}/{endAt:yyyyMMddTHHmmssZ}")) .AppendParameter(new URLParameter(DESCRIPTION_PARAM, description)); - webBrowser.OpenUrl(urlBuilder.Build()); + webBrowser.OpenUrlMainThreadOnly(urlBuilder.Build()); } } } diff --git a/Explorer/Assets/DCL/ExternalUrlPrompt/ExternalUrlPromptController.cs b/Explorer/Assets/DCL/ExternalUrlPrompt/ExternalUrlPromptController.cs index fade72b9c14..c2b9f1304b2 100644 --- a/Explorer/Assets/DCL/ExternalUrlPrompt/ExternalUrlPromptController.cs +++ b/Explorer/Assets/DCL/ExternalUrlPrompt/ExternalUrlPromptController.cs @@ -12,14 +12,14 @@ public partial class ExternalUrlPromptController : ControllerBase CanvasOrdering.SortingLayer.POPUP; - private readonly IWebBrowser webBrowser; + private readonly UnityAppWebBrowser webBrowser; private readonly ICursor cursor; private readonly List trustedDomains = new (); private Action resultCallback; public ExternalUrlPromptController( ViewFactoryMethod viewFactory, - IWebBrowser webBrowser, + UnityAppWebBrowser webBrowser, ICursor cursor) : base(viewFactory) { this.webBrowser = webBrowser; @@ -40,7 +40,7 @@ protected override void OnViewShow() if (trustedDomains.Contains(inputData.Uri.Host)) { - webBrowser.OpenUrl(inputData.Uri.OriginalString); + webBrowser.OpenUrlMainThreadOnly(inputData.Uri.OriginalString); viewInstance.CloseButton.OnClickAsync(CancellationToken.None).Forget(); return; } @@ -53,10 +53,10 @@ protected override void OnViewShow() case ExternalUrlPromptResultType.ApprovedTrusted: if (!trustedDomains.Contains(inputData.Uri.Host)) trustedDomains.Add(inputData.Uri.Host); - webBrowser.OpenUrl(inputData.Uri.OriginalString); + webBrowser.OpenUrlMainThreadOnly(inputData.Uri.OriginalString); break; case ExternalUrlPromptResultType.Approved: - webBrowser.OpenUrl(inputData.Uri.OriginalString); + webBrowser.OpenUrlMainThreadOnly(inputData.Uri.OriginalString); break; } }); diff --git a/Explorer/Assets/DCL/Friends/UI/FriendPanel/FriendsPanelController.cs b/Explorer/Assets/DCL/Friends/UI/FriendPanel/FriendsPanelController.cs index 77f1461c43c..2b38c7fbb7e 100644 --- a/Explorer/Assets/DCL/Friends/UI/FriendPanel/FriendsPanelController.cs +++ b/Explorer/Assets/DCL/Friends/UI/FriendPanel/FriendsPanelController.cs @@ -63,7 +63,7 @@ public FriendsPanelController(ViewFactoryMethod viewFactory, FriendsConnectivityStatusTracker friendsConnectivityStatusTracker, ProfileRepositoryWrapper profileDataProvider, IVoiceChatOrchestrator voiceChatOrchestrator, - IWebBrowser webBrowser, + UnityAppWebBrowser webBrowser, IDecentralandUrlsSource decentralandUrlsSource, ISelfProfile selfProfile) : base(viewFactory) { diff --git a/Explorer/Assets/DCL/Friends/UI/FriendPanel/Sections/Requests/RequestsSectionController.cs b/Explorer/Assets/DCL/Friends/UI/FriendPanel/Sections/Requests/RequestsSectionController.cs index f7432aa9d8f..3534b3d3b00 100644 --- a/Explorer/Assets/DCL/Friends/UI/FriendPanel/Sections/Requests/RequestsSectionController.cs +++ b/Explorer/Assets/DCL/Friends/UI/FriendPanel/Sections/Requests/RequestsSectionController.cs @@ -28,7 +28,7 @@ public class RequestsSectionController : FriendPanelSectionDoubleCollectionContr private readonly GenericContextMenu contextMenu; private readonly UserProfileContextMenuControlSettings userProfileContextMenuControlSettings; private readonly IPassportBridge passportBridge; - private readonly IWebBrowser webBrowser; + private readonly UnityAppWebBrowser webBrowser; private readonly IDecentralandUrlsSource decentralandUrlsSource; private readonly ISelfProfile selfProfile; @@ -45,7 +45,7 @@ public RequestsSectionController(RequestsSectionView view, RequestsRequestManager requestManager, IPassportBridge passportBridge, bool includeUserBlocking, - IWebBrowser webBrowser, + UnityAppWebBrowser webBrowser, IDecentralandUrlsSource decentralandUrlsSource, ISelfProfile selfProfile) : base(view, friendsService, friendEventBus, mvcManager, requestManager) diff --git a/Explorer/Assets/DCL/InWorldCamera/CameraReelGallery/CameraReelGalleryController.cs b/Explorer/Assets/DCL/InWorldCamera/CameraReelGallery/CameraReelGalleryController.cs index 1727c04b41d..756d80f8d2b 100644 --- a/Explorer/Assets/DCL/InWorldCamera/CameraReelGallery/CameraReelGalleryController.cs +++ b/Explorer/Assets/DCL/InWorldCamera/CameraReelGallery/CameraReelGalleryController.cs @@ -68,7 +68,7 @@ public delegate void ThumbnailClick( private readonly ICameraReelStorageService cameraReelStorageService; private readonly IDecentralandUrlsSource? decentralandUrlsSource; private readonly ISystemClipboard? systemClipboard; - private readonly IWebBrowser? webBrowser; + private readonly UnityAppWebBrowser? webBrowser; private readonly GalleryEventBus galleryEventBus; private readonly ReelGalleryPoolManager reelGalleryPoolManager; private readonly Dictionary monthViews = new (); @@ -100,7 +100,7 @@ public CameraReelGalleryController(CameraReelGalleryView view, bool useSignedRequest, GalleryEventBus galleryEventBus, CameraReelOptionButtonView? optionButtonView = null, - IWebBrowser? webBrowser = null, + UnityAppWebBrowser? webBrowser = null, IDecentralandUrlsSource? decentralandUrlsSource = null, ISystemClipboard? systemClipboard = null, CameraReelGalleryMessagesConfiguration? reelGalleryStringMessages = null, diff --git a/Explorer/Assets/DCL/InWorldCamera/InWorldCamera/Systems/InWorldCameraPlugin.cs b/Explorer/Assets/DCL/InWorldCamera/InWorldCamera/Systems/InWorldCameraPlugin.cs index 7a9cc9346bc..800a9632f7a 100644 --- a/Explorer/Assets/DCL/InWorldCamera/InWorldCamera/Systems/InWorldCameraPlugin.cs +++ b/Explorer/Assets/DCL/InWorldCamera/InWorldCamera/Systems/InWorldCameraPlugin.cs @@ -59,7 +59,7 @@ public class InWorldCameraPlugin : IDCLGlobalPlugin private readonly IMVCManager mvcManager; private readonly ISystemClipboard systemClipboard; private readonly IDecentralandUrlsSource decentralandUrlsSource; - private readonly IWebBrowser webBrowser; + private readonly UnityAppWebBrowser webBrowser; private readonly IProfileRepository profileRepository; private readonly IRealmNavigator realmNavigator; private readonly IWearableStorage wearableStorage; @@ -87,7 +87,7 @@ public InWorldCameraPlugin(SelfProfile selfProfile, RealmData realmData, Entity playerEntity, IPlacesAPIService placesAPIService, ICharacterObject characterObject, ICoroutineRunner coroutineRunner, ICameraReelStorageService cameraReelStorageService, ICameraReelScreenshotsStorage cameraReelScreenshotsStorage, IMVCManager mvcManager, - ISystemClipboard systemClipboard, IDecentralandUrlsSource decentralandUrlsSource, IWebBrowser webBrowser, + ISystemClipboard systemClipboard, IDecentralandUrlsSource decentralandUrlsSource, UnityAppWebBrowser webBrowser, IProfileRepository profileRepository, IRealmNavigator realmNavigator, IAssetsProvisioner assetsProvisioner, IWearableStorage wearableStorage, IWearablesProvider wearablesProvider, diff --git a/Explorer/Assets/DCL/InWorldCamera/PhotoDetail/EquippedWearableController.cs b/Explorer/Assets/DCL/InWorldCamera/PhotoDetail/EquippedWearableController.cs index 87793d02475..6c50148eb8f 100644 --- a/Explorer/Assets/DCL/InWorldCamera/PhotoDetail/EquippedWearableController.cs +++ b/Explorer/Assets/DCL/InWorldCamera/PhotoDetail/EquippedWearableController.cs @@ -18,7 +18,7 @@ public class EquippedWearableController : IDisposable { internal event Action MarketClicked; internal readonly EquippedWearableView view; - private readonly IWebBrowser webBrowser; + private readonly UnityAppWebBrowser webBrowser; private readonly IDecentralandUrlsSource decentralandUrlsSource; private readonly IThumbnailProvider thumbnailProvider; private readonly NftTypeIconSO rarityBackgrounds; @@ -28,7 +28,7 @@ public class EquippedWearableController : IDisposable private IWearable currentWearable; public EquippedWearableController(EquippedWearableView view, - IWebBrowser webBrowser, + UnityAppWebBrowser webBrowser, IDecentralandUrlsSource decentralandUrlsSource, IThumbnailProvider thumbnailProvider, NftTypeIconSO rarityBackgrounds, @@ -63,7 +63,7 @@ private void BuyWearableButtonClicked() async UniTaskVoid AnimateAndAwaitAsync() { await UniTask.Delay((int)(view.buyButtonAnimationDuration * 1000)); - webBrowser.OpenUrl(currentWearable.GetMarketplaceLink(decentralandUrlsSource)); + webBrowser.OpenUrlMainThreadOnly(currentWearable.GetMarketplaceLink(decentralandUrlsSource)); MarketClicked?.Invoke(); } diff --git a/Explorer/Assets/DCL/InWorldCamera/PhotoDetail/PhotoDetailController.cs b/Explorer/Assets/DCL/InWorldCamera/PhotoDetail/PhotoDetailController.cs index 6a4dc502c25..d13e61a6b1e 100644 --- a/Explorer/Assets/DCL/InWorldCamera/PhotoDetail/PhotoDetailController.cs +++ b/Explorer/Assets/DCL/InWorldCamera/PhotoDetail/PhotoDetailController.cs @@ -36,7 +36,7 @@ public class PhotoDetailController : ControllerBase - public static void ShareReelToX(string shareToXMessage, string reelId, IDecentralandUrlsSource decentralandUrlsSource, ISystemClipboard systemClipboard, IWebBrowser webBrowser) + public static void ShareReelToX(string shareToXMessage, string reelId, IDecentralandUrlsSource decentralandUrlsSource, ISystemClipboard systemClipboard, UnityAppWebBrowser webBrowser) { string description = shareToXMessage; string url = $"{decentralandUrlsSource.Url(DecentralandUrl.CameraReelLink)}/{reelId}"; @@ -26,7 +26,7 @@ public static void ShareReelToX(string shareToXMessage, string reelId, IDecentra string xUrl = $"https://x.com/intent/post?text={description}&url={url}"; systemClipboard.Set(xUrl); - webBrowser.OpenUrl(xUrl); + webBrowser.OpenUrlMainThreadOnly(xUrl); } /// diff --git a/Explorer/Assets/DCL/Infrastructure/Global/AppArgs/AppArgsFlags.cs b/Explorer/Assets/DCL/Infrastructure/Global/AppArgs/AppArgsFlags.cs index 2e759b3116c..9c3992f08c3 100644 --- a/Explorer/Assets/DCL/Infrastructure/Global/AppArgs/AppArgsFlags.cs +++ b/Explorer/Assets/DCL/Infrastructure/Global/AppArgs/AppArgsFlags.cs @@ -32,6 +32,12 @@ public static class AppArgsFlags /// public const string COMMUNITY = "community"; + // The opaque identity id delivered by the auth website's signin deep link (decentraland://?signin={identityId}). + public const string SIGNIN = "signin"; + + // The auth request id parameter echoed in the signin deep link, used to match a link to the login that minted it. + public const string AUTH_REQUEST_ID = "authRequestId"; + public const string FORCED_EMOTES = "self-force-emotes"; public const string SELF_PREVIEW_EMOTES = "self-preview-emotes"; public const string SELF_PREVIEW_WEARABLES = "self-preview-wearables"; diff --git a/Explorer/Assets/DCL/Infrastructure/Global/AppArgs/ApplicationParametersParser.cs b/Explorer/Assets/DCL/Infrastructure/Global/AppArgs/ApplicationParametersParser.cs index 6c3cbdd1361..a2715257e4f 100644 --- a/Explorer/Assets/DCL/Infrastructure/Global/AppArgs/ApplicationParametersParser.cs +++ b/Explorer/Assets/DCL/Infrastructure/Global/AppArgs/ApplicationParametersParser.cs @@ -90,6 +90,9 @@ public static Dictionary ProcessDeepLinkParameters(string deepLi { var output = new Dictionary(); + // Drop the optional host segment (e.g. "open" in decentraland://open?signin=... or decentraland://open/?signin=...) so only the query remains; + deepLinkString = Regex.Replace(deepLinkString, @"^(decentraland:/+)[A-Za-z][A-Za-z0-9_-]*/*\?", "$1?"); + // Update deep link so that Uri class allows the host name deepLinkString = Regex.Replace(deepLinkString, @"^decentraland:/+", "https://decentraland.org/?"); diff --git a/Explorer/Assets/DCL/Infrastructure/Global/AppArgs/Tests/AppArgsTests.cs b/Explorer/Assets/DCL/Infrastructure/Global/AppArgs/Tests/AppArgsTests.cs index cb8072441a5..baab2acbe97 100644 --- a/Explorer/Assets/DCL/Infrastructure/Global/AppArgs/Tests/AppArgsTests.cs +++ b/Explorer/Assets/DCL/Infrastructure/Global/AppArgs/Tests/AppArgsTests.cs @@ -1,9 +1,32 @@ using NUnit.Framework; +using System.Collections.Generic; namespace Global.AppArgs.Tests { public class AppArgsTest { + [Test] + public void DeepLinkSigninWithHostSegmentParsesSignin() + { + Dictionary output = ApplicationParametersParser.ProcessDeepLinkParameters("decentraland://open?signin=abc-123"); + Assert.AreEqual("abc-123", output.GetValueOrDefault(AppArgsFlags.SIGNIN), $"keys: {string.Join(", ", output.Keys)}"); + } + + [Test] + public void DeepLinkSigninWithoutHostSegmentParsesSignin() + { + Dictionary output = ApplicationParametersParser.ProcessDeepLinkParameters("decentraland://?signin=abc-123"); + Assert.AreEqual("abc-123", output.GetValueOrDefault(AppArgsFlags.SIGNIN), $"keys: {string.Join(", ", output.Keys)}"); + } + + [Test] + public void DeepLinkLegacyHostlessParamsUnaffectedByHostStripping() + { + Dictionary output = ApplicationParametersParser.ProcessDeepLinkParameters("decentraland://realm=http://127.0.0.1:8000&position=100,100"); + Assert.AreEqual("http://127.0.0.1:8000", output.GetValueOrDefault(AppArgsFlags.REALM), $"keys: {string.Join(", ", output.Keys)}"); + Assert.AreEqual("100,100", output.GetValueOrDefault(AppArgsFlags.POSITION), $"keys: {string.Join(", ", output.Keys)}"); + } + [Test] public void DebugArgSuccessWithoutFlagTest() { diff --git a/Explorer/Assets/DCL/Infrastructure/Global/Dynamic/BootstrapContainer.cs b/Explorer/Assets/DCL/Infrastructure/Global/Dynamic/BootstrapContainer.cs index 0d15ff9655d..b830f820ad2 100644 --- a/Explorer/Assets/DCL/Infrastructure/Global/Dynamic/BootstrapContainer.cs +++ b/Explorer/Assets/DCL/Infrastructure/Global/Dynamic/BootstrapContainer.cs @@ -13,6 +13,7 @@ using DCL.PluginSystem.Global; using DCL.SceneLoadingScreens.SplashScreen; using DCL.Time; +using DCL.Utilities; using DCL.Utility; using DCL.Web3.Abstract; using DCL.Web3.Accounts.Factory; @@ -42,12 +43,16 @@ public class BootstrapContainer : DCLGlobalContainer public bool EnableAnalytics => Analytics.Enabled; public DiagnosticsContainer DiagnosticsContainer { get; private set; } public IDecentralandUrlsSource DecentralandUrlsSource { get; private set; } - public IWebBrowser WebBrowser { get; private set; } + public UnityAppWebBrowser WebBrowser { get; private set; } public IWeb3AccountFactory Web3AccountFactory { get; private set; } public IAssetsProvisioner? AssetsProvisioner { get; private init; } public IBootstrap? Bootstrap { get; private set; } public IWeb3IdentityCache? IdentityCache { get; private set; } public ICompositeWeb3Provider? CompositeWeb3Provider { get; private set; } + public ReactiveProperty DeeplinkSigninIdentityId { get; } = new (null); + + // The auth request id this instance's login flow is waiting a signin deep link for (null when not logging in). + public ReactiveProperty DeeplinkLoginAwaitingSigninRequestId { get; } = new (null); public AnalyticsContainer Analytics { get; private set; } public DebugSettings.DebugSettings DebugSettings { get; private set; } public VolumeBus VolumeBus { get; private set; } @@ -129,7 +134,7 @@ await bootstrapContainer.InitializeContainerAsync deeplinkSigninIdentityId, + ReactiveProperty deeplinkLoginAwaitingSigninRequestId) { int? identityExpirationDuration = appArgs.TryGetValue(AppArgsFlags.IDENTITY_EXPIRATION_DURATION, out string? v) ? int.Parse(v!) @@ -201,8 +208,17 @@ private static ICompositeWeb3Provider CreateWeb3Dependencies( identityExpirationDuration ); - // Create Dapp authenticator (Browser wallet) - var dappAuth = new DappWeb3Authenticator( + var dappDeepLinkAuth = new DappDeepLinkAuthenticator( + webBrowser, + URLAddress.FromString(decentralandUrlsSource.Url(DecentralandUrl.ApiAuth)), + URLAddress.FromString(decentralandUrlsSource.Url(DecentralandUrl.AuthSignatureWebApp)), + web3AccountFactory, + webRequestController, + deeplinkSigninIdentityId, + deeplinkLoginAwaitingSigninRequestId + ); + + var dappAuth = new DappWeb3EthereumApi( webBrowser, URLAddress.FromString(decentralandUrlsSource.Url(DecentralandUrl.ApiAuth)), URLAddress.FromString(decentralandUrlsSource.Url(DecentralandUrl.AuthSignatureWebApp)), @@ -212,11 +228,10 @@ private static ICompositeWeb3Provider CreateWeb3Dependencies( new HashSet(sceneLoaderSettings.Web3WhitelistMethods), new HashSet(sceneLoaderSettings.Web3ReadOnlyMethods), dclEnvironment, - new AuthCodeVerificationFeatureFlag(), identityExpirationDuration ); - ICompositeWeb3Provider result = new CompositeWeb3Provider(thirdWebAuth, dappAuth, identityCache, container.Controller); + ICompositeWeb3Provider result = new CompositeWeb3Provider(thirdWebAuth, dappAuth, dappDeepLinkAuth, identityCache, container.Controller); return result; } @@ -250,11 +265,6 @@ private static IReportsHandlingSettings ProvideReportHandlingSettingsAsync(Boots } } - internal class AuthCodeVerificationFeatureFlag : DappWeb3Authenticator.ICodeVerificationFeatureFlag - { - public bool ShouldWaitForCodeVerificationFromServer => FeatureFlagsConfiguration.Instance.IsEnabled(FeatureFlagsStrings.AUTH_CODE_VALIDATION); - } - [Serializable] public class BootstrapSettings : IDCLPluginSettings { diff --git a/Explorer/Assets/DCL/Infrastructure/Global/Dynamic/Bootstraper.cs b/Explorer/Assets/DCL/Infrastructure/Global/Dynamic/Bootstraper.cs index 58fa3365957..a5cce7fc25f 100644 --- a/Explorer/Assets/DCL/Infrastructure/Global/Dynamic/Bootstraper.cs +++ b/Explorer/Assets/DCL/Infrastructure/Global/Dynamic/Bootstraper.cs @@ -105,21 +105,21 @@ public async UniTask PreInitializeSetupAsync(CancellationToken token) RealmData realmData, Entity playerEntity, ISystemMemoryCap memoryCap, - IAppArgs appArgs, + IAppArgs args, CancellationToken ct ) => await StaticContainer.CreateAsync( bootstrapContainer.Analytics, bootstrapContainer.DecentralandUrlsSource, realmData, - bootstrapContainer.AssetsProvisioner, + bootstrapContainer.AssetsProvisioner!, bootstrapContainer.ReportHandlingSettings, debugContainerBuilder, webRequestsContainer, pluginSettingsContainer, bootstrapContainer.DiagnosticsContainer, - bootstrapContainer.IdentityCache, - bootstrapContainer.CompositeWeb3Provider, + bootstrapContainer.IdentityCache!, + bootstrapContainer.CompositeWeb3Provider!, bootstrapContainer.LaunchMode, bootstrapContainer.UseRemoteAssetBundles, world, @@ -130,7 +130,7 @@ await StaticContainer.CreateAsync( diskCache, partialsDiskCache, ct, - appArgs + args ); public async UniTask<(DynamicWorldContainer?, bool)> LoadDynamicWorldContainerAsync( @@ -142,7 +142,7 @@ await StaticContainer.CreateAsync( AudioClipConfig backgroundMusic, WorldInfoTool worldInfoTool, Entity playerEntity, - IAppArgs appArgs, + IAppArgs args, ICoroutineRunner coroutineRunner, DCLVersion dclVersion, CancellationToken ct) @@ -150,13 +150,13 @@ await StaticContainer.CreateAsync( dynamicWorldDependencies = new DynamicWorldDependencies ( staticContainer.DebugContainerBuilder, - appArgs, - bootstrapContainer.AssetsProvisioner, + args, + bootstrapContainer.AssetsProvisioner!, staticContainer, pluginSettingsContainer, dynamicSettings, bootstrapContainer.CompositeWeb3Provider!, - bootstrapContainer.IdentityCache, + bootstrapContainer.IdentityCache!, splashScreen, worldInfoTool ); @@ -182,7 +182,7 @@ await StaticContainer.CreateAsync( backgroundMusic, world, playerEntity, - appArgs, + args, coroutineRunner, dclVersion, realmUrls, @@ -250,7 +250,7 @@ Entity playerEntity SceneSharedContainer sceneSharedContainer = SceneSharedContainer.Create( in staticContainer, bootstrapContainer.DecentralandUrlsSource, - bootstrapContainer.IdentityCache, + bootstrapContainer.IdentityCache!, staticContainer.WebRequestsContainer.SceneWebRequestController, dynamicWorldContainer.RealmController.RealmData, dynamicWorldContainer.ProfileRepository, diff --git a/Explorer/Assets/DCL/Infrastructure/Global/Dynamic/DynamicWorldContainer.cs b/Explorer/Assets/DCL/Infrastructure/Global/Dynamic/DynamicWorldContainer.cs index f5cc73e0116..91ff480e4d4 100644 --- a/Explorer/Assets/DCL/Infrastructure/Global/Dynamic/DynamicWorldContainer.cs +++ b/Explorer/Assets/DCL/Infrastructure/Global/Dynamic/DynamicWorldContainer.cs @@ -202,7 +202,7 @@ public override void Dispose() var nftInfoAPIClient = new OpenSeaAPIClient(staticContainer.WebRequestsContainer.WebRequestController, bootstrapContainer.DecentralandUrlsSource); var characterPreviewFactory = new CharacterPreviewFactory(staticContainer.ComponentsContainer.ComponentPoolsRegistry, appArgs); - IWebBrowser webBrowser = bootstrapContainer.WebBrowser; + UnityAppWebBrowser webBrowser = bootstrapContainer.WebBrowser; IEmoteStorage emotesCache = staticContainer.EmoteStorage; @@ -461,12 +461,12 @@ await MapRendererContainer GenericUserProfileContextMenuSettings genericUserProfileContextMenuSettingsSo = (await assetsProvisioner.ProvideMainAssetAsync(dynamicSettings.GenericUserProfileContextMenuSettings, ct)).Value; CommunityVoiceChatContextMenuConfiguration communityVoiceChatContextMenuSettingsSo = (await assetsProvisioner.ProvideMainAssetAsync(dynamicSettings.CommunityVoiceChatContextMenuSettings, ct)).Value; - // Local scene development scenes are excluded from deeplink runtime handling logic - if (!appArgs.HasFlag(AppArgsFlags.LOCAL_SCENE)) - { - var deepLinkHandleImplementation = new DeepLinkHandle(dynamicWorldParams.StartParcel, chatContainer.ChatTeleporter, ct, communitiesDataService); - deepLinkHandleImplementation.StartListenForDeepLinksAsync(ct).Forget(); - } + // Deep link listening stays alive in every mode so browser sign-in can complete; local scene + // development only opts out of navigation routing (teleports would break the scene under test). + var deepLinkHandleImplementation = new DeepLinkHandle(dynamicWorldParams.StartParcel, chatContainer.ChatTeleporter, ct, communitiesDataService, bootstrapContainer.DeeplinkSigninIdentityId, + bootstrapContainer.DeeplinkLoginAwaitingSigninRequestId, routeNavigationDeepLinks: !appArgs.HasFlag(AppArgsFlags.LOCAL_SCENE)); + + deepLinkHandleImplementation.StartListenForDeepLinksAsync(ct).Forget(); IMVCManagerMenusAccessFacade menusAccessFacade = new MVCManagerMenusAccessFacade( uiShellContainer.MvcManager, diff --git a/Explorer/Assets/DCL/Infrastructure/Global/Dynamic/MainSceneLoader.cs b/Explorer/Assets/DCL/Infrastructure/Global/Dynamic/MainSceneLoader.cs index c01a923b286..65a49807dff 100644 --- a/Explorer/Assets/DCL/Infrastructure/Global/Dynamic/MainSceneLoader.cs +++ b/Explorer/Assets/DCL/Infrastructure/Global/Dynamic/MainSceneLoader.cs @@ -456,7 +456,7 @@ private bool ShouldForceSingleRunningInstance(IAppArgs appArgs) return false; } - private async UniTask RegisterBlockedPopupAsync(IWebBrowser webBrowser, CancellationToken ct) + private async UniTask RegisterBlockedPopupAsync(UnityAppWebBrowser webBrowser, CancellationToken ct) { var blockedPopupPrefab = await bootstrapContainer!.AssetsProvisioner!.ProvideMainAssetAsync(dynamicSettings.BlockedScreenPrefab, ct); @@ -467,7 +467,7 @@ private async UniTask RegisterBlockedPopupAsync(IWebBrowser webBrowser, Cancella dynamicWorldContainer!.MvcManager.RegisterController(launcherRedirectionScreenController); } - private async UniTask> VerifyMinimumHardwareRequirementMetAsync(IAppArgs applicationParametersParser, IWebBrowser webBrowser, IAnalyticsController analytics, CancellationToken ct) + private async UniTask> VerifyMinimumHardwareRequirementMetAsync(IAppArgs applicationParametersParser, UnityAppWebBrowser webBrowser, IAnalyticsController analytics, CancellationToken ct) { var minimumSpecsGuard = new MinimumSpecsGuard(new DefaultSpecProfileProvider(), new UnitySystemInfoProvider()); diff --git a/Explorer/Assets/DCL/Infrastructure/MVC/MVCFacade/MVCManagerMenusAccessFacade.cs b/Explorer/Assets/DCL/Infrastructure/MVC/MVCFacade/MVCManagerMenusAccessFacade.cs index 195d3e09ddf..78c51f545df 100644 --- a/Explorer/Assets/DCL/Infrastructure/MVC/MVCFacade/MVCManagerMenusAccessFacade.cs +++ b/Explorer/Assets/DCL/Infrastructure/MVC/MVCFacade/MVCManagerMenusAccessFacade.cs @@ -46,7 +46,7 @@ public class MVCManagerMenusAccessFacade : IMVCManagerMenusAccessFacade private readonly IVoiceChatOrchestrator voiceChatOrchestrator; private readonly bool includeCommunities; private readonly CommunitiesDataProvider communitiesDataProvider; - private readonly IWebBrowser webBrowser; + private readonly UnityAppWebBrowser webBrowser; private readonly IDecentralandUrlsSource decentralandUrlsSource; private readonly ISelfProfile selfProfile; private readonly NearbyMuteService? nearbyMuteService; @@ -71,7 +71,7 @@ public MVCManagerMenusAccessFacade( IVoiceChatOrchestrator voiceChatOrchestrator, bool includeCommunities, CommunitiesDataProvider communitiesDataProvider, - IWebBrowser webBrowser, + UnityAppWebBrowser webBrowser, IDecentralandUrlsSource decentralandUrlsSource, ISelfProfile selfProfile, NearbyMuteService? nearbyMuteService = null) diff --git a/Explorer/Assets/DCL/MarketplaceCredits/MarketplaceCreditsMenuController.cs b/Explorer/Assets/DCL/MarketplaceCredits/MarketplaceCreditsMenuController.cs index e5d00d1d128..c4f6065ccc0 100644 --- a/Explorer/Assets/DCL/MarketplaceCredits/MarketplaceCreditsMenuController.cs +++ b/Explorer/Assets/DCL/MarketplaceCredits/MarketplaceCreditsMenuController.cs @@ -46,7 +46,7 @@ public partial class MarketplaceCreditsMenuController : ControllerBase viewInstance?.InfoLinkButtonTooltip.Show(); private void OpenInfoLink() => - webBrowser.OpenUrl(WEEKLY_REWARDS_INFO_LINK); + webBrowser.OpenUrlMainThreadOnly(WEEKLY_REWARDS_INFO_LINK); private void OpenGoShoppingLink() => - webBrowser.OpenUrl(DecentralandUrl.GoShoppingWithMarketplaceCredits); + webBrowser.OpenUrlMainThreadOnly(DecentralandUrl.GoShoppingWithMarketplaceCredits); private async UniTaskVoid ShowErrorNotificationAsync(string message, CancellationToken ct) { diff --git a/Explorer/Assets/DCL/MarketplaceCredits/Purchase/Tests/CreditPurchaseBuyHandlerShould.cs b/Explorer/Assets/DCL/MarketplaceCredits/Purchase/Tests/CreditPurchaseBuyHandlerShould.cs index 9b2eddcdc0f..128720ec262 100644 --- a/Explorer/Assets/DCL/MarketplaceCredits/Purchase/Tests/CreditPurchaseBuyHandlerShould.cs +++ b/Explorer/Assets/DCL/MarketplaceCredits/Purchase/Tests/CreditPurchaseBuyHandlerShould.cs @@ -1,7 +1,9 @@ using Cysharp.Threading.Tasks; using DCL.Browser; using DCL.MarketplaceCredits.Purchase.UI; +using DCL.Multiplayer.Connections.DecentralandUrls; using DCL.Passport.Modules; +using JetBrains.Annotations; using MVC; using NSubstitute; using NUnit.Framework; @@ -19,14 +21,14 @@ public class CreditPurchaseBuyHandlerShould private IMVCManager mvcManager = null!; private MarketplaceShopAPIClient shopAPIClient = null!; - private IWebBrowser webBrowser = null!; + private MockWebBrowser webBrowser = null!; [SetUp] public void SetUp() { mvcManager = Substitute.For(); shopAPIClient = Substitute.For(null, null); - webBrowser = Substitute.For(); + webBrowser = new MockWebBrowser(); } private CreditPurchaseBuyHandler CreateHandler(bool isEnabled) => @@ -45,7 +47,7 @@ public async Task RedirectToWebWhenFeatureIsDisabled() await handler.HandleBuyClickAsync(ITEM_URN, MARKETPLACE_URL, CreateVisuals(), _ => { }, CancellationToken.None); // Assert - webBrowser.Received(1).OpenUrl(MARKETPLACE_URL); + Assert.AreEqual(webBrowser.UrlOpened, MARKETPLACE_URL); await shopAPIClient.DidNotReceive().GetShopListingForItemAsync(Arg.Any(), Arg.Any(), Arg.Any()); } @@ -63,7 +65,7 @@ public async Task OpenPurchaseModalWhenListingIsCreditBuyable() // Assert await mvcManager.Received(1).ShowAsync(Arg.Any>(), Arg.Any()); - webBrowser.DidNotReceive().OpenUrl(Arg.Any()); + Assert.IsNull(webBrowser.UrlOpened); } [Test] @@ -79,7 +81,7 @@ public async Task RedirectToWebWhenItemHasNoCreditListing() await handler.HandleBuyClickAsync(ITEM_URN, MARKETPLACE_URL, CreateVisuals(), _ => { }, CancellationToken.None); // Assert - webBrowser.Received(1).OpenUrl(MARKETPLACE_URL); + Assert.AreEqual(webBrowser.UrlOpened, MARKETPLACE_URL); await mvcManager.DidNotReceive().ShowAsync(Arg.Any>(), Arg.Any()); } @@ -96,7 +98,7 @@ public async Task RedirectToWebWhenListingResolutionFails() await handler.HandleBuyClickAsync(ITEM_URN, MARKETPLACE_URL, CreateVisuals(), _ => { }, CancellationToken.None); // Assert - webBrowser.Received(1).OpenUrl(MARKETPLACE_URL); + Assert.AreEqual(webBrowser.UrlOpened, MARKETPLACE_URL); } [Test] @@ -109,7 +111,7 @@ public async Task RedirectToWebWhenUrnIsNotParseable() await handler.HandleBuyClickAsync("urn:decentraland:off-chain:base-avatars:brown_pants", MARKETPLACE_URL, CreateVisuals(), _ => { }, CancellationToken.None); // Assert - webBrowser.Received(1).OpenUrl(MARKETPLACE_URL); + Assert.AreEqual(webBrowser.UrlOpened, MARKETPLACE_URL); await shopAPIClient.DidNotReceive().GetShopListingForItemAsync(Arg.Any(), Arg.Any(), Arg.Any()); } @@ -164,5 +166,21 @@ public void ParseContractAndItemFromCollectionUrns() Assert.IsFalse(CreditPurchaseBuyHandler.TryParseCollectionItem("urn:decentraland:off-chain:base-avatars:brown_pants", out _, out _)); Assert.IsFalse(CreditPurchaseBuyHandler.TryParseCollectionItem("no-colons-here", out _, out _)); } + + private class MockWebBrowser : UnityAppWebBrowser + { + public string UrlOpened { get; private set; } = null; + + public MockWebBrowser() : base(Substitute.For()) + { + + } + + public override void OpenUrlMainThreadOnly(string url) => + UrlOpened = url; + + public override void OpenUrlMainThreadOnly(DecentralandUrl url) => + UrlOpened = url.ToString(); + } } } diff --git a/Explorer/Assets/DCL/MarketplaceCredits/Purchase/UI/CreditPurchaseModalController.cs b/Explorer/Assets/DCL/MarketplaceCredits/Purchase/UI/CreditPurchaseModalController.cs index c46e53f5110..5618187b96d 100644 --- a/Explorer/Assets/DCL/MarketplaceCredits/Purchase/UI/CreditPurchaseModalController.cs +++ b/Explorer/Assets/DCL/MarketplaceCredits/Purchase/UI/CreditPurchaseModalController.cs @@ -25,7 +25,7 @@ private enum ModalState private readonly ICreditsPurchaseService purchaseService; private readonly MarketplaceCreditsAPIClient creditsAPIClient; private readonly IWeb3IdentityCache identityCache; - private readonly IWebBrowser webBrowser; + private readonly UnityAppWebBrowser webBrowser; private readonly Func openGetCreditsPanelAsync; private readonly CancellationTokenSource disposalCts = new (); @@ -40,7 +40,7 @@ public CreditPurchaseModalController( ICreditsPurchaseService purchaseService, MarketplaceCreditsAPIClient creditsAPIClient, IWeb3IdentityCache identityCache, - IWebBrowser webBrowser, + UnityAppWebBrowser webBrowser, Func openGetCreditsPanelAsync) : base(viewFactory) { @@ -175,7 +175,7 @@ private void OnGetCreditsClicked() private void OnOpenMarketplaceClicked() { if (!string.IsNullOrEmpty(inputData.FallbackMarketplaceUrl)) - webBrowser.OpenUrl(inputData.FallbackMarketplaceUrl); + webBrowser.OpenUrlMainThreadOnly(inputData.FallbackMarketplaceUrl); } private async UniTask PurchaseAsync(CancellationToken ct) diff --git a/Explorer/Assets/DCL/MarketplaceCredits/Sections/MarketplaceCreditsProgramEndedSubController.cs b/Explorer/Assets/DCL/MarketplaceCredits/Sections/MarketplaceCreditsProgramEndedSubController.cs index f0c806850a2..1b5627f98c8 100644 --- a/Explorer/Assets/DCL/MarketplaceCredits/Sections/MarketplaceCreditsProgramEndedSubController.cs +++ b/Explorer/Assets/DCL/MarketplaceCredits/Sections/MarketplaceCreditsProgramEndedSubController.cs @@ -29,11 +29,11 @@ public class MarketplaceCreditsProgramEndedSubController : IDisposable private readonly string subtitleMarketOffline = $"Please check the #product-status channel in Decentraland's Discord server for updates if service does not resume shortly."; private readonly MarketplaceCreditsProgramEndedSubView subView; - private readonly IWebBrowser webBrowser; + private readonly UnityAppWebBrowser webBrowser; public MarketplaceCreditsProgramEndedSubController( MarketplaceCreditsProgramEndedSubView subView, - IWebBrowser webBrowser) + UnityAppWebBrowser webBrowser) { this.subView = subView; this.webBrowser = webBrowser; @@ -134,13 +134,13 @@ private void OpenLink(string id) switch (id) { case SUBSCRIBE_LINK_ID: - webBrowser.OpenUrl(DecentralandUrl.NewsletterSubscriptionLink); + webBrowser.OpenUrlMainThreadOnly(DecentralandUrl.NewsletterSubscriptionLink); break; case X_LINK_ID: - webBrowser.OpenUrl(DecentralandUrl.TwitterLink); + webBrowser.OpenUrlMainThreadOnly(DecentralandUrl.TwitterLink); break; case DISCORD_LINK_ID: - webBrowser.OpenUrl(DecentralandUrl.DiscordDirectLink); + webBrowser.OpenUrlMainThreadOnly(DecentralandUrl.DiscordDirectLink); break; } diff --git a/Explorer/Assets/DCL/MarketplaceCredits/Sections/MarketplaceCreditsWelcomeSubController.cs b/Explorer/Assets/DCL/MarketplaceCredits/Sections/MarketplaceCreditsWelcomeSubController.cs index 3c3cebae140..40a5d3039fa 100644 --- a/Explorer/Assets/DCL/MarketplaceCredits/Sections/MarketplaceCreditsWelcomeSubController.cs +++ b/Explorer/Assets/DCL/MarketplaceCredits/Sections/MarketplaceCreditsWelcomeSubController.cs @@ -21,7 +21,7 @@ public class MarketplaceCreditsWelcomeSubController : IDisposable private readonly MarketplaceCreditsGoalsOfTheWeekSubController marketplaceCreditsGoalsOfTheWeekSubController; private readonly MarketplaceCreditsWeekGoalsCompletedSubController marketplaceCreditsWeekGoalsCompletedSubController; private readonly MarketplaceCreditsProgramEndedSubController marketplaceCreditsProgramEndedSubController; - private readonly IWebBrowser webBrowser; + private readonly UnityAppWebBrowser webBrowser; private readonly MarketplaceCreditsAPIClient marketplaceCreditsAPIClient; private readonly ISelfProfile selfProfile; private readonly IInputBlock inputBlock; @@ -38,7 +38,7 @@ public MarketplaceCreditsWelcomeSubController( MarketplaceCreditsGoalsOfTheWeekSubController marketplaceCreditsGoalsOfTheWeekSubController, MarketplaceCreditsWeekGoalsCompletedSubController marketplaceCreditsWeekGoalsCompletedSubController, MarketplaceCreditsProgramEndedSubController marketplaceCreditsProgramEndedSubController, - IWebBrowser webBrowser, + UnityAppWebBrowser webBrowser, MarketplaceCreditsAPIClient marketplaceCreditsAPIClient, ISelfProfile selfProfile, IInputBlock inputBlock) @@ -243,7 +243,7 @@ private void RedirectToSection(bool ignoreHasUserStartedProgramFlag = false) } private void OpenLearnMoreLink() => - webBrowser.OpenUrl(MarketplaceCreditsMenuController.WEEKLY_REWARDS_INFO_LINK); + webBrowser.OpenUrlMainThreadOnly(MarketplaceCreditsMenuController.WEEKLY_REWARDS_INFO_LINK); } diff --git a/Explorer/Assets/DCL/Multiplayer/Connections/Demo/ArchipelagoFakeIdentityCache.cs b/Explorer/Assets/DCL/Multiplayer/Connections/Demo/ArchipelagoFakeIdentityCache.cs index 0778e9e205f..fd92918eb25 100644 --- a/Explorer/Assets/DCL/Multiplayer/Connections/Demo/ArchipelagoFakeIdentityCache.cs +++ b/Explorer/Assets/DCL/Multiplayer/Connections/Demo/ArchipelagoFakeIdentityCache.cs @@ -27,7 +27,7 @@ DecentralandEnvironment dclEnvironment if (identityCache.Identity is null) { - IWeb3Identity? identity = await new DappWeb3Authenticator.Default(identityCache, decentralandUrlsSource, web3AccountFactory, dclEnvironment) + IWeb3Identity? identity = await new DappWeb3EthereumApi.Default(identityCache, decentralandUrlsSource, web3AccountFactory, dclEnvironment) .LoginAsync(LoginPayload.ForDappFlow(LoginMethod.ANY), CancellationToken.None); identityCache.Identity = identity; diff --git a/Explorer/Assets/DCL/Navmap/EventInfoPanelController.cs b/Explorer/Assets/DCL/Navmap/EventInfoPanelController.cs index a412305dd34..4b03746a0ad 100644 --- a/Explorer/Assets/DCL/Navmap/EventInfoPanelController.cs +++ b/Explorer/Assets/DCL/Navmap/EventInfoPanelController.cs @@ -26,7 +26,7 @@ public class EventInfoPanelController private readonly ObjectPool scheduleElementPool; private readonly GoogleUserCalendar userCalendar; private readonly SharePlacesAndEventsContextMenuController shareContextMenu; - private readonly IWebBrowser webBrowser; + private readonly UnityAppWebBrowser webBrowser; private readonly IDecentralandUrlsSource decentralandUrlsSource; private readonly ImageController thumbnailController; private readonly MultiStateButtonController interestedButtonController; @@ -43,7 +43,7 @@ public EventInfoPanelController(EventInfoPanelView view, ObjectPool scheduleElementPool, GoogleUserCalendar userCalendar, SharePlacesAndEventsContextMenuController shareContextMenu, - IWebBrowser webBrowser, + UnityAppWebBrowser webBrowser, IDecentralandUrlsSource decentralandUrlsSource, ImageControllerProvider imageControllerProvider) { @@ -128,7 +128,7 @@ public void Set(EventDTO @event, PlacesData.PlaceInfo place) } private void OpenUrl(string url) => - webBrowser.OpenUrl(url); + webBrowser.OpenUrlMainThreadOnly(url); private void AddRecurrentEvents(EventDTO @event) { diff --git a/Explorer/Assets/DCL/Navmap/PlaceInfoPanelController.cs b/Explorer/Assets/DCL/Navmap/PlaceInfoPanelController.cs index 7f1096dec29..7e2c2d1ad56 100644 --- a/Explorer/Assets/DCL/Navmap/PlaceInfoPanelController.cs +++ b/Explorer/Assets/DCL/Navmap/PlaceInfoPanelController.cs @@ -41,7 +41,7 @@ public class PlaceInfoPanelController : IDisposable private readonly HttpEventsApiService eventsApiService; private readonly ObjectPool eventElementPool ; private readonly SharePlacesAndEventsContextMenuController shareContextMenu; - private readonly IWebBrowser webBrowser; + private readonly UnityAppWebBrowser webBrowser; private readonly IMVCManager mvcManager; private readonly GalleryEventBus galleryEventBus; private readonly HomePlaceEventBus homePlaceEventBus; @@ -73,7 +73,7 @@ public PlaceInfoPanelController(PlaceInfoPanelView view, HttpEventsApiService eventsApiService, ObjectPool eventElementPool, SharePlacesAndEventsContextMenuController shareContextMenu, - IWebBrowser webBrowser, + UnityAppWebBrowser webBrowser, IMVCManager mvcManager, HomePlaceEventBus homePlaceEventBus, IDonationsService donationsService, @@ -373,7 +373,7 @@ private void Share() } private void OpenUrl(string url) => - webBrowser.OpenUrl(url); + webBrowser.OpenUrlMainThreadOnly(url); private void OnLikeButtonClick(bool isEnabled) { diff --git a/Explorer/Assets/DCL/Navmap/SatelliteController.cs b/Explorer/Assets/DCL/Navmap/SatelliteController.cs index 9e0eb7f299c..c0a503a609d 100644 --- a/Explorer/Assets/DCL/Navmap/SatelliteController.cs +++ b/Explorer/Assets/DCL/Navmap/SatelliteController.cs @@ -1,75 +1,73 @@ -using DCL.Browser; -using DCL.Character.CharacterMotion.Components; -using DCL.MapRenderer; -using DCL.MapRenderer.ConsumerUtils; -using DCL.MapRenderer.MapCameraController; -using DCL.MapRenderer.MapLayers; -using DCL.UI; -using System; -using UnityEngine; - -namespace DCL.Navmap -{ - public class SatelliteController : ISection - { - private const string GENESIS_CITY_LINK = "https://genesis.city/"; - - private readonly SatelliteView view; - private readonly RectTransform rectTransform; - private readonly IMapRenderer mapRenderer; - private readonly IWebBrowser webBrowser; - - private IMapCameraController cameraController; - - public SatelliteController( - SatelliteView view, - MapCameraDragBehavior.MapCameraDragBehaviorData mapCameraDragBehaviorData, - IMapRenderer mapRenderer, - IWebBrowser webBrowser) - { - this.view = view; - this.mapRenderer = mapRenderer; - this.webBrowser = webBrowser; - - rectTransform = view.GetComponent(); - view.SatelliteRenderImage.EmbedMapCameraDragBehavior(mapCameraDragBehaviorData); - view.OnClickedGenesisCityLink += OnClickedGenesisCityLink; - } - - private void OnClickedGenesisCityLink() - { - webBrowser.OpenUrl(GENESIS_CITY_LINK); - } - - public void InjectCameraController(IMapCameraController controller) - { - cameraController = controller; - } - - public void Activate() - { - view.SatelliteRenderImage.texture = cameraController.GetRenderTexture(); - view.SatellitePixelPerfectMapRendererTextureProvider.Activate(cameraController); - view.SatelliteRenderImage.Activate(null, cameraController.GetRenderTexture(), cameraController); - view.gameObject.SetActive(true); - } - - public void Deactivate() - { - mapRenderer.SetSharedLayer(MapLayer.SatelliteAtlas, false); - view.SatellitePixelPerfectMapRendererTextureProvider.Deactivate(); - view.SatelliteRenderImage.Deactivate(); - view.gameObject.SetActive(false); - } - - public void Animate(int triggerId) - { - view.gameObject.SetActive(triggerId == UIAnimationHashes.IN); - } - - public void ResetAnimator() { } - - public RectTransform GetRectTransform() => - rectTransform; - } -} +using DCL.Browser; +using DCL.MapRenderer; +using DCL.MapRenderer.ConsumerUtils; +using DCL.MapRenderer.MapCameraController; +using DCL.MapRenderer.MapLayers; +using DCL.UI; +using UnityEngine; + +namespace DCL.Navmap +{ + public class SatelliteController : ISection + { + private const string GENESIS_CITY_LINK = "https://genesis.city/"; + + private readonly SatelliteView view; + private readonly RectTransform rectTransform; + private readonly IMapRenderer mapRenderer; + private readonly UnityAppWebBrowser webBrowser; + + private IMapCameraController cameraController; + + public SatelliteController( + SatelliteView view, + MapCameraDragBehavior.MapCameraDragBehaviorData mapCameraDragBehaviorData, + IMapRenderer mapRenderer, + UnityAppWebBrowser webBrowser) + { + this.view = view; + this.mapRenderer = mapRenderer; + this.webBrowser = webBrowser; + + rectTransform = view.GetComponent(); + view.SatelliteRenderImage.EmbedMapCameraDragBehavior(mapCameraDragBehaviorData); + view.OnClickedGenesisCityLink += OnClickedGenesisCityLink; + } + + private void OnClickedGenesisCityLink() + { + webBrowser.OpenUrlMainThreadOnly(GENESIS_CITY_LINK); + } + + public void InjectCameraController(IMapCameraController controller) + { + cameraController = controller; + } + + public void Activate() + { + view.SatelliteRenderImage.texture = cameraController.GetRenderTexture(); + view.SatellitePixelPerfectMapRendererTextureProvider.Activate(cameraController); + view.SatelliteRenderImage.Activate(null, cameraController.GetRenderTexture(), cameraController); + view.gameObject.SetActive(true); + } + + public void Deactivate() + { + mapRenderer.SetSharedLayer(MapLayer.SatelliteAtlas, false); + view.SatellitePixelPerfectMapRendererTextureProvider.Deactivate(); + view.SatelliteRenderImage.Deactivate(); + view.gameObject.SetActive(false); + } + + public void Animate(int triggerId) + { + view.gameObject.SetActive(triggerId == UIAnimationHashes.IN); + } + + public void ResetAnimator() { } + + public RectTransform GetRectTransform() => + rectTransform; + } +} diff --git a/Explorer/Assets/DCL/Navmap/SharePlacesAndEventsContextMenuController.cs b/Explorer/Assets/DCL/Navmap/SharePlacesAndEventsContextMenuController.cs index 021ddefe502..ab2df08b59e 100644 --- a/Explorer/Assets/DCL/Navmap/SharePlacesAndEventsContextMenuController.cs +++ b/Explorer/Assets/DCL/Navmap/SharePlacesAndEventsContextMenuController.cs @@ -19,7 +19,7 @@ public class SharePlacesAndEventsContextMenuController private readonly SharePlacesAndEventsContextMenuView view; private readonly WarningNotificationView warningNotificationView; private readonly ISystemClipboard clipboard; - private readonly IWebBrowser webBrowser; + private readonly UnityAppWebBrowser webBrowser; private readonly IDecentralandUrlsSource decentralandUrlsSource; private string? twitterLink; private string? copyLink; @@ -28,7 +28,7 @@ public class SharePlacesAndEventsContextMenuController public SharePlacesAndEventsContextMenuController(SharePlacesAndEventsContextMenuView view, WarningNotificationView warningNotificationView, ISystemClipboard clipboard, - IWebBrowser webBrowser, + UnityAppWebBrowser webBrowser, IDecentralandUrlsSource decentralandUrlsSource) { this.view = view; @@ -94,7 +94,7 @@ async UniTaskVoid ShowToastAsync(CancellationToken ct) private void ShareOnTwitter() { if (string.IsNullOrEmpty(twitterLink)) return; - webBrowser.OpenUrl(twitterLink); + webBrowser.OpenUrlMainThreadOnly(twitterLink); Hide(); } } diff --git a/Explorer/Assets/DCL/NetworkDefinitions/Browser/IWebBrowser.cs b/Explorer/Assets/DCL/NetworkDefinitions/Browser/IWebBrowser.cs deleted file mode 100644 index 698acc5b60a..00000000000 --- a/Explorer/Assets/DCL/NetworkDefinitions/Browser/IWebBrowser.cs +++ /dev/null @@ -1,14 +0,0 @@ -using DCL.Multiplayer.Connections.DecentralandUrls; - -// ReSharper disable once CheckNamespace -namespace DCL.Browser -{ - public interface IWebBrowser - { - void OpenUrl(string url); - - void OpenUrl(DecentralandUrl url); - - string GetUrl(DecentralandUrl url); - } -} diff --git a/Explorer/Assets/DCL/NetworkDefinitions/Browser/IWebBrowser.cs.meta b/Explorer/Assets/DCL/NetworkDefinitions/Browser/IWebBrowser.cs.meta deleted file mode 100644 index ab227da5574..00000000000 --- a/Explorer/Assets/DCL/NetworkDefinitions/Browser/IWebBrowser.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 6dfb94a703104a5ba0989671bd46c74e -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Explorer/Assets/DCL/NetworkDefinitions/Browser/SupportRequestService.cs b/Explorer/Assets/DCL/NetworkDefinitions/Browser/SupportRequestService.cs index df35df885c3..682ef875ebd 100644 --- a/Explorer/Assets/DCL/NetworkDefinitions/Browser/SupportRequestService.cs +++ b/Explorer/Assets/DCL/NetworkDefinitions/Browser/SupportRequestService.cs @@ -6,18 +6,18 @@ namespace DCL.Browser { public class SupportRequestService { - private readonly IWebBrowser webBrowser; + private readonly UnityAppWebBrowser webBrowser; public event Action? SupportRequested; - public SupportRequestService(IWebBrowser webBrowser) + public SupportRequestService(UnityAppWebBrowser webBrowser) { this.webBrowser = webBrowser; } public void OpenSupport() { - webBrowser.OpenUrl(DecentralandUrl.Help); + webBrowser.OpenUrlMainThreadOnly(DecentralandUrl.Help); SupportRequested?.Invoke(); } } diff --git a/Explorer/Assets/DCL/NetworkDefinitions/Browser/UnityAppWebBrowser.cs b/Explorer/Assets/DCL/NetworkDefinitions/Browser/UnityAppWebBrowser.cs index b2ba0a0eb14..73266de52bf 100644 --- a/Explorer/Assets/DCL/NetworkDefinitions/Browser/UnityAppWebBrowser.cs +++ b/Explorer/Assets/DCL/NetworkDefinitions/Browser/UnityAppWebBrowser.cs @@ -5,7 +5,7 @@ // ReSharper disable once CheckNamespace namespace DCL.Browser { - public class UnityAppWebBrowser : IWebBrowser + public class UnityAppWebBrowser { private readonly IDecentralandUrlsSource decentralandUrlsSource; @@ -14,14 +14,14 @@ public UnityAppWebBrowser(IDecentralandUrlsSource decentralandUrlsSource) this.decentralandUrlsSource = decentralandUrlsSource; } - public void OpenUrl(string url) + public virtual void OpenUrlMainThreadOnly(string url) { Application.OpenURL(Uri.EscapeUriString(url)); } - public void OpenUrl(DecentralandUrl url) + public virtual void OpenUrlMainThreadOnly(DecentralandUrl url) { - OpenUrl(decentralandUrlsSource.Url(url)); + OpenUrlMainThreadOnly(decentralandUrlsSource.Url(url)); } public string GetUrl(DecentralandUrl url) => diff --git a/Explorer/Assets/DCL/NftPrompt/NftPromptController.cs b/Explorer/Assets/DCL/NftPrompt/NftPromptController.cs index 70a11ad7d7e..c5896016b61 100644 --- a/Explorer/Assets/DCL/NftPrompt/NftPromptController.cs +++ b/Explorer/Assets/DCL/NftPrompt/NftPromptController.cs @@ -21,7 +21,7 @@ public partial class NftPromptController : ControllerBase CanvasOrdering.SortingLayer.POPUP; - private readonly IWebBrowser webBrowser; + private readonly UnityAppWebBrowser webBrowser; private readonly ICursor cursor; private readonly INftMarketAPIClient nftInfoAPIClient; private readonly ImageControllerProvider imageControllerProvider; @@ -34,7 +34,7 @@ public partial class NftPromptController : ControllerBase wearablesItemsPool; @@ -56,7 +56,7 @@ public CreationsDetailsPassportModuleController( NftTypeIconSO rarityBackgrounds, NFTColorsSO rarityColors, NftTypeIconSO categoryIcons, - IWebBrowser webBrowser, + UnityAppWebBrowser webBrowser, ImageControllerProvider imageControllerProvider, PassportErrorsController passportErrorsController, CreditPurchaseBuyHandler creditPurchaseBuyHandler) @@ -261,7 +261,7 @@ private void SetupItemView(EquippedItemPassportFieldView itemView, MarketplaceCa string itemUrn = item.urn ?? string.Empty; string rarityName = item.rarity ?? string.Empty; UnityAction buyListener = () => OnBuyClicked(itemView, itemUrn, marketplaceLink, rarityName, raritySprite, rarityColor); - UnityAction viewListener = () => webBrowser.OpenUrl(marketplaceLink); + UnityAction viewListener = () => webBrowser.OpenUrlMainThreadOnly(marketplaceLink); itemView.BuyButton.onClick.AddListener(buyListener); itemView.ViewButton.onClick.AddListener(viewListener); navigationListeners[itemView] = (buyListener, viewListener); diff --git a/Explorer/Assets/DCL/Passport/Modules/CreditPurchaseBuyHandler.cs b/Explorer/Assets/DCL/Passport/Modules/CreditPurchaseBuyHandler.cs index b4372260707..345a1cf0339 100644 --- a/Explorer/Assets/DCL/Passport/Modules/CreditPurchaseBuyHandler.cs +++ b/Explorer/Assets/DCL/Passport/Modules/CreditPurchaseBuyHandler.cs @@ -35,11 +35,11 @@ public ItemVisuals(string name, string rarityName, Sprite? thumbnail, Sprite? ra private readonly IMVCManager mvcManager; private readonly MarketplaceShopAPIClient shopAPIClient; - private readonly IWebBrowser webBrowser; + private readonly UnityAppWebBrowser webBrowser; private readonly bool isEnabled; private readonly Dictionary listingCache = new (); - public CreditPurchaseBuyHandler(IMVCManager mvcManager, MarketplaceShopAPIClient shopAPIClient, IWebBrowser webBrowser, bool isEnabled) + public CreditPurchaseBuyHandler(IMVCManager mvcManager, MarketplaceShopAPIClient shopAPIClient, UnityAppWebBrowser webBrowser, bool isEnabled) { this.mvcManager = mvcManager; this.shopAPIClient = shopAPIClient; @@ -78,7 +78,7 @@ public async UniTask HandleBuyClickAsync(string itemUrn, string marketplaceUrl, { if (!isEnabled) { - webBrowser.OpenUrl(marketplaceUrl); + webBrowser.OpenUrlMainThreadOnly(marketplaceUrl); return; } @@ -96,7 +96,7 @@ public async UniTask HandleBuyClickAsync(string itemUrn, string marketplaceUrl, catch (Exception e) { ReportHub.LogWarning(ReportCategory.CREDITS_PURCHASE, $"Listing resolution failed for {itemUrn}: {e.Message}"); - webBrowser.OpenUrl(marketplaceUrl); + webBrowser.OpenUrlMainThreadOnly(marketplaceUrl); return; } finally @@ -109,7 +109,7 @@ public async UniTask HandleBuyClickAsync(string itemUrn, string marketplaceUrl, if (listing == null) { - webBrowser.OpenUrl(marketplaceUrl); + webBrowser.OpenUrlMainThreadOnly(marketplaceUrl); return; } diff --git a/Explorer/Assets/DCL/Passport/Modules/EquippedItemsPassportModuleController.cs b/Explorer/Assets/DCL/Passport/Modules/EquippedItemsPassportModuleController.cs index 5f51d46cebf..06fe82bf201 100644 --- a/Explorer/Assets/DCL/Passport/Modules/EquippedItemsPassportModuleController.cs +++ b/Explorer/Assets/DCL/Passport/Modules/EquippedItemsPassportModuleController.cs @@ -37,7 +37,7 @@ public class EquippedItemsPassportModuleController : IPassportModuleController private readonly NFTColorsSO rarityColors; private readonly NftTypeIconSO categoryIcons; private readonly IThumbnailProvider thumbnailProvider; - private readonly IWebBrowser webBrowser; + private readonly UnityAppWebBrowser webBrowser; private readonly IDecentralandUrlsSource decentralandUrlsSource; private readonly PassportErrorsController passportErrorsController; private readonly IObjectPool loadingItemsPool; @@ -58,7 +58,7 @@ public EquippedItemsPassportModuleController( NFTColorsSO rarityColors, NftTypeIconSO categoryIcons, IThumbnailProvider thumbnailProvider, - IWebBrowser webBrowser, + UnityAppWebBrowser webBrowser, IDecentralandUrlsSource decentralandUrlsSource, PassportErrorsController passportErrorsController, CreditPurchaseBuyHandler creditPurchaseBuyHandler) diff --git a/Explorer/Assets/DCL/Passport/Modules/UserBasicInfoPassportModuleController.cs b/Explorer/Assets/DCL/Passport/Modules/UserBasicInfoPassportModuleController.cs index e65fd37a743..c6447451e09 100644 --- a/Explorer/Assets/DCL/Passport/Modules/UserBasicInfoPassportModuleController.cs +++ b/Explorer/Assets/DCL/Passport/Modules/UserBasicInfoPassportModuleController.cs @@ -22,7 +22,7 @@ public class UserBasicInfoPassportModuleController : IPassportModuleController private readonly UserWalletAddressElementPresenter walletAddressElementPresenter; private readonly UserBasicInfoPassportModuleView view; private readonly ISelfProfile selfProfile; - private readonly IWebBrowser webBrowser; + private readonly UnityAppWebBrowser webBrowser; private readonly IMVCManager mvcManager; private readonly INftNamesProvider nftNamesProvider; private readonly IDecentralandUrlsSource decentralandUrlsSource; @@ -38,7 +38,7 @@ public class UserBasicInfoPassportModuleController : IPassportModuleController public UserBasicInfoPassportModuleController( UserBasicInfoPassportModuleView view, ISelfProfile selfProfile, - IWebBrowser webBrowser, + UnityAppWebBrowser webBrowser, IMVCManager mvcManager, INftNamesProvider nftNamesProvider, IDecentralandUrlsSource decentralandUrlsSource, @@ -148,7 +148,7 @@ async UniTaskVoid ShowNameEditorAsync(CancellationToken ct) private void ClaimName() { - webBrowser.OpenUrl(decentralandUrlsSource.Url(DecentralandUrl.MarketplaceClaimName)); + webBrowser.OpenUrlMainThreadOnly(decentralandUrlsSource.Url(DecentralandUrl.MarketplaceClaimName)); NameClaimRequested?.Invoke(); } } diff --git a/Explorer/Assets/DCL/Passport/PassportController.cs b/Explorer/Assets/DCL/Passport/PassportController.cs index ed5a9ec843f..b8d728125d4 100644 --- a/Explorer/Assets/DCL/Passport/PassportController.cs +++ b/Explorer/Assets/DCL/Passport/PassportController.cs @@ -87,7 +87,7 @@ private enum OpenBadgeSectionOrigin private readonly ISelfProfile selfProfile; private readonly World world; private readonly IThumbnailProvider thumbnailProvider; - private readonly IWebBrowser webBrowser; + private readonly UnityAppWebBrowser webBrowser; private readonly IDecentralandUrlsSource decentralandUrlsSource; private readonly BadgesAPIClient badgesAPIClient; private readonly PassportProfileInfoController passportProfileInfoController; @@ -182,7 +182,7 @@ public PassportController( World world, Entity playerEntity, IThumbnailProvider thumbnailProvider, - IWebBrowser webBrowser, + UnityAppWebBrowser webBrowser, IDecentralandUrlsSource decentralandUrlsSource, BadgesAPIClient badgesAPIClient, IInputBlock inputBlock, diff --git a/Explorer/Assets/DCL/PerformanceAndDiagnostics/Diagnostics/ReportsHandling/ReportsHandlingSettingsProduction.asset b/Explorer/Assets/DCL/PerformanceAndDiagnostics/Diagnostics/ReportsHandling/ReportsHandlingSettingsProduction.asset index d9d63562f5d..57f1e67ae01 100644 --- a/Explorer/Assets/DCL/PerformanceAndDiagnostics/Diagnostics/ReportsHandling/ReportsHandlingSettingsProduction.asset +++ b/Explorer/Assets/DCL/PerformanceAndDiagnostics/Diagnostics/ReportsHandling/ReportsHandlingSettingsProduction.asset @@ -448,6 +448,12 @@ MonoBehaviour: Severity: 0 - Category: MULTIPLAYER Severity: 2 + - Category: AUTHENTICATION + Severity: 3 + - Category: AUTHENTICATION + Severity: 2 + - Category: AUTHENTICATION + Severity: 0 sentryMatrix: entries: - Category: AUDIO_SOURCES diff --git a/Explorer/Assets/DCL/Places/PlacesCardSocialActionsController.cs b/Explorer/Assets/DCL/Places/PlacesCardSocialActionsController.cs index 74b72ff9570..626a4025b0a 100644 --- a/Explorer/Assets/DCL/Places/PlacesCardSocialActionsController.cs +++ b/Explorer/Assets/DCL/Places/PlacesCardSocialActionsController.cs @@ -39,7 +39,7 @@ public class PlacesCardSocialActionsController private readonly IPlacesAPIService placesAPIService; private readonly IRealmNavigator realmNavigator; - private readonly IWebBrowser webBrowser; + private readonly UnityAppWebBrowser webBrowser; private readonly ISystemClipboard clipboard; private readonly IDecentralandUrlsSource dclUrlSource; private readonly INavmapBus? navmapBus; @@ -49,7 +49,7 @@ public class PlacesCardSocialActionsController public PlacesCardSocialActionsController( IPlacesAPIService placesAPIService, IRealmNavigator realmNavigator, - IWebBrowser webBrowser, + UnityAppWebBrowser webBrowser, ISystemClipboard clipboard, IDecentralandUrlsSource dclUrlSource, INavmapBus? navmapBus, @@ -194,7 +194,7 @@ public void SharePlace(PlacesData.PlaceInfo placeInfo) var description = string.Format(TWITTER_PLACE_DESCRIPTION, placeInfo.title); var twitterLink = string.Format(dclUrlSource.Url(DecentralandUrl.TwitterNewPostLink), description, "DCLPlace", GetPlaceCopyLink(placeInfo)); - webBrowser.OpenUrl(twitterLink); + webBrowser.OpenUrlMainThreadOnly(twitterLink); PlaceShared?.Invoke(placeInfo); } diff --git a/Explorer/Assets/DCL/Places/PlacesController.cs b/Explorer/Assets/DCL/Places/PlacesController.cs index 1c4515c7bd9..f8ae990f45c 100644 --- a/Explorer/Assets/DCL/Places/PlacesController.cs +++ b/Explorer/Assets/DCL/Places/PlacesController.cs @@ -41,7 +41,7 @@ public PlacesController( PlaceCategoriesSO placesCategories, IInputBlock inputBlock, ISelfProfile selfProfile, - IWebBrowser webBrowser, + UnityAppWebBrowser webBrowser, IFriendsService? friendsService, ProfileRepositoryWrapper profileRepositoryWrapper, IMVCManager mvcManager, diff --git a/Explorer/Assets/DCL/Places/PlacesResultsController.cs b/Explorer/Assets/DCL/Places/PlacesResultsController.cs index 036590be0bb..d1a403ebbfb 100644 --- a/Explorer/Assets/DCL/Places/PlacesResultsController.cs +++ b/Explorer/Assets/DCL/Places/PlacesResultsController.cs @@ -45,7 +45,7 @@ public class PlacesResultsController : IDisposable private readonly IPlacesAPIService placesAPIService; private readonly PlacesStateService placesStateService; private readonly ISelfProfile selfProfile; - private readonly IWebBrowser webBrowser; + private readonly UnityAppWebBrowser webBrowser; private readonly PlacesCardSocialActionsController placesCardSocialActionsController; private readonly IFriendsService? friendsService; private readonly IMVCManager mvcManager; @@ -69,7 +69,7 @@ public PlacesResultsController( IPlacesAPIService placesAPIService, PlacesStateService placesStateService, ISelfProfile selfProfile, - IWebBrowser webBrowser, + UnityAppWebBrowser webBrowser, IFriendsService? friendsService, ProfileRepositoryWrapper profileRepositoryWrapper, IMVCManager mvcManager, @@ -140,7 +140,7 @@ private void OnExplorePlacesClicked() => placesController.OpenSection(PlacesSection.BROWSE, force: true, resetCategory: true); private void GetANameClicked() => - webBrowser.OpenUrl(DecentralandUrl.MarketplaceClaimName); + webBrowser.OpenUrlMainThreadOnly(DecentralandUrl.MarketplaceClaimName); private void TryLoadMorePlaces() { diff --git a/Explorer/Assets/DCL/PluginSystem/Global/BackpackSubPlugin.cs b/Explorer/Assets/DCL/PluginSystem/Global/BackpackSubPlugin.cs index 8b5164019e8..1579136ba1a 100644 --- a/Explorer/Assets/DCL/PluginSystem/Global/BackpackSubPlugin.cs +++ b/Explorer/Assets/DCL/PluginSystem/Global/BackpackSubPlugin.cs @@ -58,7 +58,7 @@ internal class BackpackSubPlugin : IDisposable private readonly CharacterPreviewEventBus characterPreviewEventBus; private readonly IInputBlock inputBlock; private readonly IAppArgs appArgs; - private readonly IWebBrowser webBrowser; + private readonly UnityAppWebBrowser webBrowser; private readonly WarningNotificationView inWorldWarningNotificationView; private readonly IThumbnailProvider thumbnailProvider; private readonly ProfileChangesBus profileChangesBus; @@ -97,7 +97,7 @@ public BackpackSubPlugin( Arch.Core.World world, Entity playerEntity, IAppArgs appArgs, - IWebBrowser webBrowser, + UnityAppWebBrowser webBrowser, WarningNotificationView inWorldWarningNotificationView, IThumbnailProvider thumbnailProvider, ProfileChangesBus profileChangesBus, diff --git a/Explorer/Assets/DCL/PluginSystem/Global/CommunitiesPlugin.cs b/Explorer/Assets/DCL/PluginSystem/Global/CommunitiesPlugin.cs index 8a7163cbf10..6de2bdc3313 100644 --- a/Explorer/Assets/DCL/PluginSystem/Global/CommunitiesPlugin.cs +++ b/Explorer/Assets/DCL/PluginSystem/Global/CommunitiesPlugin.cs @@ -54,7 +54,7 @@ public class CommunitiesPlugin : IDCLGlobalPlugin private readonly ISelfProfile selfProfile; private readonly IRealmNavigator realmNavigator; private readonly ISystemClipboard clipboard; - private readonly IWebBrowser webBrowser; + private readonly UnityAppWebBrowser webBrowser; private readonly HttpEventsApiService eventsApiService; private readonly ChatEventBus chatEventBus; private readonly RPCCommunitiesService rpcCommunitiesService; @@ -86,7 +86,7 @@ public CommunitiesPlugin(IMVCManager mvcManager, ISelfProfile selfProfile, IRealmNavigator realmNavigator, ISystemClipboard clipboard, - IWebBrowser webBrowser, + UnityAppWebBrowser webBrowser, HttpEventsApiService eventsApiService, ChatEventBus chatEventBus, GalleryEventBus galleryEventBus, diff --git a/Explorer/Assets/DCL/PluginSystem/Global/CreditPurchasePlugin.cs b/Explorer/Assets/DCL/PluginSystem/Global/CreditPurchasePlugin.cs index 291868b1f65..44a71c1ea47 100644 --- a/Explorer/Assets/DCL/PluginSystem/Global/CreditPurchasePlugin.cs +++ b/Explorer/Assets/DCL/PluginSystem/Global/CreditPurchasePlugin.cs @@ -21,7 +21,7 @@ public class CreditPurchasePlugin : IDCLGlobalPlugin private readonly IProfileRepository profileRepository; private readonly Entity playerEntity; private readonly Arch.Core.World world; - private readonly IWebBrowser webBrowser; + private readonly UnityAppWebBrowser webBrowser; private readonly IDecentralandUrlsSource decentralandUrlsSource; private readonly IInputBlock inputBlock; private readonly ICompositeWeb3Provider web3Provider; @@ -46,7 +46,7 @@ public DonationsPlugin(IMVCManager mvcManager, IProfileRepository profileRepository, Entity playerEntity, Arch.Core.World world, - IWebBrowser webBrowser, + UnityAppWebBrowser webBrowser, IDecentralandUrlsSource decentralandUrlsSource, IInputBlock inputBlock, ICompositeWeb3Provider web3Provider) diff --git a/Explorer/Assets/DCL/PluginSystem/Global/ExplorePanelPlugin.cs b/Explorer/Assets/DCL/PluginSystem/Global/ExplorePanelPlugin.cs index c85416b1861..9b6d493c6ae 100644 --- a/Explorer/Assets/DCL/PluginSystem/Global/ExplorePanelPlugin.cs +++ b/Explorer/Assets/DCL/PluginSystem/Global/ExplorePanelPlugin.cs @@ -105,7 +105,7 @@ public class ExplorePanelPlugin : IDCLGlobalPlugin(); var eventInfoViewFactory = EventDetailPanelController.CreateLazily(eventDetailPanelViewAsset, null); eventDetailPanelController = new EventDetailPanelController(eventInfoViewFactory, - webRequestController, - clipboard, - webBrowser, - eventsApiService, eventsThumbnailLoader, eventCardActionsController); mvcManager.RegisterController(eventDetailPanelController); diff --git a/Explorer/Assets/DCL/PluginSystem/Global/ExternalUrlPromptPlugin.cs b/Explorer/Assets/DCL/PluginSystem/Global/ExternalUrlPromptPlugin.cs index a7968caad54..0420bb882e0 100644 --- a/Explorer/Assets/DCL/PluginSystem/Global/ExternalUrlPromptPlugin.cs +++ b/Explorer/Assets/DCL/PluginSystem/Global/ExternalUrlPromptPlugin.cs @@ -15,14 +15,14 @@ namespace DCL.PluginSystem.Global public class ExternalUrlPromptPlugin : IDCLGlobalPlugin { private readonly IAssetsProvisioner assetsProvisioner; - private readonly IWebBrowser webBrowser; + private readonly UnityAppWebBrowser webBrowser; private readonly IMVCManager mvcManager; private readonly ICursor cursor; private ExternalUrlPromptController? externalUrlPromptController; public ExternalUrlPromptPlugin( IAssetsProvisioner assetsProvisioner, - IWebBrowser webBrowser, + UnityAppWebBrowser webBrowser, IMVCManager mvcManager, ICursor cursor) { diff --git a/Explorer/Assets/DCL/PluginSystem/Global/FriendsContainer.cs b/Explorer/Assets/DCL/PluginSystem/Global/FriendsContainer.cs index 8e1cb1ac440..d72df446fa8 100644 --- a/Explorer/Assets/DCL/PluginSystem/Global/FriendsContainer.cs +++ b/Explorer/Assets/DCL/PluginSystem/Global/FriendsContainer.cs @@ -89,7 +89,7 @@ public FriendsContainer( IUserBlockingCache injectedUserBlockingCache, ProfileRepositoryWrapper profileDataProvider, IVoiceChatOrchestrator voiceChatOrchestrator, - IWebBrowser webBrowser, + UnityAppWebBrowser webBrowser, IDecentralandUrlsSource decentralandUrlsSource) { this.mainUIView = mainUIView; diff --git a/Explorer/Assets/DCL/PluginSystem/Global/GiftingPlugin.cs b/Explorer/Assets/DCL/PluginSystem/Global/GiftingPlugin.cs index b387a110963..b7e66f01d46 100644 --- a/Explorer/Assets/DCL/PluginSystem/Global/GiftingPlugin.cs +++ b/Explorer/Assets/DCL/PluginSystem/Global/GiftingPlugin.cs @@ -52,7 +52,7 @@ public class GiftingPlugin : IDCLGlobalPlugin private readonly IWeb3IdentityCache web3IdentityCache; private readonly IThumbnailProvider thumbnailProvider; private readonly IEventBus eventBus; - private readonly IWebBrowser webBrowser; + private readonly UnityAppWebBrowser webBrowser; private readonly ICompositeWeb3Provider web3Provider; private readonly IDecentralandUrlsSource decentralandUrlsSource; private readonly ImageControllerProvider imageControllerProvider; @@ -76,7 +76,7 @@ public GiftingPlugin(IAssetsProvisioner assetsProvisioner, IWeb3IdentityCache web3IdentityCache, IThumbnailProvider thumbnailProvider, IEventBus eventBus, - IWebBrowser webBrowser, + UnityAppWebBrowser webBrowser, ICompositeWeb3Provider web3Provider, IDecentralandUrlsSource decentralandUrlsSource, ImageControllerProvider imageControllerProvider) diff --git a/Explorer/Assets/DCL/PluginSystem/Global/MarketplaceCreditsPlugin.cs b/Explorer/Assets/DCL/PluginSystem/Global/MarketplaceCreditsPlugin.cs index 797809a4a3f..9659f30a216 100644 --- a/Explorer/Assets/DCL/PluginSystem/Global/MarketplaceCreditsPlugin.cs +++ b/Explorer/Assets/DCL/PluginSystem/Global/MarketplaceCreditsPlugin.cs @@ -25,7 +25,7 @@ public class MarketplaceCreditsPlugin : IDCLGlobalPlugin { private readonly IAssetsProvisioner assetsProvisioner; - private readonly IWebBrowser webBrowser; + private readonly UnityAppWebBrowser webBrowser; private readonly IMVCManager mvcManager; private readonly INftMarketAPIClient nftInfoAPIClient; private readonly ImageControllerProvider imageControllerProvider; @@ -26,7 +26,7 @@ public class NftPromptPlugin : IDCLGlobalPlugin private readonly ICharacterPreviewFactory characterPreviewFactory; private readonly CharacterPreviewEventBus characterPreviewEventBus; private readonly ISelfProfile selfProfile; - private readonly IWebBrowser webBrowser; + private readonly UnityAppWebBrowser webBrowser; private readonly IDecentralandUrlsSource decentralandUrlsSource; private readonly BadgesAPIClient badgesAPIClient; private readonly IInputBlock inputBlock; @@ -81,7 +81,7 @@ public PassportPlugin( ICharacterPreviewFactory characterPreviewFactory, CharacterPreviewEventBus characterPreviewEventBus, ISelfProfile selfProfile, - IWebBrowser webBrowser, + UnityAppWebBrowser webBrowser, IDecentralandUrlsSource decentralandUrlsSource, BadgesAPIClient badgesAPIClient, IInputBlock inputBlock, diff --git a/Explorer/Assets/DCL/PluginSystem/Global/SidebarPlugin.cs b/Explorer/Assets/DCL/PluginSystem/Global/SidebarPlugin.cs index 919fe21b651..f08f4e418d6 100644 --- a/Explorer/Assets/DCL/PluginSystem/Global/SidebarPlugin.cs +++ b/Explorer/Assets/DCL/PluginSystem/Global/SidebarPlugin.cs @@ -50,8 +50,8 @@ public class SidebarPlugin : IDCLGlobalPlugin private readonly IWeb3IdentityCache web3IdentityCache; private readonly IProfileRepository profileRepository; private readonly IWebRequestController webRequestController; - private readonly IWebBrowser webBrowser; - private readonly IWeb3Authenticator web3Authenticator; + private readonly UnityAppWebBrowser webBrowser; + private readonly ICompositeWeb3Provider web3Authenticator; private readonly IUserInAppInitializationFlow userInAppInitializationFlow; private readonly IProfileCache profileCache; private readonly Arch.Core.World globalWorld; @@ -91,8 +91,8 @@ public SidebarPlugin( IWeb3IdentityCache web3IdentityCache, IProfileRepository profileRepository, IWebRequestController webRequestController, - IWebBrowser webBrowser, - IWeb3Authenticator web3Authenticator, + UnityAppWebBrowser webBrowser, + ICompositeWeb3Provider web3Authenticator, IUserInAppInitializationFlow userInAppInitializationFlow, IProfileCache profileCache, Arch.Core.World globalWorld, diff --git a/Explorer/Assets/DCL/PluginSystem/Global/Web3AuthenticationPlugin.cs b/Explorer/Assets/DCL/PluginSystem/Global/Web3AuthenticationPlugin.cs index 17aadf4a6e9..e30f96da162 100644 --- a/Explorer/Assets/DCL/PluginSystem/Global/Web3AuthenticationPlugin.cs +++ b/Explorer/Assets/DCL/PluginSystem/Global/Web3AuthenticationPlugin.cs @@ -32,7 +32,7 @@ public class Web3AuthenticationPlugin : IDCLGlobalPlugin private readonly IDebugContainerBuilder debugContainerBuilder; private readonly IMVCManager mvcManager; private readonly ISelfProfile selfProfile; - private readonly IWebBrowser webBrowser; + private readonly UnityAppWebBrowser webBrowser; private readonly IRealmData realmData; private readonly IWeb3IdentityCache storedIdentityProvider; private readonly ICharacterPreviewFactory characterPreviewFactory; @@ -58,7 +58,7 @@ public Web3AuthenticationPlugin( IDebugContainerBuilder debugContainerBuilder, IMVCManager mvcManager, ISelfProfile selfProfile, - IWebBrowser webBrowser, + UnityAppWebBrowser webBrowser, IRealmData realmData, IWeb3IdentityCache storedIdentityProvider, ICharacterPreviewFactory characterPreviewFactory, diff --git a/Explorer/Assets/DCL/RuntimeDeepLink/DeepLinkHandle.cs b/Explorer/Assets/DCL/RuntimeDeepLink/DeepLinkHandle.cs index 748b6c31ceb..4cabc14fbdd 100644 --- a/Explorer/Assets/DCL/RuntimeDeepLink/DeepLinkHandle.cs +++ b/Explorer/Assets/DCL/RuntimeDeepLink/DeepLinkHandle.cs @@ -1,15 +1,23 @@ -using DCL.Utility.Types; - namespace DCL.RuntimeDeepLink { - public interface IDeepLinkHandle + public enum DeepLinkHandleResult { - public string Name { get; } + CONSUMED, + NO_MATCHES, /// - /// Implementations of the method must be exception free. + /// A signin deep link arrived that this instance must not consume: either no login here is waiting + /// for one, or its authRequestId does not match the request this login minted. It is left untouched + /// so the instance it was minted for can claim it from the shared bridge file, rather than a + /// concurrent or idle Explorer instance consuming and deleting it first. Kept until claimed by the + /// matching login (bounded by a timeout). /// - public Result HandleDeepLink(DeepLink deeplink); + DEFERRED, + } + + public interface IDeepLinkHandle + { + DeepLinkHandleResult HandleDeepLink(DeepLink deeplink); class Null : IDeepLinkHandle { @@ -17,10 +25,9 @@ class Null : IDeepLinkHandle private Null() { } - public string Name => "Null Implementation"; - public Result HandleDeepLink(DeepLink deeplink) => - Result.SuccessResult(); + public DeepLinkHandleResult HandleDeepLink(DeepLink deeplink) => + DeepLinkHandleResult.CONSUMED; } } } diff --git a/Explorer/Assets/DCL/RuntimeDeepLink/DeepLinkHandleImplementation.cs b/Explorer/Assets/DCL/RuntimeDeepLink/DeepLinkHandleImplementation.cs index a9bdc4b78dc..bff5fda641b 100644 --- a/Explorer/Assets/DCL/RuntimeDeepLink/DeepLinkHandleImplementation.cs +++ b/Explorer/Assets/DCL/RuntimeDeepLink/DeepLinkHandleImplementation.cs @@ -2,8 +2,9 @@ using Cysharp.Threading.Tasks; using DCL.Chat.Commands; using DCL.Communities; +using DCL.Diagnostics; using DCL.RealmNavigation; -using DCL.Utility.Types; +using DCL.Utilities; using Global.AppArgs; using System.Threading; using UnityEngine; @@ -16,24 +17,51 @@ public class DeepLinkHandle : IDeepLinkHandle private readonly ChatTeleporter chatTeleporter; private readonly CancellationToken token; private readonly CommunityDataService communityDataService; + private readonly ReactiveProperty deeplinkSigninIdentityId; + private readonly IReadonlyReactiveProperty loginAwaitingSigninRequestId; + private readonly bool routeNavigationDeepLinks; - public DeepLinkHandle(StartParcel startParcel, ChatTeleporter chatTeleporter, CancellationToken token, CommunityDataService communityDataService) + public DeepLinkHandle(StartParcel startParcel, ChatTeleporter chatTeleporter, CancellationToken token, CommunityDataService communityDataService, ReactiveProperty deeplinkSigninIdentityId, + IReadonlyReactiveProperty loginAwaitingSigninRequestId, bool routeNavigationDeepLinks) { this.startParcel = startParcel; this.chatTeleporter = chatTeleporter; this.token = token; this.communityDataService = communityDataService; + this.deeplinkSigninIdentityId = deeplinkSigninIdentityId; + this.loginAwaitingSigninRequestId = loginAwaitingSigninRequestId; + this.routeNavigationDeepLinks = routeNavigationDeepLinks; } - public string Name => "Real Implementation"; - - public Result HandleDeepLink(DeepLink deeplink) + public DeepLinkHandleResult HandleDeepLink(DeepLink deeplink) { + string? signin = deeplink.ValueOf(AppArgsFlags.SIGNIN); + + if (!string.IsNullOrEmpty(signin)) + { + string? awaitedRequestId = loginAwaitingSigninRequestId.Value; + + // Guard: only consume a signin while a login here is waiting for one, and only if the link + // was minted for that login. + if (string.IsNullOrEmpty(awaitedRequestId) || deeplink.ValueOf(AppArgsFlags.AUTH_REQUEST_ID) != awaitedRequestId) + return DeepLinkHandleResult.DEFERRED; + + // The id persists in the property until it is overwritten or cleared. + deeplinkSigninIdentityId.Value = signin; + return DeepLinkHandleResult.CONSUMED; + } + + if (!routeNavigationDeepLinks) + { + ReportHub.Log(ReportCategory.RUNTIME_DEEPLINKS, $"navigation deep link routing is disabled, dropping: {deeplink}"); + return DeepLinkHandleResult.CONSUMED; + } + Vector2Int? position = PositionFrom(deeplink); URLDomain? realm = RealmFrom(deeplink); string? communityId = CommunityFrom(deeplink); - var result = Result.ErrorResult("no matches"); + var handled = false; if (realm.HasValue) { @@ -42,7 +70,7 @@ public Result HandleDeepLink(DeepLink deeplink) else chatTeleporter.TeleportToRealmAsync(realm.Value.Value, token).Forget(); - result = Result.SuccessResult(); + handled = true; } else if (position.HasValue) { @@ -53,16 +81,16 @@ public Result HandleDeepLink(DeepLink deeplink) else startParcel.Assign(parcel); - result = Result.SuccessResult(); + handled = true; } if (!string.IsNullOrEmpty(communityId)) { communityDataService.ShowCommunityDeepLinkNotification(communityId); - result = Result.SuccessResult(); + handled = true; } - return result; + return handled ? DeepLinkHandleResult.CONSUMED : DeepLinkHandleResult.NO_MATCHES; } private static URLDomain? RealmFrom(DeepLink deepLink) diff --git a/Explorer/Assets/DCL/RuntimeDeepLink/DeepLinkSentinel.cs b/Explorer/Assets/DCL/RuntimeDeepLink/DeepLinkSentinel.cs index e7f0b9b3627..0ef1385ad1f 100644 --- a/Explorer/Assets/DCL/RuntimeDeepLink/DeepLinkSentinel.cs +++ b/Explorer/Assets/DCL/RuntimeDeepLink/DeepLinkSentinel.cs @@ -3,9 +3,9 @@ using DCL.Utilities.Extensions; using DCL.Utility.Types; using System; +using System.Diagnostics; using System.IO; using System.Threading; -using UnityEngine; namespace DCL.RuntimeDeepLink { @@ -13,6 +13,9 @@ public static class DeepLinkSentinel { private static readonly TimeSpan CHECK_IN_PERIOD = TimeSpan.FromMilliseconds(200); + // Maximum time a deferred signin bridge file is retained on disk; without this cap it would be re-read on every check-in forever. + private static readonly TimeSpan DEFERRED_SIGNIN_LIFETIME = TimeSpan.FromSeconds(300); + #if UNITY_EDITOR_WIN || UNITY_STANDALONE_WIN || PLATFORM_STANDALONE_WIN // path for: C:\Users\\AppData\Local\DecentralandLauncherLight\ private static readonly string DEEP_LINK_BRIDGE_PATH = @@ -36,34 +39,82 @@ public static class DeepLinkSentinel /// public static async UniTaskVoid StartListenForDeepLinksAsync(this IDeepLinkHandle handle, CancellationToken token) { + // Measures how long the current file has sat deferred (a signin nobody is logging in for yet), + // so it can be dropped once DEFERRED_SIGNIN_LIFETIME elapses instead of re-read indefinitely. + var deferralTimer = new Stopwatch(); + while (token.IsCancellationRequested == false) { bool cancelled = await UniTask.Delay(CHECK_IN_PERIOD, cancellationToken: token).SuppressCancellationThrow(); if (cancelled) continue; // File.Exists method is lightweight and can be used in this loop - if (!File.Exists(DEEP_LINK_BRIDGE_PATH)) continue; + if (!File.Exists(DEEP_LINK_BRIDGE_PATH)) + { + deferralTimer.Reset(); + continue; + } Result contentResult = await File.ReadAllTextAsync(DEEP_LINK_BRIDGE_PATH, token)!.SuppressToResultAsync(ReportCategory.RUNTIME_DEEPLINKS); - if (contentResult.Success == false) continue; - // Notify emitter that file has been consumed - File.Delete(DEEP_LINK_BRIDGE_PATH); + // Transient IO read failure: leave the file for the next check-in. + if (!contentResult.Success) continue; + // Parse before deleting: a corrupt file is dropped, a valid one is handled. Result deepLinkCreateResult = DeepLink.FromJson(contentResult.Value); - if (deepLinkCreateResult.Success) + if (deepLinkCreateResult.Success == false) { - DeepLink deeplink = deepLinkCreateResult.Value; - Result handleResult = handle.HandleDeepLink(deeplink); + ReportHub.LogError(ReportCategory.RUNTIME_DEEPLINKS, $"Cannot deserialize deeplink content: {deepLinkCreateResult.ErrorMessage}"); + TryDeleteBridgeFile(); + deferralTimer.Reset(); + continue; + } - if (handleResult.Success) - ReportHub.Log(ReportCategory.RUNTIME_DEEPLINKS, $"{handle.Name} successfully handled deeplink: {deeplink}"); - else - ReportHub.LogError(ReportCategory.RUNTIME_DEEPLINKS, $"{handle.Name} raised error on handle deeplink: {deeplink}, error {handleResult.ErrorMessage}"); + DeepLinkHandleResult result = handle.HandleDeepLink(deepLinkCreateResult.Value); + + if (result == DeepLinkHandleResult.DEFERRED) + { + // Leave the file in place so the awaiting login can claim it. + if (!deferralTimer.IsRunning) + deferralTimer.Restart(); + + if (deferralTimer.Elapsed < DEFERRED_SIGNIN_LIFETIME) + continue; + + ReportHub.LogWarning(ReportCategory.RUNTIME_DEEPLINKS, $"no login claimed the signin deeplink within {DEFERRED_SIGNIN_LIFETIME.TotalSeconds:0}s, dropping it"); + TryDeleteBridgeFile(); + deferralTimer.Reset(); + continue; } - else - ReportHub.LogError(ReportCategory.RUNTIME_DEEPLINKS, $"Cannot deserialize deeplink content: {deepLinkCreateResult.ErrorMessage}"); + + deferralTimer.Reset(); + + switch (result) + { + case DeepLinkHandleResult.CONSUMED: + ReportHub.Log(ReportCategory.RUNTIME_DEEPLINKS, "successfully handled deeplink"); + break; + case DeepLinkHandleResult.NO_MATCHES: + ReportHub.LogWarning(ReportCategory.RUNTIME_DEEPLINKS, "found no actionable content in deeplink"); + break; + } + + // Unmatched links are dropped as well: keeping the file would re-read it on every check-in. + TryDeleteBridgeFile(); + } + } + + private static void TryDeleteBridgeFile() + { + try + { + File.Delete(DEEP_LINK_BRIDGE_PATH); + } + catch (Exception e) + { + // Delete can fail transiently (file locked/rewritten by the launcher). Log and keep the loop alive. + ReportHub.LogError(ReportCategory.RUNTIME_DEEPLINKS, $"Failed to delete deeplink bridge file: {e.Message}"); } } } diff --git a/Explorer/Assets/DCL/UI/ConfirmationDialog/ReportUserHelper.cs b/Explorer/Assets/DCL/UI/ConfirmationDialog/ReportUserHelper.cs index 1f11596bc50..12abcb330db 100644 --- a/Explorer/Assets/DCL/UI/ConfirmationDialog/ReportUserHelper.cs +++ b/Explorer/Assets/DCL/UI/ConfirmationDialog/ReportUserHelper.cs @@ -19,7 +19,7 @@ public static async UniTask ShowConfirmAndReportAsync( string reportCategory, string reportedUserId, ISelfProfile selfProfile, - IWebBrowser webBrowser, + UnityAppWebBrowser webBrowser, IDecentralandUrlsSource decentralandUrlsSource, CancellationToken ct) { @@ -36,7 +36,7 @@ public static async UniTask ShowConfirmAndReportAsync( Profile? ownProfile = await selfProfile.ProfileAsync(ct); - webBrowser.OpenUrl(string.Format(decentralandUrlsSource.Url(DecentralandUrl.ReportUserForm), + webBrowser.OpenUrlMainThreadOnly(string.Format(decentralandUrlsSource.Url(DecentralandUrl.ReportUserForm), ownProfile != null ? ownProfile.UserId : string.Empty, reportedUserId)); } diff --git a/Explorer/Assets/DCL/UI/GenericContextMenu/Controllers/GenericUserProfileContextMenuController.cs b/Explorer/Assets/DCL/UI/GenericContextMenu/Controllers/GenericUserProfileContextMenuController.cs index f4e5ead2c26..9aa9f0f4d30 100644 --- a/Explorer/Assets/DCL/UI/GenericContextMenu/Controllers/GenericUserProfileContextMenuController.cs +++ b/Explorer/Assets/DCL/UI/GenericContextMenu/Controllers/GenericUserProfileContextMenuController.cs @@ -73,7 +73,7 @@ public class GenericUserProfileContextMenuController private readonly bool isCommunitiesFeatureEnabled; private readonly bool isUserBlockingFeatureEnabled; private readonly IVoiceChatOrchestratorActions voiceChatOrchestrator; - private readonly IWebBrowser webBrowser; + private readonly UnityAppWebBrowser webBrowser; private readonly IDecentralandUrlsSource decentralandUrlsSource; private readonly GenericUserProfileContextMenuSettings contextMenuSettings; private readonly ISelfProfile selfProfile; @@ -121,7 +121,7 @@ public GenericUserProfileContextMenuController( bool isCommunitiesFeatureEnabled, CommunitiesDataProvider communitiesDataProvider, IVoiceChatOrchestratorActions voiceChatOrchestrator, - IWebBrowser webBrowser, + UnityAppWebBrowser webBrowser, IDecentralandUrlsSource decentralandUrlsSource, ISelfProfile selfProfile, NearbyMuteService? nearbyMuteService = null) diff --git a/Explorer/Assets/DCL/UI/Profiles/Names/ProfileNameEditorController.cs b/Explorer/Assets/DCL/UI/Profiles/Names/ProfileNameEditorController.cs index 2184dad8f76..cd87bc327da 100644 --- a/Explorer/Assets/DCL/UI/Profiles/Names/ProfileNameEditorController.cs +++ b/Explorer/Assets/DCL/UI/Profiles/Names/ProfileNameEditorController.cs @@ -16,7 +16,7 @@ namespace DCL.UI.ProfileNames { public class ProfileNameEditorController : ControllerBase { - private readonly IWebBrowser webBrowser; + private readonly UnityAppWebBrowser webBrowser; private readonly ISelfProfile selfProfile; private readonly INftNamesProvider nftNamesProvider; private readonly IDecentralandUrlsSource decentralandUrlsSource; @@ -32,7 +32,7 @@ public class ProfileNameEditorController : ControllerBase public event Action? NameClaimRequested; public ProfileNameEditorController(ViewFactoryMethod viewFactory, - IWebBrowser webBrowser, + UnityAppWebBrowser webBrowser, ISelfProfile selfProfile, INftNamesProvider nftNamesProvider, IDecentralandUrlsSource decentralandUrlsSource, @@ -85,7 +85,7 @@ protected override void OnViewInstantiated() claimedConfig.saveButtonInteractable = i != -1; }); - claimedConfig.clickeableLink.OnLinkClicked += url => webBrowser.OpenUrl(url); + claimedConfig.clickeableLink.OnLinkClicked += url => webBrowser.OpenUrlMainThreadOnly(url); viewInstance.OverlayCloseButton.onClick.AddListener(Close); @@ -180,7 +180,7 @@ void SetUpNonClaimed(ProfileNameEditorView.NonClaimedNameConfig config, Profile private void ClaimNewName() { - webBrowser.OpenUrl(decentralandUrlsSource.Url(DecentralandUrl.MarketplaceClaimName)); + webBrowser.OpenUrlMainThreadOnly(decentralandUrlsSource.Url(DecentralandUrl.MarketplaceClaimName)); NameClaimRequested?.Invoke(); } diff --git a/Explorer/Assets/DCL/UI/Profiles/ProfileMenuController.cs b/Explorer/Assets/DCL/UI/Profiles/ProfileMenuController.cs index 71435f954ae..662c9888a73 100644 --- a/Explorer/Assets/DCL/UI/Profiles/ProfileMenuController.cs +++ b/Explorer/Assets/DCL/UI/Profiles/ProfileMenuController.cs @@ -20,8 +20,8 @@ public class ProfileMenuController : ControllerBase private readonly IWeb3IdentityCache identityCache; private readonly World world; private readonly Entity playerEntity; - private readonly IWebBrowser webBrowser; - private readonly IWeb3Authenticator web3Authenticator; + private readonly UnityAppWebBrowser webBrowser; + private readonly ICompositeWeb3Provider web3Authenticator; private readonly IUserInAppInitializationFlow userInAppInitializationFlow; private readonly IProfileCache profileCache; private readonly IPassportBridge passportBridge; @@ -36,8 +36,8 @@ public ProfileMenuController( IWeb3IdentityCache identityCache, World world, Entity playerEntity, - IWebBrowser webBrowser, - IWeb3Authenticator web3Authenticator, + UnityAppWebBrowser webBrowser, + ICompositeWeb3Provider web3Authenticator, IUserInAppInitializationFlow userInAppInitializationFlow, IProfileCache profileCache, IPassportBridge passportBridge, diff --git a/Explorer/Assets/DCL/UI/Sidebar/HelpMenu/HelpMenuController.cs b/Explorer/Assets/DCL/UI/Sidebar/HelpMenu/HelpMenuController.cs index e59f442fcfe..4c4637f7fd4 100644 --- a/Explorer/Assets/DCL/UI/Sidebar/HelpMenu/HelpMenuController.cs +++ b/Explorer/Assets/DCL/UI/Sidebar/HelpMenu/HelpMenuController.cs @@ -11,7 +11,7 @@ namespace DCL.UI.Sidebar.HelpMenu public class HelpMenuController : ControllerBase { private readonly IMVCManager mvcManager; - private readonly IWebBrowser webBrowser; + private readonly UnityAppWebBrowser webBrowser; private readonly SupportRequestService supportRequestService; private UniTaskCompletionSource? closeViewTask; @@ -19,7 +19,7 @@ public class HelpMenuController : ControllerBase public override CanvasOrdering.SortingLayer Layer => CanvasOrdering.SortingLayer.POPUP; - public HelpMenuController(ViewFactoryMethod viewFactory, IMVCManager mvcManager, IWebBrowser webBrowser, SupportRequestService supportRequestService) + public HelpMenuController(ViewFactoryMethod viewFactory, IMVCManager mvcManager, UnityAppWebBrowser webBrowser, SupportRequestService supportRequestService) : base(viewFactory) { this.mvcManager = mvcManager; @@ -69,7 +69,7 @@ private void OnMouseAndKeyControlsClicked() private void OnFaqClicked() { CloseView(); - webBrowser.OpenUrl(DecentralandUrl.Faqs); + webBrowser.OpenUrlMainThreadOnly(DecentralandUrl.Faqs); } private void OnContactSupportClicked() @@ -81,7 +81,7 @@ private void OnContactSupportClicked() private void OnDiscordClicked() { CloseView(); - webBrowser.OpenUrl(DecentralandUrl.Discord); + webBrowser.OpenUrlMainThreadOnly(DecentralandUrl.Discord); } private void CloseView() => closeViewTask?.TrySetResult(); diff --git a/Explorer/Assets/DCL/UI/Sidebar/SidebarController.cs b/Explorer/Assets/DCL/UI/Sidebar/SidebarController.cs index 7a5e013f47b..1970e5fba29 100644 --- a/Explorer/Assets/DCL/UI/Sidebar/SidebarController.cs +++ b/Explorer/Assets/DCL/UI/Sidebar/SidebarController.cs @@ -49,7 +49,7 @@ public class SidebarController : ControllerBase private readonly IMVCManager mvcManager; private readonly SidebarProfileButtonPresenter profileButtonPresenter; private readonly SmartWearablesSideBarTooltipController smartWearablesTooltipController; - private readonly IWebBrowser webBrowser; + private readonly UnityAppWebBrowser webBrowser; private readonly IChatHistory chatHistory; private readonly ISelfProfile selfProfile; private readonly IRealmData realmData; @@ -89,7 +89,7 @@ public SidebarController(ViewFactoryMethod viewFactory, IMVCManager mvcManager, SidebarProfileButtonPresenter profileButtonPresenter, SmartWearablesSideBarTooltipController smartWearablesTooltipController, - IWebBrowser webBrowser, + UnityAppWebBrowser webBrowser, IChatHistory chatHistory, ISelfProfile selfProfile, IRealmData realmData, @@ -304,7 +304,7 @@ async UniTaskVoid OpenReferralWebsiteAsync(CancellationToken ct) .AppendPath(URLPath.FromString($"profile/accounts/{myProfile.UserId}/referral")) .Build(); - webBrowser.OpenUrl(url); + webBrowser.OpenUrlMainThreadOnly(url); } catch (OperationCanceledException) { } catch (Exception e) { ReportHub.LogException(e, ReportCategory.PROFILE); } @@ -451,7 +451,7 @@ private void OnMarketplaceButtonClicked() urlBuilder.Clear(); urlBuilder.AppendDomain(URLDomain.FromString(decentralandUrlsSource.Url(DecentralandUrl.Market))); urlBuilder.AppendParameter(marketplaceSourceParam); - webBrowser.OpenUrl(urlBuilder.Build()); + webBrowser.OpenUrlMainThreadOnly(urlBuilder.Build()); } private async UniTaskVoid OpenPanelAsync( diff --git a/Explorer/Assets/DCL/UI/SystemMenu/SystemSectionPresenter.cs b/Explorer/Assets/DCL/UI/SystemMenu/SystemSectionPresenter.cs index 98083e89bc2..0d180a8fbd7 100644 --- a/Explorer/Assets/DCL/UI/SystemMenu/SystemSectionPresenter.cs +++ b/Explorer/Assets/DCL/UI/SystemMenu/SystemSectionPresenter.cs @@ -21,8 +21,8 @@ public class SystemSectionPresenter : IDisposable public event Action? OnClosed; private readonly SystemMenuView view; - private readonly IWebBrowser webBrowser; - private readonly IWeb3Authenticator web3Authenticator; + private readonly UnityAppWebBrowser webBrowser; + private readonly ICompositeWeb3Provider web3Authenticator; private readonly IUserInAppInitializationFlow userInAppInitializationFlow; private readonly IWeb3IdentityCache web3IdentityCache; private readonly IProfileCache profileCache; @@ -36,8 +36,8 @@ public SystemSectionPresenter( SystemMenuView view, World world, Entity playerEntity, - IWebBrowser webBrowser, - IWeb3Authenticator web3Authenticator, + UnityAppWebBrowser webBrowser, + ICompositeWeb3Provider web3Authenticator, IUserInAppInitializationFlow userInAppInitializationFlow, IProfileCache profileCache, IWeb3IdentityCache web3IdentityCache, @@ -97,10 +97,10 @@ private void CloseView() } private void ShowTermsOfService() => - webBrowser.OpenUrl(DecentralandUrl.TermsOfUse); + webBrowser.OpenUrlMainThreadOnly(DecentralandUrl.TermsOfUse); private void ShowPrivacyPolicy() => - webBrowser.OpenUrl(DecentralandUrl.PrivacyPolicy); + webBrowser.OpenUrlMainThreadOnly(DecentralandUrl.PrivacyPolicy); private void Logout() diff --git a/Explorer/Assets/DCL/Web3/Authenticators/Exceptions/DeeplinkSigninRetrievalException.cs b/Explorer/Assets/DCL/Web3/Authenticators/Exceptions/DeeplinkSigninRetrievalException.cs new file mode 100644 index 00000000000..eb8b22d7350 --- /dev/null +++ b/Explorer/Assets/DCL/Web3/Authenticators/Exceptions/DeeplinkSigninRetrievalException.cs @@ -0,0 +1,38 @@ +namespace DCL.Web3.Authenticators +{ + /// + /// Raised when fetching the identity minted by the deep-link sign-in flow + /// (GET /identities/{identityId}) fails with a known status code. + /// + public class DeeplinkSigninRetrievalException : Web3Exception + { + public enum ErrorReason + { + /// 404: the identity does not exist or has already been retrieved (identities are single-use). + NOT_FOUND, + + /// 410: the identity expired before retrieval (server-side TTL is 15 minutes). + EXPIRED, + + /// 403: the retrieval came from a different IP than the one that stored the identity (commonly a VPN or private relay). + IP_MISMATCH, + } + + public ErrorReason Reason { get; } + + public DeeplinkSigninRetrievalException(ErrorReason reason, string identityId) + : base(MessageFor(reason, identityId)) + { + Reason = reason; + } + + private static string MessageFor(ErrorReason reason, string identityId) => + reason switch + { + ErrorReason.NOT_FOUND => $"Signin identity {identityId} was not found or was already retrieved", + ErrorReason.EXPIRED => $"Signin identity {identityId} expired before it was retrieved", + ErrorReason.IP_MISMATCH => $"Signin identity {identityId} was stored from a different IP: a VPN or private relay is likely interfering", + _ => $"Signin identity {identityId} retrieval failed: {reason}", + }; + } +} diff --git a/Explorer/Assets/DCL/Web3/Authenticators/Exceptions/DeeplinkSigninRetrievalException.cs.meta b/Explorer/Assets/DCL/Web3/Authenticators/Exceptions/DeeplinkSigninRetrievalException.cs.meta new file mode 100644 index 00000000000..5e61d4568ed --- /dev/null +++ b/Explorer/Assets/DCL/Web3/Authenticators/Exceptions/DeeplinkSigninRetrievalException.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: ecb0ca6ce100dc142a3deca47de0206b \ No newline at end of file diff --git a/Explorer/Assets/DCL/Web3/Authenticators/ICompositeWeb3Provider.cs b/Explorer/Assets/DCL/Web3/Authenticators/ICompositeWeb3Provider.cs index 4abf420874d..ca5b51de044 100644 --- a/Explorer/Assets/DCL/Web3/Authenticators/ICompositeWeb3Provider.cs +++ b/Explorer/Assets/DCL/Web3/Authenticators/ICompositeWeb3Provider.cs @@ -1,4 +1,5 @@ using Cysharp.Threading.Tasks; +using System.Threading; namespace DCL.Web3.Authenticators { @@ -10,16 +11,22 @@ namespace DCL.Web3.Authenticators /// /// Interface for composite authentication provider that supports multiple authentication methods. - /// Combines base authentication, Ethereum API, Dapp verification, and OTP flows. + /// Combines base authentication, Ethereum API, and OTP flows. /// This is the single entry point for all Web3 authentication needs. /// - public interface ICompositeWeb3Provider : IWeb3Authenticator, IEthereumApi, IDappVerificationHandler, IOtpAuthenticator + public interface ICompositeWeb3Provider : IWeb3Authenticator, IEthereumApi, IOtpAuthenticator { /// /// Currently selected authentication method /// AuthProvider CurrentProvider { set; } + /// + /// Clears the local session (identity cache, analytics identity) and releases + /// provider-side login resources where the current provider holds any. + /// + UniTask LogoutAsync(CancellationToken ct); + /// /// Returns true if ThirdWeb OTP method is currently selected /// diff --git a/Explorer/Assets/DCL/Web3/Authenticators/IDappVerificationHandler.cs b/Explorer/Assets/DCL/Web3/Authenticators/IDappVerificationHandler.cs deleted file mode 100644 index 6bb62f9ba50..00000000000 --- a/Explorer/Assets/DCL/Web3/Authenticators/IDappVerificationHandler.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System; - -namespace DCL.Web3.Authenticators -{ - /// - /// Interface for handling Dapp wallet verification flow. - /// Used when user authenticates via browser wallet (MetaMask, WalletConnect, etc.) - /// - public interface IDappVerificationHandler - { - /// - /// Raised when verification code should be displayed to the user. - /// Always invoked on the main thread. - /// - public event Action<(int code, DateTime expiration, string requestId)>? VerificationRequired; - } -} diff --git a/Explorer/Assets/DCL/Web3/Authenticators/IDappVerificationHandler.cs.meta b/Explorer/Assets/DCL/Web3/Authenticators/IDappVerificationHandler.cs.meta deleted file mode 100644 index 3c1b37e3e46..00000000000 --- a/Explorer/Assets/DCL/Web3/Authenticators/IDappVerificationHandler.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 447b69cf9ca1a3944be0bff61fc3de4f \ No newline at end of file diff --git a/Explorer/Assets/DCL/Web3/Authenticators/IWeb3Authenticator.cs b/Explorer/Assets/DCL/Web3/Authenticators/IWeb3Authenticator.cs index f52373cc2de..ef75d0cf166 100644 --- a/Explorer/Assets/DCL/Web3/Authenticators/IWeb3Authenticator.cs +++ b/Explorer/Assets/DCL/Web3/Authenticators/IWeb3Authenticator.cs @@ -8,8 +8,6 @@ namespace DCL.Web3.Authenticators public interface IWeb3Authenticator : IDisposable { UniTask LoginAsync(LoginPayload payload, CancellationToken ct); - - UniTask LogoutAsync(CancellationToken ct); } public enum LoginMethod diff --git a/Explorer/Assets/DCL/Web3/Authenticators/Implementations/CompositeWeb3Provider.cs b/Explorer/Assets/DCL/Web3/Authenticators/Implementations/CompositeWeb3Provider.cs index b6d56126216..6c9856791f9 100644 --- a/Explorer/Assets/DCL/Web3/Authenticators/Implementations/CompositeWeb3Provider.cs +++ b/Explorer/Assets/DCL/Web3/Authenticators/Implementations/CompositeWeb3Provider.cs @@ -11,25 +11,19 @@ namespace DCL.Web3.Authenticators /// /// Composite provider that wraps both authentication methods (ThirdWeb OTP and Dapp Wallet) /// and delegates calls to the currently selected method. - /// Implements ICompositeWeb3Provider which combines IWeb3Authenticator, IEthereumApi, - /// IDappVerificationHandler and IOtpAuthenticator to provide a single entry point for all Web3 needs. + /// Implements ICompositeWeb3Provider which combines IWeb3Authenticator, IEthereumApi + /// and IOtpAuthenticator to provide a single entry point for all Web3 needs. /// public class CompositeWeb3Provider : ICompositeWeb3Provider { private readonly ThirdWebAuthenticator thirdWebAuth; - private readonly DappWeb3Authenticator dappAuth; + private readonly DappWeb3EthereumApi dappEthereumApi; + private readonly IWeb3Authenticator dappLogin; private readonly IWeb3IdentityCache identityCache; private readonly IAnalyticsController analytics; public AuthProvider CurrentProvider { private get; set; } = AuthProvider.Dapp; - // IDappVerificationHandler - delegates to dappAuth - public event Action<(int code, DateTime expiration, string requestId)>? VerificationRequired - { - add => dappAuth.VerificationRequired += value; - remove => dappAuth.VerificationRequired -= value; - } - public event Action? OTPSendSucceeded { add => thirdWebAuth.OTPSendSucceeded += value; @@ -38,17 +32,19 @@ public event Action? OTPSendSucceeded public bool IsThirdWebOTP => CurrentProvider == AuthProvider.ThirdWeb; - private IWeb3Authenticator currentAuthenticator => CurrentProvider == AuthProvider.ThirdWeb ? thirdWebAuth : dappAuth; - private IEthereumApi currentEthereumApi => CurrentProvider == AuthProvider.ThirdWeb ? thirdWebAuth : dappAuth; + private IWeb3Authenticator currentAuthenticator => CurrentProvider == AuthProvider.ThirdWeb ? thirdWebAuth : dappLogin; + private IEthereumApi currentEthereumApi => CurrentProvider == AuthProvider.ThirdWeb ? thirdWebAuth : dappEthereumApi; public CompositeWeb3Provider( ThirdWebAuthenticator thirdWebAuth, - DappWeb3Authenticator dappAuth, + DappWeb3EthereumApi dappEthereumApi, + DappDeepLinkAuthenticator dappLogin, IWeb3IdentityCache identityCache, IAnalyticsController analytics) { this.thirdWebAuth = thirdWebAuth ?? throw new ArgumentNullException(nameof(thirdWebAuth)); - this.dappAuth = dappAuth ?? throw new ArgumentNullException(nameof(dappAuth)); + this.dappEthereumApi = dappEthereumApi ?? throw new ArgumentNullException(nameof(dappEthereumApi)); + this.dappLogin = dappLogin ?? throw new ArgumentNullException(nameof(dappLogin)); this.identityCache = identityCache ?? throw new ArgumentNullException(nameof(identityCache)); this.analytics = analytics ?? throw new ArgumentNullException(nameof(analytics)); } @@ -56,7 +52,8 @@ public CompositeWeb3Provider( public void Dispose() { thirdWebAuth.Dispose(); - dappAuth.Dispose(); + dappEthereumApi.Dispose(); + dappLogin.Dispose(); identityCache.Dispose(); } @@ -76,7 +73,15 @@ public async UniTask LoginAsync(LoginPayload payload, Cancellatio public async UniTask LogoutAsync(CancellationToken ct) { analytics.Identify(null); - await currentAuthenticator.LogoutAsync(ct); + + // ThirdWeb is the only provider holding a login session of its own. + if (IsThirdWebOTP) + await thirdWebAuth.LogoutAsync(ct); + else + // Abort any in-flight browser signature confirmation so an approval arriving + // after logout cannot complete under the logged-out session. + await dappEthereumApi.DisconnectFromAuthApiAsync(); + identityCache.Clear(); } diff --git a/Explorer/Assets/DCL/Web3/Authenticators/Implementations/Dapp/DappDeepLinkAuthenticator.cs b/Explorer/Assets/DCL/Web3/Authenticators/Implementations/Dapp/DappDeepLinkAuthenticator.cs new file mode 100644 index 00000000000..4c184abc351 --- /dev/null +++ b/Explorer/Assets/DCL/Web3/Authenticators/Implementations/Dapp/DappDeepLinkAuthenticator.cs @@ -0,0 +1,195 @@ +using CommunicationData.URLHelpers; +using Cysharp.Threading.Tasks; +using DCL.Browser; +using DCL.Diagnostics; +using DCL.Utilities; +using DCL.Web3.Abstract; +using DCL.Web3.Chains; +using DCL.Web3.Identities; +using DCL.WebRequests; +using Nethereum.Signer; +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Threading; +using Utility.Multithreading; + +namespace DCL.Web3.Authenticators +{ + /// + /// Production wallet sign-in via browser and OS deep link: generates a client-side auth request id, + /// opens the browser on the signature web app for the user to sign with their wallet, then awaits the + /// deep link that carries the resulting identity id (matched against that request id) and resolves the + /// identity from the auth server. + /// + public class DappDeepLinkAuthenticator : IWeb3Authenticator + { + private const int DEEPLINK_TIMEOUT_SECONDS = 300; + + private readonly UnityAppWebBrowser webBrowser; + private readonly URLAddress authApiUrl; + private readonly URLAddress signatureWebAppUrl; + private readonly IWeb3AccountFactory web3AccountFactory; + private readonly IWebRequestController webRequestController; + private readonly ReactiveProperty deeplinkSigninIdentityId; + private readonly ReactiveProperty loginAwaitingSigninRequestId; + private readonly URLBuilder urlBuilder = new (); + private readonly DCLSemaphoreSlim loginMutex = new (); + + public DappDeepLinkAuthenticator( + UnityAppWebBrowser webBrowser, + URLAddress authApiUrl, + URLAddress signatureWebAppUrl, + IWeb3AccountFactory web3AccountFactory, + IWebRequestController webRequestController, + ReactiveProperty deeplinkSigninIdentityId, + ReactiveProperty loginAwaitingSigninRequestId) + { + this.webBrowser = webBrowser; + this.authApiUrl = authApiUrl; + this.signatureWebAppUrl = signatureWebAppUrl; + this.web3AccountFactory = web3AccountFactory; + this.webRequestController = webRequestController; + this.deeplinkSigninIdentityId = deeplinkSigninIdentityId; + this.loginAwaitingSigninRequestId = loginAwaitingSigninRequestId; + } + + public void Dispose() + { + loginMutex.Dispose(); + } + + public async UniTask LoginAsync(LoginPayload payload, CancellationToken ct) + { + await loginMutex.WaitAsync(ct); + + try + { + // A signin id stored before this attempt minted its request cannot belong to it: drop it + // so a stale or foreign deep link does not complete this login with another session's identity. + deeplinkSigninIdentityId.Value = null; + + await UniTask.SwitchToMainThread(ct); + + // Client-generated id embedded in the browser URL; no server round-trip needed before opening the browser. + var authRequestId = Guid.NewGuid().ToString(); + var url = $"{signatureWebAppUrl}/{authRequestId}?loginMethod={payload.Method}&flow=deeplink"; +#if UNITY_EDITOR + + // Without this flag the auth website also launches a standalone Explorer build, + // which would steal the signin from the editor. + url += "&bridgeOnly"; +#endif + + webBrowser.OpenUrlMainThreadOnly(url); + + // Resolves when the OS delivers the deep link that carries the identity id. + string identityId = await WaitForSigninAsync(authRequestId, ct); + + return await FetchIdentityByIdAsync(identityId, ct); + } + finally { loginMutex.Release(); } + } + + /// + /// Awaits the first non-empty identityId, starting from the currently stored one, and consumes it. + /// + private async UniTask WaitForSigninAsync(string requestId, CancellationToken ct) + { + var completionSource = new UniTaskCompletionSource(); + + // Publishes the request id awaited by the pipeline. + loginAwaitingSigninRequestId.Value = requestId; + + using var subscription = deeplinkSigninIdentityId.UseCurrentValueAndSubscribeToUpdate(completionSource, + static (identityId, completion) => + { + if (!string.IsNullOrEmpty(identityId)) + completion.TrySetResult(identityId); + }, ct); + + try { return await completionSource.Task.Timeout(TimeSpan.FromSeconds(DEEPLINK_TIMEOUT_SECONDS), DelayType.Realtime).AttachExternalCancellation(ct); } + finally + { + // Stop accepting signins and consume the id on success, timeout and cancellation alike, so a + // later login attempt never resolves against a signin delivered for this one. + loginAwaitingSigninRequestId.Value = null; + deeplinkSigninIdentityId.Value = null; + } + } + + private async UniTask FetchIdentityByIdAsync(string identityId, CancellationToken ct) + { + urlBuilder.Clear(); + + urlBuilder.AppendDomain(URLDomain.FromString(authApiUrl)) + .AppendPath(new URLPath($"identities/{identityId}")); + + var commonArguments = new CommonArguments(urlBuilder.Build()); + + IdentityAuthResponseDto json = await webRequestController.GetAsync(commonArguments, ct, ReportCategory.AUTHENTICATION) + .CreateFromNewtonsoftJsonAsync() + .WithCustomExceptionAsync(e => e.ResponseCode switch + { + 404 => new DeeplinkSigninRetrievalException(DeeplinkSigninRetrievalException.ErrorReason.NOT_FOUND, identityId), + 410 => new DeeplinkSigninRetrievalException(DeeplinkSigninRetrievalException.ErrorReason.EXPIRED, identityId), + 403 => new DeeplinkSigninRetrievalException(DeeplinkSigninRetrievalException.ErrorReason.IP_MISMATCH, identityId), + _ => e, + }); + + string? signerAddress = null; + string? ephemeralPayload = null; + + foreach (AuthLink authLink in json.identity.authChain) + if (authLink.type == AuthLinkType.SIGNER) + signerAddress = authLink.payload; + else if (authLink.type is AuthLinkType.ECDSA_EPHEMERAL or AuthLinkType.ECDSA_EIP_1654_EPHEMERAL) + ephemeralPayload = authLink.payload; + + if (signerAddress is not { Length: > 0 }) + throw new Web3Exception($"Sign-in identity {identityId} has no SIGNER link in its auth chain"); + + if (ephemeralPayload is not { Length: > 0 }) + throw new Web3Exception($"Sign-in identity {identityId} has no ephemeral link in its auth chain"); + + IWeb3Account ephemeralAccount = web3AccountFactory.CreateAccount(new EthECKey(json.identity.ephemeralIdentity.privateKey)); + + // Every signed request is made with this ephemeral key: if it does not match the address the wallet + // signed into the ephemeral link, servers reject every signature. Fail fast at login instead. + if (!ephemeralPayload.Contains(ephemeralAccount.Address, StringComparison.OrdinalIgnoreCase)) + throw new Web3Exception($"Sign-in identity {identityId} is inconsistent: the ephemeral private key does not match the auth chain ephemeral address {ephemeralAccount.Address}"); + + var authChain = AuthChain.Create(); + + foreach (AuthLink authLink in json.identity.authChain) + authChain.Set(authLink); + + DateTime expiration = DateTime.Parse(json.identity.expiration, null, DateTimeStyles.RoundtripKind); + + return new DecentralandIdentity(new Web3Address(signerAddress), ephemeralAccount, expiration, authChain, IWeb3Identity.Web3IdentitySource.DEEPLINK); + } + + // Field names mirror the auth server's JSON payloads verbatim, so they intentionally break the naming rules. + [Serializable] + private struct IdentityAuthResponseDto + { + public IdentityDto identity; + + [Serializable] + public struct IdentityDto + { + public string expiration; + public EphemeralIdentityDto ephemeralIdentity; + public List authChain; + } + + [Serializable] + public struct EphemeralIdentityDto + { + public string address; + public string privateKey; + public string publicKey; + } + } + } +} diff --git a/Explorer/Assets/DCL/Web3/Authenticators/Implementations/Dapp/DappDeepLinkAuthenticator.cs.meta b/Explorer/Assets/DCL/Web3/Authenticators/Implementations/Dapp/DappDeepLinkAuthenticator.cs.meta new file mode 100644 index 00000000000..4b72427151c --- /dev/null +++ b/Explorer/Assets/DCL/Web3/Authenticators/Implementations/Dapp/DappDeepLinkAuthenticator.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 91ddac7c757b5e74c9d9a9ead64da6dd \ No newline at end of file diff --git a/Explorer/Assets/DCL/Web3/Authenticators/Implementations/Dapp/DappWeb3Authenticator.ICodeVerificationFeatureFlag.cs b/Explorer/Assets/DCL/Web3/Authenticators/Implementations/Dapp/DappWeb3Authenticator.ICodeVerificationFeatureFlag.cs deleted file mode 100644 index 3b768c49f3c..00000000000 --- a/Explorer/Assets/DCL/Web3/Authenticators/Implementations/Dapp/DappWeb3Authenticator.ICodeVerificationFeatureFlag.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace DCL.Web3.Authenticators -{ - public partial class DappWeb3Authenticator - { - public interface ICodeVerificationFeatureFlag - { - public bool ShouldWaitForCodeVerificationFromServer { get; } - } - } -} diff --git a/Explorer/Assets/DCL/Web3/Authenticators/Implementations/Dapp/DappWeb3Authenticator.ICodeVerificationFeatureFlag.cs.meta b/Explorer/Assets/DCL/Web3/Authenticators/Implementations/Dapp/DappWeb3Authenticator.ICodeVerificationFeatureFlag.cs.meta deleted file mode 100644 index de30f6f1ca2..00000000000 --- a/Explorer/Assets/DCL/Web3/Authenticators/Implementations/Dapp/DappWeb3Authenticator.ICodeVerificationFeatureFlag.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: c1518914ba266434a9280117d00451ea \ No newline at end of file diff --git a/Explorer/Assets/DCL/Web3/Authenticators/Implementations/Dapp/DappWeb3Authenticator.TransactionApiResponse.cs b/Explorer/Assets/DCL/Web3/Authenticators/Implementations/Dapp/DappWeb3Authenticator.TransactionApiResponse.cs deleted file mode 100644 index 12138998f46..00000000000 --- a/Explorer/Assets/DCL/Web3/Authenticators/Implementations/Dapp/DappWeb3Authenticator.TransactionApiResponse.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System; - -namespace DCL.Web3.Authenticators -{ - public partial class DappWeb3Authenticator - { - [Serializable] - public struct TransactionApiResponse - { - public string txHash; - } - } -} \ No newline at end of file diff --git a/Explorer/Assets/DCL/Web3/Authenticators/Implementations/Dapp/DappWeb3Authenticator.TransactionApiResponse.cs.meta b/Explorer/Assets/DCL/Web3/Authenticators/Implementations/Dapp/DappWeb3Authenticator.TransactionApiResponse.cs.meta deleted file mode 100644 index 90bcad5db13..00000000000 --- a/Explorer/Assets/DCL/Web3/Authenticators/Implementations/Dapp/DappWeb3Authenticator.TransactionApiResponse.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: c1bc092dc90b18d4c9a88ef720128422 \ No newline at end of file diff --git a/Explorer/Assets/DCL/Web3/Authenticators/Implementations/Dapp/DappWeb3Authenticator.TransferAuthApiRequest.cs b/Explorer/Assets/DCL/Web3/Authenticators/Implementations/Dapp/DappWeb3Authenticator.TransferAuthApiRequest.cs deleted file mode 100644 index 24fddd54323..00000000000 --- a/Explorer/Assets/DCL/Web3/Authenticators/Implementations/Dapp/DappWeb3Authenticator.TransferAuthApiRequest.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System; - -namespace DCL.Web3.Authenticators -{ - public partial class DappWeb3Authenticator - { - [Serializable] - public struct TransferAuthApiRequest - { - public string method; - public object[] @params; - } - } -} \ No newline at end of file diff --git a/Explorer/Assets/DCL/Web3/Authenticators/Implementations/Dapp/DappWeb3Authenticator.TransferAuthApiRequest.cs.meta b/Explorer/Assets/DCL/Web3/Authenticators/Implementations/Dapp/DappWeb3Authenticator.TransferAuthApiRequest.cs.meta deleted file mode 100644 index dbfdec40154..00000000000 --- a/Explorer/Assets/DCL/Web3/Authenticators/Implementations/Dapp/DappWeb3Authenticator.TransferAuthApiRequest.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: dc75ab5ffcbd30743abf601ea5a2ead4 \ No newline at end of file diff --git a/Explorer/Assets/DCL/Web3/Authenticators/Implementations/Dapp/DappWeb3Authenticator.VerificationStatus.cs b/Explorer/Assets/DCL/Web3/Authenticators/Implementations/Dapp/DappWeb3Authenticator.VerificationStatus.cs deleted file mode 100644 index 8699a10d4e8..00000000000 --- a/Explorer/Assets/DCL/Web3/Authenticators/Implementations/Dapp/DappWeb3Authenticator.VerificationStatus.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System; - -namespace DCL.Web3.Authenticators -{ - public partial class DappWeb3Authenticator - { - [Serializable] - private struct CodeVerificationStatus - { - public string requestId; - } - } -} diff --git a/Explorer/Assets/DCL/Web3/Authenticators/Implementations/Dapp/DappWeb3Authenticator.VerificationStatus.cs.meta b/Explorer/Assets/DCL/Web3/Authenticators/Implementations/Dapp/DappWeb3Authenticator.VerificationStatus.cs.meta deleted file mode 100644 index 1a9f2065ec8..00000000000 --- a/Explorer/Assets/DCL/Web3/Authenticators/Implementations/Dapp/DappWeb3Authenticator.VerificationStatus.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 5c9ce2ca4b793fd45b2b0af94c16b7d5 \ No newline at end of file diff --git a/Explorer/Assets/DCL/Web3/Authenticators/Implementations/Dapp/DappWeb3Authenticator.Default.cs b/Explorer/Assets/DCL/Web3/Authenticators/Implementations/Dapp/DappWeb3EthereumApi.Default.cs similarity index 70% rename from Explorer/Assets/DCL/Web3/Authenticators/Implementations/Dapp/DappWeb3Authenticator.Default.cs rename to Explorer/Assets/DCL/Web3/Authenticators/Implementations/Dapp/DappWeb3EthereumApi.Default.cs index f26dc0b0b40..66dcf5c923c 100644 --- a/Explorer/Assets/DCL/Web3/Authenticators/Implementations/Dapp/DappWeb3Authenticator.Default.cs +++ b/Explorer/Assets/DCL/Web3/Authenticators/Implementations/Dapp/DappWeb3EthereumApi.Default.cs @@ -4,23 +4,16 @@ using DCL.Multiplayer.Connections.DecentralandUrls; using DCL.Web3.Abstract; using DCL.Web3.Identities; -using System; using System.Collections.Generic; using System.Threading; namespace DCL.Web3.Authenticators { - public partial class DappWeb3Authenticator + public partial class DappWeb3EthereumApi { - public class Default : IWeb3Authenticator, IEthereumApi, IDappVerificationHandler + public class Default : IWeb3Authenticator, IEthereumApi { - private readonly DappWeb3Authenticator origin; - - public event Action<(int code, DateTime expiration, string requestId)>? VerificationRequired - { - add => origin.VerificationRequired += value; - remove => origin.VerificationRequired -= value; - } + private readonly DappWeb3EthereumApi origin; public Default(IWeb3IdentityCache identityCache, IDecentralandUrlsSource decentralandUrlsSource, IWeb3AccountFactory web3AccountFactory, DecentralandEnvironment environment) { @@ -28,7 +21,7 @@ public Default(IWeb3IdentityCache identityCache, IDecentralandUrlsSource decentr URLAddress signatureUrl = URLAddress.FromString(decentralandUrlsSource.Url(DecentralandUrl.AuthSignatureWebApp)); URLDomain rpcServerUrl = URLDomain.FromString(decentralandUrlsSource.Url(DecentralandUrl.ApiRpc)); - origin = new DappWeb3Authenticator( + origin = new DappWeb3EthereumApi( new UnityAppWebBrowser(decentralandUrlsSource), authApiUrl, signatureUrl, @@ -58,8 +51,7 @@ public Default(IWeb3IdentityCache identityCache, IDecentralandUrlsSource decentr "eth_getTransactionCount", "eth_getBlockByNumber", "eth_getCode" }, - environment, - new InvalidAuthCodeVerificationFeatureFlag() + environment ); } @@ -73,18 +65,6 @@ public UniTask SendAsync(EthApiRequest request, Web3RequestSourc // IWeb3Authenticator public UniTask LoginAsync(LoginPayload payload, CancellationToken ct) => origin.LoginAsync(payload, ct); - - public UniTask LogoutAsync(CancellationToken ct) => - origin.LogoutAsync(ct); - - // IDappVerificationHandler - public void CancelCurrentWeb3Operation() => - origin.CancelCurrentWeb3Operation(); - - private class InvalidAuthCodeVerificationFeatureFlag : ICodeVerificationFeatureFlag - { - public bool ShouldWaitForCodeVerificationFromServer => false; - } } } } diff --git a/Explorer/Assets/DCL/Web3/Authenticators/Implementations/Dapp/DappWeb3Authenticator.Default.cs.meta b/Explorer/Assets/DCL/Web3/Authenticators/Implementations/Dapp/DappWeb3EthereumApi.Default.cs.meta similarity index 100% rename from Explorer/Assets/DCL/Web3/Authenticators/Implementations/Dapp/DappWeb3Authenticator.Default.cs.meta rename to Explorer/Assets/DCL/Web3/Authenticators/Implementations/Dapp/DappWeb3EthereumApi.Default.cs.meta diff --git a/Explorer/Assets/DCL/Web3/Authenticators/Implementations/Dapp/DappWeb3Authenticator.EthRequest.cs b/Explorer/Assets/DCL/Web3/Authenticators/Implementations/Dapp/DappWeb3EthereumApi.EthRequest.cs similarity index 86% rename from Explorer/Assets/DCL/Web3/Authenticators/Implementations/Dapp/DappWeb3Authenticator.EthRequest.cs rename to Explorer/Assets/DCL/Web3/Authenticators/Implementations/Dapp/DappWeb3EthereumApi.EthRequest.cs index 75d68a581d3..f9f8d43fdce 100644 --- a/Explorer/Assets/DCL/Web3/Authenticators/Implementations/Dapp/DappWeb3Authenticator.EthRequest.cs +++ b/Explorer/Assets/DCL/Web3/Authenticators/Implementations/Dapp/DappWeb3EthereumApi.EthRequest.cs @@ -3,7 +3,7 @@ namespace DCL.Web3.Authenticators { - public partial class DappWeb3Authenticator + public partial class DappWeb3EthereumApi { [Serializable] private struct AuthorizedEthApiRequest diff --git a/Explorer/Assets/DCL/Web3/Authenticators/Implementations/Dapp/DappWeb3Authenticator.EthRequest.cs.meta b/Explorer/Assets/DCL/Web3/Authenticators/Implementations/Dapp/DappWeb3EthereumApi.EthRequest.cs.meta similarity index 100% rename from Explorer/Assets/DCL/Web3/Authenticators/Implementations/Dapp/DappWeb3Authenticator.EthRequest.cs.meta rename to Explorer/Assets/DCL/Web3/Authenticators/Implementations/Dapp/DappWeb3EthereumApi.EthRequest.cs.meta diff --git a/Explorer/Assets/DCL/Web3/Authenticators/Implementations/Dapp/DappWeb3Authenticator.LoginAuthApiRequest.cs b/Explorer/Assets/DCL/Web3/Authenticators/Implementations/Dapp/DappWeb3EthereumApi.LoginAuthApiRequest.cs similarity index 82% rename from Explorer/Assets/DCL/Web3/Authenticators/Implementations/Dapp/DappWeb3Authenticator.LoginAuthApiRequest.cs rename to Explorer/Assets/DCL/Web3/Authenticators/Implementations/Dapp/DappWeb3EthereumApi.LoginAuthApiRequest.cs index 2dfde7a57f3..2c8e4dd91f7 100644 --- a/Explorer/Assets/DCL/Web3/Authenticators/Implementations/Dapp/DappWeb3Authenticator.LoginAuthApiRequest.cs +++ b/Explorer/Assets/DCL/Web3/Authenticators/Implementations/Dapp/DappWeb3EthereumApi.LoginAuthApiRequest.cs @@ -2,7 +2,7 @@ namespace DCL.Web3.Authenticators { - public partial class DappWeb3Authenticator + public partial class DappWeb3EthereumApi { [Serializable] public struct LoginAuthApiRequest diff --git a/Explorer/Assets/DCL/Web3/Authenticators/Implementations/Dapp/DappWeb3Authenticator.LoginAuthApiRequest.cs.meta b/Explorer/Assets/DCL/Web3/Authenticators/Implementations/Dapp/DappWeb3EthereumApi.LoginAuthApiRequest.cs.meta similarity index 100% rename from Explorer/Assets/DCL/Web3/Authenticators/Implementations/Dapp/DappWeb3Authenticator.LoginAuthApiRequest.cs.meta rename to Explorer/Assets/DCL/Web3/Authenticators/Implementations/Dapp/DappWeb3EthereumApi.LoginAuthApiRequest.cs.meta diff --git a/Explorer/Assets/DCL/Web3/Authenticators/Implementations/Dapp/DappWeb3Authenticator.LoginAuthApiResponse.cs b/Explorer/Assets/DCL/Web3/Authenticators/Implementations/Dapp/DappWeb3EthereumApi.LoginAuthApiResponse.cs similarity index 84% rename from Explorer/Assets/DCL/Web3/Authenticators/Implementations/Dapp/DappWeb3Authenticator.LoginAuthApiResponse.cs rename to Explorer/Assets/DCL/Web3/Authenticators/Implementations/Dapp/DappWeb3EthereumApi.LoginAuthApiResponse.cs index dfbc361d06f..ce21e5ea0d0 100644 --- a/Explorer/Assets/DCL/Web3/Authenticators/Implementations/Dapp/DappWeb3Authenticator.LoginAuthApiResponse.cs +++ b/Explorer/Assets/DCL/Web3/Authenticators/Implementations/Dapp/DappWeb3EthereumApi.LoginAuthApiResponse.cs @@ -2,7 +2,7 @@ namespace DCL.Web3.Authenticators { - public partial class DappWeb3Authenticator + public partial class DappWeb3EthereumApi { [Serializable] private struct LoginAuthApiResponse diff --git a/Explorer/Assets/DCL/Web3/Authenticators/Implementations/Dapp/DappWeb3Authenticator.LoginAuthApiResponse.cs.meta b/Explorer/Assets/DCL/Web3/Authenticators/Implementations/Dapp/DappWeb3EthereumApi.LoginAuthApiResponse.cs.meta similarity index 100% rename from Explorer/Assets/DCL/Web3/Authenticators/Implementations/Dapp/DappWeb3Authenticator.LoginAuthApiResponse.cs.meta rename to Explorer/Assets/DCL/Web3/Authenticators/Implementations/Dapp/DappWeb3EthereumApi.LoginAuthApiResponse.cs.meta diff --git a/Explorer/Assets/DCL/Web3/Authenticators/Implementations/Dapp/DappWeb3Authenticator.MethodResponse.cs b/Explorer/Assets/DCL/Web3/Authenticators/Implementations/Dapp/DappWeb3EthereumApi.MethodResponse.cs similarity index 84% rename from Explorer/Assets/DCL/Web3/Authenticators/Implementations/Dapp/DappWeb3Authenticator.MethodResponse.cs rename to Explorer/Assets/DCL/Web3/Authenticators/Implementations/Dapp/DappWeb3EthereumApi.MethodResponse.cs index 446681d4940..ba503b91070 100644 --- a/Explorer/Assets/DCL/Web3/Authenticators/Implementations/Dapp/DappWeb3Authenticator.MethodResponse.cs +++ b/Explorer/Assets/DCL/Web3/Authenticators/Implementations/Dapp/DappWeb3EthereumApi.MethodResponse.cs @@ -2,7 +2,7 @@ namespace DCL.Web3.Authenticators { - public partial class DappWeb3Authenticator + public partial class DappWeb3EthereumApi { [Serializable] private struct MethodResponse diff --git a/Explorer/Assets/DCL/Web3/Authenticators/Implementations/Dapp/DappWeb3Authenticator.MethodResponse.cs.meta b/Explorer/Assets/DCL/Web3/Authenticators/Implementations/Dapp/DappWeb3EthereumApi.MethodResponse.cs.meta similarity index 100% rename from Explorer/Assets/DCL/Web3/Authenticators/Implementations/Dapp/DappWeb3Authenticator.MethodResponse.cs.meta rename to Explorer/Assets/DCL/Web3/Authenticators/Implementations/Dapp/DappWeb3EthereumApi.MethodResponse.cs.meta diff --git a/Explorer/Assets/DCL/Web3/Authenticators/Implementations/Dapp/DappWeb3Authenticator.SignatureIdResponse.cs b/Explorer/Assets/DCL/Web3/Authenticators/Implementations/Dapp/DappWeb3EthereumApi.SignatureIdResponse.cs similarity index 86% rename from Explorer/Assets/DCL/Web3/Authenticators/Implementations/Dapp/DappWeb3Authenticator.SignatureIdResponse.cs rename to Explorer/Assets/DCL/Web3/Authenticators/Implementations/Dapp/DappWeb3EthereumApi.SignatureIdResponse.cs index 42522810093..f102ff91c20 100644 --- a/Explorer/Assets/DCL/Web3/Authenticators/Implementations/Dapp/DappWeb3Authenticator.SignatureIdResponse.cs +++ b/Explorer/Assets/DCL/Web3/Authenticators/Implementations/Dapp/DappWeb3EthereumApi.SignatureIdResponse.cs @@ -2,7 +2,7 @@ namespace DCL.Web3.Authenticators { - public partial class DappWeb3Authenticator + public partial class DappWeb3EthereumApi { [Serializable] private struct SignatureIdResponse diff --git a/Explorer/Assets/DCL/Web3/Authenticators/Implementations/Dapp/DappWeb3Authenticator.SignatureIdResponse.cs.meta b/Explorer/Assets/DCL/Web3/Authenticators/Implementations/Dapp/DappWeb3EthereumApi.SignatureIdResponse.cs.meta similarity index 100% rename from Explorer/Assets/DCL/Web3/Authenticators/Implementations/Dapp/DappWeb3Authenticator.SignatureIdResponse.cs.meta rename to Explorer/Assets/DCL/Web3/Authenticators/Implementations/Dapp/DappWeb3EthereumApi.SignatureIdResponse.cs.meta diff --git a/Explorer/Assets/DCL/Web3/Authenticators/Implementations/Dapp/DappWeb3Authenticator.cs b/Explorer/Assets/DCL/Web3/Authenticators/Implementations/Dapp/DappWeb3EthereumApi.cs similarity index 82% rename from Explorer/Assets/DCL/Web3/Authenticators/Implementations/Dapp/DappWeb3Authenticator.cs rename to Explorer/Assets/DCL/Web3/Authenticators/Implementations/Dapp/DappWeb3EthereumApi.cs index b0e3f6fc317..3f147bcda02 100644 --- a/Explorer/Assets/DCL/Web3/Authenticators/Implementations/Dapp/DappWeb3Authenticator.cs +++ b/Explorer/Assets/DCL/Web3/Authenticators/Implementations/Dapp/DappWeb3EthereumApi.cs @@ -20,14 +20,14 @@ namespace DCL.Web3.Authenticators { - public partial class DappWeb3Authenticator : IWeb3Authenticator, IEthereumApi, IDappVerificationHandler + public partial class DappWeb3EthereumApi : IEthereumApi { - private const double IDENTITY_EXPIRATION_PERIOD = 30; + private const double IDENTITY_EXPIRATION_PERIOD_FALLBACK_IN_DAYS = 30; private const int TIMEOUT_SECONDS = 30; private const int RPC_BUFFER_SIZE = 50000; - private readonly IWebBrowser webBrowser; + private readonly UnityAppWebBrowser webBrowser; private readonly URLAddress authApiUrl; private readonly URLAddress signatureWebAppUrl; private readonly URLDomain rpcServerUrl; @@ -36,7 +36,6 @@ public partial class DappWeb3Authenticator : IWeb3Authenticator, IEthereumApi, I private readonly HashSet whitelistMethods; private readonly HashSet readOnlyMethods; private readonly DecentralandEnvironment environment; - private readonly ICodeVerificationFeatureFlag codeVerificationFeatureFlag; private readonly int? identityExpirationDuration; // Allow only one web3 operation at a time @@ -49,14 +48,8 @@ public partial class DappWeb3Authenticator : IWeb3Authenticator, IEthereumApi, I private SocketIO? authApiWebSocket; private DCLWebSocket? rpcWebSocket; private UniTaskCompletionSource? signatureOutcomeTask; - private UniTaskCompletionSource? codeVerificationTask; - public delegate void VerificationDelegate(int code, DateTime expiration); - private VerificationDelegate? signatureVerificationCallback; - - public event Action<(int code, DateTime expiration, string requestId)>? VerificationRequired; - - public DappWeb3Authenticator(IWebBrowser webBrowser, + public DappWeb3EthereumApi(UnityAppWebBrowser webBrowser, URLAddress authApiUrl, URLAddress signatureWebAppUrl, URLDomain rpcServerUrl, @@ -64,7 +57,7 @@ public DappWeb3Authenticator(IWebBrowser webBrowser, IWeb3AccountFactory web3AccountFactory, HashSet whitelistMethods, HashSet readOnlyMethods, - DecentralandEnvironment environment, ICodeVerificationFeatureFlag codeVerificationFeatureFlag, + DecentralandEnvironment environment, int? identityExpirationDuration = null) { this.webBrowser = webBrowser; @@ -76,7 +69,6 @@ public DappWeb3Authenticator(IWebBrowser webBrowser, this.whitelistMethods = whitelistMethods; this.readOnlyMethods = readOnlyMethods; this.environment = environment; - this.codeVerificationFeatureFlag = codeVerificationFeatureFlag; this.identityExpirationDuration = identityExpirationDuration; } @@ -141,13 +133,13 @@ public async UniTask SendAsync(EthApiRequest request, Web3Reques } /// - /// 1. An authentication request is sent to the server - /// 2. Open a tab to let the user sign through the browser with his custom installed wallet - /// 3. Use the signature information to generate the identity + /// Legacy socket-based wallet sign-in (kept for the Archipelago dev playgrounds via + /// ). The production wallet flow is . /// /// Login payload containing the authentication method + /// Token that cancels the login flow /// - public async UniTask LoginAsync(LoginPayload payload, CancellationToken ct) + private async UniTask LoginAsync(LoginPayload payload, CancellationToken ct) { await mutex.WaitAsync(ct); @@ -166,7 +158,7 @@ public async UniTask LoginAsync(LoginPayload payload, Cancellatio // 1 week expiration day, just like unity-renderer DateTime sessionExpiration = identityExpirationDuration != null ? DateTime.UtcNow.AddSeconds(identityExpirationDuration.Value) - : DateTime.UtcNow.AddDays(IDENTITY_EXPIRATION_PERIOD); + : DateTime.UtcNow.AddDays(IDENTITY_EXPIRATION_PERIOD_FALLBACK_IN_DAYS); string ephemeralMessage = CreateEphemeralMessage(ephemeralAccount, sessionExpiration); @@ -183,11 +175,6 @@ public async UniTask LoginAsync(LoginPayload payload, Cancellatio await UniTask.SwitchToMainThread(ct); - if (codeVerificationFeatureFlag.ShouldWaitForCodeVerificationFromServer) - WaitForCodeVerificationAsync(authenticationResponse.requestId, authenticationResponse.code, signatureExpiration, ct).Forget(); - else - VerificationRequired?.Invoke((authenticationResponse.code, signatureExpiration, authenticationResponse.requestId)); - LoginAuthApiResponse response = await RequestSignatureAsync(authenticationResponse.requestId, payload.Method, signatureExpiration, ct); @@ -204,7 +191,7 @@ public async UniTask LoginAsync(LoginPayload payload, Cancellatio // To keep cohesiveness between the platform, convert the user address to lower case return new DecentralandIdentity(new Web3Address(response.sender), - ephemeralAccount, sessionExpiration, authChain, IWeb3Identity.Web3IdentitySource.Dapp); + ephemeralAccount, sessionExpiration, authChain, IWeb3Identity.Web3IdentitySource.DAPP); } catch (Exception) { @@ -226,24 +213,15 @@ public async UniTask LoginAsync(LoginPayload payload, Cancellatio } } - public async UniTask LogoutAsync(CancellationToken ct) => - await DisconnectFromAuthApiAsync(); - - public void CancelCurrentWeb3Operation() - { - // Cancel the task waiting for the browser signature - signatureOutcomeTask?.TrySetCanceled(); - - // Also cancel code verification if that's what was hanging (during Login) - codeVerificationTask?.TrySetCanceled(); - } - - private async UniTask DisconnectFromAuthApiAsync() + /// + /// Drops the auth-api socket and aborts any in-flight browser signature confirmation, + /// so an approval arriving later cannot complete under the previous session. + /// + public async UniTask DisconnectFromAuthApiAsync() { if (authApiWebSocket is { Connected: true }) await authApiWebSocket.DisconnectAsync(); - codeVerificationTask?.TrySetCanceled(); signatureOutcomeTask?.TrySetCanceled(); } @@ -375,8 +353,6 @@ private async UniTask SendWithConfirmationAsync(EthApiRequest re await UniTask.SwitchToMainThread(ct); - signatureVerificationCallback?.Invoke(authenticationResponse.code, signatureExpiration); - MethodResponse response = await RequestSignatureAsync(authenticationResponse.requestId, null, signatureExpiration, ct); if (authApiPendingOperations <= 1) @@ -443,9 +419,6 @@ private string CreateEphemeralMessage(IWeb3Account ephemeralAccount, DateTime ex private void ProcessSignatureOutcomeMessage(SocketIOResponse response) => signatureOutcomeTask?.TrySetResult(response); - private void ProcessCodeVerificationStatus(SocketIOResponse response) => - codeVerificationTask?.TrySetResult(response); - private async UniTask RequestSignatureAsync(string requestId, LoginMethod? method, DateTime expiration, CancellationToken ct) { string url = @@ -453,7 +426,7 @@ private async UniTask RequestSignatureAsync(string requestId, LoginMethod? ? $"{signatureWebAppUrl}/{requestId}?loginMethod={method.Value}" : $"{signatureWebAppUrl}/{requestId}"; - webBrowser.OpenUrl(url); + webBrowser.OpenUrlMainThreadOnly(url); signatureOutcomeTask?.TrySetCanceled(ct); signatureOutcomeTask = new UniTaskCompletionSource(); @@ -506,7 +479,6 @@ private async UniTask ConnectToAuthApiAsync() authApiWebSocket.JsonSerializer = new NewtonsoftJsonSerializer(new JsonSerializerSettings()); authApiWebSocket.On("outcome", ProcessSignatureOutcomeMessage); - authApiWebSocket.On("request-validation-status", ProcessCodeVerificationStatus); authApiWebSocket.OnDisconnected += OnWebSocketDisconnected; authApiWebSocket.OnError += OnWebSocketError; } @@ -521,13 +493,11 @@ await authApiWebSocket private void OnWebSocketError(object sender, string error) { signatureOutcomeTask?.TrySetException(new WebSocketException(WebSocketError.Faulted, error)); - codeVerificationTask?.TrySetException(new WebSocketException(WebSocketError.Faulted, error)); } private void OnWebSocketDisconnected(object sender, string reason) { signatureOutcomeTask?.TrySetException(new WebSocketException(WebSocketError.ConnectionClosedPrematurely, reason)); - codeVerificationTask?.TrySetException(new WebSocketException(WebSocketError.ConnectionClosedPrematurely, reason)); } private bool IsReadOnly(EthApiRequest request) @@ -538,32 +508,5 @@ private bool IsReadOnly(EthApiRequest request) return false; } - - /// - /// Waits until we receive the verification status from the server - /// So then we raise the VerificationRequired event - /// - private async UniTask WaitForCodeVerificationAsync(string requestId, int code, DateTime expiration, CancellationToken ct) - { - codeVerificationTask?.TrySetCanceled(ct); - codeVerificationTask = new UniTaskCompletionSource(); - - TimeSpan duration = expiration - DateTime.UtcNow; - - try - { - SocketIOResponse response = await codeVerificationTask.Task.Timeout(duration).AttachExternalCancellation(ct); - - CodeVerificationStatus validation = response.GetValue(); - - if (validation.requestId == requestId) - { - await UniTask.SwitchToMainThread(ct); - VerificationRequired?.Invoke((code, expiration, requestId)); - } - } - catch (TimeoutException e) { throw new CodeVerificationException($"Code verification expired: {expiration}", e); } - catch (WebSocketException e) { throw new CodeVerificationException("An error occurred while verifying the code: unable to complete the operation due to a WebSocket issue", e); } - } } } diff --git a/Explorer/Assets/DCL/Web3/Authenticators/Implementations/Dapp/DappWeb3Authenticator.cs.meta b/Explorer/Assets/DCL/Web3/Authenticators/Implementations/Dapp/DappWeb3EthereumApi.cs.meta similarity index 100% rename from Explorer/Assets/DCL/Web3/Authenticators/Implementations/Dapp/DappWeb3Authenticator.cs.meta rename to Explorer/Assets/DCL/Web3/Authenticators/Implementations/Dapp/DappWeb3EthereumApi.cs.meta diff --git a/Explorer/Assets/DCL/Web3/Authenticators/Implementations/PrivateKeyAuthenticator.cs b/Explorer/Assets/DCL/Web3/Authenticators/Implementations/PrivateKeyAuthenticator.cs index a5cf0c9f72c..9594ef1e261 100644 --- a/Explorer/Assets/DCL/Web3/Authenticators/Implementations/PrivateKeyAuthenticator.cs +++ b/Explorer/Assets/DCL/Web3/Authenticators/Implementations/PrivateKeyAuthenticator.cs @@ -34,7 +34,7 @@ public void Dispose() { } public bool IsExpired => false; public AuthChain AuthChain { get; } - public IWeb3Identity.Web3IdentitySource Source { get; set; } = IWeb3Identity.Web3IdentitySource.None; + public IWeb3Identity.Web3IdentitySource Source { get; set; } = IWeb3Identity.Web3IdentitySource.NONE; public AuthChain Sign(string entityId) { @@ -108,8 +108,5 @@ private static AuthChain CreateAuthChain(IWeb3Account account, IWeb3Account ephe return authChain; } - - public UniTask LogoutAsync(CancellationToken ct) => - UniTask.CompletedTask; } } diff --git a/Explorer/Assets/DCL/Web3/Authenticators/Implementations/RandomGeneratedWeb3Authenticator.cs b/Explorer/Assets/DCL/Web3/Authenticators/Implementations/RandomGeneratedWeb3Authenticator.cs index c0d48e61e4c..2fb637fba6c 100644 --- a/Explorer/Assets/DCL/Web3/Authenticators/Implementations/RandomGeneratedWeb3Authenticator.cs +++ b/Explorer/Assets/DCL/Web3/Authenticators/Implementations/RandomGeneratedWeb3Authenticator.cs @@ -45,13 +45,10 @@ public UniTask LoginAsync(LoginPayload payload, CancellationToken ephemeralAccount, expiration, authChain, - IWeb3Identity.Web3IdentitySource.None + IWeb3Identity.Web3IdentitySource.NONE ).AsUniTaskResult(); } - public UniTask LogoutAsync(CancellationToken ct) => - UniTask.CompletedTask; - public UniTask RequestTransferAsync(string giftUrn, string recipientAddress, CancellationToken ct) { throw new NotImplementedException(); diff --git a/Explorer/Assets/DCL/Web3/Authenticators/Implementations/TokenFileAuthenticator.cs b/Explorer/Assets/DCL/Web3/Authenticators/Implementations/TokenFileAuthenticator.cs index ea2d40aa707..b14af50a27c 100644 --- a/Explorer/Assets/DCL/Web3/Authenticators/Implementations/TokenFileAuthenticator.cs +++ b/Explorer/Assets/DCL/Web3/Authenticators/Implementations/TokenFileAuthenticator.cs @@ -93,12 +93,9 @@ private async UniTask LoginAsync(CancellationToken ct) DateTime expiration = DateTime.Parse(json.identity.expiration, null, DateTimeStyles.RoundtripKind); return new DecentralandIdentity(new Web3Address(address), ephemeralAccount, expiration, authChain, - IWeb3Identity.Web3IdentitySource.TokenFile); + IWeb3Identity.Web3IdentitySource.TOKEN_FILE); } - public UniTask LogoutAsync(CancellationToken ct) => - UniTask.CompletedTask; - public UniTask RequestTransferAsync(string giftUrn, string recipientAddress, CancellationToken ct) { throw new NotImplementedException(); diff --git a/Explorer/Assets/DCL/Web3/Authenticators/Implementations/TrackedTokenFileAuthenticator.cs b/Explorer/Assets/DCL/Web3/Authenticators/Implementations/TrackedTokenFileAuthenticator.cs index 52f184a1f51..a5adc9a9442 100644 --- a/Explorer/Assets/DCL/Web3/Authenticators/Implementations/TrackedTokenFileAuthenticator.cs +++ b/Explorer/Assets/DCL/Web3/Authenticators/Implementations/TrackedTokenFileAuthenticator.cs @@ -62,9 +62,6 @@ public async UniTask LoginAsync(LoginPayload payload, Cancellatio } } - public UniTask LogoutAsync(CancellationToken ct) => - inner.LogoutAsync(ct); - public void Dispose() => inner.Dispose(); } diff --git a/Explorer/Assets/DCL/Web3/Identities/IWeb3Identity.cs b/Explorer/Assets/DCL/Web3/Identities/IWeb3Identity.cs index 58d80e65e36..21aa395d288 100644 --- a/Explorer/Assets/DCL/Web3/Identities/IWeb3Identity.cs +++ b/Explorer/Assets/DCL/Web3/Identities/IWeb3Identity.cs @@ -18,11 +18,12 @@ public interface IWeb3Identity : IDisposable enum Web3IdentitySource { - None, - Cached, - TokenFile, - Dapp, - OTP + NONE, + CACHED, + TOKEN_FILE, + DAPP, + OTP, + DEEPLINK, } class Random : IWeb3Identity @@ -55,7 +56,7 @@ private Random(Web3Address address, DateTime expiration, IWeb3Account ephemeralA public IWeb3Account EphemeralAccount { get; } public bool IsExpired { get; } public AuthChain AuthChain { get; } - public Web3IdentitySource Source { get; set; } = Web3IdentitySource.None; + public Web3IdentitySource Source { get; set; } = Web3IdentitySource.NONE; public AuthChain Sign(string entityId) => throw new Exception("RandomIdentity cannot sign anything"); diff --git a/Explorer/Assets/DCL/Web3/Identities/PlayerPrefsIdentityProvider.DecentralandIdentityWithNethereumAccountJsonSerializer.cs b/Explorer/Assets/DCL/Web3/Identities/PlayerPrefsIdentityProvider.DecentralandIdentityWithNethereumAccountJsonSerializer.cs index 6a48a08ae53..6809bf73594 100644 --- a/Explorer/Assets/DCL/Web3/Identities/PlayerPrefsIdentityProvider.DecentralandIdentityWithNethereumAccountJsonSerializer.cs +++ b/Explorer/Assets/DCL/Web3/Identities/PlayerPrefsIdentityProvider.DecentralandIdentityWithNethereumAccountJsonSerializer.cs @@ -35,7 +35,7 @@ public DecentralandIdentityWithNethereumAccountJsonSerializer(IWeb3AccountFactor accountFactory.CreateAccount(new EthECKey(jsonRoot.key)), DateTime.Parse(jsonRoot.expiration, null, DateTimeStyles.RoundtripKind), authChain, - IWeb3Identity.Web3IdentitySource.Cached); + IWeb3Identity.Web3IdentitySource.CACHED); } public string Serialize(IWeb3Identity identity) diff --git a/Explorer/Web3.csproj.DotSettings b/Explorer/Web3.csproj.DotSettings new file mode 100644 index 00000000000..869205a4df0 --- /dev/null +++ b/Explorer/Web3.csproj.DotSettings @@ -0,0 +1,2 @@ + + True \ No newline at end of file