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

[PM-328] Move files for team-tools (#2857)

* Extract Import-Api endpoints into separate controller

Moved ciphers/import and ciphers/import-organization into new ImportController
Paths have been kept intact for now (no changes on clients needed)
Moved request-models used for import into tools-subfolder

* Update CODEOWNERS for team-tools-dev

* Move HibpController (reports) to tools

* Moving files related to Send

* Moving files related to ReferenceEvent

* Removed unneeded newline
This commit is contained in:
Daniel James Smith
2023-04-18 14:05:17 +02:00
committed by GitHub
parent baec7745f7
commit 4e7b9d2edd
91 changed files with 292 additions and 178 deletions

View File

@ -1,6 +1,6 @@
using Bit.Core.Auth.Entities;
using Bit.Core.Entities;
using Bit.Core.Enums;
using Bit.Core.Tools.Entities;
using Bit.Core.Vault.Entities;
namespace Bit.Core.Services;

View File

@ -1,8 +0,0 @@
using Bit.Core.Models.Business;
namespace Bit.Core.Services;
public interface IReferenceEventService
{
Task RaiseEventAsync(ReferenceEvent referenceEvent);
}

View File

@ -1,16 +0,0 @@
using Bit.Core.Entities;
using Bit.Core.Models.Data;
namespace Bit.Core.Services;
public interface ISendService
{
Task DeleteSendAsync(Send send);
Task SaveSendAsync(Send send);
Task<string> SaveFileSendAsync(Send send, SendFileData data, long fileLength);
Task UploadFileToExistingSendAsync(Stream stream, Send send);
Task<(Send, bool, bool)> AccessAsync(Guid sendId, string password);
string HashPassword(string password);
Task<(string, bool, bool)> GetSendFileDownloadUrlAsync(Send send, string fileId, string password);
Task<bool> ValidateSendFile(Send send);
}

View File

@ -1,16 +0,0 @@
using Bit.Core.Entities;
using Bit.Core.Enums;
namespace Bit.Core.Services;
public interface ISendFileStorageService
{
FileUploadType FileUploadType { get; }
Task UploadNewFileAsync(Stream stream, Send send, string fileId);
Task DeleteFileAsync(Send send, string fileId);
Task DeleteFilesForOrganizationAsync(Guid organizationId);
Task DeleteFilesForUserAsync(Guid userId);
Task<string> GetSendFileDownloadUrlAsync(Send send, string fileId);
Task<string> GetSendFileUploadUrlAsync(Send send, string fileId);
Task<(bool, long?)> ValidateFileAsync(Send send, string fileId, long expectedFileSize, long leeway);
}

View File

@ -4,6 +4,7 @@ using Bit.Core.Auth.Models;
using Bit.Core.Entities;
using Bit.Core.Enums;
using Bit.Core.Models.Business;
using Bit.Core.Tools.Entities;
using Bit.Core.Vault.Entities;
using Fido2NetLib;
using Microsoft.AspNetCore.Identity;

View File

@ -2,10 +2,10 @@
using Azure.Storage.Queues;
using Bit.Core.Auth.Entities;
using Bit.Core.Context;
using Bit.Core.Entities;
using Bit.Core.Enums;
using Bit.Core.Models;
using Bit.Core.Settings;
using Bit.Core.Tools.Entities;
using Bit.Core.Utilities;
using Bit.Core.Vault.Entities;
using Microsoft.AspNetCore.Http;

View File

@ -1,48 +0,0 @@
using System.Text;
using System.Text.Json;
using Azure.Storage.Queues;
using Bit.Core.Models.Business;
using Bit.Core.Settings;
using Bit.Core.Utilities;
namespace Bit.Core.Services;
public class AzureQueueReferenceEventService : IReferenceEventService
{
private const string _queueName = "reference-events";
private readonly QueueClient _queueClient;
private readonly GlobalSettings _globalSettings;
public AzureQueueReferenceEventService(
GlobalSettings globalSettings)
{
_queueClient = new QueueClient(globalSettings.Events.ConnectionString, _queueName);
_globalSettings = globalSettings;
}
public async Task RaiseEventAsync(ReferenceEvent referenceEvent)
{
await SendMessageAsync(referenceEvent);
}
private async Task SendMessageAsync(ReferenceEvent referenceEvent)
{
if (_globalSettings.SelfHosted)
{
// Ignore for self-hosted
return;
}
try
{
var message = JsonSerializer.Serialize(referenceEvent, JsonHelpers.IgnoreWritingNullAndCamelCase);
// Messages need to be base64 encoded
var encodedMessage = Convert.ToBase64String(Encoding.UTF8.GetBytes(message));
await _queueClient.SendMessageAsync(encodedMessage);
}
catch
{
// Ignore failure
}
}
}

View File

@ -1,141 +0,0 @@
using Azure.Storage.Blobs;
using Azure.Storage.Blobs.Models;
using Azure.Storage.Sas;
using Bit.Core.Entities;
using Bit.Core.Enums;
using Bit.Core.Settings;
using Microsoft.Extensions.Logging;
namespace Bit.Core.Services;
public class AzureSendFileStorageService : ISendFileStorageService
{
public const string FilesContainerName = "sendfiles";
private static readonly TimeSpan _downloadLinkLiveTime = TimeSpan.FromMinutes(1);
private readonly BlobServiceClient _blobServiceClient;
private readonly ILogger<AzureSendFileStorageService> _logger;
private BlobContainerClient _sendFilesContainerClient;
public FileUploadType FileUploadType => FileUploadType.Azure;
public static string SendIdFromBlobName(string blobName) => blobName.Split('/')[0];
public static string BlobName(Send send, string fileId) => $"{send.Id}/{fileId}";
public AzureSendFileStorageService(
GlobalSettings globalSettings,
ILogger<AzureSendFileStorageService> logger)
{
_blobServiceClient = new BlobServiceClient(globalSettings.Send.ConnectionString);
_logger = logger;
}
public async Task UploadNewFileAsync(Stream stream, Send send, string fileId)
{
await InitAsync();
var blobClient = _sendFilesContainerClient.GetBlobClient(BlobName(send, fileId));
var metadata = new Dictionary<string, string>();
if (send.UserId.HasValue)
{
metadata.Add("userId", send.UserId.Value.ToString());
}
else
{
metadata.Add("organizationId", send.OrganizationId.Value.ToString());
}
var headers = new BlobHttpHeaders
{
ContentDisposition = $"attachment; filename=\"{fileId}\""
};
await blobClient.UploadAsync(stream, new BlobUploadOptions { Metadata = metadata, HttpHeaders = headers });
}
public async Task DeleteFileAsync(Send send, string fileId) => await DeleteBlobAsync(BlobName(send, fileId));
public async Task DeleteBlobAsync(string blobName)
{
await InitAsync();
var blobClient = _sendFilesContainerClient.GetBlobClient(blobName);
await blobClient.DeleteIfExistsAsync();
}
public async Task DeleteFilesForOrganizationAsync(Guid organizationId)
{
await InitAsync();
}
public async Task DeleteFilesForUserAsync(Guid userId)
{
await InitAsync();
}
public async Task<string> GetSendFileDownloadUrlAsync(Send send, string fileId)
{
await InitAsync();
var blobClient = _sendFilesContainerClient.GetBlobClient(BlobName(send, fileId));
var sasUri = blobClient.GenerateSasUri(BlobSasPermissions.Read, DateTime.UtcNow.Add(_downloadLinkLiveTime));
return sasUri.ToString();
}
public async Task<string> GetSendFileUploadUrlAsync(Send send, string fileId)
{
await InitAsync();
var blobClient = _sendFilesContainerClient.GetBlobClient(BlobName(send, fileId));
var sasUri = blobClient.GenerateSasUri(BlobSasPermissions.Create | BlobSasPermissions.Write, DateTime.UtcNow.Add(_downloadLinkLiveTime));
return sasUri.ToString();
}
public async Task<(bool, long?)> ValidateFileAsync(Send send, string fileId, long expectedFileSize, long leeway)
{
await InitAsync();
var blobClient = _sendFilesContainerClient.GetBlobClient(BlobName(send, fileId));
try
{
var blobProperties = await blobClient.GetPropertiesAsync();
var metadata = blobProperties.Value.Metadata;
if (send.UserId.HasValue)
{
metadata["userId"] = send.UserId.Value.ToString();
}
else
{
metadata["organizationId"] = send.OrganizationId.Value.ToString();
}
await blobClient.SetMetadataAsync(metadata);
var headers = new BlobHttpHeaders
{
ContentDisposition = $"attachment; filename=\"{fileId}\""
};
await blobClient.SetHttpHeadersAsync(headers);
var length = blobProperties.Value.ContentLength;
if (length < expectedFileSize - leeway || length > expectedFileSize + leeway)
{
return (false, length);
}
return (true, length);
}
catch (Exception ex)
{
_logger.LogError(ex, "Unhandled error in ValidateFileAsync");
return (false, null);
}
}
private async Task InitAsync()
{
if (_sendFilesContainerClient == null)
{
_sendFilesContainerClient = _blobServiceClient.GetBlobContainerClient(FilesContainerName);
await _sendFilesContainerClient.CreateIfNotExistsAsync(PublicAccessType.None, null, null);
}
}
}

View File

@ -1,10 +1,11 @@
using Bit.Core.Context;
using Bit.Core.Entities;
using Bit.Core.Enums;
using Bit.Core.Exceptions;
using Bit.Core.Models.Business;
using Bit.Core.Models.Data;
using Bit.Core.Repositories;
using Bit.Core.Tools.Enums;
using Bit.Core.Tools.Models.Business;
using Bit.Core.Tools.Services;
namespace Bit.Core.Services;

View File

@ -1,105 +0,0 @@
using Bit.Core.Entities;
using Bit.Core.Enums;
using Bit.Core.Settings;
namespace Bit.Core.Services;
public class LocalSendStorageService : ISendFileStorageService
{
private readonly string _baseDirPath;
private readonly string _baseSendUrl;
private string RelativeFilePath(Send send, string fileID) => $"{send.Id}/{fileID}";
private string FilePath(Send send, string fileID) => $"{_baseDirPath}/{RelativeFilePath(send, fileID)}";
public FileUploadType FileUploadType => FileUploadType.Direct;
public LocalSendStorageService(
GlobalSettings globalSettings)
{
_baseDirPath = globalSettings.Send.BaseDirectory;
_baseSendUrl = globalSettings.Send.BaseUrl;
}
public async Task UploadNewFileAsync(Stream stream, Send send, string fileId)
{
await InitAsync();
var path = FilePath(send, fileId);
Directory.CreateDirectory(Path.GetDirectoryName(path));
using (var fs = File.Create(path))
{
stream.Seek(0, SeekOrigin.Begin);
await stream.CopyToAsync(fs);
}
}
public async Task DeleteFileAsync(Send send, string fileId)
{
await InitAsync();
var path = FilePath(send, fileId);
DeleteFileIfExists(path);
DeleteDirectoryIfExistsAndEmpty(Path.GetDirectoryName(path));
}
public async Task DeleteFilesForOrganizationAsync(Guid organizationId)
{
await InitAsync();
}
public async Task DeleteFilesForUserAsync(Guid userId)
{
await InitAsync();
}
public async Task<string> GetSendFileDownloadUrlAsync(Send send, string fileId)
{
await InitAsync();
return $"{_baseSendUrl}/{RelativeFilePath(send, fileId)}";
}
private void DeleteFileIfExists(string path)
{
if (File.Exists(path))
{
File.Delete(path);
}
}
private void DeleteDirectoryIfExistsAndEmpty(string path)
{
if (Directory.Exists(path) && !Directory.EnumerateFiles(path).Any())
{
Directory.Delete(path);
}
}
private Task InitAsync()
{
if (!Directory.Exists(_baseDirPath))
{
Directory.CreateDirectory(_baseDirPath);
}
return Task.FromResult(0);
}
public Task<string> GetSendFileUploadUrlAsync(Send send, string fileId)
=> Task.FromResult($"/sends/{send.Id}/file/{fileId}");
public Task<(bool, long?)> ValidateFileAsync(Send send, string fileId, long expectedFileSize, long leeway)
{
long? length = null;
var path = FilePath(send, fileId);
if (!File.Exists(path))
{
return Task.FromResult((false, length));
}
length = new FileInfo(path).Length;
if (expectedFileSize < length - leeway || expectedFileSize > length + leeway)
{
return Task.FromResult((false, length));
}
return Task.FromResult((true, length));
}
}

View File

@ -1,8 +1,8 @@
using Bit.Core.Auth.Entities;
using Bit.Core.Entities;
using Bit.Core.Enums;
using Bit.Core.Repositories;
using Bit.Core.Settings;
using Bit.Core.Tools.Entities;
using Bit.Core.Utilities;
using Bit.Core.Vault.Entities;
using Microsoft.AspNetCore.Http;

View File

@ -2,12 +2,12 @@
using System.Text.RegularExpressions;
using Bit.Core.Auth.Entities;
using Bit.Core.Context;
using Bit.Core.Entities;
using Bit.Core.Enums;
using Bit.Core.Models;
using Bit.Core.Models.Data;
using Bit.Core.Repositories;
using Bit.Core.Settings;
using Bit.Core.Tools.Entities;
using Bit.Core.Vault.Entities;
using Microsoft.AspNetCore.Http;
using Microsoft.Azure.NotificationHubs;

View File

@ -1,9 +1,9 @@
using Bit.Core.Auth.Entities;
using Bit.Core.Context;
using Bit.Core.Entities;
using Bit.Core.Enums;
using Bit.Core.Models;
using Bit.Core.Settings;
using Bit.Core.Tools.Entities;
using Bit.Core.Vault.Entities;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;

View File

@ -14,6 +14,9 @@ using Bit.Core.Models.Data.Organizations.Policies;
using Bit.Core.Models.OrganizationConnectionConfigs;
using Bit.Core.Repositories;
using Bit.Core.Settings;
using Bit.Core.Tools.Enums;
using Bit.Core.Tools.Models.Business;
using Bit.Core.Tools.Services;
using Bit.Core.Utilities;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.Extensions.Logging;

View File

@ -1,12 +1,12 @@
using Bit.Core.Auth.Entities;
using Bit.Core.Context;
using Bit.Core.Entities;
using Bit.Core.Enums;
using Bit.Core.IdentityServer;
using Bit.Core.Models;
using Bit.Core.Models.Api;
using Bit.Core.Repositories;
using Bit.Core.Settings;
using Bit.Core.Tools.Entities;
using Bit.Core.Vault.Entities;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;

View File

@ -1,339 +0,0 @@
using System.Text.Json;
using Bit.Core.Context;
using Bit.Core.Entities;
using Bit.Core.Enums;
using Bit.Core.Exceptions;
using Bit.Core.Models.Business;
using Bit.Core.Models.Data;
using Bit.Core.Models.Data.Organizations.Policies;
using Bit.Core.Repositories;
using Bit.Core.Settings;
using Bit.Core.Utilities;
using Microsoft.AspNetCore.Identity;
namespace Bit.Core.Services;
public class SendService : ISendService
{
public const long MAX_FILE_SIZE = Constants.FileSize501mb;
public const string MAX_FILE_SIZE_READABLE = "500 MB";
private readonly ISendRepository _sendRepository;
private readonly IUserRepository _userRepository;
private readonly IPolicyRepository _policyRepository;
private readonly IUserService _userService;
private readonly IOrganizationRepository _organizationRepository;
private readonly ISendFileStorageService _sendFileStorageService;
private readonly IPasswordHasher<User> _passwordHasher;
private readonly IPushNotificationService _pushService;
private readonly IReferenceEventService _referenceEventService;
private readonly GlobalSettings _globalSettings;
private readonly ICurrentContext _currentContext;
private const long _fileSizeLeeway = 1024L * 1024L; // 1MB
public SendService(
ISendRepository sendRepository,
IUserRepository userRepository,
IUserService userService,
IOrganizationRepository organizationRepository,
ISendFileStorageService sendFileStorageService,
IPasswordHasher<User> passwordHasher,
IPushNotificationService pushService,
IReferenceEventService referenceEventService,
GlobalSettings globalSettings,
IPolicyRepository policyRepository,
ICurrentContext currentContext)
{
_sendRepository = sendRepository;
_userRepository = userRepository;
_userService = userService;
_policyRepository = policyRepository;
_organizationRepository = organizationRepository;
_sendFileStorageService = sendFileStorageService;
_passwordHasher = passwordHasher;
_pushService = pushService;
_referenceEventService = referenceEventService;
_globalSettings = globalSettings;
_currentContext = currentContext;
}
public async Task SaveSendAsync(Send send)
{
// Make sure user can save Sends
await ValidateUserCanSaveAsync(send.UserId, send);
if (send.Id == default(Guid))
{
await _sendRepository.CreateAsync(send);
await _pushService.PushSyncSendCreateAsync(send);
await RaiseReferenceEventAsync(send, ReferenceEventType.SendCreated);
}
else
{
send.RevisionDate = DateTime.UtcNow;
await _sendRepository.UpsertAsync(send);
await _pushService.PushSyncSendUpdateAsync(send);
}
}
public async Task<string> SaveFileSendAsync(Send send, SendFileData data, long fileLength)
{
if (send.Type != SendType.File)
{
throw new BadRequestException("Send is not of type \"file\".");
}
if (fileLength < 1)
{
throw new BadRequestException("No file data.");
}
var storageBytesRemaining = await StorageRemainingForSendAsync(send);
if (storageBytesRemaining < fileLength)
{
throw new BadRequestException("Not enough storage available.");
}
var fileId = Utilities.CoreHelpers.SecureRandomString(32, upper: false, special: false);
try
{
data.Id = fileId;
data.Size = fileLength;
data.Validated = false;
send.Data = JsonSerializer.Serialize(data,
JsonHelpers.IgnoreWritingNull);
await SaveSendAsync(send);
return await _sendFileStorageService.GetSendFileUploadUrlAsync(send, fileId);
}
catch
{
// Clean up since this is not transactional
await _sendFileStorageService.DeleteFileAsync(send, fileId);
throw;
}
}
public async Task UploadFileToExistingSendAsync(Stream stream, Send send)
{
if (send?.Data == null)
{
throw new BadRequestException("Send does not have file data");
}
if (send.Type != SendType.File)
{
throw new BadRequestException("Not a File Type Send.");
}
var data = JsonSerializer.Deserialize<SendFileData>(send.Data);
if (data.Validated)
{
throw new BadRequestException("File has already been uploaded.");
}
await _sendFileStorageService.UploadNewFileAsync(stream, send, data.Id);
if (!await ValidateSendFile(send))
{
throw new BadRequestException("File received does not match expected file length.");
}
}
public async Task<bool> ValidateSendFile(Send send)
{
var fileData = JsonSerializer.Deserialize<SendFileData>(send.Data);
var (valid, realSize) = await _sendFileStorageService.ValidateFileAsync(send, fileData.Id, fileData.Size, _fileSizeLeeway);
if (!valid || realSize > MAX_FILE_SIZE)
{
// File reported differs in size from that promised. Must be a rogue client. Delete Send
await DeleteSendAsync(send);
return false;
}
// Update Send data if necessary
if (realSize != fileData.Size)
{
fileData.Size = realSize.Value;
}
fileData.Validated = true;
send.Data = JsonSerializer.Serialize(fileData,
JsonHelpers.IgnoreWritingNull);
await SaveSendAsync(send);
return valid;
}
public async Task DeleteSendAsync(Send send)
{
await _sendRepository.DeleteAsync(send);
if (send.Type == Enums.SendType.File)
{
var data = JsonSerializer.Deserialize<SendFileData>(send.Data);
await _sendFileStorageService.DeleteFileAsync(send, data.Id);
}
await _pushService.PushSyncSendDeleteAsync(send);
}
public (bool grant, bool passwordRequiredError, bool passwordInvalidError) SendCanBeAccessed(Send send,
string password)
{
var now = DateTime.UtcNow;
if (send == null || send.MaxAccessCount.GetValueOrDefault(int.MaxValue) <= send.AccessCount ||
send.ExpirationDate.GetValueOrDefault(DateTime.MaxValue) < now || send.Disabled ||
send.DeletionDate < now)
{
return (false, false, false);
}
if (!string.IsNullOrWhiteSpace(send.Password))
{
if (string.IsNullOrWhiteSpace(password))
{
return (false, true, false);
}
var passwordResult = _passwordHasher.VerifyHashedPassword(new User(), send.Password, password);
if (passwordResult == PasswordVerificationResult.SuccessRehashNeeded)
{
send.Password = HashPassword(password);
}
if (passwordResult == PasswordVerificationResult.Failed)
{
return (false, false, true);
}
}
return (true, false, false);
}
// Response: Send, password required, password invalid
public async Task<(string, bool, bool)> GetSendFileDownloadUrlAsync(Send send, string fileId, string password)
{
if (send.Type != SendType.File)
{
throw new BadRequestException("Can only get a download URL for a file type of Send");
}
var (grantAccess, passwordRequired, passwordInvalid) = SendCanBeAccessed(send, password);
if (!grantAccess)
{
return (null, passwordRequired, passwordInvalid);
}
send.AccessCount++;
await _sendRepository.ReplaceAsync(send);
await _pushService.PushSyncSendUpdateAsync(send);
return (await _sendFileStorageService.GetSendFileDownloadUrlAsync(send, fileId), false, false);
}
// Response: Send, password required, password invalid
public async Task<(Send, bool, bool)> AccessAsync(Guid sendId, string password)
{
var send = await _sendRepository.GetByIdAsync(sendId);
var (grantAccess, passwordRequired, passwordInvalid) = SendCanBeAccessed(send, password);
if (!grantAccess)
{
return (null, passwordRequired, passwordInvalid);
}
// TODO: maybe move this to a simple ++ sproc?
if (send.Type != SendType.File)
{
// File sends are incremented during file download
send.AccessCount++;
}
await _sendRepository.ReplaceAsync(send);
await _pushService.PushSyncSendUpdateAsync(send);
await RaiseReferenceEventAsync(send, ReferenceEventType.SendAccessed);
return (send, false, false);
}
private async Task RaiseReferenceEventAsync(Send send, ReferenceEventType eventType)
{
await _referenceEventService.RaiseEventAsync(new ReferenceEvent
{
Id = send.UserId ?? default,
Type = eventType,
Source = ReferenceEventSource.User,
SendType = send.Type,
MaxAccessCount = send.MaxAccessCount,
HasPassword = !string.IsNullOrWhiteSpace(send.Password),
});
}
public string HashPassword(string password)
{
return _passwordHasher.HashPassword(new User(), password);
}
private async Task ValidateUserCanSaveAsync(Guid? userId, Send send)
{
if (!userId.HasValue || (!_currentContext.Organizations?.Any() ?? true))
{
return;
}
var disableSendPolicyCount = await _policyRepository.GetCountByTypeApplicableToUserIdAsync(userId.Value,
PolicyType.DisableSend);
if (disableSendPolicyCount > 0)
{
throw new BadRequestException("Due to an Enterprise Policy, you are only able to delete an existing Send.");
}
if (send.HideEmail.GetValueOrDefault())
{
var sendOptionsPolicies = await _policyRepository.GetManyByTypeApplicableToUserIdAsync(userId.Value, PolicyType.SendOptions);
if (sendOptionsPolicies.Any(p => p.GetDataModel<SendOptionsPolicyData>()?.DisableHideEmail ?? false))
{
throw new BadRequestException("Due to an Enterprise Policy, you are not allowed to hide your email address from recipients when creating or editing a Send.");
}
}
}
private async Task<long> StorageRemainingForSendAsync(Send send)
{
var storageBytesRemaining = 0L;
if (send.UserId.HasValue)
{
var user = await _userRepository.GetByIdAsync(send.UserId.Value);
if (!await _userService.CanAccessPremium(user))
{
throw new BadRequestException("You must have premium status to use file Sends.");
}
if (!user.EmailVerified)
{
throw new BadRequestException("You must confirm your email to use file Sends.");
}
if (user.Premium)
{
storageBytesRemaining = user.StorageBytesRemaining();
}
else
{
// Users that get access to file storage/premium from their organization get the default
// 1 GB max storage.
storageBytesRemaining = user.StorageBytesRemaining(
_globalSettings.SelfHosted ? (short)10240 : (short)1);
}
}
else if (send.OrganizationId.HasValue)
{
var org = await _organizationRepository.GetByIdAsync(send.OrganizationId.Value);
if (!org.MaxStorageGb.HasValue)
{
throw new BadRequestException("This organization cannot use file sends.");
}
storageBytesRemaining = org.StorageBytesRemaining();
}
return storageBytesRemaining;
}
}

View File

@ -9,6 +9,10 @@ using Bit.Core.Exceptions;
using Bit.Core.Models.Business;
using Bit.Core.Repositories;
using Bit.Core.Settings;
using Bit.Core.Tools.Entities;
using Bit.Core.Tools.Enums;
using Bit.Core.Tools.Models.Business;
using Bit.Core.Tools.Services;
using Bit.Core.Utilities;
using Bit.Core.Vault.Entities;
using Bit.Core.Vault.Repositories;

View File

@ -1,6 +1,6 @@
using Bit.Core.Auth.Entities;
using Bit.Core.Entities;
using Bit.Core.Enums;
using Bit.Core.Tools.Entities;
using Bit.Core.Vault.Entities;
namespace Bit.Core.Services;

View File

@ -1,11 +0,0 @@
using Bit.Core.Models.Business;
namespace Bit.Core.Services;
public class NoopReferenceEventService : IReferenceEventService
{
public Task RaiseEventAsync(ReferenceEvent referenceEvent)
{
return Task.CompletedTask;
}
}

View File

@ -1,44 +0,0 @@
using Bit.Core.Entities;
using Bit.Core.Enums;
namespace Bit.Core.Services;
public class NoopSendFileStorageService : ISendFileStorageService
{
public FileUploadType FileUploadType => FileUploadType.Direct;
public Task UploadNewFileAsync(Stream stream, Send send, string attachmentId)
{
return Task.FromResult(0);
}
public Task DeleteFileAsync(Send send, string fileId)
{
return Task.FromResult(0);
}
public Task DeleteFilesForOrganizationAsync(Guid organizationId)
{
return Task.FromResult(0);
}
public Task DeleteFilesForUserAsync(Guid userId)
{
return Task.FromResult(0);
}
public Task<string> GetSendFileDownloadUrlAsync(Send send, string fileId)
{
return Task.FromResult((string)null);
}
public Task<string> GetSendFileUploadUrlAsync(Send send, string fileId)
{
return Task.FromResult((string)null);
}
public Task<(bool, long?)> ValidateFileAsync(Send send, string fileId, long expectedFileSize, long leeway)
{
return Task.FromResult((false, default(long?)));
}
}