Compare commits

..
5 Commits
16 changed files with 64 additions and 46 deletions

No files matched your search

@@ -199,7 +199,7 @@ public sealed class AgentDataSourceSelection (ILogger<AgentDataSourceSelection>
// Call the ERI server to get the server description: // Call the ERI server to get the server description:
// //
using var eriClient = ERIClientFactory.Get(eriDataSource.Version, eriDataSource)!; using var eriClient = ERIClientFactory.Get(eriDataSource.Version, eriDataSource)!;
var authResponse = await eriClient.AuthenticateAsync(eriDataSource, rustService, token); var authResponse = await eriClient.AuthenticateAsync(rustService, cancellationToken: token);
if (authResponse.Successful) if (authResponse.Successful)
{ {
var serverDescriptionResponse = await eriClient.GetDataSourceInfoAsync(token); var serverDescriptionResponse = await eriClient.GetDataSourceInfoAsync(token);
@@ -13,6 +13,8 @@ public partial class Changelog
public static readonly Log[] LOGS = public static readonly Log[] LOGS =
[ [
new (209, "v0.9.34, build 209 (2025-03-11 13:02 UTC)", "v0.9.34.md"),
new (208, "v0.9.33, build 208 (2025-03-11 08:14 UTC)", "v0.9.33.md"),
new (207, "v0.9.32, build 207 (2025-03-08 20:15 UTC)", "v0.9.32.md"), new (207, "v0.9.32, build 207 (2025-03-08 20:15 UTC)", "v0.9.32.md"),
new (206, "v0.9.31, build 206 (2025-03-03 15:33 UTC)", "v0.9.31.md"), new (206, "v0.9.31, build 206 (2025-03-03 15:33 UTC)", "v0.9.31.md"),
new (205, "v0.9.30, build 205 (2025-02-24 19:55 UTC)", "v0.9.30.md"), new (205, "v0.9.30, build 205 (2025-02-24 19:55 UTC)", "v0.9.30.md"),
@@ -98,7 +98,7 @@ public partial class DataSourceERI_V1InfoDialog : ComponentBase, IAsyncDisposabl
return; return;
} }
var loginResult = await client.AuthenticateAsync(this.DataSource, this.RustService); var loginResult = await client.AuthenticateAsync(this.RustService);
if (!loginResult.Successful) if (!loginResult.Successful)
{ {
this.dataIssues.Add(loginResult.Message); this.dataIssues.Add(loginResult.Message);
@@ -188,13 +188,8 @@ public partial class DataSourceERI_V1Dialog : ComponentBase, ISecretId
try try
{ {
var cts = new CancellationTokenSource(TimeSpan.FromSeconds(14)); var cts = new CancellationTokenSource(TimeSpan.FromSeconds(14));
var dataSource = new DataSourceERI_V1 this.DataSource = this.CreateDataSource();
{ using var client = ERIClientFactory.Get(ERIVersion.V1, this.DataSource);
Hostname = this.dataHostname,
Port = this.dataPort
};
using var client = ERIClientFactory.Get(ERIVersion.V1, dataSource);
if(client is null) if(client is null)
{ {
await this.form.Validate(); await this.form.Validate();
@@ -216,7 +211,7 @@ public partial class DataSourceERI_V1Dialog : ComponentBase, ISecretId
this.availableAuthMethods = authSchemes.Data!.Select(n => n.AuthMethod).ToList(); this.availableAuthMethods = authSchemes.Data!.Select(n => n.AuthMethod).ToList();
var loginResult = await client.AuthenticateAsync(this.DataSource, this.RustService, cts.Token); var loginResult = await client.AuthenticateAsync(this.RustService, this.dataSecret, cts.Token);
if (!loginResult.Successful) if (!loginResult.Successful)
{ {
await this.form.Validate(); await this.form.Validate();
@@ -62,7 +62,7 @@ public readonly record struct DataSourceERI_V1 : IERIDataSource
var logger = Program.SERVICE_PROVIDER.GetRequiredService<ILogger<DataSourceERI_V1>>(); var logger = Program.SERVICE_PROVIDER.GetRequiredService<ILogger<DataSourceERI_V1>>();
using var eriClient = ERIClientFactory.Get(this.Version, this)!; using var eriClient = ERIClientFactory.Get(this.Version, this)!;
var authResponse = await eriClient.AuthenticateAsync(this, rustService, token); var authResponse = await eriClient.AuthenticateAsync(rustService, cancellationToken: token);
if (authResponse.Successful) if (authResponse.Successful)
{ {
var retrievalRequest = new RetrievalRequest var retrievalRequest = new RetrievalRequest
@@ -1,10 +1,14 @@
using System.Text.Json; using System.Text.Json;
using System.Text.Json.Serialization; using System.Text.Json.Serialization;
using AIStudio.Settings;
namespace AIStudio.Tools.ERIClient; namespace AIStudio.Tools.ERIClient;
public abstract class ERIClientBase(string baseAddress) : IDisposable public abstract class ERIClientBase(IERIDataSource dataSource) : IDisposable
{ {
protected readonly IERIDataSource dataSource = dataSource;
protected static readonly JsonSerializerOptions JSON_OPTIONS = new() protected static readonly JsonSerializerOptions JSON_OPTIONS = new()
{ {
WriteIndented = true, WriteIndented = true,
@@ -21,7 +25,7 @@ public abstract class ERIClientBase(string baseAddress) : IDisposable
protected readonly HttpClient httpClient = new() protected readonly HttpClient httpClient = new()
{ {
BaseAddress = new Uri(baseAddress), BaseAddress = new Uri($"{dataSource.Hostname}:{dataSource.Port}"),
}; };
protected string securityToken = string.Empty; protected string securityToken = string.Empty;
@@ -7,7 +7,7 @@ public static class ERIClientFactory
{ {
public static IERIClient? Get(ERIVersion version, IERIDataSource dataSource) => version switch public static IERIClient? Get(ERIVersion version, IERIDataSource dataSource) => version switch
{ {
ERIVersion.V1 => new ERIClientV1($"{dataSource.Hostname}:{dataSource.Port}"), ERIVersion.V1 => new ERIClientV1(dataSource),
_ => null _ => null
}; };
@@ -7,7 +7,7 @@ using AIStudio.Tools.Services;
namespace AIStudio.Tools.ERIClient; namespace AIStudio.Tools.ERIClient;
public class ERIClientV1(string baseAddress) : ERIClientBase(baseAddress), IERIClient public class ERIClientV1(IERIDataSource dataSource) : ERIClientBase(dataSource), IERIClient
{ {
#region Implementation of IERIClient #region Implementation of IERIClient
@@ -59,13 +59,13 @@ public class ERIClientV1(string baseAddress) : ERIClientBase(baseAddress), IERIC
} }
} }
public async Task<APIResponse<AuthResponse>> AuthenticateAsync(IERIDataSource dataSource, RustService rustService, CancellationToken cancellationToken = default) public async Task<APIResponse<AuthResponse>> AuthenticateAsync(RustService rustService, string? temporarySecret = null, CancellationToken cancellationToken = default)
{ {
try try
{ {
var authMethod = dataSource.AuthMethod; var authMethod = this.dataSource.AuthMethod;
var username = dataSource.Username; var username = this.dataSource.Username;
switch (dataSource.AuthMethod) switch (this.dataSource.AuthMethod)
{ {
case AuthMethod.NONE: case AuthMethod.NONE:
using (var request = new HttpRequestMessage(HttpMethod.Post, $"auth?authMethod={authMethod}")) using (var request = new HttpRequestMessage(HttpMethod.Post, $"auth?authMethod={authMethod}"))
@@ -99,17 +99,24 @@ public class ERIClientV1(string baseAddress) : ERIClientBase(baseAddress), IERIC
} }
case AuthMethod.USERNAME_PASSWORD: case AuthMethod.USERNAME_PASSWORD:
var passwordResponse = await rustService.GetSecret(dataSource); string password;
if (!passwordResponse.Success) if (string.IsNullOrWhiteSpace(temporarySecret))
{ {
return new() var passwordResponse = await rustService.GetSecret(this.dataSource);
if (!passwordResponse.Success)
{ {
Successful = false, return new()
Message = "Failed to retrieve the password." {
}; Successful = false,
} Message = "Failed to retrieve the password."
};
}
password = await passwordResponse.Secret.Decrypt(Program.ENCRYPTION);
}
else
password = temporarySecret;
var password = await passwordResponse.Secret.Decrypt(Program.ENCRYPTION);
using (var request = new HttpRequestMessage(HttpMethod.Post, $"auth?authMethod={authMethod}")) using (var request = new HttpRequestMessage(HttpMethod.Post, $"auth?authMethod={authMethod}"))
{ {
// We must send both values inside the header. The username field is named 'user'. // We must send both values inside the header. The username field is named 'user'.
@@ -146,17 +153,24 @@ public class ERIClientV1(string baseAddress) : ERIClientBase(baseAddress), IERIC
} }
case AuthMethod.TOKEN: case AuthMethod.TOKEN:
var tokenResponse = await rustService.GetSecret(dataSource); string token;
if (!tokenResponse.Success) if (string.IsNullOrWhiteSpace(temporarySecret))
{ {
return new() var tokenResponse = await rustService.GetSecret(this.dataSource);
if (!tokenResponse.Success)
{ {
Successful = false, return new()
Message = "Failed to retrieve the access token." {
}; Successful = false,
} Message = "Failed to retrieve the access token."
};
}
token = await tokenResponse.Secret.Decrypt(Program.ENCRYPTION);
}
else
token = temporarySecret;
var token = await tokenResponse.Secret.Decrypt(Program.ENCRYPTION);
using (var request = new HttpRequestMessage(HttpMethod.Post, $"auth?authMethod={authMethod}")) using (var request = new HttpRequestMessage(HttpMethod.Post, $"auth?authMethod={authMethod}"))
{ {
request.Headers.Add("Authorization", $"Bearer {token}"); request.Headers.Add("Authorization", $"Bearer {token}");
@@ -1,4 +1,3 @@
using AIStudio.Settings;
using AIStudio.Tools.ERIClient.DataModel; using AIStudio.Tools.ERIClient.DataModel;
using AIStudio.Tools.Services; using AIStudio.Tools.Services;
@@ -19,11 +18,11 @@ public interface IERIClient : IDisposable
/// <summary> /// <summary>
/// Authenticate the user to the ERI server. /// Authenticate the user to the ERI server.
/// </summary> /// </summary>
/// <param name="dataSource">The data source to use.</param>
/// <param name="rustService">The Rust service.</param> /// <param name="rustService">The Rust service.</param>
/// <param name="temporarySecret">The temporary secret when adding a new data source, and the secret is not yet stored in the OS.</param>
/// <param name="cancellationToken">The cancellation token.</param> /// <param name="cancellationToken">The cancellation token.</param>
/// <returns>The authentication response.</returns> /// <returns>The authentication response.</returns>
public Task<APIResponse<AuthResponse>> AuthenticateAsync(IERIDataSource dataSource, RustService rustService, CancellationToken cancellationToken = default); public Task<APIResponse<AuthResponse>> AuthenticateAsync(RustService rustService, string? temporarySecret = null, CancellationToken cancellationToken = default);
/// <summary> /// <summary>
/// Retrieves the data source information from the ERI server. /// Retrieves the data source information from the ERI server.
@@ -113,7 +113,7 @@ public sealed class DataSourceService
} }
this.logger.LogInformation($"Authenticating with ERI source '{source.Name}' (id={source.Id})..."); this.logger.LogInformation($"Authenticating with ERI source '{source.Name}' (id={source.Id})...");
var loginResult = await client.AuthenticateAsync(eriSource, this.rustService, cancellationTokenSource.Token); var loginResult = await client.AuthenticateAsync(this.rustService, cancellationToken: cancellationTokenSource.Token);
if (!loginResult.Successful) if (!loginResult.Successful)
{ {
this.logger.LogWarning($"Authentication with ERI source '{source.Name}' (id={source.Id}) failed. We skip this source. Reason: {loginResult.Message}"); this.logger.LogWarning($"Authentication with ERI source '{source.Name}' (id={source.Id}) failed. We skip this source. Reason: {loginResult.Message}");
@@ -0,0 +1,2 @@
# v0.9.33, build 208 (2025-03-11 08:14 UTC)
- Fixed a bug where the authentication methods for added ERI servers were not applied correctly. Thanks Kerstin `KeSah001` for reporting this issue.
@@ -0,0 +1,2 @@
# v0.9.34, build 209 (2025-03-11 13:02 UTC)
- Fixed another bug related to ERI server authentication when adding new servers.
+4 -4
View File
@@ -1,9 +1,9 @@
0.9.32 0.9.34
2025-03-08 20:15:02 UTC 2025-03-11 13:02:01 UTC
207 209
8.0.113 (commit 8f216348dc) 8.0.113 (commit 8f216348dc)
8.0.13 (commit eba546b0f0) 8.0.13 (commit eba546b0f0)
1.85.0 (commit 4d91de4e4) 1.85.0 (commit 4d91de4e4)
7.16.0 7.16.0
1.8.1 1.8.1
5a726577ca2, release 2429788ccc0, release
+1 -1
View File
@@ -2350,7 +2350,7 @@ checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
[[package]] [[package]]
name = "mindwork-ai-studio" name = "mindwork-ai-studio"
version = "0.9.32" version = "0.9.34"
dependencies = [ dependencies = [
"aes", "aes",
"arboard", "arboard",
+1 -1
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "mindwork-ai-studio" name = "mindwork-ai-studio"
version = "0.9.32" version = "0.9.34"
edition = "2021" edition = "2021"
description = "MindWork AI Studio" description = "MindWork AI Studio"
authors = ["Thorsten Sommer"] authors = ["Thorsten Sommer"]
+1 -1
View File
@@ -6,7 +6,7 @@
}, },
"package": { "package": {
"productName": "MindWork AI Studio", "productName": "MindWork AI Studio",
"version": "0.9.32" "version": "0.9.34"
}, },
"tauri": { "tauri": {
"allowlist": { "allowlist": {