Fix SimpleFIN integration for beta-bridge.simplefin.org
HttpClient does not extract Basic Auth credentials from URLs with embedded user:pass@host format. Parse the access URL, build the Authorization header explicitly, and strip credentials from the request URI. Also send Content-Length: 0 on token exchange POST and update setup instructions to point to beta-bridge.simplefin.org. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
using System.Net.Http.Headers;
|
||||
using System.Net.Http.Json;
|
||||
using System.Text;
|
||||
using Purrse.Plugins.Abstractions;
|
||||
@@ -28,7 +29,7 @@ public class SimpleFinSyncProvider : IAccountSyncProvider
|
||||
// Decode base64 setup token to get the claim URL
|
||||
var claimUrl = Encoding.UTF8.GetString(Convert.FromBase64String(setupToken));
|
||||
|
||||
var response = await _httpClient.PostAsync(claimUrl, null);
|
||||
var response = await _httpClient.PostAsync(claimUrl, new StringContent(string.Empty));
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
var accessUrl = await response.Content.ReadAsStringAsync();
|
||||
@@ -39,7 +40,7 @@ public class SimpleFinSyncProvider : IAccountSyncProvider
|
||||
{
|
||||
var accessUrl = configuration.GetValueOrDefault("AccessUrl") ?? string.Empty;
|
||||
|
||||
var response = await _httpClient.GetFromJsonAsync<SimpleFinAccountSet>($"{accessUrl}/accounts");
|
||||
var response = await GetWithAuthAsync($"{accessUrl}/accounts");
|
||||
if (response == null)
|
||||
return new List<SyncAccount>();
|
||||
|
||||
@@ -60,7 +61,7 @@ public class SimpleFinSyncProvider : IAccountSyncProvider
|
||||
var startUnix = new DateTimeOffset(startDate).ToUnixTimeSeconds();
|
||||
var endUnix = new DateTimeOffset(endDate).ToUnixTimeSeconds();
|
||||
|
||||
var response = await _httpClient.GetFromJsonAsync<SimpleFinAccountSet>(
|
||||
var response = await GetWithAuthAsync(
|
||||
$"{accessUrl}/accounts?start-date={startUnix}&end-date={endUnix}");
|
||||
|
||||
if (response == null)
|
||||
@@ -90,6 +91,25 @@ public class SimpleFinSyncProvider : IAccountSyncProvider
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// HttpClient does not extract Basic Auth credentials from URLs (user:pass@host).
|
||||
/// This method parses the URI, builds the Authorization header, and strips credentials from the request URL.
|
||||
/// </summary>
|
||||
private async Task<SimpleFinAccountSet?> GetWithAuthAsync(string url)
|
||||
{
|
||||
var uri = new Uri(url);
|
||||
var request = new HttpRequestMessage(HttpMethod.Get, new UriBuilder(uri) { UserName = "", Password = "" }.Uri);
|
||||
if (!string.IsNullOrEmpty(uri.UserInfo))
|
||||
{
|
||||
var credentials = Convert.ToBase64String(Encoding.UTF8.GetBytes(uri.UserInfo));
|
||||
request.Headers.Authorization = new AuthenticationHeaderValue("Basic", credentials);
|
||||
}
|
||||
|
||||
var response = await _httpClient.SendAsync(request);
|
||||
response.EnsureSuccessStatusCode();
|
||||
return await response.Content.ReadFromJsonAsync<SimpleFinAccountSet>();
|
||||
}
|
||||
|
||||
private static string GuessAccountType(string name)
|
||||
{
|
||||
var lower = name.ToLowerInvariant();
|
||||
|
||||
Reference in New Issue
Block a user