Hide email address in Sends (#310)

* Let organizations disable anonymous Sends only

* Add HideEmail to send models and service

* Delete unnecessary model

* Enforce new Send policy, fix naming conventions

* Fix linting

* Fully disable editing anonymous Sends per policy

* Revert disableSendPolicy, add sendOptionsPolicy

* Rework UI for enforcing disableHideEmail

* Fix linting and cleanup after refactor
This commit is contained in:
Thomas Rittson 2021-03-26 08:27:43 +10:00 committed by GitHub
parent cfc7687815
commit 0735569479
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 24 additions and 2 deletions

View File

@ -47,6 +47,7 @@ export class AddEditComponent implements OnInit {
copyLink = false; copyLink = false;
disableSend = false; disableSend = false;
disableHideEmail = false;
send: SendView; send: SendView;
deletionDate: string; deletionDate: string;
deletionDateFallback: string; deletionDateFallback: string;
@ -149,14 +150,23 @@ export class AddEditComponent implements OnInit {
} }
async load() { async load() {
const policies = await this.policyService.getAll(PolicyType.DisableSend); const disableSendPolicies = await this.policyService.getAll(PolicyType.DisableSend);
const organizations = await this.userService.getAllOrganizations(); const organizations = await this.userService.getAllOrganizations();
this.disableSend = organizations.some(o => { this.disableSend = organizations.some(o => {
return o.enabled && return o.enabled &&
o.status === OrganizationUserStatusType.Confirmed && o.status === OrganizationUserStatusType.Confirmed &&
o.usePolicies && o.usePolicies &&
!o.canManagePolicies && !o.canManagePolicies &&
policies.some(p => p.organizationId === o.id && p.enabled); disableSendPolicies.some(p => p.organizationId === o.id && p.enabled);
});
const sendOptionsPolicies = await this.policyService.getAll(PolicyType.SendOptions);
this.disableHideEmail = await organizations.some(o => {
return o.enabled &&
o.status === OrganizationUserStatusType.Confirmed &&
o.usePolicies &&
!o.canManagePolicies &&
sendOptionsPolicies.some(p => p.organizationId === o.id && p.enabled && p.data.disableHideEmail);
}); });
this.canAccessPremium = await this.userService.canAccessPremium(); this.canAccessPremium = await this.userService.canAccessPremium();

View File

@ -6,4 +6,5 @@ export enum PolicyType {
RequireSso = 4, // Requires users to authenticate with SSO RequireSso = 4, // Requires users to authenticate with SSO
PersonalOwnership = 5, // Disables personal vault ownership for adding/cloning items PersonalOwnership = 5, // Disables personal vault ownership for adding/cloning items
DisableSend = 6, // Disables the ability to create and edit Bitwarden Sends DisableSend = 6, // Disables the ability to create and edit Bitwarden Sends
SendOptions = 7, // Sets restrictions or defaults for Bitwarden Sends
} }

View File

@ -22,6 +22,7 @@ export class SendData {
deletionDate: string; deletionDate: string;
password: string; password: string;
disabled: boolean; disabled: boolean;
hideEmail: boolean;
constructor(response?: SendResponse, userId?: string) { constructor(response?: SendResponse, userId?: string) {
if (response == null) { if (response == null) {
@ -42,6 +43,7 @@ export class SendData {
this.deletionDate = response.deletionDate; this.deletionDate = response.deletionDate;
this.password = response.password; this.password = response.password;
this.disabled = response.disable; this.disabled = response.disable;
this.hideEmail = response.hideEmail;
switch (this.type) { switch (this.type) {
case SendType.Text: case SendType.Text:

View File

@ -30,6 +30,7 @@ export class Send extends Domain {
deletionDate: Date; deletionDate: Date;
password: string; password: string;
disabled: boolean; disabled: boolean;
hideEmail: boolean;
constructor(obj?: SendData, alreadyEncrypted: boolean = false) { constructor(obj?: SendData, alreadyEncrypted: boolean = false) {
super(); super();
@ -54,6 +55,7 @@ export class Send extends Domain {
this.revisionDate = obj.revisionDate != null ? new Date(obj.revisionDate) : null; this.revisionDate = obj.revisionDate != null ? new Date(obj.revisionDate) : null;
this.deletionDate = obj.deletionDate != null ? new Date(obj.deletionDate) : null; this.deletionDate = obj.deletionDate != null ? new Date(obj.deletionDate) : null;
this.expirationDate = obj.expirationDate != null ? new Date(obj.expirationDate) : null; this.expirationDate = obj.expirationDate != null ? new Date(obj.expirationDate) : null;
this.hideEmail = obj.hideEmail;
switch (this.type) { switch (this.type) {
case SendType.Text: case SendType.Text:

View File

@ -18,6 +18,7 @@ export class SendRequest {
file: SendFileApi; file: SendFileApi;
password: string; password: string;
disabled: boolean; disabled: boolean;
hideEmail: boolean;
constructor(send: Send, fileLength?: number) { constructor(send: Send, fileLength?: number) {
this.type = send.type; this.type = send.type;
@ -30,6 +31,7 @@ export class SendRequest {
this.key = send.key != null ? send.key.encryptedString : null; this.key = send.key != null ? send.key.encryptedString : null;
this.password = send.password; this.password = send.password;
this.disabled = send.disabled; this.disabled = send.disabled;
this.hideEmail = send.hideEmail;
switch (this.type) { switch (this.type) {
case SendType.Text: case SendType.Text:

View File

@ -21,6 +21,7 @@ export class SendResponse extends BaseResponse {
deletionDate: string; deletionDate: string;
password: string; password: string;
disable: boolean; disable: boolean;
hideEmail: boolean;
constructor(response: any) { constructor(response: any) {
super(response); super(response);
@ -37,6 +38,7 @@ export class SendResponse extends BaseResponse {
this.deletionDate = this.getResponseProperty('DeletionDate'); this.deletionDate = this.getResponseProperty('DeletionDate');
this.password = this.getResponseProperty('Password'); this.password = this.getResponseProperty('Password');
this.disable = this.getResponseProperty('Disabled') || false; this.disable = this.getResponseProperty('Disabled') || false;
this.hideEmail = this.getResponseProperty('HideEmail') || false;
const text = this.getResponseProperty('Text'); const text = this.getResponseProperty('Text');
if (text != null) { if (text != null) {

View File

@ -25,6 +25,7 @@ export class SendView implements View {
expirationDate: Date = null; expirationDate: Date = null;
password: string = null; password: string = null;
disabled: boolean = false; disabled: boolean = false;
hideEmail: boolean = false;
constructor(s?: Send) { constructor(s?: Send) {
if (!s) { if (!s) {
@ -41,6 +42,7 @@ export class SendView implements View {
this.expirationDate = s.expirationDate; this.expirationDate = s.expirationDate;
this.disabled = s.disabled; this.disabled = s.disabled;
this.password = s.password; this.password = s.password;
this.hideEmail = s.hideEmail;
} }
get urlB64Key(): string { get urlB64Key(): string {

View File

@ -50,6 +50,7 @@ export class SendService implements SendServiceAbstraction {
send.id = model.id; send.id = model.id;
send.type = model.type; send.type = model.type;
send.disabled = model.disabled; send.disabled = model.disabled;
send.hideEmail = model.hideEmail;
send.maxAccessCount = model.maxAccessCount; send.maxAccessCount = model.maxAccessCount;
if (model.key == null) { if (model.key == null) {
model.key = await this.cryptoFunctionService.randomBytes(16); model.key = await this.cryptoFunctionService.randomBytes(16);