Switch to JWT authentication (#32)

* switch to jwt authentication

* update api to main/jwt

* bump version

Co-authored-by: rootdarkarchon <root.darkarchon@outlook.com>
This commit is contained in:
rootdarkarchon
2023-01-02 17:08:56 +01:00
committed by GitHub
parent 6aace54910
commit e2931c73ed
6 changed files with 38 additions and 14 deletions

Submodule MareAPI updated: c01c4990d4...6645eaf63f

View File

@@ -3,7 +3,7 @@
<PropertyGroup> <PropertyGroup>
<Authors></Authors> <Authors></Authors>
<Company></Company> <Company></Company>
<Version>0.5.18</Version> <Version>0.5.19</Version>
<Description></Description> <Description></Description>
<Copyright></Copyright> <Copyright></Copyright>
<PackageProjectUrl>https://github.com/Penumbra-Sync/client</PackageProjectUrl> <PackageProjectUrl>https://github.com/Penumbra-Sync/client</PackageProjectUrl>

View File

@@ -512,7 +512,7 @@ public class SettingsUi : Window, IDisposable
{ {
_configuration.FullPause = marePaused; _configuration.FullPause = marePaused;
_configuration.Save(); _configuration.Save();
Task.Run(_apiController.CreateConnections); Task.Run(() => _apiController.CreateConnections(false));
} }
UiShared.DrawHelpText("Completely pauses the sync and clears your current data (not uploaded files) on the service."); UiShared.DrawHelpText("Completely pauses the sync and clears your current data (not uploaded files) on the service.");

View File

@@ -395,7 +395,7 @@ public class UiShared : IDisposable
{ {
_pluginConfiguration.FullPause = false; _pluginConfiguration.FullPause = false;
_pluginConfiguration.Save(); _pluginConfiguration.Save();
Task.Run(_apiController.CreateConnections); Task.Run(() => _apiController.CreateConnections(true));
} }
} }
@@ -432,7 +432,7 @@ public class UiShared : IDisposable
_pluginConfiguration.ClientSecret[_pluginConfiguration.ApiUri] = _secretKey; _pluginConfiguration.ClientSecret[_pluginConfiguration.ApiUri] = _secretKey;
_pluginConfiguration.Save(); _pluginConfiguration.Save();
_secretKey = string.Empty; _secretKey = string.Empty;
Task.Run(_apiController.CreateConnections); Task.Run(() => _apiController.CreateConnections(true));
_enterSecretKey = false; _enterSecretKey = false;
callBackOnExit?.Invoke(); callBackOnExit?.Invoke();
} }

View File

