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:
2
MareAPI
2
MareAPI
Submodule MareAPI updated: c01c4990d4...6645eaf63f
@@ -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>
|
||||||
|
|||||||
@@ -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.");
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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())
|
||||||
|
|||||||
Reference in New Issue
Block a user