From 04aeddc5de99b8b9dca4c36b9e4489d14ee5c739 Mon Sep 17 00:00:00 2001
From: Thomas Rittson <31796059+eliykat@users.noreply.github.com>
Date: Tue, 30 Mar 2021 02:01:42 +1000
Subject: [PATCH] Hide email address in Sends (#1340)
* Add HideEmail model properties and locale strings
* Fix UI strings
* Add HideEmail to SendService
* Add HideEmail option to UI
* Tidy up declarations
* Add Bitwarden Send translation warning
---
src/App/Pages/Send/SendAddEditPage.xaml | 26 +++++++++++++++++++
.../Pages/Send/SendAddEditPageViewModel.cs | 20 ++++++++++++++
src/App/Resources/AppResources.Designer.cs | 12 +++++++++
src/App/Resources/AppResources.resx | 7 +++++
src/App/Utilities/AppHelpers.cs | 20 ++++++++++++++
src/Core/Enums/PolicyType.cs | 1 +
src/Core/Models/Data/SendData.cs | 2 ++
src/Core/Models/Domain/Send.cs | 2 ++
src/Core/Models/Request/SendRequest.cs | 2 ++
src/Core/Models/Response/SendResponse.cs | 1 +
src/Core/Models/View/SendView.cs | 2 ++
src/Core/Services/SendService.cs | 1 +
12 files changed, 96 insertions(+)
diff --git a/src/App/Pages/Send/SendAddEditPage.xaml b/src/App/Pages/Send/SendAddEditPage.xaml
index 963312d6b..bf2871e5a 100644
--- a/src/App/Pages/Send/SendAddEditPage.xaml
+++ b/src/App/Pages/Send/SendAddEditPage.xaml
@@ -89,6 +89,18 @@
StyleClass="text-muted, text-sm, text-bold"
HorizontalTextAlignment="Center" />
+
+
+
+
+
+
+
diff --git a/src/App/Pages/Send/SendAddEditPageViewModel.cs b/src/App/Pages/Send/SendAddEditPageViewModel.cs
index e3624779e..24b74b882 100644
--- a/src/App/Pages/Send/SendAddEditPageViewModel.cs
+++ b/src/App/Pages/Send/SendAddEditPageViewModel.cs
@@ -42,6 +42,9 @@ namespace Bit.App.Pages
nameof(IsText),
nameof(IsFile),
};
+ private bool _disableHideEmail;
+ private bool _sendOptionsPolicyInEffect;
+ private bool _disableHideEmailControl;
public SendAddEditPageViewModel()
{
@@ -91,6 +94,7 @@ namespace Bit.App.Pages
public byte[] FileData { get; set; }
public string NewPassword { get; set; }
public bool ShareOnSave { get; set; }
+ public bool DisableHideEmailControl { get; set; }
public List> TypeOptions { get; }
public List> DeletionTypeOptions { get; }
public List> ExpirationTypeOptions { get; }
@@ -194,6 +198,16 @@ namespace Bit.App.Pages
nameof(ShowPasswordIcon)
});
}
+ public bool DisableHideEmail
+ {
+ get => _disableHideEmail;
+ set => SetProperty(ref _disableHideEmail, value);
+ }
+ public bool SendOptionsPolicyInEffect
+ {
+ get => _sendOptionsPolicyInEffect;
+ set => SetProperty(ref _sendOptionsPolicyInEffect, value);
+ }
public bool EditMode => !string.IsNullOrWhiteSpace(SendId);
public bool IsText => Send?.Type == SendType.Text;
public bool IsFile => Send?.Type == SendType.File;
@@ -206,6 +220,8 @@ namespace Bit.App.Pages
PageTitle = EditMode ? AppResources.EditSend : AppResources.AddSend;
_canAccessPremium = await _userService.CanAccessPremiumAsync();
SendEnabled = ! await AppHelpers.IsSendDisabledByPolicyAsync();
+ DisableHideEmail = await AppHelpers.IsHideEmailDisabledByPolicyAsync();
+ SendOptionsPolicyInEffect = SendEnabled && DisableHideEmail;
}
public async Task LoadAsync()
@@ -243,6 +259,10 @@ namespace Bit.App.Pages
_isOverridingPickers = false;
}
+ DisableHideEmailControl = !SendEnabled ||
+ (!EditMode && DisableHideEmail) ||
+ (EditMode && DisableHideEmail && !Send.HideEmail);
+
return true;
}
diff --git a/src/App/Resources/AppResources.Designer.cs b/src/App/Resources/AppResources.Designer.cs
index a03c02c4b..91d893e33 100644
--- a/src/App/Resources/AppResources.Designer.cs
+++ b/src/App/Resources/AppResources.Designer.cs
@@ -3484,5 +3484,17 @@ namespace Bit.App.Resources {
return ResourceManager.GetString("AboutSend", resourceCulture);
}
}
+
+ public static string HideEmail {
+ get {
+ return ResourceManager.GetString("HideEmail", resourceCulture);
+ }
+ }
+
+ public static string SendOptionsPolicyInEffect {
+ get {
+ return ResourceManager.GetString("SendOptionsPolicyInEffect", resourceCulture);
+ }
+ }
}
}
diff --git a/src/App/Resources/AppResources.resx b/src/App/Resources/AppResources.resx
index 806ab4c2f..95451e1b8 100644
--- a/src/App/Resources/AppResources.resx
+++ b/src/App/Resources/AppResources.resx
@@ -1975,4 +1975,11 @@
About Send
'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.
+
+ Hide my email address from recipients.
+
+
+ One or more organization policies are affecting your Send options.
+ 'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.
+
diff --git a/src/App/Utilities/AppHelpers.cs b/src/App/Utilities/AppHelpers.cs
index 73b1e1f1f..ccce790ed 100644
--- a/src/App/Utilities/AppHelpers.cs
+++ b/src/App/Utilities/AppHelpers.cs
@@ -311,6 +311,26 @@ namespace Bit.App.Utilities
});
}
+ public static async Task IsHideEmailDisabledByPolicyAsync()
+ {
+ var policyService = ServiceContainer.Resolve("policyService");
+ var userService = ServiceContainer.Resolve("userService");
+
+ var policies = await policyService.GetAll(PolicyType.SendOptions);
+ var organizations = await userService.GetAllOrganizationAsync();
+ return organizations.Any(o =>
+ {
+ return o.Enabled &&
+ o.Status == OrganizationUserStatusType.Confirmed &&
+ o.UsePolicies &&
+ !o.canManagePolicies &&
+ policies.Any(p => p.OrganizationId == o.Id &&
+ p.Enabled &&
+ p.Data.ContainsKey("disableHideEmail") &&
+ (bool)p.Data["disableHideEmail"]);
+ });
+ }
+
public static async Task PerformUpdateTasksAsync(ISyncService syncService,
IDeviceActionService deviceActionService, IStorageService storageService)
{
diff --git a/src/Core/Enums/PolicyType.cs b/src/Core/Enums/PolicyType.cs
index 87959d252..8dd175da9 100644
--- a/src/Core/Enums/PolicyType.cs
+++ b/src/Core/Enums/PolicyType.cs
@@ -9,5 +9,6 @@
RequireSso = 4, // Requires users to authenticate with SSO
PersonalOwnership = 5, // Disables personal vault ownership for adding/cloning items
DisableSend = 6, // Disables the ability to create and edit Sends
+ SendOptions = 7, // Sets restrictions or defaults for Bitwarden Sends
}
}
diff --git a/src/Core/Models/Data/SendData.cs b/src/Core/Models/Data/SendData.cs
index e25be5e34..ce891b3cc 100644
--- a/src/Core/Models/Data/SendData.cs
+++ b/src/Core/Models/Data/SendData.cs
@@ -24,6 +24,7 @@ namespace Bit.Core.Models.Data
DeletionDate = response.DeletionDate;
Password = response.Password;
Disabled = response.Disabled;
+ HideEmail = response.HideEmail.GetValueOrDefault();
switch (Type)
{
@@ -54,5 +55,6 @@ namespace Bit.Core.Models.Data
public DateTime DeletionDate { get; set; }
public string Password { get; set; }
public bool Disabled { get; set; }
+ public bool HideEmail { get; set; }
}
}
diff --git a/src/Core/Models/Domain/Send.cs b/src/Core/Models/Domain/Send.cs
index 8d86c22f8..0fcc6ae8a 100644
--- a/src/Core/Models/Domain/Send.cs
+++ b/src/Core/Models/Domain/Send.cs
@@ -27,6 +27,7 @@ namespace Bit.Core.Models.Domain
public DateTime DeletionDate { get; set; }
public string Password { get; set; }
public bool Disabled { get; set; }
+ public bool HideEmail { get; set; }
public Send() : base() { }
@@ -49,6 +50,7 @@ namespace Bit.Core.Models.Domain
RevisionDate = data.RevisionDate;
DeletionDate = data.DeletionDate;
ExpirationDate = data.ExpirationDate;
+ HideEmail = data.HideEmail;
switch (Type)
{
diff --git a/src/Core/Models/Request/SendRequest.cs b/src/Core/Models/Request/SendRequest.cs
index f23614bb6..fb3d643a9 100644
--- a/src/Core/Models/Request/SendRequest.cs
+++ b/src/Core/Models/Request/SendRequest.cs
@@ -19,6 +19,7 @@ namespace Bit.Core.Models.Request
public SendFileApi File { get; set; }
public string Password { get; set; }
public bool Disabled { get; set; }
+ public bool HideEmail { get; set; }
public SendRequest(Send send, long? fileLength)
{
@@ -32,6 +33,7 @@ namespace Bit.Core.Models.Request
Key = send.Key?.EncryptedString;
Password = send.Password;
Disabled = send.Disabled;
+ HideEmail = send.HideEmail;
switch (Type)
{
diff --git a/src/Core/Models/Response/SendResponse.cs b/src/Core/Models/Response/SendResponse.cs
index ce38f664f..ca6a3bc84 100644
--- a/src/Core/Models/Response/SendResponse.cs
+++ b/src/Core/Models/Response/SendResponse.cs
@@ -21,5 +21,6 @@ namespace Bit.Core.Models.Response
public DateTime DeletionDate { get; set; }
public string Password { get; set; }
public bool Disabled { get; set; }
+ public bool? HideEmail { get; set; }
}
}
diff --git a/src/Core/Models/View/SendView.cs b/src/Core/Models/View/SendView.cs
index 49d589f37..dcc5264e9 100644
--- a/src/Core/Models/View/SendView.cs
+++ b/src/Core/Models/View/SendView.cs
@@ -21,6 +21,7 @@ namespace Bit.Core.Models.View
ExpirationDate = send.ExpirationDate;
Disabled = send.Disabled;
Password = send.Password;
+ HideEmail = send.HideEmail;
}
public string Id { get; set; }
@@ -45,5 +46,6 @@ namespace Bit.Core.Models.View
public bool Expired => ExpirationDate.HasValue && ExpirationDate.Value <= DateTime.UtcNow;
public bool PendingDelete => DeletionDate <= DateTime.UtcNow;
public string DisplayDate => DeletionDate.ToLocalTime().ToString("MMM d, yyyy, h:mm tt");
+ public bool HideEmail { get; set; }
}
}
diff --git a/src/Core/Services/SendService.cs b/src/Core/Services/SendService.cs
index ee5a3b405..b410d3525 100644
--- a/src/Core/Services/SendService.cs
+++ b/src/Core/Services/SendService.cs
@@ -101,6 +101,7 @@ namespace Bit.Core.Services
Key = await _cryptoService.EncryptAsync(model.Key, key),
Name = await _cryptoService.EncryptAsync(model.Name, model.CryptoKey),
Notes = await _cryptoService.EncryptAsync(model.Notes, model.CryptoKey),
+ HideEmail = model.HideEmail
};
byte[] encryptedFileData = null;