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:
parent
f8940e4be5
commit
e350daeeee
@ -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)
|
||||
{
|
||||
|
@ -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") { }
|
||||
}
|
||||
}
|
@ -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; }
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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))
|
||||
|
@ -26,5 +26,10 @@ namespace Bit.Core.Services
|
||||
{
|
||||
return Task.FromResult(0);
|
||||
}
|
||||
|
||||
public Task<string> GetSendFileDownloadUrlAsync(string fileId)
|
||||
{
|
||||
return Task.FromResult((string)null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user