Migrated the get secret calls from Tauri JS to the runtime API

This commit is contained in:
tsommer committed 2024-08-28 21:00:19 +02:00
1 parent 273376ad97
commit 97854e7eaa
53 files changed
+299 -243

No files matched your search

+7 -6
View File
@@ -93,20 +93,21 @@ public sealed class Encryption(ILogger<Encryption> logger, byte[] secretPassword
public async Task<string> Decrypt(EncryptedText encryptedData)
{
// Build a memory stream to access the given base64 encoded data:
await using var encodedEncryptedStream = new MemoryStream(Encoding.ASCII.GetBytes(encryptedData));
await using var encodedEncryptedStream = new MemoryStream(Encoding.ASCII.GetBytes(encryptedData.EncryptedData));
// Wrap around the base64 decoder stream:
await using var base64Stream = new CryptoStream(encodedEncryptedStream, new FromBase64Transform(), CryptoStreamMode.Read);
// A buffer for the salt's bytes:
var readSaltBytes = new byte[16]; // 16 bytes = Guid
// Read the salt's bytes out of the stream:
var readBytes = await base64Stream.ReadAsync(readSaltBytes);
if(readBytes != 16)
var readBytes = 0;
var cts = new CancellationTokenSource(TimeSpan.FromSeconds(1));
while(readBytes < readSaltBytes.Length && !cts.Token.IsCancellationRequested)
{
logger.LogError($"Read {readBytes} bytes instead of 16 bytes for the salt.");
throw new CryptographicException("Failed to read the salt bytes.");
readBytes += await base64Stream.ReadAsync(readSaltBytes, readBytes, readSaltBytes.Length - readBytes, cts.Token);
await Task.Delay(TimeSpan.FromMilliseconds(60), cts.Token);
}
// Check the salt bytes:
@@ -0,0 +1,7 @@
using System.Text.Json.Serialization;
namespace AIStudio.Tools.Rust;
public readonly record struct GetSecretRequest(
string Destination,
[property:JsonPropertyName("user_name")] string UserName);
@@ -0,0 +1,9 @@
namespace AIStudio.Tools.Rust;
/// <summary>
/// Data structure for any requested secret.
/// </summary>
/// <param name="Success">True, when the secret was successfully retrieved.</param>
/// <param name="Secret">The secret, e.g., API key.</param>
/// <param name="Issue">The issue, when the secret could not be retrieved.</param>
public readonly record struct RequestedSecret(bool Success, EncryptedText Secret, string Issue);
@@ -1,4 +1,4 @@
namespace AIStudio.Tools;
namespace AIStudio.Tools.Rust;
/// <summary>
/// The response from the set clipboard operation.
@@ -1,6 +1,6 @@
using System.Text.Json.Serialization;
namespace AIStudio.Tools;
namespace AIStudio.Tools.Rust;
/// <summary>
/// The response of the update check.
@@ -1,19 +1,24 @@
using AIStudio.Provider;
using AIStudio.Tools.Rust;
// ReSharper disable NotAccessedPositionalProperty.Local
namespace AIStudio.Tools;
/// <summary>
/// Calling Rust functions.
/// </summary>
public sealed class Rust(string apiPort) : IDisposable
public sealed class RustService(string apiPort) : IDisposable
{
private readonly HttpClient http = new()
{
BaseAddress = new Uri($"http://127.0.0.1:{apiPort}"),
};
private ILogger<Rust>? logger;
private ILogger<RustService>? logger;
private Encryption? encryptor;
public void SetLogger(ILogger<Rust> logService)
public void SetLogger(ILogger<RustService> logService)
{
this.logger = logService;
}
@@ -87,7 +92,8 @@ public sealed class Rust(string apiPort) : IDisposable
var severity = Severity.Error;
try
{
var response = await this.http.PostAsync("/clipboard/set", new StringContent(await text.Encrypt(this.encryptor!)));
var encryptedText = await text.Encrypt(this.encryptor!);
var response = await this.http.PostAsync("/clipboard/set", new StringContent(encryptedText.EncryptedData));
if (!response.IsSuccessStatusCode)
{
this.logger!.LogError($"Failed to copy the text to the clipboard due to an network error: '{response.StatusCode}'");
@@ -136,7 +142,7 @@ public sealed class Rust(string apiPort) : IDisposable
}
}
public async Task InstallUpdate(IJSRuntime jsRuntime)
public async Task InstallUpdate()
{
try
{
@@ -149,6 +155,28 @@ public sealed class Rust(string apiPort) : IDisposable
throw;
}
}
/// <summary>
/// Try to get the API key for the given provider.
/// </summary>
/// <param name="provider">The provider to get the API key for.</param>
/// <returns>The requested secret.</returns>
public async Task<RequestedSecret> GetAPIKey(IProvider provider)
{
var secretRequest = new GetSecretRequest($"provider::{provider.Id}::{provider.InstanceName}::api_key", Environment.UserName);
var result = await this.http.PostAsJsonAsync("/secrets/get", secretRequest);
if (!result.IsSuccessStatusCode)
{
this.logger!.LogError($"Failed to get the API key for provider '{provider.Id}' due to an API issue: '{result.StatusCode}'");
return new RequestedSecret(false, new EncryptedText(string.Empty), "Failed to get the API key due to an API issue.");
}
var secret = await result.Content.ReadFromJsonAsync<RequestedSecret>();
if (!secret.Success)
this.logger!.LogError($"Failed to get the API key for provider '{provider.Id}': '{secret.Issue}'");
return secret;
}
#region IDisposable
@@ -6,11 +6,11 @@ namespace AIStudio.Tools.Services;
/// Wire up the clipboard service to copy Markdown to the clipboard.
/// We use our own Rust-based clipboard service for this.
/// </summary>
public sealed class MarkdownClipboardService(Rust rust, ISnackbar snackbar) : IMudMarkdownClipboardService
public sealed class MarkdownClipboardService(RustService rust, ISnackbar snackbar) : IMudMarkdownClipboardService
{
private ISnackbar Snackbar { get; } = snackbar;
private Rust Rust { get; } = rust;
private RustService Rust { get; } = rust;
/// <summary>
/// Gets called when the user wants to copy the Markdown to the clipboard.
@@ -12,11 +12,11 @@ public sealed class UpdateService : BackgroundService, IMessageBusReceiver
private readonly SettingsManager settingsManager;
private readonly MessageBus messageBus;
private readonly Rust rust;
private readonly RustService rust;
private TimeSpan updateInterval;
public UpdateService(MessageBus messageBus, SettingsManager settingsManager, Rust rust)
public UpdateService(MessageBus messageBus, SettingsManager settingsManager, RustService rust)
{
this.settingsManager = settingsManager;
this.messageBus = messageBus;
@@ -1,7 +0,0 @@
namespace AIStudio.Tools;
/// <summary>
/// Model for setting clipboard text.
/// </summary>
/// <param name="Text">The text to set to the clipboard.</param>
public record SetClipboardText(string Text);