diff --git a/CHANGELOG.md b/CHANGELOG.md index c644343d..76a4992d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,8 +6,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning 2.0](https://semver.org/spec/v2.0.0.html). ## v2.10.1 +### Changed +- Improved error message when logging in with a Lykos account fails due to incorrect email or password. ### Fixed - Fixed package launch not working when environment variable `SETUPTOOLS_USE_DISTUTILS` is set due to conflict with a default environment variable. User environment variables will now correctly override any default environment variables. +- Fixed "No refresh token found" error when failing to login with Lykos account in some cases. ## v2.10.0 ### Added diff --git a/StabilityMatrix.Avalonia/ViewModels/Dialogs/LykosLoginViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Dialogs/LykosLoginViewModel.cs index 471d052b..7dd14a8b 100644 --- a/StabilityMatrix.Avalonia/ViewModels/Dialogs/LykosLoginViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/Dialogs/LykosLoginViewModel.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; +using System.Net; using System.Threading.Tasks; using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; @@ -90,7 +91,15 @@ public partial class LykosLoginViewModel : TaskDialogViewModelBase } catch (ApiException e) { - LoginError = new AppException("Failed to login", $"{e.StatusCode} - {e.Message}"); + LoginError = e.StatusCode switch + { + HttpStatusCode.Unauthorized + => new AppException( + "Incorrect email or password", + "Please try again or reset your password" + ), + _ => new AppException("Failed to login", $"{e.StatusCode} - {e.Message}") + }; } } diff --git a/StabilityMatrix.Avalonia/Views/Dialogs/LykosLoginDialog.axaml b/StabilityMatrix.Avalonia/Views/Dialogs/LykosLoginDialog.axaml index 98ab8228..0f0de8a5 100644 --- a/StabilityMatrix.Avalonia/Views/Dialogs/LykosLoginDialog.axaml +++ b/StabilityMatrix.Avalonia/Views/Dialogs/LykosLoginDialog.axaml @@ -14,6 +14,7 @@ xmlns:mdxaml="https://github.com/whistyun/Markdown.Avalonia.Tight" xmlns:ctxt="clr-namespace:ColorTextBlock.Avalonia;assembly=ColorTextBlock.Avalonia" Focusable="True" + MaxWidth="400" d:DataContext="{x:Static mocks:DesignData.LykosLoginViewModel}" d:DesignHeight="350" d:DesignWidth="400" diff --git a/StabilityMatrix.Core/Api/TokenAuthHeaderHandler.cs b/StabilityMatrix.Core/Api/TokenAuthHeaderHandler.cs index 25cdaa6f..b042d6b7 100644 --- a/StabilityMatrix.Core/Api/TokenAuthHeaderHandler.cs +++ b/StabilityMatrix.Core/Api/TokenAuthHeaderHandler.cs @@ -22,8 +22,8 @@ public class TokenAuthHeaderHandler : DelegatingHandler .HandleResult( r => r.StatusCode is HttpStatusCode.Unauthorized or HttpStatusCode.Forbidden - && r.RequestMessage?.Headers.Authorization - is { Scheme: "Bearer", Parameter: not null } + && r.RequestMessage?.Headers.Authorization is { Scheme: "Bearer", Parameter: { } param } + && !string.IsNullOrWhiteSpace(param) ) .RetryAsync( async (result, _) => @@ -35,9 +35,7 @@ public class TokenAuthHeaderHandler : DelegatingHandler "Refreshing access token for status ({StatusCode})", result.Result.StatusCode ); - var (newToken, _) = await tokenProvider - .RefreshTokensAsync() - .ConfigureAwait(false); + var (newToken, _) = await tokenProvider.RefreshTokensAsync().ConfigureAwait(false); Logger.Info( "Access token refreshed: {OldToken} -> {NewToken}", @@ -46,10 +44,6 @@ public class TokenAuthHeaderHandler : DelegatingHandler ); } ); - - // InnerHandler must be left as null when using DI, but must be assigned a value when - // using RestService.For - // InnerHandler = new HttpClientHandler(); } protected override Task SendAsync( @@ -59,9 +53,17 @@ public class TokenAuthHeaderHandler : DelegatingHandler { return policy.ExecuteAsync(async () => { - var accessToken = await tokenProvider.GetAccessTokenAsync().ConfigureAwait(false); + // Only add if Authorization is already set to Bearer and access token is not empty + // this allows some routes to not use the access token + if (request.Headers.Authorization is { Scheme: "Bearer" }) + { + var accessToken = await tokenProvider.GetAccessTokenAsync().ConfigureAwait(false); - request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken); + if (!string.IsNullOrWhiteSpace(accessToken)) + { + request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken); + } + } return await base.SendAsync(request, cancellationToken).ConfigureAwait(false); });