mirror of
https://github.com/bitwarden/mobile
synced 2025-12-05 23:53:33 +00:00
Compare commits
3 Commits
auth/pm-33
...
PM-2149-im
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
07b428f478 | ||
|
|
86985eaf47 | ||
|
|
8148bb9ff2 |
@@ -83,7 +83,7 @@ namespace Bit.Droid.Services
|
|||||||
return launchIntentSender != null;
|
return launchIntentSender != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task ShowLoadingAsync(string text)
|
public async Task ShowLoadingAsync(string text, System.Threading.CancellationTokenSource cts = null, string cancelButtonText = null)
|
||||||
{
|
{
|
||||||
if (_progressDialog != null)
|
if (_progressDialog != null)
|
||||||
{
|
{
|
||||||
@@ -98,10 +98,16 @@ namespace Bit.Droid.Services
|
|||||||
txtLoading.Text = text;
|
txtLoading.Text = text;
|
||||||
txtLoading.SetTextColor(ThemeHelpers.TextColor);
|
txtLoading.SetTextColor(ThemeHelpers.TextColor);
|
||||||
|
|
||||||
_progressDialog = new AlertDialog.Builder(activity)
|
var progressDialogBuilder = new AlertDialog.Builder(activity)
|
||||||
.SetView(dialogView)
|
.SetView(dialogView)
|
||||||
.SetCancelable(false)
|
.SetCancelable(cts != null);
|
||||||
.Create();
|
|
||||||
|
if (cts != null)
|
||||||
|
{
|
||||||
|
progressDialogBuilder.SetNegativeButton(cancelButtonText ?? AppResources.Cancel, (sender, args) => cts?.Cancel());
|
||||||
|
}
|
||||||
|
|
||||||
|
_progressDialog = progressDialogBuilder.Create();
|
||||||
_progressDialog.Show();
|
_progressDialog.Show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using System.Threading.Tasks;
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using Bit.Core.Enums;
|
using Bit.Core.Enums;
|
||||||
using Bit.Core.Models;
|
using Bit.Core.Models;
|
||||||
|
|
||||||
@@ -13,7 +14,7 @@ namespace Bit.App.Abstractions
|
|||||||
string GetBuildNumber();
|
string GetBuildNumber();
|
||||||
|
|
||||||
void Toast(string text, bool longDuration = false);
|
void Toast(string text, bool longDuration = false);
|
||||||
Task ShowLoadingAsync(string text);
|
Task ShowLoadingAsync(string text, CancellationTokenSource cts = null, string cancelButtonText = null);
|
||||||
Task HideLoadingAsync();
|
Task HideLoadingAsync();
|
||||||
Task<string> DisplayPromptAync(string title = null, string description = null, string text = null,
|
Task<string> DisplayPromptAync(string title = null, string description = null, string text = null,
|
||||||
string okButtonText = null, string cancelButtonText = null, bool numericKeyboard = false,
|
string okButtonText = null, string cancelButtonText = null, bool numericKeyboard = false,
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Windows.Input;
|
using System.Windows.Input;
|
||||||
using Bit.App.Abstractions;
|
using Bit.App.Abstractions;
|
||||||
@@ -31,6 +32,7 @@ namespace Bit.App.Pages
|
|||||||
private bool _hasUpdatedKey;
|
private bool _hasUpdatedKey;
|
||||||
private bool _canAccessAttachments;
|
private bool _canAccessAttachments;
|
||||||
private string _fileName;
|
private string _fileName;
|
||||||
|
private CancellationTokenSource _uploadCts;
|
||||||
|
|
||||||
public AttachmentsPageViewModel()
|
public AttachmentsPageViewModel()
|
||||||
{
|
{
|
||||||
@@ -119,11 +121,15 @@ namespace Bit.App.Pages
|
|||||||
AppResources.AnErrorHasOccurred);
|
AppResources.AnErrorHasOccurred);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_uploadCts = new CancellationTokenSource();
|
||||||
|
var uploadCts = _uploadCts;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await _deviceActionService.ShowLoadingAsync(AppResources.Saving);
|
await _deviceActionService.ShowLoadingAsync(AppResources.Saving, uploadCts);
|
||||||
_cipherDomain = await _cipherService.SaveAttachmentRawWithServerAsync(
|
_cipherDomain = await _cipherService.SaveAttachmentRawWithServerAsync(
|
||||||
_cipherDomain, FileName, FileData);
|
_cipherDomain, FileName, FileData, uploadCts.Token);
|
||||||
Cipher = await _cipherDomain.DecryptAsync();
|
Cipher = await _cipherDomain.DecryptAsync();
|
||||||
await _deviceActionService.HideLoadingAsync();
|
await _deviceActionService.HideLoadingAsync();
|
||||||
_platformUtilsService.ShowToast("success", null, AppResources.AttachementAdded);
|
_platformUtilsService.ShowToast("success", null, AppResources.AttachementAdded);
|
||||||
@@ -132,6 +138,11 @@ namespace Bit.App.Pages
|
|||||||
FileName = null;
|
FileName = null;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
catch (OperationCanceledException)
|
||||||
|
{
|
||||||
|
await _deviceActionService.HideLoadingAsync();
|
||||||
|
await _platformUtilsService.ShowDialogAsync(AppResources.UploadHasBeenCanceled, AppResources.Attachments);
|
||||||
|
}
|
||||||
catch (ApiException e)
|
catch (ApiException e)
|
||||||
{
|
{
|
||||||
_logger.Exception(e);
|
_logger.Exception(e);
|
||||||
|
|||||||
45
src/App/Resources/AppResources.Designer.cs
generated
45
src/App/Resources/AppResources.Designer.cs
generated
@@ -202,6 +202,24 @@ namespace Bit.App.Resources {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Biometric unlock for this account is disabled pending verification of master password..
|
||||||
|
/// </summary>
|
||||||
|
public static string AccountBiometricInvalidated {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("AccountBiometricInvalidated", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Autofill biometric unlock for this account is disabled pending verification of master password..
|
||||||
|
/// </summary>
|
||||||
|
public static string AccountBiometricInvalidatedExtension {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("AccountBiometricInvalidatedExtension", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized string similar to Your new account has been created! You may now log in..
|
/// Looks up a localized string similar to Your new account has been created! You may now log in..
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -967,24 +985,6 @@ namespace Bit.App.Resources {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Looks up a localized string similar to Biometric unlock disabled pending verification of master password..
|
|
||||||
/// </summary>
|
|
||||||
public static string AccountBiometricInvalidated {
|
|
||||||
get {
|
|
||||||
return ResourceManager.GetString("AccountBiometricInvalidated", resourceCulture);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Looks up a localized string similar to Biometric unlock for autofill disabled pending verification of master password..
|
|
||||||
/// </summary>
|
|
||||||
public static string AccountBiometricInvalidatedExtension {
|
|
||||||
get {
|
|
||||||
return ResourceManager.GetString("AccountBiometricInvalidatedExtension", resourceCulture);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized string similar to Biometrics.
|
/// Looks up a localized string similar to Biometrics.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -6515,6 +6515,15 @@ namespace Bit.App.Resources {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Upload has been canceled.
|
||||||
|
/// </summary>
|
||||||
|
public static string UploadHasBeenCanceled {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("UploadHasBeenCanceled", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized string similar to Uppercase (A to Z).
|
/// Looks up a localized string similar to Uppercase (A to Z).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -2631,4 +2631,7 @@ Do you want to switch to this account?</value>
|
|||||||
<data name="CurrentMasterPassword" xml:space="preserve">
|
<data name="CurrentMasterPassword" xml:space="preserve">
|
||||||
<value>Current master password</value>
|
<value>Current master password</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="UploadHasBeenCanceled" xml:space="preserve">
|
||||||
|
<value>Upload has been canceled</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Bit.Core.Enums;
|
using Bit.Core.Enums;
|
||||||
using Bit.Core.Models.Domain;
|
using Bit.Core.Models.Domain;
|
||||||
@@ -47,16 +48,16 @@ namespace Bit.Core.Abstractions
|
|||||||
Task RefreshIdentityTokenAsync();
|
Task RefreshIdentityTokenAsync();
|
||||||
Task<SsoPrevalidateResponse> PreValidateSso(string identifier);
|
Task<SsoPrevalidateResponse> PreValidateSso(string identifier);
|
||||||
Task<TResponse> SendAsync<TRequest, TResponse>(HttpMethod method, string path,
|
Task<TResponse> SendAsync<TRequest, TResponse>(HttpMethod method, string path,
|
||||||
TRequest body, bool authed, bool hasResponse, Action<HttpRequestMessage> alterRequest, bool logoutOnUnauthorized = true);
|
TRequest body, bool authed, bool hasResponse, Action<HttpRequestMessage> alterRequest, bool logoutOnUnauthorized = true, CancellationToken cancellationToken = default);
|
||||||
void SetUrls(EnvironmentUrls urls);
|
void SetUrls(EnvironmentUrls urls);
|
||||||
[Obsolete("Mar 25 2021: This method has been deprecated in favor of direct uploads. This method still exists for backward compatibility with old server versions.")]
|
[Obsolete("Mar 25 2021: This method has been deprecated in favor of direct uploads. This method still exists for backward compatibility with old server versions.")]
|
||||||
Task<CipherResponse> PostCipherAttachmentLegacyAsync(string id, MultipartFormDataContent data);
|
Task<CipherResponse> PostCipherAttachmentLegacyAsync(string id, MultipartFormDataContent data);
|
||||||
Task<AttachmentUploadDataResponse> PostCipherAttachmentAsync(string id, AttachmentRequest request);
|
Task<AttachmentUploadDataResponse> PostCipherAttachmentAsync(string id, AttachmentRequest request, CancellationToken cancellationToken);
|
||||||
Task<AttachmentResponse> GetAttachmentData(string cipherId, string attachmentId);
|
Task<AttachmentResponse> GetAttachmentData(string cipherId, string attachmentId);
|
||||||
Task PostShareCipherAttachmentAsync(string id, string attachmentId, MultipartFormDataContent data,
|
Task PostShareCipherAttachmentAsync(string id, string attachmentId, MultipartFormDataContent data,
|
||||||
string organizationId);
|
string organizationId);
|
||||||
Task<AttachmentUploadDataResponse> RenewAttachmentUploadUrlAsync(string id, string attachmentId);
|
Task<AttachmentUploadDataResponse> RenewAttachmentUploadUrlAsync(string id, string attachmentId, CancellationToken cancellationToken);
|
||||||
Task PostAttachmentFileAsync(string id, string attachmentId, MultipartFormDataContent data);
|
Task PostAttachmentFileAsync(string id, string attachmentId, MultipartFormDataContent data, CancellationToken cancellationToken);
|
||||||
Task<List<BreachAccountResponse>> GetHibpBreachAsync(string username);
|
Task<List<BreachAccountResponse>> GetHibpBreachAsync(string username);
|
||||||
Task PostTwoFactorEmailAsync(TwoFactorEmailRequest request);
|
Task PostTwoFactorEmailAsync(TwoFactorEmailRequest request);
|
||||||
Task PutDeviceTokenAsync(string identifier, DeviceTokenRequest request);
|
Task PutDeviceTokenAsync(string identifier, DeviceTokenRequest request);
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Bit.Core.Models.Domain;
|
using Bit.Core.Models.Domain;
|
||||||
|
|
||||||
@@ -6,6 +7,6 @@ namespace Bit.Core.Abstractions
|
|||||||
{
|
{
|
||||||
public interface IAzureFileUploadService
|
public interface IAzureFileUploadService
|
||||||
{
|
{
|
||||||
Task Upload(string uri, EncByteArray data, Func<Task<string>> renewalCallback);
|
Task Upload(string uri, EncByteArray data, Func<CancellationToken, Task<string>> renewalCallback, CancellationToken cancellationToken);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Bit.Core.Enums;
|
using Bit.Core.Enums;
|
||||||
using Bit.Core.Models.Data;
|
using Bit.Core.Models.Data;
|
||||||
@@ -27,7 +28,7 @@ namespace Bit.Core.Abstractions
|
|||||||
Task<Cipher> GetAsync(string id);
|
Task<Cipher> GetAsync(string id);
|
||||||
Task<CipherView> GetLastUsedForUrlAsync(string url);
|
Task<CipherView> GetLastUsedForUrlAsync(string url);
|
||||||
Task ReplaceAsync(Dictionary<string, CipherData> ciphers);
|
Task ReplaceAsync(Dictionary<string, CipherData> ciphers);
|
||||||
Task<Cipher> SaveAttachmentRawWithServerAsync(Cipher cipher, string filename, byte[] data);
|
Task<Cipher> SaveAttachmentRawWithServerAsync(Cipher cipher, string filename, byte[] data, CancellationToken cancellationToken);
|
||||||
Task SaveCollectionsWithServerAsync(Cipher cipher);
|
Task SaveCollectionsWithServerAsync(Cipher cipher);
|
||||||
Task SaveNeverDomainAsync(string domain);
|
Task SaveNeverDomainAsync(string domain);
|
||||||
Task SaveWithServerAsync(Cipher cipher);
|
Task SaveWithServerAsync(Cipher cipher);
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using System.Threading.Tasks;
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using Bit.Core.Models.Domain;
|
using Bit.Core.Models.Domain;
|
||||||
using Bit.Core.Models.Response;
|
using Bit.Core.Models.Response;
|
||||||
|
|
||||||
@@ -6,7 +7,7 @@ namespace Bit.Core.Abstractions
|
|||||||
{
|
{
|
||||||
public interface IFileUploadService
|
public interface IFileUploadService
|
||||||
{
|
{
|
||||||
Task UploadCipherAttachmentFileAsync(AttachmentUploadDataResponse uploadData, EncString fileName, EncByteArray encryptedFileData);
|
Task UploadCipherAttachmentFileAsync(AttachmentUploadDataResponse uploadData, EncString fileName, EncByteArray encryptedFileData, CancellationToken cancellationToken);
|
||||||
Task UploadSendFileAsync(SendFileUploadDataResponse uploadData, EncString fileName, EncByteArray encryptedFileData);
|
Task UploadSendFileAsync(SendFileUploadDataResponse uploadData, EncString fileName, EncByteArray encryptedFileData);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ using System.Collections.Generic;
|
|||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Bit.Core.Abstractions;
|
using Bit.Core.Abstractions;
|
||||||
using Bit.Core.Enums;
|
using Bit.Core.Enums;
|
||||||
@@ -342,10 +343,10 @@ namespace Bit.Core.Services
|
|||||||
string.Concat("/ciphers/", id, "/attachment"), data, true, true);
|
string.Concat("/ciphers/", id, "/attachment"), data, true, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<AttachmentUploadDataResponse> PostCipherAttachmentAsync(string id, AttachmentRequest request)
|
public Task<AttachmentUploadDataResponse> PostCipherAttachmentAsync(string id, AttachmentRequest request, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
return SendAsync<AttachmentRequest, AttachmentUploadDataResponse>(HttpMethod.Post,
|
return SendAsync<AttachmentRequest, AttachmentUploadDataResponse>(HttpMethod.Post,
|
||||||
$"/ciphers/{id}/attachment/v2", request, true, true);
|
$"/ciphers/{id}/attachment/v2", request, true, true, cancellationToken: cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<AttachmentResponse> GetAttachmentData(string cipherId, string attachmentId) =>
|
public Task<AttachmentResponse> GetAttachmentData(string cipherId, string attachmentId) =>
|
||||||
@@ -365,12 +366,12 @@ namespace Bit.Core.Services
|
|||||||
data, true, false);
|
data, true, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<AttachmentUploadDataResponse> RenewAttachmentUploadUrlAsync(string cipherId, string attachmentId) =>
|
public Task<AttachmentUploadDataResponse> RenewAttachmentUploadUrlAsync(string cipherId, string attachmentId, CancellationToken cancellationToken) =>
|
||||||
SendAsync<AttachmentUploadDataResponse>(HttpMethod.Get, $"/ciphers/{cipherId}/attachment/{attachmentId}/renew", true);
|
SendAsync<AttachmentUploadDataResponse>(HttpMethod.Get, $"/ciphers/{cipherId}/attachment/{attachmentId}/renew", true, cancellationToken);
|
||||||
|
|
||||||
public Task PostAttachmentFileAsync(string cipherId, string attachmentId, MultipartFormDataContent data) =>
|
public Task PostAttachmentFileAsync(string cipherId, string attachmentId, MultipartFormDataContent data, CancellationToken cancellationToken) =>
|
||||||
SendAsync(HttpMethod.Post,
|
SendAsync(HttpMethod.Post,
|
||||||
$"/ciphers/{cipherId}/attachment/{attachmentId}", data, true);
|
$"/ciphers/{cipherId}/attachment/{attachmentId}", data, true, cancellationToken);
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
@@ -639,12 +640,12 @@ namespace Bit.Core.Services
|
|||||||
|
|
||||||
public Task SendAsync(HttpMethod method, string path, bool authed) =>
|
public Task SendAsync(HttpMethod method, string path, bool authed) =>
|
||||||
SendAsync<object, object>(method, path, null, authed, false);
|
SendAsync<object, object>(method, path, null, authed, false);
|
||||||
public Task SendAsync<TRequest>(HttpMethod method, string path, TRequest body, bool authed) =>
|
public Task SendAsync<TRequest>(HttpMethod method, string path, TRequest body, bool authed, CancellationToken cancellationToken = default) =>
|
||||||
SendAsync<TRequest, object>(method, path, body, authed, false);
|
SendAsync<TRequest, object>(method, path, body, authed, false, cancellationToken: cancellationToken);
|
||||||
public Task<TResponse> SendAsync<TResponse>(HttpMethod method, string path, bool authed) =>
|
public Task<TResponse> SendAsync<TResponse>(HttpMethod method, string path, bool authed, CancellationToken cancellationToken = default) =>
|
||||||
SendAsync<object, TResponse>(method, path, null, authed, true);
|
SendAsync<object, TResponse>(method, path, null, authed, true, cancellationToken: cancellationToken);
|
||||||
public async Task<TResponse> SendAsync<TRequest, TResponse>(HttpMethod method, string path, TRequest body,
|
public async Task<TResponse> SendAsync<TRequest, TResponse>(HttpMethod method, string path, TRequest body,
|
||||||
bool authed, bool hasResponse, Action<HttpRequestMessage> alterRequest = null, bool logoutOnUnauthorized = true)
|
bool authed, bool hasResponse, Action<HttpRequestMessage> alterRequest = null, bool logoutOnUnauthorized = true, CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
using (var requestMessage = new HttpRequestMessage())
|
using (var requestMessage = new HttpRequestMessage())
|
||||||
{
|
{
|
||||||
@@ -696,7 +697,15 @@ namespace Bit.Core.Services
|
|||||||
HttpResponseMessage response;
|
HttpResponseMessage response;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
response = await _httpClient.SendAsync(requestMessage);
|
response = await _httpClient.SendAsync(requestMessage, cancellationToken);
|
||||||
|
}
|
||||||
|
catch (OperationCanceledException)
|
||||||
|
{
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
catch (Exception ex) when (ex.Message?.Contains("Socket closed") == true)
|
||||||
|
{
|
||||||
|
throw new OperationCanceledException();
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ using System.Net;
|
|||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Net.Http.Headers;
|
using System.Net.Http.Headers;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Web;
|
using System.Web;
|
||||||
using Bit.Core.Abstractions;
|
using Bit.Core.Abstractions;
|
||||||
@@ -29,19 +30,19 @@ namespace Bit.Core.Services
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Upload(string uri, EncByteArray data, Func<Task<string>> renewalCallback)
|
public async Task Upload(string uri, EncByteArray data, Func<CancellationToken, Task<string>> renewalCallback, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
if (data?.Buffer?.Length <= MAX_SINGLE_BLOB_UPLOAD_SIZE)
|
if (data?.Buffer?.Length <= MAX_SINGLE_BLOB_UPLOAD_SIZE)
|
||||||
{
|
{
|
||||||
await AzureUploadBlob(uri, data);
|
await AzureUploadBlob(uri, data, cancellationToken);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
await AzureUploadBlocks(uri, data, renewalCallback);
|
await AzureUploadBlocks(uri, data, renewalCallback, cancellationToken);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task AzureUploadBlob(string uri, EncByteArray data)
|
private async Task AzureUploadBlob(string uri, EncByteArray data, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
using (var requestMessage = new HttpRequestMessage())
|
using (var requestMessage = new HttpRequestMessage())
|
||||||
{
|
{
|
||||||
@@ -57,7 +58,7 @@ namespace Bit.Core.Services
|
|||||||
requestMessage.Method = HttpMethod.Put;
|
requestMessage.Method = HttpMethod.Put;
|
||||||
requestMessage.RequestUri = uriBuilder.Uri;
|
requestMessage.RequestUri = uriBuilder.Uri;
|
||||||
|
|
||||||
var blobResponse = await _httpClient.SendAsync(requestMessage);
|
var blobResponse = await _httpClient.SendAsync(requestMessage, cancellationToken);
|
||||||
|
|
||||||
if (blobResponse.StatusCode != HttpStatusCode.Created)
|
if (blobResponse.StatusCode != HttpStatusCode.Created)
|
||||||
{
|
{
|
||||||
@@ -66,7 +67,7 @@ namespace Bit.Core.Services
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task AzureUploadBlocks(string uri, EncByteArray data, Func<Task<string>> renewalFunc)
|
private async Task AzureUploadBlocks(string uri, EncByteArray data, Func<CancellationToken, Task<string>> renewalFunc, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
_httpClient.Timeout = TimeSpan.FromHours(3);
|
_httpClient.Timeout = TimeSpan.FromHours(3);
|
||||||
var baseParams = HttpUtility.ParseQueryString(CoreHelpers.GetUri(uri).Query);
|
var baseParams = HttpUtility.ParseQueryString(CoreHelpers.GetUri(uri).Query);
|
||||||
@@ -82,7 +83,7 @@ namespace Bit.Core.Services
|
|||||||
|
|
||||||
while (blockIndex < numBlocks)
|
while (blockIndex < numBlocks)
|
||||||
{
|
{
|
||||||
uri = await RenewUriIfNecessary(uri, renewalFunc);
|
uri = await RenewUriIfNecessary(uri, renewalFunc, cancellationToken);
|
||||||
var blockUriBuilder = new UriBuilder(uri);
|
var blockUriBuilder = new UriBuilder(uri);
|
||||||
var blockId = EncodeBlockId(blockIndex);
|
var blockId = EncodeBlockId(blockIndex);
|
||||||
var blockParams = HttpUtility.ParseQueryString(blockUriBuilder.Query);
|
var blockParams = HttpUtility.ParseQueryString(blockUriBuilder.Query);
|
||||||
@@ -101,7 +102,7 @@ namespace Bit.Core.Services
|
|||||||
requestMessage.Method = HttpMethod.Put;
|
requestMessage.Method = HttpMethod.Put;
|
||||||
requestMessage.RequestUri = blockUriBuilder.Uri;
|
requestMessage.RequestUri = blockUriBuilder.Uri;
|
||||||
|
|
||||||
var blockResponse = await _httpClient.SendAsync(requestMessage);
|
var blockResponse = await _httpClient.SendAsync(requestMessage, cancellationToken);
|
||||||
|
|
||||||
if (blockResponse.StatusCode != HttpStatusCode.Created)
|
if (blockResponse.StatusCode != HttpStatusCode.Created)
|
||||||
{
|
{
|
||||||
@@ -115,7 +116,7 @@ namespace Bit.Core.Services
|
|||||||
|
|
||||||
using (var requestMessage = new HttpRequestMessage())
|
using (var requestMessage = new HttpRequestMessage())
|
||||||
{
|
{
|
||||||
uri = await RenewUriIfNecessary(uri, renewalFunc);
|
uri = await RenewUriIfNecessary(uri, renewalFunc, cancellationToken);
|
||||||
var blockListXml = GenerateBlockListXml(blocksStaged);
|
var blockListXml = GenerateBlockListXml(blocksStaged);
|
||||||
var blockListUriBuilder = new UriBuilder(uri);
|
var blockListUriBuilder = new UriBuilder(uri);
|
||||||
var blockListParams = HttpUtility.ParseQueryString(blockListUriBuilder.Query);
|
var blockListParams = HttpUtility.ParseQueryString(blockListUriBuilder.Query);
|
||||||
@@ -130,7 +131,7 @@ namespace Bit.Core.Services
|
|||||||
requestMessage.Method = HttpMethod.Put;
|
requestMessage.Method = HttpMethod.Put;
|
||||||
requestMessage.RequestUri = blockListUriBuilder.Uri;
|
requestMessage.RequestUri = blockListUriBuilder.Uri;
|
||||||
|
|
||||||
var blockListResponse = await _httpClient.SendAsync(requestMessage);
|
var blockListResponse = await _httpClient.SendAsync(requestMessage, cancellationToken);
|
||||||
|
|
||||||
if (blockListResponse.StatusCode != HttpStatusCode.Created)
|
if (blockListResponse.StatusCode != HttpStatusCode.Created)
|
||||||
{
|
{
|
||||||
@@ -139,13 +140,13 @@ namespace Bit.Core.Services
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<string> RenewUriIfNecessary(string uri, Func<Task<string>> renewalFunc)
|
private async Task<string> RenewUriIfNecessary(string uri, Func<CancellationToken, Task<string>> renewalFunc, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var uriParams = HttpUtility.ParseQueryString(CoreHelpers.GetUri(uri).Query);
|
var uriParams = HttpUtility.ParseQueryString(CoreHelpers.GetUri(uri).Query);
|
||||||
|
|
||||||
if (DateTime.TryParse(uriParams.Get("se") ?? "", out DateTime expiry) && expiry < DateTime.UtcNow.AddSeconds(1))
|
if (DateTime.TryParse(uriParams.Get("se") ?? "", out DateTime expiry) && expiry < DateTime.UtcNow.AddSeconds(1))
|
||||||
{
|
{
|
||||||
return await renewalFunc();
|
return await renewalFunc(cancellationToken);
|
||||||
}
|
}
|
||||||
return uri;
|
return uri;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Net.Http.Headers;
|
using System.Net.Http.Headers;
|
||||||
using System.Net.Mime;
|
using System.Net.Mime;
|
||||||
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Bit.Core.Models.Domain;
|
using Bit.Core.Models.Domain;
|
||||||
|
|
||||||
@@ -9,21 +10,21 @@ namespace Bit.Core.Services
|
|||||||
{
|
{
|
||||||
public class BitwardenFileUploadService
|
public class BitwardenFileUploadService
|
||||||
{
|
{
|
||||||
|
private readonly ApiService _apiService;
|
||||||
|
|
||||||
public BitwardenFileUploadService(ApiService apiService)
|
public BitwardenFileUploadService(ApiService apiService)
|
||||||
{
|
{
|
||||||
_apiService = apiService;
|
_apiService = apiService;
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly ApiService _apiService;
|
public async Task Upload(string encryptedFileName, EncByteArray encryptedFileData, Func<MultipartFormDataContent, CancellationToken, Task> apiCall, CancellationToken cancellationToken)
|
||||||
|
|
||||||
public async Task Upload(string encryptedFileName, EncByteArray encryptedFileData, Func<MultipartFormDataContent, Task> apiCall)
|
|
||||||
{
|
{
|
||||||
var fd = new MultipartFormDataContent($"--BWMobileFormBoundary{DateTime.UtcNow.Ticks}")
|
var fd = new MultipartFormDataContent($"--BWMobileFormBoundary{DateTime.UtcNow.Ticks}")
|
||||||
{
|
{
|
||||||
{ new ByteArrayContent(encryptedFileData.Buffer) { Headers = { ContentType = new MediaTypeHeaderValue(MediaTypeNames.Application.Octet) } }, "data", encryptedFileName }
|
{ new ByteArrayContent(encryptedFileData.Buffer) { Headers = { ContentType = new MediaTypeHeaderValue(MediaTypeNames.Application.Octet) } }, "data", encryptedFileName }
|
||||||
};
|
};
|
||||||
|
|
||||||
await apiCall(fd);
|
await apiCall(fd, cancellationToken);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ using System.IO;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Bit.Core.Abstractions;
|
using Bit.Core.Abstractions;
|
||||||
using Bit.Core.Enums;
|
using Bit.Core.Enums;
|
||||||
@@ -555,13 +556,15 @@ namespace Bit.Core.Services
|
|||||||
await UpsertAsync(data);
|
await UpsertAsync(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<Cipher> SaveAttachmentRawWithServerAsync(Cipher cipher, string filename, byte[] data)
|
public async Task<Cipher> SaveAttachmentRawWithServerAsync(Cipher cipher, string filename, byte[] data, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var orgKey = await _cryptoService.GetOrgKeyAsync(cipher.OrganizationId);
|
var orgKey = await _cryptoService.GetOrgKeyAsync(cipher.OrganizationId);
|
||||||
var encFileName = await _cryptoService.EncryptAsync(filename, orgKey);
|
var encFileName = await _cryptoService.EncryptAsync(filename, orgKey);
|
||||||
var (attachmentKey, orgEncAttachmentKey) = await _cryptoService.MakeEncKeyAsync(orgKey);
|
var (attachmentKey, orgEncAttachmentKey) = await _cryptoService.MakeEncKeyAsync(orgKey);
|
||||||
var encFileData = await _cryptoService.EncryptToBytesAsync(data, attachmentKey);
|
var encFileData = await _cryptoService.EncryptToBytesAsync(data, attachmentKey);
|
||||||
|
|
||||||
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
CipherResponse response;
|
CipherResponse response;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -572,9 +575,9 @@ namespace Bit.Core.Services
|
|||||||
FileSize = encFileData.Buffer.Length,
|
FileSize = encFileData.Buffer.Length,
|
||||||
};
|
};
|
||||||
|
|
||||||
var uploadDataResponse = await _apiService.PostCipherAttachmentAsync(cipher.Id, request);
|
var uploadDataResponse = await _apiService.PostCipherAttachmentAsync(cipher.Id, request, cancellationToken);
|
||||||
response = uploadDataResponse.CipherResponse;
|
response = uploadDataResponse.CipherResponse;
|
||||||
await _fileUploadService.UploadCipherAttachmentFileAsync(uploadDataResponse, encFileName, encFileData);
|
await _fileUploadService.UploadCipherAttachmentFileAsync(uploadDataResponse, encFileName, encFileData, cancellationToken);
|
||||||
}
|
}
|
||||||
catch (ApiException e) when (e.Error.StatusCode == System.Net.HttpStatusCode.NotFound || e.Error.StatusCode == System.Net.HttpStatusCode.MethodNotAllowed)
|
catch (ApiException e) when (e.Error.StatusCode == System.Net.HttpStatusCode.NotFound || e.Error.StatusCode == System.Net.HttpStatusCode.MethodNotAllowed)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Bit.Core.Abstractions;
|
using Bit.Core.Abstractions;
|
||||||
using Bit.Core.Enums;
|
using Bit.Core.Enums;
|
||||||
@@ -21,7 +22,7 @@ namespace Bit.Core.Services
|
|||||||
private readonly ApiService _apiService;
|
private readonly ApiService _apiService;
|
||||||
|
|
||||||
public async Task UploadCipherAttachmentFileAsync(AttachmentUploadDataResponse uploadData,
|
public async Task UploadCipherAttachmentFileAsync(AttachmentUploadDataResponse uploadData,
|
||||||
EncString encryptedFileName, EncByteArray encryptedFileData)
|
EncString encryptedFileName, EncByteArray encryptedFileData, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -29,15 +30,15 @@ namespace Bit.Core.Services
|
|||||||
{
|
{
|
||||||
case FileUploadType.Direct:
|
case FileUploadType.Direct:
|
||||||
await _bitwardenFileUploadService.Upload(encryptedFileName.EncryptedString, encryptedFileData,
|
await _bitwardenFileUploadService.Upload(encryptedFileName.EncryptedString, encryptedFileData,
|
||||||
fd => _apiService.PostAttachmentFileAsync(uploadData.CipherResponse.Id, uploadData.AttachmentId, fd));
|
(fd, ct) => _apiService.PostAttachmentFileAsync(uploadData.CipherResponse.Id, uploadData.AttachmentId, fd, ct), cancellationToken);
|
||||||
break;
|
break;
|
||||||
case FileUploadType.Azure:
|
case FileUploadType.Azure:
|
||||||
Func<Task<string>> renewalCallback = async () =>
|
Func<CancellationToken, Task<string>> renewalCallback = async ct =>
|
||||||
{
|
{
|
||||||
var response = await _apiService.RenewAttachmentUploadUrlAsync(uploadData.CipherResponse.Id, uploadData.AttachmentId);
|
var response = await _apiService.RenewAttachmentUploadUrlAsync(uploadData.CipherResponse.Id, uploadData.AttachmentId, ct);
|
||||||
return response.Url;
|
return response.Url;
|
||||||
};
|
};
|
||||||
await _azureFileUploadService.Upload(uploadData.Url, encryptedFileData, renewalCallback);
|
await _azureFileUploadService.Upload(uploadData.Url, encryptedFileData, renewalCallback, cancellationToken);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new Exception($"Unkown file upload type: {uploadData.FileUploadType}");
|
throw new Exception($"Unkown file upload type: {uploadData.FileUploadType}");
|
||||||
@@ -58,16 +59,16 @@ namespace Bit.Core.Services
|
|||||||
{
|
{
|
||||||
case FileUploadType.Direct:
|
case FileUploadType.Direct:
|
||||||
await _bitwardenFileUploadService.Upload(fileName.EncryptedString, encryptedFileData,
|
await _bitwardenFileUploadService.Upload(fileName.EncryptedString, encryptedFileData,
|
||||||
fd => _apiService.PostSendFileAsync(uploadData.SendResponse.Id, uploadData.SendResponse.File.Id, fd));
|
(fd, _) => _apiService.PostSendFileAsync(uploadData.SendResponse.Id, uploadData.SendResponse.File.Id, fd), default);
|
||||||
break;
|
break;
|
||||||
case FileUploadType.Azure:
|
case FileUploadType.Azure:
|
||||||
Func<Task<string>> renewalCallback = async () =>
|
Func<CancellationToken, Task<string>> renewalCallback = async ct =>
|
||||||
{
|
{
|
||||||
var response = await _apiService.RenewFileUploadUrlAsync(uploadData.SendResponse.Id, uploadData.SendResponse.File.Id);
|
var response = await _apiService.RenewFileUploadUrlAsync(uploadData.SendResponse.Id, uploadData.SendResponse.File.Id);
|
||||||
return response.Url;
|
return response.Url;
|
||||||
};
|
};
|
||||||
|
|
||||||
await _azureFileUploadService.Upload(uploadData.Url, encryptedFileData, renewalCallback);
|
await _azureFileUploadService.Upload(uploadData.Url, encryptedFileData, renewalCallback, default);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new Exception("Unknown file upload type");
|
throw new Exception("Unknown file upload type");
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Bit.App.Abstractions;
|
using Bit.App.Abstractions;
|
||||||
using Bit.App.Resources;
|
using Bit.App.Resources;
|
||||||
@@ -61,7 +62,7 @@ namespace Bit.iOS.Core.Services
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task ShowLoadingAsync(string text)
|
public Task ShowLoadingAsync(string text, CancellationTokenSource cts = null, string cancelButtonText = null)
|
||||||
{
|
{
|
||||||
if (_progressAlert != null)
|
if (_progressAlert != null)
|
||||||
{
|
{
|
||||||
@@ -84,6 +85,14 @@ namespace Bit.iOS.Core.Services
|
|||||||
_progressAlert = UIAlertController.Create(null, text, UIAlertControllerStyle.Alert);
|
_progressAlert = UIAlertController.Create(null, text, UIAlertControllerStyle.Alert);
|
||||||
_progressAlert.View.TintColor = UIColor.Black;
|
_progressAlert.View.TintColor = UIColor.Black;
|
||||||
_progressAlert.View.Add(loadingIndicator);
|
_progressAlert.View.Add(loadingIndicator);
|
||||||
|
if (cts != null)
|
||||||
|
{
|
||||||
|
_progressAlert.AddAction(UIAlertAction.Create(cancelButtonText ?? AppResources.Cancel, UIAlertActionStyle.Cancel, x =>
|
||||||
|
{
|
||||||
|
cts.Cancel();
|
||||||
|
result.TrySetResult(0);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
vc.PresentViewController(_progressAlert, false, () => result.TrySetResult(0));
|
vc.PresentViewController(_progressAlert, false, () => result.TrySetResult(0));
|
||||||
return result.Task;
|
return result.Task;
|
||||||
|
|||||||
Reference in New Issue
Block a user