1
0
mirror of https://github.com/bitwarden/server.git synced 2025-05-22 12:04:27 -05:00

Use sas token for send downloads (#1157)

* Remove Url from SendFileModel

Url is now generated on the fly with limited lifetime.

New model houses the download url generated

* Create API endpoint for getting Send file download url

* Generate limited-life Azure download urls

* Lint fix
This commit is contained in:
Matt Gibson 2021-02-24 13:03:16 -06:00 committed by GitHub
parent f8940e4be5
commit e350daeeee
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 54 additions and 3 deletions

View File

@ -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<SendFileDownloadDataResponseModel> GetSendFileDownloadData(string id)
{
return new SendFileDownloadDataResponseModel()
{
Id = id,
Url = await _sendFileStorageService.GetSendFileDownloadUrlAsync(id),
};
}
[HttpGet("{id}")]
public async Task<SendResponseModel> Get(string id)
{

View File

@ -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") { }
}
}

View File

@ -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; }

View File

@ -11,5 +11,6 @@ namespace Bit.Core.Services
Task DeleteFileAsync(string fileId);
Task DeleteFilesForOrganizationAsync(Guid organizationId);
Task DeleteFilesForUserAsync(Guid userId);
Task<string> GetSendFileDownloadUrlAsync(string fileId);
}
}

View File

@ -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<string> 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);
}
}
}

View File

@ -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<string> GetSendFileDownloadUrlAsync(string fileId)
{
await InitAsync();
return $"{_baseSendUrl}/{fileId}";
}
private void DeleteFileIfExists(string path)
{
if (File.Exists(path))

View File

@ -26,5 +26,10 @@ namespace Bit.Core.Services
{
return Task.FromResult(0);
}
public Task<string> GetSendFileDownloadUrlAsync(string fileId)
{
return Task.FromResult((string)null);
}
}
}