@@ -46,24 +46,26 @@ public partial class ApiController
private async Task<string> DownloadFileHttpClient(Uri url, IProgress<long> progress, CancellationToken ct) private async Task<string> DownloadFileHttpClient(Uri url, IProgress<long> progress, CancellationToken ct)
{ {
using var client = new HttpClient(); using var client = new HttpClient();
client.DefaultRequestHeaders.Add("Authorization", SecretKey); client.DefaultRequestHeaders.Add(AuthorizationJwtHeader.Key, AuthorizationJwtHeader.Value);
int attempts = 0; int attempts = 0;
bool failed = true; bool failed = true;
const int maxAttempts = 10; const int maxAttempts = 10;
HttpResponseMessage response = null!; HttpResponseMessage response = null!;
HttpStatusCode? lastError = HttpStatusCode.OK; HttpStatusCode? lastError = HttpStatusCode.OK;
var bypassUrl = new Uri(url, "?nocache=" + DateTime.UtcNow.Ticks);
while (failed && attempts < maxAttempts && !ct.IsCancellationRequested) while (failed && attempts < maxAttempts && !ct.IsCancellationRequested)
{ {
try try
{ {
response = await client.GetAsync(url, HttpCompletionOption.ResponseHeadersRead, ct).ConfigureAwait(false); response = await client.GetAsync(bypassUrl, HttpCompletionOption.ResponseHeadersRead, ct).ConfigureAwait(false);
response.EnsureSuccessStatusCode(); response.EnsureSuccessStatusCode();
failed = false; failed = false;
} }
catch (HttpRequestException ex) catch (HttpRequestException ex)
{ {
Logger.Warn($"Attempt {attempts}: Error during download of {url}, HttpStatusCode: {ex.StatusCode}"); Logger.Warn($"Attempt {attempts}: Error during download of {bypassUrl}, HttpStatusCode: {ex.StatusCode}");
lastError = ex.StatusCode; lastError = ex.StatusCode;
if (ex.StatusCode is HttpStatusCode.NotFound or HttpStatusCode.Unauthorized) if (ex.StatusCode is HttpStatusCode.NotFound or HttpStatusCode.Unauthorized)
{ {
@@ -98,13 +100,13 @@ public partial class ApiController
progress.Report(bytesRead); progress.Report(bytesRead);
} }
Logger.Debug($"{url} downloaded to {fileName}"); Logger.Debug($"{bypassUrl} downloaded to {fileName}");
return fileName; return fileName;
} }
} }
catch (Exception ex) catch (Exception ex)
{ {
Logger.Warn($"Error during file download of {url}", ex); Logger.Warn($"Error during file download of {bypassUrl}", ex);
try try
{ {
File.Delete(fileName); File.Delete(fileName);

View File

@@ -3,6 +3,8 @@ using System.Collections.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Net.Http; using System.Net.Http;
using System.Security.Cryptography;
using System.Text;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using MareSynchronos.API; using MareSynchronos.API;
@@ -29,6 +31,8 @@ public partial class ApiController : IDisposable, IMareHubClient
private readonly DalamudUtil _dalamudUtil; private readonly DalamudUtil _dalamudUtil;
private readonly FileCacheManager _fileDbManager; private readonly FileCacheManager _fileDbManager;
private CancellationTokenSource _connectionCancellationTokenSource; private CancellationTokenSource _connectionCancellationTokenSource;
private string _jwtToken = string.Empty;
private KeyValuePair<string, string> AuthorizationJwtHeader => new("Authorization", "Bearer " + _jwtToken);
private HubConnection? _mareHub; private HubConnection? _mareHub;
@@ -70,7 +74,7 @@ public partial class ApiController : IDisposable, IMareHubClient
private void DalamudUtilOnLogIn() private void DalamudUtilOnLogIn()
{ {
Task.Run(CreateConnections); Task.Run(() => CreateConnections(true));
} }
@@ -134,7 +138,7 @@ public partial class ApiController : IDisposable, IMareHubClient
} }
} }
public async Task CreateConnections() public async Task CreateConnections(bool forceGetToken = false)
{ {
Logger.Debug("CreateConnections called"); Logger.Debug("CreateConnections called");
@@ -169,6 +173,24 @@ public partial class ApiController : IDisposable, IMareHubClient
{ {
Logger.Debug("Building connection"); Logger.Debug("Building connection");
if (string.IsNullOrEmpty(_jwtToken) || forceGetToken)
{
Logger.Debug("Requesting new JWT token");
using HttpClient httpClient = new();
var postUri = new Uri(new Uri(ApiUri
.Replace("wss://", "https://", StringComparison.OrdinalIgnoreCase)
.Replace("ws://", "http://", StringComparison.OrdinalIgnoreCase)), MareAuth.AuthFullPath);
using var sha256 = SHA256.Create();
var auth = BitConverter.ToString(sha256.ComputeHash(Encoding.UTF8.GetBytes(SecretKey))).Replace("-", "", StringComparison.OrdinalIgnoreCase);
var result = await httpClient.PostAsync(postUri, new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("auth", auth)
})).ConfigureAwait(false);
result.EnsureSuccessStatusCode();
_jwtToken = await result.Content.ReadAsStringAsync().ConfigureAwait(false);
Logger.Debug("JWT Token Success");
}
while (!_dalamudUtil.IsPlayerPresent && !token.IsCancellationRequested) while (!_dalamudUtil.IsPlayerPresent && !token.IsCancellationRequested)
{ {
Logger.Debug("Player not loaded in yet, waiting"); Logger.Debug("Player not loaded in yet, waiting");
@@ -253,7 +275,7 @@ public partial class ApiController : IDisposable, IMareHubClient
private Task MareHubOnReconnected(string? arg) private Task MareHubOnReconnected(string? arg)
{ {
_ = Task.Run(CreateConnections); _ = Task.Run(() => CreateConnections(false));
return Task.CompletedTask; return Task.CompletedTask;
} }
@@ -332,7 +354,7 @@ public partial class ApiController : IDisposable, IMareHubClient
return new HubConnectionBuilder() return new HubConnectionBuilder()
.WithUrl(ApiUri + hubName, options => .WithUrl(ApiUri + hubName, options =>
{ {
options.Headers.Add("Authorization", SecretKey); options.Headers.Add(AuthorizationJwtHeader);
options.Transports = HttpTransportType.WebSockets | HttpTransportType.ServerSentEvents | HttpTransportType.LongPolling; options.Transports = HttpTransportType.WebSockets | HttpTransportType.ServerSentEvents | HttpTransportType.LongPolling;
}) })
.WithAutomaticReconnect(new ForeverRetryPolicy()) .WithAutomaticReconnect(new ForeverRetryPolicy())