1
0
mirror of https://github.com/bitwarden/server.git synced 2025-07-03 00:52:49 -05:00

chore: update LastActivityDate on installation token refresh (#5081)

This commit is contained in:
Addison Beck
2025-01-06 16:22:03 -05:00
committed by GitHub
parent cd7c4bf6ce
commit 90f7bfe63d
13 changed files with 229 additions and 7 deletions

View File

@ -165,6 +165,7 @@ public static class FeatureFlagKeys
public const string AppReviewPrompt = "app-review-prompt";
public const string ResellerManagedOrgAlert = "PM-15814-alert-owners-of-reseller-managed-orgs";
public const string UsePricingService = "use-pricing-service";
public const string RecordInstallationLastActivityDate = "installation-last-activity-date";
public static List<string> GetAllKeys()
{

View File

@ -0,0 +1,14 @@
namespace Bit.Core.Platform.Installations;
/// <summary>
/// Command interface responsible for updating data on an `Installation`
/// record.
/// </summary>
/// <remarks>
/// This interface is implemented by `UpdateInstallationCommand`
/// </remarks>
/// <seealso cref="Bit.Core.Platform.Installations.UpdateInstallationCommand"/>
public interface IUpdateInstallationCommand
{
Task UpdateLastActivityDateAsync(Guid installationId);
}

View File

@ -0,0 +1,53 @@
namespace Bit.Core.Platform.Installations;
/// <summary>
/// Commands responsible for updating an installation from
/// `InstallationRepository`.
/// </summary>
/// <remarks>
/// If referencing: you probably want the interface
/// `IUpdateInstallationCommand` instead of directly calling this class.
/// </remarks>
/// <seealso cref="IUpdateInstallationCommand"/>
public class UpdateInstallationCommand : IUpdateInstallationCommand
{
private readonly IGetInstallationQuery _getInstallationQuery;
private readonly IInstallationRepository _installationRepository;
private readonly TimeProvider _timeProvider;
public UpdateInstallationCommand(
IGetInstallationQuery getInstallationQuery,
IInstallationRepository installationRepository,
TimeProvider timeProvider
)
{
_getInstallationQuery = getInstallationQuery;
_installationRepository = installationRepository;
_timeProvider = timeProvider;
}
public async Task UpdateLastActivityDateAsync(Guid installationId)
{
if (installationId == default)
{
throw new Exception
(
"Tried to update the last activity date for " +
"an installation, but an invalid installation id was " +
"provided."
);
}
var installation = await _getInstallationQuery.GetByIdAsync(installationId);
if (installation == null)
{
throw new Exception
(
"Tried to update the last activity date for " +
$"installation {installationId.ToString()}, but no " +
"installation was found for that id."
);
}
installation.LastActivityDate = _timeProvider.GetUtcNow().UtcDateTime;
await _installationRepository.UpsertAsync(installation);
}
}

View File

@ -19,6 +19,7 @@ public class Installation : ITableObject<Guid>
public string Key { get; set; } = null!;
public bool Enabled { get; set; }
public DateTime CreationDate { get; internal set; } = DateTime.UtcNow;
public DateTime? LastActivityDate { get; internal set; }
public void SetNewId()
{

View File

@ -0,0 +1,30 @@
namespace Bit.Core.Platform.Installations;
/// <summary>
/// Queries responsible for fetching an installation from
/// `InstallationRepository`.
/// </summary>
/// <remarks>
/// If referencing: you probably want the interface `IGetInstallationQuery`
/// instead of directly calling this class.
/// </remarks>
/// <seealso cref="IGetInstallationQuery"/>
public class GetInstallationQuery : IGetInstallationQuery
{
private readonly IInstallationRepository _installationRepository;
public GetInstallationQuery(IInstallationRepository installationRepository)
{
_installationRepository = installationRepository;
}
/// <inheritdoc cref="IGetInstallationQuery.GetByIdAsync"/>
public async Task<Installation> GetByIdAsync(Guid installationId)
{
if (installationId == default(Guid))
{
return null;
}
return await _installationRepository.GetByIdAsync(installationId);
}
}

View File

@ -0,0 +1,20 @@
namespace Bit.Core.Platform.Installations;
/// <summary>
/// Query interface responsible for fetching an installation from
/// `InstallationRepository`.
/// </summary>
/// <remarks>
/// This interface is implemented by `GetInstallationQuery`
/// </remarks>
/// <seealso cref="GetInstallationQuery"/>
public interface IGetInstallationQuery
{
/// <summary>
/// Retrieves an installation from the `InstallationRepository` by its id.
/// </summary>
/// <param name="installationId">The GUID id of the installation.</param>
/// <returns>A task containing an `Installation`.</returns>
/// <seealso cref="T:Bit.Core.Platform.Installations.Repositories.IInstallationRepository"/>
Task<Installation> GetByIdAsync(Guid installationId);
}

View File

@ -0,0 +1,19 @@
using Bit.Core.Platform.Installations;
using Microsoft.Extensions.DependencyInjection;
namespace Bit.Core.Platform;
public static class PlatformServiceCollectionExtensions
{
/// <summary>
/// Extend DI to include commands and queries exported from the Platform
/// domain.
/// </summary>
public static IServiceCollection AddPlatformServices(this IServiceCollection services)
{
services.AddScoped<IGetInstallationQuery, GetInstallationQuery>();
services.AddScoped<IUpdateInstallationCommand, UpdateInstallationCommand>();
return services;
}
}

View File

@ -9,7 +9,6 @@ namespace Bit.Core.Platform.Push.Internal;
public class RelayPushRegistrationService : BaseIdentityClientService, IPushRegistrationService
{
public RelayPushRegistrationService(
IHttpClientFactory httpFactory,
GlobalSettings globalSettings,