mirror of
https://github.com/bitwarden/server
synced 2026-02-06 03:33:43 +00:00
Move all event integration code to Dirt (#6757)
* Move all event integration code to Dirt * Format to fix lint
This commit is contained in:
@@ -1,3 +0,0 @@
|
||||
namespace Bit.Core.AdminConsole.Models.Data.EventIntegrations;
|
||||
|
||||
public record DatadogIntegration(string ApiKey, Uri Uri);
|
||||
@@ -1,3 +0,0 @@
|
||||
namespace Bit.Core.AdminConsole.Models.Data.EventIntegrations;
|
||||
|
||||
public record DatadogIntegrationConfigurationDetails(string ApiKey, Uri Uri);
|
||||
@@ -1,38 +0,0 @@
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Settings;
|
||||
|
||||
namespace Bit.Core.AdminConsole.Models.Data.EventIntegrations;
|
||||
|
||||
public class DatadogListenerConfiguration(GlobalSettings globalSettings)
|
||||
: ListenerConfiguration(globalSettings), IIntegrationListenerConfiguration
|
||||
{
|
||||
public IntegrationType IntegrationType
|
||||
{
|
||||
get => IntegrationType.Datadog;
|
||||
}
|
||||
|
||||
public string EventQueueName
|
||||
{
|
||||
get => _globalSettings.EventLogging.RabbitMq.DatadogEventsQueueName;
|
||||
}
|
||||
|
||||
public string IntegrationQueueName
|
||||
{
|
||||
get => _globalSettings.EventLogging.RabbitMq.DatadogIntegrationQueueName;
|
||||
}
|
||||
|
||||
public string IntegrationRetryQueueName
|
||||
{
|
||||
get => _globalSettings.EventLogging.RabbitMq.DatadogIntegrationRetryQueueName;
|
||||
}
|
||||
|
||||
public string EventSubscriptionName
|
||||
{
|
||||
get => _globalSettings.EventLogging.AzureServiceBus.DatadogEventSubscriptionName;
|
||||
}
|
||||
|
||||
public string IntegrationSubscriptionName
|
||||
{
|
||||
get => _globalSettings.EventLogging.AzureServiceBus.DatadogIntegrationSubscriptionName;
|
||||
}
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
namespace Bit.Core.AdminConsole.Models.Data.EventIntegrations;
|
||||
|
||||
public record HecIntegration(Uri Uri, string Scheme, string Token, string? Service = null);
|
||||
@@ -1,38 +0,0 @@
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Settings;
|
||||
|
||||
namespace Bit.Core.AdminConsole.Models.Data.EventIntegrations;
|
||||
|
||||
public class HecListenerConfiguration(GlobalSettings globalSettings)
|
||||
: ListenerConfiguration(globalSettings), IIntegrationListenerConfiguration
|
||||
{
|
||||
public IntegrationType IntegrationType
|
||||
{
|
||||
get => IntegrationType.Hec;
|
||||
}
|
||||
|
||||
public string EventQueueName
|
||||
{
|
||||
get => _globalSettings.EventLogging.RabbitMq.HecEventsQueueName;
|
||||
}
|
||||
|
||||
public string IntegrationQueueName
|
||||
{
|
||||
get => _globalSettings.EventLogging.RabbitMq.HecIntegrationQueueName;
|
||||
}
|
||||
|
||||
public string IntegrationRetryQueueName
|
||||
{
|
||||
get => _globalSettings.EventLogging.RabbitMq.HecIntegrationRetryQueueName;
|
||||
}
|
||||
|
||||
public string EventSubscriptionName
|
||||
{
|
||||
get => _globalSettings.EventLogging.AzureServiceBus.HecEventSubscriptionName;
|
||||
}
|
||||
|
||||
public string IntegrationSubscriptionName
|
||||
{
|
||||
get => _globalSettings.EventLogging.AzureServiceBus.HecIntegrationSubscriptionName;
|
||||
}
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
namespace Bit.Core.AdminConsole.Models.Data.EventIntegrations;
|
||||
|
||||
public interface IEventListenerConfiguration
|
||||
{
|
||||
public string EventQueueName { get; }
|
||||
public string EventSubscriptionName { get; }
|
||||
public string EventTopicName { get; }
|
||||
public int EventPrefetchCount { get; }
|
||||
public int EventMaxConcurrentCalls { get; }
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
using Bit.Core.Enums;
|
||||
|
||||
namespace Bit.Core.AdminConsole.Models.Data.EventIntegrations;
|
||||
|
||||
public interface IIntegrationListenerConfiguration : IEventListenerConfiguration
|
||||
{
|
||||
public IntegrationType IntegrationType { get; }
|
||||
public string IntegrationQueueName { get; }
|
||||
public string IntegrationRetryQueueName { get; }
|
||||
public string IntegrationSubscriptionName { get; }
|
||||
public string IntegrationTopicName { get; }
|
||||
public int MaxRetries { get; }
|
||||
public int IntegrationPrefetchCount { get; }
|
||||
public int IntegrationMaxConcurrentCalls { get; }
|
||||
|
||||
public string RoutingKey
|
||||
{
|
||||
get => IntegrationType.ToRoutingKey();
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
using Bit.Core.Enums;
|
||||
|
||||
namespace Bit.Core.AdminConsole.Models.Data.EventIntegrations;
|
||||
|
||||
public interface IIntegrationMessage
|
||||
{
|
||||
IntegrationType IntegrationType { get; }
|
||||
string MessageId { get; set; }
|
||||
string? OrganizationId { get; set; }
|
||||
int RetryCount { get; }
|
||||
DateTime? DelayUntilDate { get; }
|
||||
void ApplyRetry(DateTime? handlerDelayUntilDate);
|
||||
string ToJson();
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
namespace Bit.Core.AdminConsole.Models.Data.EventIntegrations;
|
||||
|
||||
/// <summary>
|
||||
/// Categories of event integration failures used for classification and retry logic.
|
||||
/// </summary>
|
||||
public enum IntegrationFailureCategory
|
||||
{
|
||||
/// <summary>
|
||||
/// Service is temporarily unavailable (503, upstream outage, maintenance).
|
||||
/// </summary>
|
||||
ServiceUnavailable,
|
||||
|
||||
/// <summary>
|
||||
/// Authentication failed (401, 403, invalid_auth, token issues).
|
||||
/// </summary>
|
||||
AuthenticationFailed,
|
||||
|
||||
/// <summary>
|
||||
/// Configuration error (invalid config, channel_not_found, etc.).
|
||||
/// </summary>
|
||||
ConfigurationError,
|
||||
|
||||
/// <summary>
|
||||
/// Rate limited (429, rate_limited).
|
||||
/// </summary>
|
||||
RateLimited,
|
||||
|
||||
/// <summary>
|
||||
/// Transient error (timeouts, 500, network errors).
|
||||
/// </summary>
|
||||
TransientError,
|
||||
|
||||
/// <summary>
|
||||
/// Permanent failure unrelated to authentication/config (e.g., unrecoverable payload/format issue).
|
||||
/// </summary>
|
||||
PermanentFailure
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
namespace Bit.Core.AdminConsole.Models.Data.EventIntegrations;
|
||||
|
||||
public class IntegrationFilterGroup
|
||||
{
|
||||
public bool AndOperator { get; init; } = true;
|
||||
public List<IntegrationFilterRule>? Rules { get; init; }
|
||||
public List<IntegrationFilterGroup>? Groups { get; init; }
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
namespace Bit.Core.AdminConsole.Models.Data.EventIntegrations;
|
||||
|
||||
public enum IntegrationFilterOperation
|
||||
{
|
||||
Equals = 0,
|
||||
NotEquals = 1,
|
||||
In = 2,
|
||||
NotIn = 3
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
namespace Bit.Core.AdminConsole.Models.Data.EventIntegrations;
|
||||
|
||||
public class IntegrationFilterRule
|
||||
{
|
||||
public required string Property { get; set; }
|
||||
public required IntegrationFilterOperation Operation { get; set; }
|
||||
public required object? Value { get; set; }
|
||||
}
|
||||
|
||||
@@ -1,84 +0,0 @@
|
||||
namespace Bit.Core.AdminConsole.Models.Data.EventIntegrations;
|
||||
|
||||
/// <summary>
|
||||
/// Represents the result of an integration handler operation, including success status,
|
||||
/// failure categorization, and retry metadata. Use the <see cref="Succeed"/> factory method
|
||||
/// for successful operations or <see cref="Fail"/> for failures with automatic retry-ability
|
||||
/// determination based on the failure category.
|
||||
/// </summary>
|
||||
public class IntegrationHandlerResult
|
||||
{
|
||||
/// <summary>
|
||||
/// True if the integration send succeeded, false otherwise.
|
||||
/// </summary>
|
||||
public bool Success { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The integration message that was processed.
|
||||
/// </summary>
|
||||
public IIntegrationMessage Message { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Optional UTC date/time indicating when a failed operation should be retried.
|
||||
/// Will be used by the retry queue to delay re-sending the message.
|
||||
/// Usually set based on the Retry-After header from rate-limited responses.
|
||||
/// </summary>
|
||||
public DateTime? DelayUntilDate { get; private init; }
|
||||
|
||||
/// <summary>
|
||||
/// Category of the failure. Null for successful results.
|
||||
/// </summary>
|
||||
public IntegrationFailureCategory? Category { get; private init; }
|
||||
|
||||
/// <summary>
|
||||
/// Detailed failure reason or error message. Empty for successful results.
|
||||
/// </summary>
|
||||
public string? FailureReason { get; private init; }
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether the operation is retryable.
|
||||
/// Computed from the failure category.
|
||||
/// </summary>
|
||||
public bool Retryable => Category switch
|
||||
{
|
||||
IntegrationFailureCategory.RateLimited => true,
|
||||
IntegrationFailureCategory.TransientError => true,
|
||||
IntegrationFailureCategory.ServiceUnavailable => true,
|
||||
IntegrationFailureCategory.AuthenticationFailed => false,
|
||||
IntegrationFailureCategory.ConfigurationError => false,
|
||||
IntegrationFailureCategory.PermanentFailure => false,
|
||||
null => false,
|
||||
_ => false
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Creates a successful result.
|
||||
/// </summary>
|
||||
public static IntegrationHandlerResult Succeed(IIntegrationMessage message)
|
||||
{
|
||||
return new IntegrationHandlerResult(success: true, message: message);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a failed result with a failure category and reason.
|
||||
/// </summary>
|
||||
public static IntegrationHandlerResult Fail(
|
||||
IIntegrationMessage message,
|
||||
IntegrationFailureCategory category,
|
||||
string failureReason,
|
||||
DateTime? delayUntil = null)
|
||||
{
|
||||
return new IntegrationHandlerResult(success: false, message: message)
|
||||
{
|
||||
Category = category,
|
||||
FailureReason = failureReason,
|
||||
DelayUntilDate = delayUntil
|
||||
};
|
||||
}
|
||||
|
||||
private IntegrationHandlerResult(bool success, IIntegrationMessage message)
|
||||
{
|
||||
Success = success;
|
||||
Message = message;
|
||||
}
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
using System.Text.Json;
|
||||
using Bit.Core.Enums;
|
||||
|
||||
namespace Bit.Core.AdminConsole.Models.Data.EventIntegrations;
|
||||
|
||||
public class IntegrationMessage : IIntegrationMessage
|
||||
{
|
||||
public IntegrationType IntegrationType { get; set; }
|
||||
public required string MessageId { get; set; }
|
||||
public string? OrganizationId { get; set; }
|
||||
public required string RenderedTemplate { get; set; }
|
||||
public int RetryCount { get; set; } = 0;
|
||||
public DateTime? DelayUntilDate { get; set; }
|
||||
|
||||
public void ApplyRetry(DateTime? handlerDelayUntilDate)
|
||||
{
|
||||
RetryCount++;
|
||||
|
||||
var baseTime = handlerDelayUntilDate ?? DateTime.UtcNow;
|
||||
var backoffSeconds = Math.Pow(2, RetryCount);
|
||||
var jitterSeconds = Random.Shared.Next(0, 3);
|
||||
|
||||
DelayUntilDate = baseTime.AddSeconds(backoffSeconds + jitterSeconds);
|
||||
}
|
||||
|
||||
public virtual string ToJson()
|
||||
{
|
||||
return JsonSerializer.Serialize(this);
|
||||
}
|
||||
}
|
||||
|
||||
public class IntegrationMessage<T> : IntegrationMessage
|
||||
{
|
||||
public required T Configuration { get; set; }
|
||||
|
||||
public override string ToJson()
|
||||
{
|
||||
return JsonSerializer.Serialize(this);
|
||||
}
|
||||
|
||||
public static IntegrationMessage<T>? FromJson(string json)
|
||||
{
|
||||
return JsonSerializer.Deserialize<IntegrationMessage<T>>(json);
|
||||
}
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using Bit.Core.AdminConsole.Entities;
|
||||
|
||||
namespace Bit.Core.AdminConsole.Models.Data.EventIntegrations;
|
||||
|
||||
public class IntegrationOAuthState
|
||||
{
|
||||
private const int _orgHashLength = 12;
|
||||
private static readonly TimeSpan _maxAge = TimeSpan.FromMinutes(20);
|
||||
|
||||
public Guid IntegrationId { get; }
|
||||
private DateTimeOffset Issued { get; }
|
||||
private string OrganizationIdHash { get; }
|
||||
|
||||
private IntegrationOAuthState(Guid integrationId, string organizationIdHash, DateTimeOffset issued)
|
||||
{
|
||||
IntegrationId = integrationId;
|
||||
OrganizationIdHash = organizationIdHash;
|
||||
Issued = issued;
|
||||
}
|
||||
|
||||
public static IntegrationOAuthState FromIntegration(OrganizationIntegration integration, TimeProvider timeProvider)
|
||||
{
|
||||
var integrationId = integration.Id;
|
||||
var issuedUtc = timeProvider.GetUtcNow();
|
||||
var organizationIdHash = ComputeOrgHash(integration.OrganizationId, issuedUtc.ToUnixTimeSeconds());
|
||||
|
||||
return new IntegrationOAuthState(integrationId, organizationIdHash, issuedUtc);
|
||||
}
|
||||
|
||||
public static IntegrationOAuthState? FromString(string state, TimeProvider timeProvider)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(state)) return null;
|
||||
|
||||
var parts = state.Split('.');
|
||||
if (parts.Length != 3) return null;
|
||||
|
||||
// Verify timestamp
|
||||
if (!long.TryParse(parts[2], out var unixSeconds)) return null;
|
||||
|
||||
var issuedUtc = DateTimeOffset.FromUnixTimeSeconds(unixSeconds);
|
||||
var now = timeProvider.GetUtcNow();
|
||||
var age = now - issuedUtc;
|
||||
|
||||
if (age > _maxAge) return null;
|
||||
|
||||
// Parse integration id and store org
|
||||
if (!Guid.TryParse(parts[0], out var integrationId)) return null;
|
||||
var organizationIdHash = parts[1];
|
||||
|
||||
return new IntegrationOAuthState(integrationId, organizationIdHash, issuedUtc);
|
||||
}
|
||||
|
||||
public bool ValidateOrg(Guid orgId)
|
||||
{
|
||||
var expected = ComputeOrgHash(orgId, Issued.ToUnixTimeSeconds());
|
||||
return expected == OrganizationIdHash;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{IntegrationId}.{OrganizationIdHash}.{Issued.ToUnixTimeSeconds()}";
|
||||
}
|
||||
|
||||
private static string ComputeOrgHash(Guid orgId, long timestamp)
|
||||
{
|
||||
var bytes = SHA256.HashData(Encoding.UTF8.GetBytes($"{orgId:N}:{timestamp}"));
|
||||
return Convert.ToHexString(bytes)[.._orgHashLength];
|
||||
}
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
using System.Text.Json;
|
||||
using Bit.Core.AdminConsole.Entities;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Models.Data;
|
||||
using Bit.Core.Models.Data.Organizations.OrganizationUsers;
|
||||
|
||||
namespace Bit.Core.AdminConsole.Models.Data.EventIntegrations;
|
||||
|
||||
public class IntegrationTemplateContext(EventMessage eventMessage)
|
||||
{
|
||||
public EventMessage Event { get; } = eventMessage;
|
||||
|
||||
public string DomainName => Event.DomainName;
|
||||
public string IpAddress => Event.IpAddress;
|
||||
public DeviceType? DeviceType => Event.DeviceType;
|
||||
public Guid? ActingUserId => Event.ActingUserId;
|
||||
public Guid? OrganizationUserId => Event.OrganizationUserId;
|
||||
public DateTime Date => Event.Date;
|
||||
public EventType Type => Event.Type;
|
||||
public Guid? UserId => Event.UserId;
|
||||
public Guid? OrganizationId => Event.OrganizationId;
|
||||
public Guid? CipherId => Event.CipherId;
|
||||
public Guid? CollectionId => Event.CollectionId;
|
||||
public Guid? GroupId => Event.GroupId;
|
||||
public Guid? PolicyId => Event.PolicyId;
|
||||
public Guid? IdempotencyId => Event.IdempotencyId;
|
||||
public Guid? ProviderId => Event.ProviderId;
|
||||
public Guid? ProviderUserId => Event.ProviderUserId;
|
||||
public Guid? ProviderOrganizationId => Event.ProviderOrganizationId;
|
||||
public Guid? InstallationId => Event.InstallationId;
|
||||
public Guid? SecretId => Event.SecretId;
|
||||
public Guid? ProjectId => Event.ProjectId;
|
||||
public Guid? ServiceAccountId => Event.ServiceAccountId;
|
||||
public Guid? GrantedServiceAccountId => Event.GrantedServiceAccountId;
|
||||
|
||||
public string DateIso8601 => Date.ToString("o");
|
||||
public string EventMessage => JsonSerializer.Serialize(Event);
|
||||
|
||||
public OrganizationUserUserDetails? User { get; set; }
|
||||
public string? UserName => User?.Name;
|
||||
public string? UserEmail => User?.Email;
|
||||
public OrganizationUserType? UserType => User?.Type;
|
||||
|
||||
public OrganizationUserUserDetails? ActingUser { get; set; }
|
||||
public string? ActingUserName => ActingUser?.Name;
|
||||
public string? ActingUserEmail => ActingUser?.Email;
|
||||
public OrganizationUserType? ActingUserType => ActingUser?.Type;
|
||||
|
||||
public Group? Group { get; set; }
|
||||
public string? GroupName => Group?.Name;
|
||||
|
||||
public Organization? Organization { get; set; }
|
||||
public string? OrganizationName => Organization?.DisplayName();
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
using Bit.Core.Settings;
|
||||
|
||||
namespace Bit.Core.AdminConsole.Models.Data.EventIntegrations;
|
||||
|
||||
public abstract class ListenerConfiguration
|
||||
{
|
||||
protected GlobalSettings _globalSettings;
|
||||
|
||||
public ListenerConfiguration(GlobalSettings globalSettings)
|
||||
{
|
||||
_globalSettings = globalSettings;
|
||||
}
|
||||
|
||||
public int MaxRetries
|
||||
{
|
||||
get => _globalSettings.EventLogging.MaxRetries;
|
||||
}
|
||||
|
||||
public string EventTopicName
|
||||
{
|
||||
get => _globalSettings.EventLogging.AzureServiceBus.EventTopicName;
|
||||
}
|
||||
|
||||
public string IntegrationTopicName
|
||||
{
|
||||
get => _globalSettings.EventLogging.AzureServiceBus.IntegrationTopicName;
|
||||
}
|
||||
|
||||
public int EventPrefetchCount
|
||||
{
|
||||
get => _globalSettings.EventLogging.AzureServiceBus.DefaultPrefetchCount;
|
||||
}
|
||||
|
||||
public int EventMaxConcurrentCalls
|
||||
{
|
||||
get => _globalSettings.EventLogging.AzureServiceBus.DefaultMaxConcurrentCalls;
|
||||
}
|
||||
|
||||
public int IntegrationPrefetchCount
|
||||
{
|
||||
get => _globalSettings.EventLogging.AzureServiceBus.DefaultPrefetchCount;
|
||||
}
|
||||
|
||||
public int IntegrationMaxConcurrentCalls
|
||||
{
|
||||
get => _globalSettings.EventLogging.AzureServiceBus.DefaultMaxConcurrentCalls;
|
||||
}
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
using Bit.Core.Settings;
|
||||
|
||||
namespace Bit.Core.AdminConsole.Models.Data.EventIntegrations;
|
||||
|
||||
public class RepositoryListenerConfiguration(GlobalSettings globalSettings)
|
||||
: ListenerConfiguration(globalSettings), IEventListenerConfiguration
|
||||
{
|
||||
public string EventQueueName
|
||||
{
|
||||
get => _globalSettings.EventLogging.RabbitMq.EventRepositoryQueueName;
|
||||
}
|
||||
|
||||
public string EventSubscriptionName
|
||||
{
|
||||
get => _globalSettings.EventLogging.AzureServiceBus.EventRepositorySubscriptionName;
|
||||
}
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
namespace Bit.Core.AdminConsole.Models.Data.EventIntegrations;
|
||||
|
||||
public record SlackIntegration(string Token);
|
||||
@@ -1,3 +0,0 @@
|
||||
namespace Bit.Core.AdminConsole.Models.Data.EventIntegrations;
|
||||
|
||||
public record SlackIntegrationConfiguration(string ChannelId);
|
||||
@@ -1,3 +0,0 @@
|
||||
namespace Bit.Core.AdminConsole.Models.Data.EventIntegrations;
|
||||
|
||||
public record SlackIntegrationConfigurationDetails(string ChannelId, string Token);
|
||||
@@ -1,38 +0,0 @@
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Settings;
|
||||
|
||||
namespace Bit.Core.AdminConsole.Models.Data.EventIntegrations;
|
||||
|
||||
public class SlackListenerConfiguration(GlobalSettings globalSettings) :
|
||||
ListenerConfiguration(globalSettings), IIntegrationListenerConfiguration
|
||||
{
|
||||
public IntegrationType IntegrationType
|
||||
{
|
||||
get => IntegrationType.Slack;
|
||||
}
|
||||
|
||||
public string EventQueueName
|
||||
{
|
||||
get => _globalSettings.EventLogging.RabbitMq.SlackEventsQueueName;
|
||||
}
|
||||
|
||||
public string IntegrationQueueName
|
||||
{
|
||||
get => _globalSettings.EventLogging.RabbitMq.SlackIntegrationQueueName;
|
||||
}
|
||||
|
||||
public string IntegrationRetryQueueName
|
||||
{
|
||||
get => _globalSettings.EventLogging.RabbitMq.SlackIntegrationRetryQueueName;
|
||||
}
|
||||
|
||||
public string EventSubscriptionName
|
||||
{
|
||||
get => _globalSettings.EventLogging.AzureServiceBus.SlackEventSubscriptionName;
|
||||
}
|
||||
|
||||
public string IntegrationSubscriptionName
|
||||
{
|
||||
get => _globalSettings.EventLogging.AzureServiceBus.SlackIntegrationSubscriptionName;
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
using Bit.Core.Models.Teams;
|
||||
|
||||
namespace Bit.Core.AdminConsole.Models.Data.EventIntegrations;
|
||||
|
||||
public record TeamsIntegration(
|
||||
string TenantId,
|
||||
IReadOnlyList<TeamInfo> Teams,
|
||||
string? ChannelId = null,
|
||||
Uri? ServiceUrl = null)
|
||||
{
|
||||
public bool IsCompleted => !string.IsNullOrEmpty(ChannelId) && ServiceUrl is not null;
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
namespace Bit.Core.AdminConsole.Models.Data.EventIntegrations;
|
||||
|
||||
public record TeamsIntegrationConfigurationDetails(string ChannelId, Uri ServiceUrl);
|
||||
@@ -1,38 +0,0 @@
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Settings;
|
||||
|
||||
namespace Bit.Core.AdminConsole.Models.Data.EventIntegrations;
|
||||
|
||||
public class TeamsListenerConfiguration(GlobalSettings globalSettings) :
|
||||
ListenerConfiguration(globalSettings), IIntegrationListenerConfiguration
|
||||
{
|
||||
public IntegrationType IntegrationType
|
||||
{
|
||||
get => IntegrationType.Teams;
|
||||
}
|
||||
|
||||
public string EventQueueName
|
||||
{
|
||||
get => _globalSettings.EventLogging.RabbitMq.TeamsEventsQueueName;
|
||||
}
|
||||
|
||||
public string IntegrationQueueName
|
||||
{
|
||||
get => _globalSettings.EventLogging.RabbitMq.TeamsIntegrationQueueName;
|
||||
}
|
||||
|
||||
public string IntegrationRetryQueueName
|
||||
{
|
||||
get => _globalSettings.EventLogging.RabbitMq.TeamsIntegrationRetryQueueName;
|
||||
}
|
||||
|
||||
public string EventSubscriptionName
|
||||
{
|
||||
get => _globalSettings.EventLogging.AzureServiceBus.TeamsEventSubscriptionName;
|
||||
}
|
||||
|
||||
public string IntegrationSubscriptionName
|
||||
{
|
||||
get => _globalSettings.EventLogging.AzureServiceBus.TeamsIntegrationSubscriptionName;
|
||||
}
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
namespace Bit.Core.AdminConsole.Models.Data.EventIntegrations;
|
||||
|
||||
public record WebhookIntegration(Uri Uri, string? Scheme = null, string? Token = null);
|
||||
@@ -1,3 +0,0 @@
|
||||
namespace Bit.Core.AdminConsole.Models.Data.EventIntegrations;
|
||||
|
||||
public record WebhookIntegrationConfiguration(Uri Uri, string? Scheme = null, string? Token = null);
|
||||
@@ -1,3 +0,0 @@
|
||||
namespace Bit.Core.AdminConsole.Models.Data.EventIntegrations;
|
||||
|
||||
public record WebhookIntegrationConfigurationDetails(Uri Uri, string? Scheme = null, string? Token = null);
|
||||
@@ -1,38 +0,0 @@
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Settings;
|
||||
|
||||
namespace Bit.Core.AdminConsole.Models.Data.EventIntegrations;
|
||||
|
||||
public class WebhookListenerConfiguration(GlobalSettings globalSettings)
|
||||
: ListenerConfiguration(globalSettings), IIntegrationListenerConfiguration
|
||||
{
|
||||
public IntegrationType IntegrationType
|
||||
{
|
||||
get => IntegrationType.Webhook;
|
||||
}
|
||||
|
||||
public string EventQueueName
|
||||
{
|
||||
get => _globalSettings.EventLogging.RabbitMq.WebhookEventsQueueName;
|
||||
}
|
||||
|
||||
public string IntegrationQueueName
|
||||
{
|
||||
get => _globalSettings.EventLogging.RabbitMq.WebhookIntegrationQueueName;
|
||||
}
|
||||
|
||||
public string IntegrationRetryQueueName
|
||||
{
|
||||
get => _globalSettings.EventLogging.RabbitMq.WebhookIntegrationRetryQueueName;
|
||||
}
|
||||
|
||||
public string EventSubscriptionName
|
||||
{
|
||||
get => _globalSettings.EventLogging.AzureServiceBus.WebhookEventSubscriptionName;
|
||||
}
|
||||
|
||||
public string IntegrationSubscriptionName
|
||||
{
|
||||
get => _globalSettings.EventLogging.AzureServiceBus.WebhookIntegrationSubscriptionName;
|
||||
}
|
||||
}
|
||||
@@ -1,66 +0,0 @@
|
||||
using System.Text.Json.Nodes;
|
||||
using Bit.Core.Enums;
|
||||
|
||||
#nullable enable
|
||||
|
||||
namespace Bit.Core.Models.Data.Organizations;
|
||||
|
||||
public class OrganizationIntegrationConfigurationDetails
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
public Guid OrganizationId { get; set; }
|
||||
public Guid OrganizationIntegrationId { get; set; }
|
||||
public IntegrationType IntegrationType { get; set; }
|
||||
public EventType? EventType { get; set; }
|
||||
public string? Configuration { get; set; }
|
||||
public string? Filters { get; set; }
|
||||
public string? IntegrationConfiguration { get; set; }
|
||||
public string? Template { get; set; }
|
||||
|
||||
public JsonObject MergedConfiguration
|
||||
{
|
||||
get
|
||||
{
|
||||
var integrationJson = IntegrationConfigurationJson;
|
||||
|
||||
foreach (var kvp in ConfigurationJson)
|
||||
{
|
||||
integrationJson[kvp.Key] = kvp.Value?.DeepClone();
|
||||
}
|
||||
|
||||
return integrationJson;
|
||||
}
|
||||
}
|
||||
|
||||
private JsonObject ConfigurationJson
|
||||
{
|
||||
get
|
||||
{
|
||||
try
|
||||
{
|
||||
var configuration = Configuration ?? string.Empty;
|
||||
return JsonNode.Parse(configuration) as JsonObject ?? new JsonObject();
|
||||
}
|
||||
catch
|
||||
{
|
||||
return new JsonObject();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private JsonObject IntegrationConfigurationJson
|
||||
{
|
||||
get
|
||||
{
|
||||
try
|
||||
{
|
||||
var integration = IntegrationConfiguration ?? string.Empty;
|
||||
return JsonNode.Parse(integration) as JsonObject ?? new JsonObject();
|
||||
}
|
||||
catch
|
||||
{
|
||||
return new JsonObject();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Bit.Core.Models.Slack;
|
||||
|
||||
public abstract class SlackApiResponse
|
||||
{
|
||||
public bool Ok { get; set; }
|
||||
[JsonPropertyName("response_metadata")]
|
||||
public SlackResponseMetadata ResponseMetadata { get; set; } = new();
|
||||
public string Error { get; set; } = string.Empty;
|
||||
}
|
||||
|
||||
public class SlackResponseMetadata
|
||||
{
|
||||
[JsonPropertyName("next_cursor")]
|
||||
public string NextCursor { get; set; } = string.Empty;
|
||||
}
|
||||
|
||||
public class SlackChannelListResponse : SlackApiResponse
|
||||
{
|
||||
public List<SlackChannel> Channels { get; set; } = new();
|
||||
}
|
||||
|
||||
public class SlackUserResponse : SlackApiResponse
|
||||
{
|
||||
public SlackUser User { get; set; } = new();
|
||||
}
|
||||
|
||||
public class SlackOAuthResponse : SlackApiResponse
|
||||
{
|
||||
[JsonPropertyName("access_token")]
|
||||
public string AccessToken { get; set; } = string.Empty;
|
||||
public SlackTeam Team { get; set; } = new();
|
||||
}
|
||||
|
||||
public class SlackSendMessageResponse : SlackApiResponse
|
||||
{
|
||||
[JsonPropertyName("channel")]
|
||||
public string Channel { get; set; } = string.Empty;
|
||||
}
|
||||
|
||||
public class SlackTeam
|
||||
{
|
||||
public string Id { get; set; } = string.Empty;
|
||||
}
|
||||
|
||||
public class SlackChannel
|
||||
{
|
||||
public string Id { get; set; } = string.Empty;
|
||||
public string Name { get; set; } = string.Empty;
|
||||
}
|
||||
|
||||
public class SlackUser
|
||||
{
|
||||
public string Id { get; set; } = string.Empty;
|
||||
public string Name { get; set; } = string.Empty;
|
||||
}
|
||||
|
||||
public class SlackDmResponse : SlackApiResponse
|
||||
{
|
||||
public SlackChannel Channel { get; set; } = new();
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Bit.Core.Models.Teams;
|
||||
|
||||
/// <summary>Represents the response returned by the Microsoft OAuth 2.0 token endpoint.
|
||||
/// See <see href="https://learn.microsoft.com/graph/auth-v2-user">Microsoft identity platform and OAuth 2.0
|
||||
/// authorization code flow</see>.</summary>
|
||||
public class TeamsOAuthResponse
|
||||
{
|
||||
/// <summary>The access token issued by Microsoft, used to call the Microsoft Graph API.</summary>
|
||||
[JsonPropertyName("access_token")]
|
||||
public string AccessToken { get; set; } = string.Empty;
|
||||
}
|
||||
|
||||
/// <summary>Represents the response from the <c>/me/joinedTeams</c> Microsoft Graph API call.
|
||||
/// See <see href="https://learn.microsoft.com/graph/api/user-list-joinedteams">List joined teams -
|
||||
/// Microsoft Graph v1.0</see>.</summary>
|
||||
public class JoinedTeamsResponse
|
||||
{
|
||||
/// <summary>The collection of teams that the user has joined.</summary>
|
||||
[JsonPropertyName("value")]
|
||||
public List<TeamInfo> Value { get; set; } = [];
|
||||
}
|
||||
|
||||
/// <summary>Represents a Microsoft Teams team returned by the Graph API.
|
||||
/// See <see href="https://learn.microsoft.com/graph/api/resources/team">Team resource type -
|
||||
/// Microsoft Graph v1.0</see>.</summary>
|
||||
public class TeamInfo
|
||||
{
|
||||
/// <summary>The unique identifier of the team.</summary>
|
||||
[JsonPropertyName("id")]
|
||||
public string Id { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>The name of the team.</summary>
|
||||
[JsonPropertyName("displayName")]
|
||||
public string DisplayName { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>The ID of the Microsoft Entra tenant for this team.</summary>
|
||||
[JsonPropertyName("tenantId")]
|
||||
public string TenantId { get; set; } = string.Empty;
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
using Microsoft.Bot.Connector.Authentication;
|
||||
|
||||
namespace Bit.Core.AdminConsole.Models.Teams;
|
||||
|
||||
public class TeamsBotCredentialProvider(string clientId, string clientSecret) : ICredentialProvider
|
||||
{
|
||||
private const string _microsoftBotFrameworkIssuer = AuthenticationConstants.ToBotFromChannelTokenIssuer;
|
||||
|
||||
public Task<bool> IsValidAppIdAsync(string appId)
|
||||
{
|
||||
return Task.FromResult(appId == clientId);
|
||||
}
|
||||
|
||||
public Task<string?> GetAppPasswordAsync(string appId)
|
||||
{
|
||||
return Task.FromResult(appId == clientId ? clientSecret : null);
|
||||
}
|
||||
|
||||
public Task<bool> IsAuthenticationDisabledAsync()
|
||||
{
|
||||
return Task.FromResult(false);
|
||||
}
|
||||
|
||||
public Task<bool> ValidateIssuerAsync(string issuer)
|
||||
{
|
||||
return Task.FromResult(issuer == _microsoftBotFrameworkIssuer);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user