integrating the security rules and badge to the plugin overview page

This commit is contained in:
nilsk 2026-03-31 15:37:01 +02:00
parent 09d13e66c2
commit 3f2d76337a
2 changed files with 75 additions and 26 deletions

View File

@ -1,4 +1,5 @@
@using AIStudio.Tools.PluginSystem
@using AIStudio.Tools.PluginSystem.Assistants
@inherits MSGComponentBase
@attribute [Route(Routes.PLUGINS)]
@ -64,19 +65,25 @@
</MudTd>
<MudTd>
<MudStack Row="true" Spacing="1" AlignItems="AlignItems.Center">
@if (context.Type is PluginType.ASSISTANT)
{
var assistantPlugin = PluginFactory.RunningPlugins.OfType<PluginAssistants>().FirstOrDefault(x => x.Id == context.Id);
<AssistantPluginSecurityCard Plugin="@assistantPlugin" Compact="@true" />
}
@if (context is { IsInternal: false, Type: not PluginType.CONFIGURATION })
{
var isEnabled = this.SettingsManager.IsPluginEnabled(context);
<MudTooltip Text="@(isEnabled ? T("Disable plugin") : T("Enable plugin"))">
<MudSwitch T="bool" Value="@isEnabled" ValueChanged="@(_ => this.PluginActivationStateChanged(context))"/>
var activationSwitchDisabled = this.IsActivationSwitchDisabled(context, isEnabled);
<MudTooltip Text="@this.GetActivationTooltip(context, isEnabled)">
<MudSwitch T="bool" Value="@isEnabled" ValueChanged="@(_ => this.PluginActivationStateChanged(context))" Disabled="@activationSwitchDisabled"/>
</MudTooltip>
}
@if (context is { IsInternal: false } && !string.IsNullOrWhiteSpace(context.SourceURL))
{
var sourceUrl = context.SourceURL;
var isSendingMail = IsSendingMail(sourceUrl);
if(isSendingMail)
if (isSendingMail)
{
<MudTooltip Text="@T("Send a mail")">
<MudIconButton Icon="@Icons.Material.Filled.Email" Href="@sourceUrl" Target="_blank" Size="Size.Medium"/>

View File

@ -59,7 +59,7 @@ public partial class Plugins : MSGComponentBase
return;
}
if (pluginMeta.Type is not PluginType.ASSISTANT || !this.AssistantPluginAuditSettings.RequireAuditBeforeActivation)
if (pluginMeta.Type is not PluginType.ASSISTANT)
{
this.SettingsManager.ConfigurationData.EnabledPlugins.Add(pluginMeta.Id);
await this.SettingsManager.StoreSettings();
@ -71,31 +71,37 @@ public partial class Plugins : MSGComponentBase
if (assistantPlugin is null)
return;
var pluginHash = assistantPlugin.ComputeAuditHash();
var cachedAudit = this.SettingsManager.ConfigurationData.AssistantPluginAudits.FirstOrDefault(x => x.PluginId == pluginMeta.Id);
if (cachedAudit is not null && cachedAudit.PluginHash == pluginHash)
var securityState = PluginAssistantSecurityResolver.Resolve(this.SettingsManager, assistantPlugin);
if (securityState.RequiresAudit)
{
if (cachedAudit.Level < this.AssistantPluginAuditSettings.MinimumLevel && this.AssistantPluginAuditSettings.BlockActivationBelowMinimum)
{
await this.DialogService.ShowMessageBox(this.T("Assistant Audit"), $"{cachedAudit.Level.GetName()}: {cachedAudit.Summary}", this.T("Close"));
return;
}
if (cachedAudit.Level < this.AssistantPluginAuditSettings.MinimumLevel &&
!await this.ConfirmActivationBelowMinimumAsync(pluginMeta.Name, cachedAudit.Level))
{
return;
}
this.SettingsManager.ConfigurationData.EnabledPlugins.Add(pluginMeta.Id);
await this.SettingsManager.StoreSettings();
await this.MessageBus.SendMessage<bool>(this, Event.CONFIGURATION_CHANGED);
await this.OpenAssistantAuditDialogAsync(pluginMeta.Id);
return;
}
if (securityState.IsBelowMinimum && securityState.IsBlocked)
{
var blockedAudit = securityState.Audit;
if (blockedAudit is not null)
await this.DialogService.ShowMessageBox(this.T("Assistant Audit"), $"{blockedAudit.Level.GetName()}: {blockedAudit.Summary}", this.T("Close"));
return;
}
if (securityState.IsBelowMinimum && securityState.CanOverride &&
!await this.ConfirmActivationBelowMinimumAsync(pluginMeta.Name, securityState.Audit!.Level))
{
return;
}
this.SettingsManager.ConfigurationData.EnabledPlugins.Add(pluginMeta.Id);
await this.SettingsManager.StoreSettings();
await this.MessageBus.SendMessage<bool>(this, Event.CONFIGURATION_CHANGED);
}
private async Task OpenAssistantAuditDialogAsync(Guid pluginId)
{
var parameters = new DialogParameters<AssistantPluginAuditDialog>
{
{ x => x.PluginId, pluginMeta.Id },
{ x => x.PluginId, pluginId },
};
var dialog = await this.DialogService.ShowAsync<AssistantPluginAuditDialog>(this.T("Assistant Audit"), parameters, DialogOptions.FULLSCREEN);
var result = await dialog.Result;
@ -106,7 +112,7 @@ public partial class Plugins : MSGComponentBase
this.UpsertAuditCard(auditResult.Audit);
if (auditResult.ActivatePlugin)
this.SettingsManager.ConfigurationData.EnabledPlugins.Add(pluginMeta.Id);
this.SettingsManager.ConfigurationData.EnabledPlugins.Add(pluginId);
await this.SettingsManager.StoreSettings();
await this.MessageBus.SendMessage<bool>(this, Event.CONFIGURATION_CHANGED);
@ -132,8 +138,44 @@ public partial class Plugins : MSGComponentBase
return dialogResult is not null && !dialogResult.Canceled;
}
private bool IsActivationSwitchDisabled(IPluginMetadata pluginMeta, bool isEnabled)
{
if (isEnabled || pluginMeta.Type is not PluginType.ASSISTANT)
return false;
var assistantPlugin = this.TryGetAssistantPlugin(pluginMeta.Id);
if (assistantPlugin is null)
return false;
var securityState = PluginAssistantSecurityResolver.Resolve(this.SettingsManager, assistantPlugin);
return securityState.IsBlocked && !securityState.RequiresAudit;
}
private string GetActivationTooltip(IPluginMetadata pluginMeta, bool isEnabled)
{
if (isEnabled)
return this.T("Disable plugin");
if (pluginMeta.Type is not PluginType.ASSISTANT)
return this.T("Enable plugin");
var assistantPlugin = this.TryGetAssistantPlugin(pluginMeta.Id);
if (assistantPlugin is null)
return this.T("Enable plugin");
var securityState = PluginAssistantSecurityResolver.Resolve(this.SettingsManager, assistantPlugin);
if (securityState.RequiresAudit)
return securityState.ActionLabel;
return securityState.IsBlocked
? securityState.Description
: this.T("Enable plugin");
}
private static bool IsSendingMail(string sourceUrl) => sourceUrl.TrimStart().StartsWith("mailto:", StringComparison.OrdinalIgnoreCase);
private PluginAssistants? TryGetAssistantPlugin(Guid pluginId) => PluginFactory.RunningPlugins.OfType<PluginAssistants>().FirstOrDefault(x => x.Id == pluginId);
private void UpsertAuditCard(PluginAssistantAudit audit)
{
var audits = this.SettingsManager.ConfigurationData.AssistantPluginAudits;
@ -150,7 +192,7 @@ public partial class Plugins : MSGComponentBase
{
switch (triggeredEvent)
{
case Event.PLUGINS_RELOADED:
case Event.PLUGINS_RELOADED or Event.CONFIGURATION_CHANGED:
await this.InvokeAsync(this.StateHasChanged);
break;
}