diff --git a/src/Api/Controllers/SendsController.cs b/src/Api/Controllers/SendsController.cs index 51c01c698d..0fee3e19b4 100644 --- a/src/Api/Controllers/SendsController.cs +++ b/src/Api/Controllers/SendsController.cs @@ -11,6 +11,7 @@ using Bit.Api.Utilities; using Bit.Core.Models.Table; using Bit.Core.Utilities; using Bit.Core.Settings; +using Bit.Core.Models.Api.Response; namespace Bit.Api.Controllers { @@ -21,17 +22,20 @@ namespace Bit.Api.Controllers private readonly ISendRepository _sendRepository; private readonly IUserService _userService; private readonly ISendService _sendService; + private readonly ISendFileStorageService _sendFileStorageService; private readonly GlobalSettings _globalSettings; public SendsController( ISendRepository sendRepository, IUserService userService, ISendService sendService, + ISendFileStorageService sendFileStorageService, GlobalSettings globalSettings) { _sendRepository = sendRepository; _userService = userService; _sendService = sendService; + _sendFileStorageService = sendFileStorageService; _globalSettings = globalSettings; } @@ -59,6 +63,17 @@ namespace Bit.Api.Controllers return new ObjectResult(new SendAccessResponseModel(send, _globalSettings)); } + [AllowAnonymous] + [HttpGet("access/file/{id}")] + public async Task GetSendFileDownloadData(string id) + { + return new SendFileDownloadDataResponseModel() + { + Id = id, + Url = await _sendFileStorageService.GetSendFileDownloadUrlAsync(id), + }; + } + [HttpGet("{id}")] public async Task Get(string id) { diff --git a/src/Core/Models/Api/Response/SendFileDownloadDataResponseModel.cs b/src/Core/Models/Api/Response/SendFileDownloadDataResponseModel.cs new file mode 100644 index 0000000000..72463c5618 --- /dev/null +++ b/src/Core/Models/Api/Response/SendFileDownloadDataResponseModel.cs @@ -0,0 +1,10 @@ +namespace Bit.Core.Models.Api.Response +{ + public class SendFileDownloadDataResponseModel : ResponseModel + { + public string Id { get; set; } + public string Url { get; set; } + + public SendFileDownloadDataResponseModel() : base("send-fileDownload") { } + } +} diff --git a/src/Core/Models/Api/SendFileModel.cs b/src/Core/Models/Api/SendFileModel.cs index df64e8d36f..4aa81c5725 100644 --- a/src/Core/Models/Api/SendFileModel.cs +++ b/src/Core/Models/Api/SendFileModel.cs @@ -11,14 +11,12 @@ namespace Bit.Core.Models.Api public SendFileModel(SendFileData data, GlobalSettings globalSettings) { Id = data.Id; - Url = $"{globalSettings.Send.BaseUrl}/{data.Id}"; FileName = data.FileName; Size = data.SizeString; SizeName = CoreHelpers.ReadableBytesSize(data.Size); } public string Id { get; set; } - public string Url { get; set; } [EncryptedString] [EncryptedStringLength(1000)] public string FileName { get; set; } diff --git a/src/Core/Services/ISendStorageService.cs b/src/Core/Services/ISendStorageService.cs index 9cdce2c422..1b4c5cc371 100644 --- a/src/Core/Services/ISendStorageService.cs +++ b/src/Core/Services/ISendStorageService.cs @@ -11,5 +11,6 @@ namespace Bit.Core.Services Task DeleteFileAsync(string fileId); Task DeleteFilesForOrganizationAsync(Guid organizationId); Task DeleteFilesForUserAsync(Guid userId); + Task GetSendFileDownloadUrlAsync(string fileId); } } diff --git a/src/Core/Services/Implementations/AzureSendFileStorageService.cs b/src/Core/Services/Implementations/AzureSendFileStorageService.cs index 43691d6b3d..50edc58cb3 100644 --- a/src/Core/Services/Implementations/AzureSendFileStorageService.cs +++ b/src/Core/Services/Implementations/AzureSendFileStorageService.cs @@ -12,6 +12,7 @@ namespace Bit.Core.Services { private const string FilesContainerName = "sendfiles"; + private static readonly TimeSpan _downloadLinkLiveTime = TimeSpan.FromMinutes(1); private readonly CloudBlobClient _blobClient; private CloudBlobContainer _sendFilesContainer; @@ -55,12 +56,25 @@ namespace Bit.Core.Services await InitAsync(); } + public async Task GetSendFileDownloadUrlAsync(string fileId) + { + await InitAsync(); + var blob = _sendFilesContainer.GetBlockBlobReference(fileId); + var accessPolicy = new SharedAccessBlobPolicy() + { + SharedAccessExpiryTime = DateTime.UtcNow.Add(_downloadLinkLiveTime), + Permissions = SharedAccessBlobPermissions.Read + }; + + return blob.Uri + blob.GetSharedAccessSignature(accessPolicy); + } + private async Task InitAsync() { if (_sendFilesContainer == null) { _sendFilesContainer = _blobClient.GetContainerReference(FilesContainerName); - await _sendFilesContainer.CreateIfNotExistsAsync(BlobContainerPublicAccessType.Blob, null, null); + await _sendFilesContainer.CreateIfNotExistsAsync(BlobContainerPublicAccessType.Off, null, null); } } } diff --git a/src/Core/Services/Implementations/LocalSendStorageService.cs b/src/Core/Services/Implementations/LocalSendStorageService.cs index 038d106543..a015149e8a 100644 --- a/src/Core/Services/Implementations/LocalSendStorageService.cs +++ b/src/Core/Services/Implementations/LocalSendStorageService.cs @@ -9,11 +9,13 @@ namespace Bit.Core.Services public class LocalSendStorageService : ISendFileStorageService { private readonly string _baseDirPath; + private readonly string _baseSendUrl; public LocalSendStorageService( GlobalSettings globalSettings) { _baseDirPath = globalSettings.Send.BaseDirectory; + _baseSendUrl = globalSettings.Send.BaseUrl; } public async Task UploadNewFileAsync(Stream stream, Send send, string fileId) @@ -42,6 +44,12 @@ namespace Bit.Core.Services await InitAsync(); } + public async Task GetSendFileDownloadUrlAsync(string fileId) + { + await InitAsync(); + return $"{_baseSendUrl}/{fileId}"; + } + private void DeleteFileIfExists(string path) { if (File.Exists(path)) diff --git a/src/Core/Services/NoopImplementations/NoopSendFileStorageService.cs b/src/Core/Services/NoopImplementations/NoopSendFileStorageService.cs index 9b3940af64..2b174ce36f 100644 --- a/src/Core/Services/NoopImplementations/NoopSendFileStorageService.cs +++ b/src/Core/Services/NoopImplementations/NoopSendFileStorageService.cs @@ -26,5 +26,10 @@ namespace Bit.Core.Services { return Task.FromResult(0); } + + public Task GetSendFileDownloadUrlAsync(string fileId) + { + return Task.FromResult((string)null); + } } }