From f76c79971cada1d85ffc7e73b14e9c51aeea587d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patrick=20K=C3=BChnel?= Date: Sat, 7 Dec 2024 22:10:28 +0100 Subject: [PATCH 1/6] feat(TeslaFleetApiService): improve fleet api token allowed detection --- TeslaSolarCharger/Server/Program.cs | 7 ------- TeslaSolarCharger/Server/Services/TeslaFleetApiService.cs | 4 ++-- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/TeslaSolarCharger/Server/Program.cs b/TeslaSolarCharger/Server/Program.cs index 2a3142bdd..683dca424 100644 --- a/TeslaSolarCharger/Server/Program.cs +++ b/TeslaSolarCharger/Server/Program.cs @@ -1,21 +1,14 @@ using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.OpenApi.Models; using Serilog; using Serilog.Context; -using System.Diagnostics; using System.Reflection; -using TeslaSolarCharger.Client.Pages; using TeslaSolarCharger.Model.Contracts; using TeslaSolarCharger.Server; using TeslaSolarCharger.Server.Contracts; using TeslaSolarCharger.Server.Resources.PossibleIssues.Contracts; using TeslaSolarCharger.Server.Scheduling; -using TeslaSolarCharger.Server.Services.ApiServices.Contracts; using TeslaSolarCharger.Server.Services.Contracts; -using TeslaSolarCharger.Server.Services.GridPrice.Contracts; using TeslaSolarCharger.Services; -using TeslaSolarCharger.Services.Services.Contracts; using TeslaSolarCharger.Shared; using TeslaSolarCharger.Shared.Contracts; using TeslaSolarCharger.Shared.Dtos.Contracts; diff --git a/TeslaSolarCharger/Server/Services/TeslaFleetApiService.cs b/TeslaSolarCharger/Server/Services/TeslaFleetApiService.cs index 500f37bf1..a2bf9eefc 100644 --- a/TeslaSolarCharger/Server/Services/TeslaFleetApiService.cs +++ b/TeslaSolarCharger/Server/Services/TeslaFleetApiService.cs @@ -1251,11 +1251,11 @@ public async Task RefreshFleetApiRequestsAreAllowed() } var responseValue = JsonConvert.DeserializeObject>(responseString); - settings.AllowUnlimitedFleetApiRequests = responseValue?.Value != false; + settings.AllowUnlimitedFleetApiRequests = responseValue?.Value == true; } catch (Exception) { - settings.AllowUnlimitedFleetApiRequests = true; + settings.AllowUnlimitedFleetApiRequests = false; } } From 156e975283ceb131f3447cbd27fd6e2302413c40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patrick=20K=C3=BChnel?= Date: Sat, 21 Dec 2024 09:34:00 +0100 Subject: [PATCH 2/6] feat(BackendApiService): request additional user scopes --- .../Services/Server/BackendApiService.cs | 2 +- .../Server/Services/BackendApiService.cs | 2 +- .../Server/Services/TeslaFleetApiService.cs | 16 ++++++++++------ 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/TeslaSolarCharger.Tests/Services/Server/BackendApiService.cs b/TeslaSolarCharger.Tests/Services/Server/BackendApiService.cs index 32c12ea0f..0b5556d90 100644 --- a/TeslaSolarCharger.Tests/Services/Server/BackendApiService.cs +++ b/TeslaSolarCharger.Tests/Services/Server/BackendApiService.cs @@ -25,7 +25,7 @@ public void CanEnCodeCorrectUrl() State = "8774fbe7-f9aa-4e36-8e88-5c8b27137f20", }; var url = backendApiService.GenerateAuthUrl(requestInformation, "en-US"); - var expectedUrl = "https://auth.tesla.com/oauth2/v3/authorize?&client_id=f29f71d6285a-4873-8b6b-80f15854892e&locale=en-US&prompt=login&redirect_uri=https%3A%2F%2Fwww.teslasolarcharger.de%2F&response_type=code&scope=offline_access%20vehicle_device_data%20vehicle_cmds%20vehicle_charging_cmds&state=8774fbe7-f9aa-4e36-8e88-5c8b27137f20"; + var expectedUrl = "https://auth.tesla.com/oauth2/v3/authorize?&client_id=f29f71d6285a-4873-8b6b-80f15854892e&locale=en-US&prompt=login&redirect_uri=https%3A%2F%2Fwww.teslasolarcharger.de%2F&response_type=code&scope=offline_access%20vehicle_device_data%20vehicle_cmds%20vehicle_charging_cmds&state=8774fbe7-f9aa-4e36-8e88-5c8b27137f20&prompt_missing_scopes=true"; Assert.Equal(expectedUrl, url); } } diff --git a/TeslaSolarCharger/Server/Services/BackendApiService.cs b/TeslaSolarCharger/Server/Services/BackendApiService.cs index 6b34c71f2..b36bbe554 100644 --- a/TeslaSolarCharger/Server/Services/BackendApiService.cs +++ b/TeslaSolarCharger/Server/Services/BackendApiService.cs @@ -77,7 +77,7 @@ internal string GenerateAuthUrl(DtoTeslaOAuthRequestInformation oAuthInformation { logger.LogTrace("{method}({@oAuthInformation})", nameof(GenerateAuthUrl), oAuthInformation); var url = - $"https://auth.tesla.com/oauth2/v3/authorize?&client_id={Uri.EscapeDataString(oAuthInformation.ClientId)}&locale={Uri.EscapeDataString(locale)}&prompt={Uri.EscapeDataString(oAuthInformation.Prompt)}&redirect_uri={Uri.EscapeDataString(oAuthInformation.RedirectUri)}&response_type={Uri.EscapeDataString(oAuthInformation.ResponseType)}&scope={Uri.EscapeDataString(oAuthInformation.Scope)}&state={Uri.EscapeDataString(oAuthInformation.State)}"; + $"https://auth.tesla.com/oauth2/v3/authorize?&client_id={Uri.EscapeDataString(oAuthInformation.ClientId)}&locale={Uri.EscapeDataString(locale)}&prompt={Uri.EscapeDataString(oAuthInformation.Prompt)}&redirect_uri={Uri.EscapeDataString(oAuthInformation.RedirectUri)}&response_type={Uri.EscapeDataString(oAuthInformation.ResponseType)}&scope={Uri.EscapeDataString(oAuthInformation.Scope)}&state={Uri.EscapeDataString(oAuthInformation.State)}&prompt_missing_scopes=true"; return url; } diff --git a/TeslaSolarCharger/Server/Services/TeslaFleetApiService.cs b/TeslaSolarCharger/Server/Services/TeslaFleetApiService.cs index a2bf9eefc..f8820ebf4 100644 --- a/TeslaSolarCharger/Server/Services/TeslaFleetApiService.cs +++ b/TeslaSolarCharger/Server/Services/TeslaFleetApiService.cs @@ -1169,18 +1169,13 @@ public async Task RefreshTokensIfAllowedAndNeeded() logger.LogError("No token found. Cannot refresh token."); return; } + var tokensToRefresh = tokens.Where(t => t.ExpiresAtUtc < (dateTimeProvider.UtcNow() + TimeSpan.FromMinutes(2))).ToList(); if (tokensToRefresh.Count < 1) { logger.LogTrace("No token needs to be refreshed."); return; } - //ToDo: needs to handle manual generated tokens. For now as soon as rate limits are introduced nobody gets refresh tokens even if they have a token not from www.teslasolarcharger.de - if (settings.AllowUnlimitedFleetApiRequests == false) - { - logger.LogError("Due to rate limitations fleet api requests are not allowed. As this version can not handle rate limits try updating to the latest version."); - return; - } foreach (var tokenToRefresh in tokensToRefresh) { @@ -1217,6 +1212,13 @@ await errorHandlingService.HandleError(nameof(TeslaFleetApiService), nameof(Send await HandleNonSuccessTeslaApiStatusCodes(response.StatusCode, tokenToRefresh, responseString, TeslaApiRequestType.Other).ConfigureAwait(false); } response.EnsureSuccessStatusCode(); + if (settings.AllowUnlimitedFleetApiRequests == false) + { + logger.LogError("Due to rate limitations fleet api requests are not allowed. As this version can not handle rate limits try updating to the latest version."); + teslaSolarChargerContext.TeslaTokens.Remove(tokenToRefresh); + await teslaSolarChargerContext.SaveChangesAsync().ConfigureAwait(false); + return; + } var newToken = JsonConvert.DeserializeObject(responseString) ?? throw new InvalidDataException("Could not get token from string."); tokenToRefresh.AccessToken = newToken.AccessToken; tokenToRefresh.RefreshToken = newToken.RefreshToken; @@ -1231,6 +1233,8 @@ await errorHandlingService.HandleError(nameof(TeslaFleetApiService), nameof(Send public async Task RefreshFleetApiRequestsAreAllowed() { logger.LogTrace("{method}()", nameof(RefreshFleetApiRequestsAreAllowed)); + settings.AllowUnlimitedFleetApiRequests = false; + return; if (settings.AllowUnlimitedFleetApiRequests && (settings.LastFleetApiRequestAllowedCheck > dateTimeProvider.UtcNow().AddHours(-1))) { return; From aff7a7cbbee983ec3b2da05cbe01d0da7955dad6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patrick=20K=C3=BChnel?= Date: Sat, 21 Dec 2024 09:48:01 +0100 Subject: [PATCH 3/6] feat(ErrorHandlingService): add issue on fleet api requests not allowed --- TeslaSolarCharger/Server/Services/ErrorHandlingService.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/TeslaSolarCharger/Server/Services/ErrorHandlingService.cs b/TeslaSolarCharger/Server/Services/ErrorHandlingService.cs index 94339490c..3eec8e00f 100644 --- a/TeslaSolarCharger/Server/Services/ErrorHandlingService.cs +++ b/TeslaSolarCharger/Server/Services/ErrorHandlingService.cs @@ -433,6 +433,9 @@ await AddOrRemoveErrors(activeErrors, issueKeys.FleetApiTokenRequestExpired, "Te await AddOrRemoveErrors(activeErrors, issueKeys.FleetApiTokenExpired, "Tesla Token expired", "Open the Base Configuration and request a new token.", tokenState == FleetApiTokenState.Expired).ConfigureAwait(false); + await AddOrRemoveErrors(activeErrors, issueKeys.FleetApiTokenNoApiRequestsAllowed, "No Fleet API requests allowed", + "Due to changes on Tesla Fleet API billing you need to update to the latest TSC version as the current version can not handle Fleet API requests.", + tokenState == FleetApiTokenState.NoApiRequestsAllowed).ConfigureAwait(false); //Remove all token related issue keys on token error because very likely it is because of the underlaying token issue. if (tokenState != FleetApiTokenState.UpToDate && tokenState != FleetApiTokenState.NotNeeded) From dd778b1de4e2cdbc131564b55e24229aba2888fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patrick=20K=C3=BChnel?= Date: Sat, 21 Dec 2024 09:51:32 +0100 Subject: [PATCH 4/6] feat(ErrorHandlingService): update missing scopes error message --- TeslaSolarCharger/Server/Services/ErrorHandlingService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/TeslaSolarCharger/Server/Services/ErrorHandlingService.cs b/TeslaSolarCharger/Server/Services/ErrorHandlingService.cs index 3eec8e00f..fefeb67f1 100644 --- a/TeslaSolarCharger/Server/Services/ErrorHandlingService.cs +++ b/TeslaSolarCharger/Server/Services/ErrorHandlingService.cs @@ -425,7 +425,7 @@ await AddOrRemoveErrors(activeErrors, issueKeys.FleetApiTokenUnauthorized, "Flee "You recently changed your password or did not enable mobile access in your car. Enable mobile access in your car and open the Base Configuration and request a new token. Important: You need to allow access to all selectable scopes.", tokenState == FleetApiTokenState.TokenUnauthorized).ConfigureAwait(false); await AddOrRemoveErrors(activeErrors, issueKeys.FleetApiTokenMissingScopes, "Your Tesla token has missing scopes.", - "Remove Tesla Solar Charger from your third party apps as you won't get asked again for the scopes. After that request a new token in the Base Configuration and select all available scopes.", + "Open the Base Configuration and request a new token. Note: You need to allow all selectable scopes as otherwise TSC won't work properly.", tokenState == FleetApiTokenState.MissingScopes).ConfigureAwait(false); await AddOrRemoveErrors(activeErrors, issueKeys.FleetApiTokenRequestExpired, "Tesla Token could not be received", "Open the Base Configuration and request a new token.", From edad06b91658f13d05592b244233b3a526636403 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patrick=20K=C3=BChnel?= Date: Sat, 21 Dec 2024 10:04:07 +0100 Subject: [PATCH 5/6] fix(ErrorHanldingService): use correct collection on adding further error occurrences --- TeslaSolarCharger/Server/Services/ErrorHandlingService.cs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/TeslaSolarCharger/Server/Services/ErrorHandlingService.cs b/TeslaSolarCharger/Server/Services/ErrorHandlingService.cs index fefeb67f1..d3c95f995 100644 --- a/TeslaSolarCharger/Server/Services/ErrorHandlingService.cs +++ b/TeslaSolarCharger/Server/Services/ErrorHandlingService.cs @@ -433,9 +433,6 @@ await AddOrRemoveErrors(activeErrors, issueKeys.FleetApiTokenRequestExpired, "Te await AddOrRemoveErrors(activeErrors, issueKeys.FleetApiTokenExpired, "Tesla Token expired", "Open the Base Configuration and request a new token.", tokenState == FleetApiTokenState.Expired).ConfigureAwait(false); - await AddOrRemoveErrors(activeErrors, issueKeys.FleetApiTokenNoApiRequestsAllowed, "No Fleet API requests allowed", - "Due to changes on Tesla Fleet API billing you need to update to the latest TSC version as the current version can not handle Fleet API requests.", - tokenState == FleetApiTokenState.NoApiRequestsAllowed).ConfigureAwait(false); //Remove all token related issue keys on token error because very likely it is because of the underlaying token issue. if (tokenState != FleetApiTokenState.UpToDate && tokenState != FleetApiTokenState.NotNeeded) @@ -482,7 +479,7 @@ private async Task AddOrRemoveErrors(List activeErrors, string issu } else if (shouldBeActive) { - for (var i = 0; i < activeErrors.Count; i++) + for (var i = 0; i < filteredErrors.Count; i++) { if (i == 0) { From 1766c8b3b5434eca4d94bc20f958f8ec85b5bd6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patrick=20K=C3=BChnel?= Date: Sat, 21 Dec 2024 10:07:39 +0100 Subject: [PATCH 6/6] feat(TeslaFleetApiService): do not always disallow fleet api requests --- TeslaSolarCharger/Server/Services/TeslaFleetApiService.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/TeslaSolarCharger/Server/Services/TeslaFleetApiService.cs b/TeslaSolarCharger/Server/Services/TeslaFleetApiService.cs index f8820ebf4..d51761ae1 100644 --- a/TeslaSolarCharger/Server/Services/TeslaFleetApiService.cs +++ b/TeslaSolarCharger/Server/Services/TeslaFleetApiService.cs @@ -1233,8 +1233,6 @@ await errorHandlingService.HandleError(nameof(TeslaFleetApiService), nameof(Send public async Task RefreshFleetApiRequestsAreAllowed() { logger.LogTrace("{method}()", nameof(RefreshFleetApiRequestsAreAllowed)); - settings.AllowUnlimitedFleetApiRequests = false; - return; if (settings.AllowUnlimitedFleetApiRequests && (settings.LastFleetApiRequestAllowedCheck > dateTimeProvider.UtcNow().AddHours(-1))) { return;