1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-14 15:23:33 +00:00

Merge branch 'master' into EC-598-beeep-properly-store-passkeys-in-bitwarden

This commit is contained in:
Andreas Coroiu
2023-01-25 15:24:42 +01:00
1208 changed files with 94078 additions and 16018 deletions

View File

@@ -0,0 +1,20 @@
import { Observable } from "rxjs";
import { Organization } from "@bitwarden/common/models/domain/organization";
import { CollectionView } from "@bitwarden/common/models/view/collection.view";
import { FolderView } from "@bitwarden/common/models/view/folder.view";
import { DynamicTreeNode } from "../vault/vault-filter/models/dynamic-tree-node.model";
/**
* @deprecated August 30 2022: Use new VaultFilterService with observables
*/
export abstract class DeprecatedVaultFilterService {
buildOrganizations: () => Promise<Organization[]>;
buildNestedFolders: (organizationId?: string) => Observable<DynamicTreeNode<FolderView>>;
buildCollections: (organizationId?: string) => Promise<DynamicTreeNode<CollectionView>>;
buildCollapsedFilterNodes: () => Promise<Set<string>>;
storeCollapsedFilterNodes: (collapsedFilterNodes: Set<string>) => Promise<void>;
checkForSingleOrganizationPolicy: () => Promise<boolean>;
checkForPersonalOwnershipPolicy: () => Promise<boolean>;
}

View File

@@ -1,7 +1,7 @@
import { CdkDragDrop, moveItemInArray } from "@angular/cdk/drag-drop";
import { Directive, Input, OnChanges, SimpleChanges } from "@angular/core";
import { EventService } from "@bitwarden/common/abstractions/event.service";
import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service";
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
import { CipherType } from "@bitwarden/common/enums/cipherType";
import { EventType } from "@bitwarden/common/enums/eventType";
@@ -25,7 +25,10 @@ export class AddEditCustomFieldsComponent implements OnChanges {
fieldType = FieldType;
eventType = EventType;
constructor(private i18nService: I18nService, private eventService: EventService) {
constructor(
private i18nService: I18nService,
private eventCollectionService: EventCollectionService
) {
this.addFieldTypeOptions = [
{ name: i18nService.t("cfTypeText"), value: FieldType.Text },
{ name: i18nService.t("cfTypeHidden"), value: FieldType.Hidden },
@@ -74,7 +77,10 @@ export class AddEditCustomFieldsComponent implements OnChanges {
const f = field as any;
f.showValue = !f.showValue;
if (this.editMode && f.showValue) {
this.eventService.collect(EventType.Cipher_ClientToggledHiddenFieldVisible, this.cipher.id);
this.eventCollectionService.collect(
EventType.Cipher_ClientToggledHiddenFieldVisible,
this.cipher.id
);
}
}

View File

@@ -4,12 +4,15 @@ import { Observable, Subject, takeUntil, concatMap } from "rxjs";
import { AuditService } from "@bitwarden/common/abstractions/audit.service";
import { CipherService } from "@bitwarden/common/abstractions/cipher.service";
import { CollectionService } from "@bitwarden/common/abstractions/collection.service";
import { EventService } from "@bitwarden/common/abstractions/event.service";
import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service";
import { FolderService } from "@bitwarden/common/abstractions/folder/folder.service.abstraction";
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
import { LogService } from "@bitwarden/common/abstractions/log.service";
import { MessagingService } from "@bitwarden/common/abstractions/messaging.service";
import { OrganizationService } from "@bitwarden/common/abstractions/organization/organization.service.abstraction";
import {
isNotProviderUser,
OrganizationService,
} from "@bitwarden/common/abstractions/organization/organization.service.abstraction";
import { PasswordRepromptService } from "@bitwarden/common/abstractions/passwordReprompt.service";
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
import { PolicyService } from "@bitwarden/common/abstractions/policy/policy.service.abstraction";
@@ -23,6 +26,7 @@ import { SecureNoteType } from "@bitwarden/common/enums/secureNoteType";
import { UriMatchType } from "@bitwarden/common/enums/uriMatchType";
import { Utils } from "@bitwarden/common/misc/utils";
import { Cipher } from "@bitwarden/common/models/domain/cipher";
import { Organization } from "@bitwarden/common/models/domain/organization";
import { CardView } from "@bitwarden/common/models/view/card.view";
import { CipherView } from "@bitwarden/common/models/view/cipher.view";
import { CollectionView } from "@bitwarden/common/models/view/collection.view";
@@ -74,7 +78,9 @@ export class AddEditComponent implements OnInit, OnDestroy {
allowPersonal = true;
reprompt = false;
canUseReprompt = true;
organization: Organization;
protected componentName = "";
protected destroy$ = new Subject<void>();
protected writeableCollections: CollectionView[];
private personalOwnershipPolicyAppliesToActiveUser: boolean;
@@ -89,7 +95,7 @@ export class AddEditComponent implements OnInit, OnDestroy {
protected stateService: StateService,
protected collectionService: CollectionService,
protected messagingService: MessagingService,
protected eventService: EventService,
protected eventCollectionService: EventCollectionService,
protected policyService: PolicyService,
private logService: LogService,
protected passwordRepromptService: PasswordRepromptService,
@@ -135,6 +141,7 @@ export class AddEditComponent implements OnInit, OnDestroy {
{ name: i18nService.t("mr"), value: i18nService.t("mr") },
{ name: i18nService.t("mrs"), value: i18nService.t("mrs") },
{ name: i18nService.t("ms"), value: i18nService.t("ms") },
{ name: i18nService.t("mx"), value: i18nService.t("mx") },
{ name: i18nService.t("dr"), value: i18nService.t("dr") },
];
this.uriMatchOptions = [
@@ -183,11 +190,14 @@ export class AddEditComponent implements OnInit, OnDestroy {
}
const orgs = await this.organizationService.getAll();
orgs.sort(Utils.getSortFunction(this.i18nService, "name")).forEach((o) => {
if (o.enabled && o.status === OrganizationUserStatusType.Confirmed) {
this.ownershipOptions.push({ name: o.name, value: o.id });
}
});
orgs
.filter(isNotProviderUser)
.sort(Utils.getSortFunction(this.i18nService, "name"))
.forEach((o) => {
if (o.enabled && o.status === OrganizationUserStatusType.Confirmed) {
this.ownershipOptions.push({ name: o.name, value: o.id });
}
});
if (!this.allowPersonal) {
this.organizationId = this.ownershipOptions[0].value;
}
@@ -264,7 +274,7 @@ export class AddEditComponent implements OnInit, OnDestroy {
this.folders$ = this.folderService.folderViews$;
if (this.editMode && this.previousCipherId !== this.cipherId) {
this.eventService.collect(EventType.Cipher_ClientViewed, this.cipherId);
this.eventCollectionService.collect(EventType.Cipher_ClientViewed, this.cipherId);
}
this.previousCipherId = this.cipherId;
this.reprompt = this.cipher.reprompt !== CipherRepromptType.None;
@@ -395,7 +405,9 @@ export class AddEditComponent implements OnInit, OnDestroy {
this.i18nService.t("deleteItem"),
this.i18nService.t("yes"),
this.i18nService.t("no"),
"warning"
"warning",
false,
this.componentName != "" ? this.componentName + " .modal-content" : null
);
if (!confirmed) {
return false;
@@ -487,14 +499,20 @@ export class AddEditComponent implements OnInit, OnDestroy {
this.showPassword = !this.showPassword;
document.getElementById("loginPassword").focus();
if (this.editMode && this.showPassword) {
this.eventService.collect(EventType.Cipher_ClientToggledPasswordVisible, this.cipherId);
this.eventCollectionService.collect(
EventType.Cipher_ClientToggledPasswordVisible,
this.cipherId
);
}
}
async toggleCardNumber() {
this.showCardNumber = !this.showCardNumber;
if (this.showCardNumber) {
this.eventService.collect(EventType.Cipher_ClientToggledCardNumberVisible, this.cipherId);
this.eventCollectionService.collect(
EventType.Cipher_ClientToggledCardNumberVisible,
this.cipherId
);
}
}
@@ -502,7 +520,10 @@ export class AddEditComponent implements OnInit, OnDestroy {
this.showCardCode = !this.showCardCode;
document.getElementById("cardCode").focus();
if (this.editMode && this.showCardCode) {
this.eventService.collect(EventType.Cipher_ClientToggledCardCodeVisible, this.cipherId);
this.eventCollectionService.collect(
EventType.Cipher_ClientToggledCardCodeVisible,
this.cipherId
);
}
}

View File

@@ -29,6 +29,7 @@ export class AttachmentsComponent implements OnInit {
deletePromises: { [id: string]: Promise<any> } = {};
reuploadPromises: { [id: string]: Promise<any> } = {};
emergencyAccessId?: string = null;
protected componentName = "";
constructor(
protected cipherService: CipherService,
@@ -104,7 +105,9 @@ export class AttachmentsComponent implements OnInit {
this.i18nService.t("deleteAttachment"),
this.i18nService.t("yes"),
this.i18nService.t("no"),
"warning"
"warning",
false,
this.componentName != "" ? this.componentName + " .modal-content" : null
);
if (!confirmed) {
return;
@@ -292,4 +295,8 @@ export class AttachmentsComponent implements OnInit {
protected deleteCipherAttachment(attachmentId: string) {
return this.cipherService.deleteAttachmentWithServer(this.cipher.id, attachmentId);
}
protected async reupload(attachment: AttachmentView) {
// TODO: This should be removed but is needed since we re-use the same template
}
}

View File

@@ -3,7 +3,7 @@ import { UntypedFormBuilder, Validators } from "@angular/forms";
import { merge, takeUntil, Subject, startWith } from "rxjs";
import { CryptoService } from "@bitwarden/common/abstractions/crypto.service";
import { EventService } from "@bitwarden/common/abstractions/event.service";
import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service";
import { ExportService } from "@bitwarden/common/abstractions/export.service";
import { FileDownloadService } from "@bitwarden/common/abstractions/fileDownload/fileDownload.service";
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
@@ -21,8 +21,6 @@ export class ExportComponent implements OnInit, OnDestroy {
formPromise: Promise<string>;
disabledByPolicy = false;
showFilePassword: boolean;
showConfirmFilePassword: boolean;
exportForm = this.formBuilder.group({
format: ["json"],
@@ -45,7 +43,7 @@ export class ExportComponent implements OnInit, OnDestroy {
protected i18nService: I18nService,
protected platformUtilsService: PlatformUtilsService,
protected exportService: ExportService,
protected eventService: EventService,
protected eventCollectionService: EventCollectionService,
private policyService: PolicyService,
protected win: Window,
private logService: LogService,
@@ -180,7 +178,7 @@ export class ExportComponent implements OnInit, OnDestroy {
}
protected async collectEvent(): Promise<void> {
await this.eventService.collect(EventType.User_ClientExportedVault);
await this.eventCollectionService.collect(EventType.User_ClientExportedVault);
}
get format() {
@@ -199,16 +197,6 @@ export class ExportComponent implements OnInit, OnDestroy {
return this.exportForm.get("fileEncryptionType").value;
}
toggleFilePassword() {
this.showFilePassword = !this.showFilePassword;
document.getElementById("filePassword").focus();
}
toggleConfirmFilePassword() {
this.showConfirmFilePassword = !this.showConfirmFilePassword;
document.getElementById("confirmFilePassword").focus();
}
adjustValidators() {
this.exportForm.get("confirmFilePassword").reset();
this.exportForm.get("filePassword").reset();

View File

@@ -18,6 +18,7 @@ export class FolderAddEditComponent implements OnInit {
title: string;
formPromise: Promise<any>;
deletePromise: Promise<any>;
protected componentName = "";
constructor(
protected folderService: FolderService,
@@ -65,7 +66,9 @@ export class FolderAddEditComponent implements OnInit {
this.i18nService.t("deleteFolder"),
this.i18nService.t("yes"),
this.i18nService.t("no"),
"warning"
"warning",
false,
this.componentName != "" ? this.componentName + " .modal-content" : null
);
if (!confirmed) {
return false;

View File

@@ -70,13 +70,7 @@ export class GeneratorComponent implements OnInit {
];
this.subaddressOptions = [{ name: i18nService.t("random"), value: "random" }];
this.catchallOptions = [{ name: i18nService.t("random"), value: "random" }];
this.forwardOptions = [
{ name: "SimpleLogin", value: "simplelogin" },
{ name: "AnonAddy", value: "anonaddy" },
{ name: "Firefox Relay", value: "firefoxrelay" },
{ name: "Fastmail", value: "fastmail" },
{ name: "DuckDuckGo", value: "duckduckgo" },
];
this.initForwardOptions();
}
async ngOnInit() {
@@ -239,4 +233,24 @@ export class GeneratorComponent implements OnInit {
this.enforcedPasswordPolicyOptions
);
}
private async initForwardOptions() {
this.forwardOptions = [
{ name: "AnonAddy", value: "anonaddy" },
{ name: "DuckDuckGo", value: "duckduckgo" },
{ name: "Fastmail", value: "fastmail" },
{ name: "Firefox Relay", value: "firefoxrelay" },
{ name: "SimpleLogin", value: "simplelogin" },
];
this.usernameOptions = await this.usernameGenerationService.getOptions();
if (
this.usernameOptions.forwardedService == null ||
this.usernameOptions.forwardedService === ""
) {
this.forwardOptions.push({ name: "", value: null });
}
this.forwardOptions = this.forwardOptions.sort((a, b) => a.name.localeCompare(b.name));
}
}

View File

@@ -7,5 +7,5 @@
decoding="async"
loading="lazy"
/>
<i class="bwi bwi-fw bwi-lg {{ icon }}" *ngIf="!imageEnabled || !image"></i>
<i class="tw-text-muted bwi bwi-lg {{ icon }}" *ngIf="!imageEnabled || !image"></i>
</div>

View File

@@ -46,8 +46,6 @@ export class LoginComponent extends CaptchaProtectedComponent implements OnInit
protected twoFactorRoute = "2fa";
protected successRoute = "vault";
protected forcePasswordResetRoute = "update-temp-password";
protected alwaysRememberEmail = false;
protected skipRememberEmail = false;
get loggedEmail() {
return this.formGroup.value.email;
@@ -85,6 +83,7 @@ export class LoginComponent extends CaptchaProtectedComponent implements OnInit
const queryParamsEmail = params["email"];
if (queryParamsEmail != null && queryParamsEmail.indexOf("@") > -1) {
this.formGroup.get("email").setValue(queryParamsEmail);
this.loginService.setEmail(queryParamsEmail);
this.paramEmailSet = true;
}
}
@@ -98,17 +97,11 @@ export class LoginComponent extends CaptchaProtectedComponent implements OnInit
if (!this.paramEmailSet) {
this.formGroup.get("email")?.setValue(email ?? "");
}
if (!this.alwaysRememberEmail) {
let rememberEmail = this.loginService.getRememberEmail();
if (rememberEmail == null) {
rememberEmail = (await this.stateService.getRememberedEmail()) != null;
}
this.formGroup.get("rememberEmail")?.setValue(rememberEmail);
}
if (email) {
this.validateEmail();
let rememberEmail = this.loginService.getRememberEmail();
if (rememberEmail == null) {
rememberEmail = (await this.stateService.getRememberedEmail()) != null;
}
this.formGroup.get("rememberEmail")?.setValue(rememberEmail);
}
async submit(showToast = true) {
@@ -140,11 +133,7 @@ export class LoginComponent extends CaptchaProtectedComponent implements OnInit
this.formPromise = this.authService.logIn(credentials);
const response = await this.formPromise;
this.setFormValues();
if (data.rememberEmail || this.alwaysRememberEmail) {
await this.stateService.setRememberedEmail(data.email);
} else {
await this.stateService.setRememberedEmail(null);
}
await this.loginService.saveEmailSettings();
if (this.handleCaptchaRequired(response)) {
return;
} else if (response.requiresTwoFactor) {
@@ -162,7 +151,6 @@ export class LoginComponent extends CaptchaProtectedComponent implements OnInit
} else {
const disableFavicon = await this.stateService.getDisableFavicon();
await this.stateService.setDisableFavicon(!!disableFavicon);
this.loginService.clearValues();
if (this.onSuccessfulLogin != null) {
this.onSuccessfulLogin();
}
@@ -189,6 +177,7 @@ export class LoginComponent extends CaptchaProtectedComponent implements OnInit
}
async launchSsoBrowser(clientId: string, ssoRedirectUri: string) {
await this.saveEmailSettings();
// Generate necessary sso params
const passwordOptions: any = {
type: "password",
@@ -243,6 +232,11 @@ export class LoginComponent extends CaptchaProtectedComponent implements OnInit
this.loginService.setRememberEmail(this.formGroup.value.rememberEmail);
}
async saveEmailSettings() {
this.setFormValues();
await this.loginService.saveEmailSettings();
}
private getErrorToastMessage() {
const error: AllValidationErrors = this.formValidationErrorService
.getFormValidationErrors(this.formGroup.controls)

View File

@@ -3,6 +3,7 @@ import { AbstractControl, UntypedFormBuilder, ValidatorFn, Validators } from "@a
import { Router } from "@angular/router";
import { ApiService } from "@bitwarden/common/abstractions/api.service";
import { AuditService } from "@bitwarden/common/abstractions/audit.service";
import { AuthService } from "@bitwarden/common/abstractions/auth.service";
import { CryptoService } from "@bitwarden/common/abstractions/crypto.service";
import { EnvironmentService } from "@bitwarden/common/abstractions/environment.service";
@@ -38,6 +39,8 @@ export class RegisterComponent extends CaptchaProtectedComponent implements OnIn
showTerms = true;
showErrorSummary = false;
passwordStrengthResult: any;
characterMinimumMessage: string;
minimumLength = 8;
color: string;
text: string;
@@ -45,8 +48,8 @@ export class RegisterComponent extends CaptchaProtectedComponent implements OnIn
{
email: ["", [Validators.required, Validators.email]],
name: [""],
masterPassword: ["", [Validators.required, Validators.minLength(8)]],
confirmMasterPassword: ["", [Validators.required, Validators.minLength(8)]],
masterPassword: ["", [Validators.required, Validators.minLength(this.minimumLength)]],
confirmMasterPassword: ["", [Validators.required, Validators.minLength(this.minimumLength)]],
hint: [
null,
[
@@ -56,6 +59,7 @@ export class RegisterComponent extends CaptchaProtectedComponent implements OnIn
),
],
],
checkForBreaches: [false],
acceptPolicies: [false, [this.acceptPoliciesValidation()]],
},
{
@@ -85,10 +89,12 @@ export class RegisterComponent extends CaptchaProtectedComponent implements OnIn
platformUtilsService: PlatformUtilsService,
protected passwordGenerationService: PasswordGenerationService,
environmentService: EnvironmentService,
protected logService: LogService
protected logService: LogService,
protected auditService: AuditService
) {
super(environmentService, i18nService, platformUtilsService);
this.showTerms = !platformUtilsService.isSelfHost();
this.characterMinimumMessage = this.i18nService.t("characterMinimum", this.minimumLength);
}
async ngOnInit() {
@@ -212,7 +218,24 @@ export class RegisterComponent extends CaptchaProtectedComponent implements OnIn
return { isValid: false };
}
if (this.passwordStrengthResult != null && this.passwordStrengthResult.score < 3) {
const passwordWeak =
this.passwordStrengthResult != null && this.passwordStrengthResult.score < 3;
const passwordLeak =
this.formGroup.controls.checkForBreaches.value &&
(await this.auditService.passwordLeaked(this.formGroup.controls.masterPassword.value)) > 0;
if (passwordWeak && passwordLeak) {
const result = await this.platformUtilsService.showDialog(
this.i18nService.t("weakAndBreachedMasterPasswordDesc"),
this.i18nService.t("weakAndExposedMasterPassword"),
this.i18nService.t("yes"),
this.i18nService.t("no"),
"warning"
);
if (!result) {
return { isValid: false };
}
} else if (passwordWeak) {
const result = await this.platformUtilsService.showDialog(
this.i18nService.t("weakMasterPasswordDesc"),
this.i18nService.t("weakMasterPassword"),
@@ -223,7 +246,19 @@ export class RegisterComponent extends CaptchaProtectedComponent implements OnIn
if (!result) {
return { isValid: false };
}
} else if (passwordLeak) {
const result = await this.platformUtilsService.showDialog(
this.i18nService.t("exposedMasterPasswordDesc"),
this.i18nService.t("exposedMasterPassword"),
this.i18nService.t("yes"),
this.i18nService.t("no"),
"warning"
);
if (!result) {
return { isValid: false };
}
}
return { isValid: true };
}

View File

@@ -45,6 +45,7 @@ export class AddEditComponent implements OnInit, OnDestroy {
alertShown = false;
showOptions = false;
protected componentName = "";
private sendLinkBaseUrl: string;
private destroy$ = new Subject<void>();
@@ -200,25 +201,14 @@ export class AddEditComponent implements OnInit, OnDestroy {
}
this.onSavedSend.emit(this.send);
if (this.copyLink && this.link != null) {
const copySuccess = await this.copyLinkToClipboard(this.link);
if (copySuccess ?? true) {
this.platformUtilsService.showToast(
"success",
null,
this.i18nService.t(this.editMode ? "editedSend" : "createdSend")
);
} else {
await this.platformUtilsService.showDialog(
this.i18nService.t(this.editMode ? "editedSend" : "createdSend"),
null,
this.i18nService.t("ok"),
null,
"success",
null
);
await this.copyLinkToClipboard(this.link);
}
await this.handleCopyLinkToClipboard();
return;
}
this.platformUtilsService.showToast(
"success",
null,
this.i18nService.t(this.editMode ? "editedSend" : "createdSend")
);
});
try {
await this.formPromise;
@@ -242,7 +232,9 @@ export class AddEditComponent implements OnInit, OnDestroy {
this.i18nService.t("deleteSend"),
this.i18nService.t("yes"),
this.i18nService.t("no"),
"warning"
"warning",
false,
this.componentName != "" ? this.componentName + " .modal-content" : null
);
if (!confirmed) {
return false;
@@ -305,4 +297,24 @@ export class AddEditComponent implements OnInit, OnDestroy {
this.showPassword = !this.showPassword;
document.getElementById("password").focus();
}
private async handleCopyLinkToClipboard() {
const copySuccess = await this.copyLinkToClipboard(this.link);
if (copySuccess ?? true) {
this.platformUtilsService.showToast(
"success",
null,
this.i18nService.t(this.editMode ? "editedSend" : "createdSend")
);
} else {
await this.platformUtilsService.showDialog(
this.i18nService.t(this.editMode ? "editedSend" : "createdSend"),
null,
this.i18nService.t("ok"),
null,
"success",
null
);
await this.copyLinkToClipboard(this.link);
}
}
}

View File

@@ -6,6 +6,8 @@ import { ApiService } from "@bitwarden/common/abstractions/api.service";
import { CryptoService } from "@bitwarden/common/abstractions/crypto.service";
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
import { MessagingService } from "@bitwarden/common/abstractions/messaging.service";
import { OrganizationUserService } from "@bitwarden/common/abstractions/organization-user/organization-user.service";
import { OrganizationUserResetPasswordEnrollmentRequest } from "@bitwarden/common/abstractions/organization-user/requests";
import { OrganizationApiServiceAbstraction } from "@bitwarden/common/abstractions/organization/organization-api.service.abstraction";
import { PasswordGenerationService } from "@bitwarden/common/abstractions/passwordGeneration.service";
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
@@ -19,7 +21,6 @@ import { Utils } from "@bitwarden/common/misc/utils";
import { EncString } from "@bitwarden/common/models/domain/enc-string";
import { SymmetricCryptoKey } from "@bitwarden/common/models/domain/symmetric-crypto-key";
import { KeysRequest } from "@bitwarden/common/models/request/keys.request";
import { OrganizationUserResetPasswordEnrollmentRequest } from "@bitwarden/common/models/request/organization-user-reset-password-enrollment.request";
import { SetPasswordRequest } from "@bitwarden/common/models/request/set-password.request";
import { ChangePasswordComponent as BaseChangePasswordComponent } from "./change-password.component";
@@ -49,7 +50,8 @@ export class SetPasswordComponent extends BaseChangePasswordComponent {
private syncService: SyncService,
private route: ActivatedRoute,
stateService: StateService,
private organizationApiService: OrganizationApiServiceAbstraction
private organizationApiService: OrganizationApiServiceAbstraction,
private organizationUserService: OrganizationUserService
) {
super(
i18nService,
@@ -136,7 +138,7 @@ export class SetPasswordComponent extends BaseChangePasswordComponent {
resetRequest.masterPasswordHash = masterPasswordHash;
resetRequest.resetPasswordKey = encryptedKey.encryptedString;
return this.apiService.putOrganizationUserResetPasswordEnrollment(
return this.organizationUserService.putOrganizationUserResetPasswordEnrollment(
this.orgId,
userId,
resetRequest

View File

@@ -5,7 +5,10 @@ import { CipherService } from "@bitwarden/common/abstractions/cipher.service";
import { CollectionService } from "@bitwarden/common/abstractions/collection.service";
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
import { LogService } from "@bitwarden/common/abstractions/log.service";
import { OrganizationService } from "@bitwarden/common/abstractions/organization/organization.service.abstraction";
import {
isNotProviderUser,
OrganizationService,
} from "@bitwarden/common/abstractions/organization/organization.service.abstraction";
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
import { OrganizationUserStatusType } from "@bitwarden/common/enums/organizationUserStatusType";
import { Utils } from "@bitwarden/common/misc/utils";
@@ -54,7 +57,10 @@ export class ShareComponent implements OnInit, OnDestroy {
this.organizations$ = this.organizationService.organizations$.pipe(
map((orgs) => {
return orgs
.filter((o) => o.enabled && o.status === OrganizationUserStatusType.Confirmed)
.filter(
(o) =>
o.enabled && o.status === OrganizationUserStatusType.Confirmed && isNotProviderUser(o)
)
.sort(Utils.getSortFunction(this.i18nService, "name"));
})
);

View File

@@ -1,46 +0,0 @@
<ng-container *ngIf="!usesKeyConnector">
<label for="masterPassword">{{ "masterPass" | i18n }}</label>
<input
id="masterPassword"
type="password"
name="MasterPasswordHash"
class="form-control"
[formControl]="secret"
required
appAutofocus
appInputVerbatim
/>
<small class="form-text text-muted">{{ "confirmIdentity" | i18n }}</small>
</ng-container>
<ng-container *ngIf="usesKeyConnector">
<div class="form-group">
<label class="d-block">{{ "sendVerificationCode" | i18n }}</label>
<button
type="button"
class="btn btn-outline-secondary"
(click)="requestOTP()"
[disabled]="disableRequestOTP"
>
{{ "sendCode" | i18n }}
</button>
<span class="ml-2 text-success" role="alert" @sent *ngIf="sentCode">
<i class="bwi bwi-check-circle" aria-hidden="true"></i>
{{ "codeSent" | i18n }}
</span>
</div>
<div class="form-group">
<label for="verificationCode">{{ "verificationCode" | i18n }}</label>
<input
id="verificationCode"
type="input"
name="verificationCode"
class="form-control"
[formControl]="secret"
required
appAutofocus
appInputVerbatim
/>
<small class="form-text text-muted">{{ "confirmIdentity" | i18n }}</small>
</div>
</ng-container>

View File

@@ -1,6 +1,5 @@
import { animate, style, transition, trigger } from "@angular/animations";
import { Component, OnInit } from "@angular/core";
import { ControlValueAccessor, NG_VALUE_ACCESSOR, FormControl } from "@angular/forms";
import { Directive, OnInit } from "@angular/core";
import { ControlValueAccessor, FormControl } from "@angular/forms";
import { KeyConnectorService } from "@bitwarden/common/abstractions/keyConnector.service";
import { UserVerificationService } from "@bitwarden/common/abstractions/userVerification/userVerification.service.abstraction";
@@ -14,21 +13,8 @@ import { Verification } from "@bitwarden/common/types/verification";
* This is exposed to the parent component via the ControlValueAccessor interface (e.g. bind it to a FormControl).
* Use UserVerificationService to verify the user's input.
*/
@Component({
@Directive({
selector: "app-user-verification",
templateUrl: "user-verification.component.html",
providers: [
{
provide: NG_VALUE_ACCESSOR,
multi: true,
useExisting: UserVerificationComponent,
},
],
animations: [
trigger("sent", [
transition(":enter", [style({ opacity: 0 }), animate("100ms", style({ opacity: 1 }))]),
]),
],
})
// eslint-disable-next-line rxjs-angular/prefer-takeuntil
export class UserVerificationComponent implements ControlValueAccessor, OnInit {

View File

@@ -1,10 +1,11 @@
import { Directive, EventEmitter, Input, Output } from "@angular/core";
import { SearchService } from "@bitwarden/common/abstractions/search.service";
import { Organization } from "@bitwarden/common/models/domain/organization";
import { CipherView } from "@bitwarden/common/models/view/cipher.view";
@Directive()
export class CiphersComponent {
export class VaultItemsComponent {
@Input() activeCipherId: string = null;
@Output() onCipherClicked = new EventEmitter<CipherView>();
@Output() onCipherRightClicked = new EventEmitter<CipherView>();
@@ -13,19 +14,27 @@ export class CiphersComponent {
loaded = false;
ciphers: CipherView[] = [];
searchText: string;
searchPlaceholder: string = null;
filter: (cipher: CipherView) => boolean = null;
deleted = false;
organization: Organization;
accessEvents = false;
protected searchPending = false;
private searchTimeout: any = null;
private _searchText: string = null;
get searchText() {
return this._searchText;
}
set searchText(value: string) {
this._searchText = value;
}
constructor(protected searchService: SearchService) {}
async load(filter: (cipher: CipherView) => boolean = null, deleted = false) {
this.deleted = deleted || false;
this.deleted = deleted ?? false;
await this.applyFilter(filter);
this.loaded = true;
}

View File

@@ -1,6 +1,6 @@
import { Directive, Input } from "@angular/core";
import { EventService } from "@bitwarden/common/abstractions/event.service";
import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service";
import { EventType } from "@bitwarden/common/enums/eventType";
import { FieldType } from "@bitwarden/common/enums/fieldType";
import { CipherView } from "@bitwarden/common/models/view/cipher.view";
@@ -14,7 +14,7 @@ export class ViewCustomFieldsComponent {
fieldType = FieldType;
constructor(private eventService: EventService) {}
constructor(private eventCollectionService: EventCollectionService) {}
async toggleFieldValue(field: FieldView) {
if (!(await this.promptPassword())) {
@@ -25,7 +25,10 @@ export class ViewCustomFieldsComponent {
f.showValue = !f.showValue;
f.showCount = false;
if (f.showValue) {
this.eventService.collect(EventType.Cipher_ClientToggledHiddenFieldVisible, this.cipher.id);
this.eventCollectionService.collect(
EventType.Cipher_ClientToggledHiddenFieldVisible,
this.cipher.id
);
}
}

View File

@@ -15,7 +15,7 @@ import { AuditService } from "@bitwarden/common/abstractions/audit.service";
import { BroadcasterService } from "@bitwarden/common/abstractions/broadcaster.service";
import { CipherService } from "@bitwarden/common/abstractions/cipher.service";
import { CryptoService } from "@bitwarden/common/abstractions/crypto.service";
import { EventService } from "@bitwarden/common/abstractions/event.service";
import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service";
import { FileDownloadService } from "@bitwarden/common/abstractions/fileDownload/fileDownload.service";
import { FolderService } from "@bitwarden/common/abstractions/folder/folder.service.abstraction";
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
@@ -80,7 +80,7 @@ export class ViewComponent implements OnDestroy, OnInit {
protected broadcasterService: BroadcasterService,
protected ngZone: NgZone,
protected changeDetectorRef: ChangeDetectorRef,
protected eventService: EventService,
protected eventCollectionService: EventCollectionService,
protected apiService: ApiService,
protected passwordRepromptService: PasswordRepromptService,
private logService: LogService,
@@ -138,7 +138,7 @@ export class ViewComponent implements OnDestroy, OnInit {
}
if (this.previousCipherId !== this.cipherId) {
this.eventService.collect(EventType.Cipher_ClientViewed, this.cipherId);
this.eventCollectionService.collect(EventType.Cipher_ClientViewed, this.cipherId);
}
this.previousCipherId = this.cipherId;
}
@@ -238,7 +238,10 @@ export class ViewComponent implements OnDestroy, OnInit {
this.showPassword = !this.showPassword;
this.showPasswordCount = false;
if (this.showPassword) {
this.eventService.collect(EventType.Cipher_ClientToggledPasswordVisible, this.cipherId);
this.eventCollectionService.collect(
EventType.Cipher_ClientToggledPasswordVisible,
this.cipherId
);
}
}
@@ -257,7 +260,10 @@ export class ViewComponent implements OnDestroy, OnInit {
this.showCardNumber = !this.showCardNumber;
if (this.showCardNumber) {
this.eventService.collect(EventType.Cipher_ClientToggledCardNumberVisible, this.cipherId);
this.eventCollectionService.collect(
EventType.Cipher_ClientToggledCardNumberVisible,
this.cipherId
);
}
}
@@ -268,7 +274,10 @@ export class ViewComponent implements OnDestroy, OnInit {
this.showCardCode = !this.showCardCode;
if (this.showCardCode) {
this.eventService.collect(EventType.Cipher_ClientToggledCardCodeVisible, this.cipherId);
this.eventCollectionService.collect(
EventType.Cipher_ClientToggledCardCodeVisible,
this.cipherId
);
}
}
@@ -328,11 +337,14 @@ export class ViewComponent implements OnDestroy, OnInit {
);
if (typeI18nKey === "password") {
this.eventService.collect(EventType.Cipher_ClientToggledHiddenFieldVisible, this.cipherId);
this.eventCollectionService.collect(
EventType.Cipher_ClientToggledHiddenFieldVisible,
this.cipherId
);
} else if (typeI18nKey === "securityCode") {
this.eventService.collect(EventType.Cipher_ClientCopiedCardCode, this.cipherId);
this.eventCollectionService.collect(EventType.Cipher_ClientCopiedCardCode, this.cipherId);
} else if (aType === "H_Field") {
this.eventService.collect(EventType.Cipher_ClientCopiedHiddenField, this.cipherId);
this.eventCollectionService.collect(EventType.Cipher_ClientCopiedHiddenField, this.cipherId);
}
}

View File

@@ -13,8 +13,8 @@ import { ControlValueAccessor, NG_VALUE_ACCESSOR } from "@angular/forms";
],
})
export class TrueFalseValueDirective implements ControlValueAccessor {
@Input() trueValue = true;
@Input() falseValue = false;
@Input() trueValue: boolean | string = true;
@Input() falseValue: boolean | string = false;
constructor(private elementRef: ElementRef, private renderer: Renderer2) {}

View File

@@ -21,14 +21,13 @@ import { SelectCopyDirective } from "./directives/select-copy.directive";
import { StopClickDirective } from "./directives/stop-click.directive";
import { StopPropDirective } from "./directives/stop-prop.directive";
import { TrueFalseValueDirective } from "./directives/true-false-value.directive";
import { ColorPasswordCountPipe } from "./pipes/color-password-count.pipe";
import { ColorPasswordPipe } from "./pipes/color-password.pipe";
import { CreditCardNumberPipe } from "./pipes/credit-card-number.pipe";
import { EllipsisPipe } from "./pipes/ellipsis.pipe";
import { I18nPipe } from "./pipes/i18n.pipe";
import { SearchCiphersPipe } from "./pipes/search-ciphers.pipe";
import { SearchPipe } from "./pipes/search.pipe";
import { UserNamePipe } from "./pipes/user-name.pipe";
import { UserTypePipe } from "./pipes/user-type.pipe";
import { PasswordStrengthComponent } from "./shared/components/password-strength/password-strength.component";
@NgModule({
@@ -49,8 +48,6 @@ import { PasswordStrengthComponent } from "./shared/components/password-strength
AutofocusDirective,
BoxRowDirective,
CalloutComponent,
ColorPasswordCountPipe,
ColorPasswordPipe,
CreditCardNumberPipe,
EllipsisPipe,
ExportScopeCalloutComponent,
@@ -70,6 +67,7 @@ import { PasswordStrengthComponent } from "./shared/components/password-strength
LaunchClickDirective,
UserNamePipe,
PasswordStrengthComponent,
UserTypePipe,
],
exports: [
A11yInvalidDirective,
@@ -79,8 +77,6 @@ import { PasswordStrengthComponent } from "./shared/components/password-strength
BitwardenToastModule,
BoxRowDirective,
CalloutComponent,
ColorPasswordCountPipe,
ColorPasswordPipe,
CreditCardNumberPipe,
EllipsisPipe,
ExportScopeCalloutComponent,
@@ -100,7 +96,8 @@ import { PasswordStrengthComponent } from "./shared/components/password-strength
LaunchClickDirective,
UserNamePipe,
PasswordStrengthComponent,
UserTypePipe,
],
providers: [CreditCardNumberPipe, DatePipe, I18nPipe, SearchPipe, UserNamePipe],
providers: [CreditCardNumberPipe, DatePipe, I18nPipe, SearchPipe, UserNamePipe, UserTypePipe],
})
export class JslibModule {}

View File

@@ -8,7 +8,7 @@ import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
export class I18nPipe implements PipeTransform {
constructor(private i18nService: I18nService) {}
transform(id: string, p1?: string, p2?: string, p3?: string): string {
transform(id: string, p1?: string | number, p2?: string | number, p3?: string | number): string {
return this.i18nService.t(id, p1, p2, p3);
}
}

View File

@@ -1,16 +1,32 @@
import { Pipe, PipeTransform } from "@angular/core";
type PropertyValueFunction<T> = (item: T) => { toString: () => string };
@Pipe({
name: "search",
})
export class SearchPipe implements PipeTransform {
transform(
items: any[],
transform<T>(
items: T[],
searchText: string,
prop1?: string,
prop2?: string,
prop3?: string
): any[] {
prop1?: keyof T,
prop2?: keyof T,
prop3?: keyof T
): T[];
transform<T>(
items: T[],
searchText: string,
prop1?: PropertyValueFunction<T>,
prop2?: PropertyValueFunction<T>,
prop3?: PropertyValueFunction<T>
): T[];
transform<T>(
items: T[],
searchText: string,
prop1?: keyof T | PropertyValueFunction<T>,
prop2?: keyof T | PropertyValueFunction<T>,
prop3?: keyof T | PropertyValueFunction<T>
): T[] {
if (items == null || items.length === 0) {
return [];
}
@@ -21,27 +37,30 @@ export class SearchPipe implements PipeTransform {
searchText = searchText.trim().toLowerCase();
return items.filter((i) => {
if (
prop1 != null &&
i[prop1] != null &&
i[prop1].toString().toLowerCase().indexOf(searchText) > -1
) {
return true;
if (prop1 != null) {
const propValue = typeof prop1 === "function" ? prop1(i) : i[prop1];
if (propValue?.toString().toLowerCase().indexOf(searchText) > -1) {
return true;
}
}
if (
prop2 != null &&
i[prop2] != null &&
i[prop2].toString().toLowerCase().indexOf(searchText) > -1
) {
return true;
if (prop2 != null) {
const propValue = typeof prop2 === "function" ? prop2(i) : i[prop2];
if (propValue?.toString().toLowerCase().indexOf(searchText) > -1) {
return true;
}
}
if (
prop3 != null &&
i[prop3] != null &&
i[prop3].toString().toLowerCase().indexOf(searchText) > -1
) {
return true;
if (prop3 != null) {
const propValue = typeof prop3 === "function" ? prop3(i) : i[prop3];
if (propValue?.toString().toLowerCase().indexOf(searchText) > -1) {
return true;
}
}
return false;
});
}

View File

@@ -0,0 +1,29 @@
import { Pipe, PipeTransform } from "@angular/core";
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
import { OrganizationUserType } from "@bitwarden/common/enums/organizationUserType";
@Pipe({
name: "userType",
})
export class UserTypePipe implements PipeTransform {
constructor(private i18nService: I18nService) {}
transform(value?: OrganizationUserType): string {
if (value == null) {
return this.i18nService.t("unknown");
}
switch (value) {
case OrganizationUserType.Owner:
return this.i18nService.t("owner");
case OrganizationUserType.Admin:
return this.i18nService.t("admin");
case OrganizationUserType.User:
return this.i18nService.t("user");
case OrganizationUserType.Manager:
return this.i18nService.t("manager");
case OrganizationUserType.Custom:
return this.i18nService.t("custom");
}
}
}

View File

@@ -1,10 +1,13 @@
import { InjectionToken } from "@angular/core";
import { AbstractStorageService } from "@bitwarden/common/abstractions/storage.service";
import {
AbstractMemoryStorageService,
AbstractStorageService,
} from "@bitwarden/common/abstractions/storage.service";
import { StateFactory } from "@bitwarden/common/factories/stateFactory";
export const WINDOW = new InjectionToken<Window>("WINDOW");
export const MEMORY_STORAGE = new InjectionToken<AbstractStorageService>("MEMORY_STORAGE");
export const MEMORY_STORAGE = new InjectionToken<AbstractMemoryStorageService>("MEMORY_STORAGE");
export const SECURE_STORAGE = new InjectionToken<AbstractStorageService>("SECURE_STORAGE");
export const STATE_FACTORY = new InjectionToken<StateFactory>("STATE_FACTORY");
export const STATE_SERVICE_USE_CACHE = new InjectionToken<boolean>("STATE_SERVICE_USE_CACHE");

View File

@@ -2,9 +2,10 @@ import { Injector, LOCALE_ID, NgModule } from "@angular/core";
import { AccountApiService as AccountApiServiceAbstraction } from "@bitwarden/common/abstractions/account/account-api.service";
import {
InternalAccountService,
AccountService as AccountServiceAbstraction,
InternalAccountService,
} from "@bitwarden/common/abstractions/account/account.service";
import { AvatarUpdateService as AccountUpdateServiceAbstraction } from "@bitwarden/common/abstractions/account/avatar-update.service";
import { AnonymousHubService as AnonymousHubServiceAbstraction } from "@bitwarden/common/abstractions/anonymousHub.service";
import { ApiService as ApiServiceAbstraction } from "@bitwarden/common/abstractions/api.service";
import { AppIdService as AppIdServiceAbstraction } from "@bitwarden/common/abstractions/appId.service";
@@ -19,7 +20,8 @@ import { CryptoService as CryptoServiceAbstraction } from "@bitwarden/common/abs
import { CryptoFunctionService as CryptoFunctionServiceAbstraction } from "@bitwarden/common/abstractions/cryptoFunction.service";
import { EncryptService } from "@bitwarden/common/abstractions/encrypt.service";
import { EnvironmentService as EnvironmentServiceAbstraction } from "@bitwarden/common/abstractions/environment.service";
import { EventService as EventServiceAbstraction } from "@bitwarden/common/abstractions/event.service";
import { EventCollectionService as EventCollectionServiceAbstraction } from "@bitwarden/common/abstractions/event/event-collection.service";
import { EventUploadService as EventUploadServiceAbstraction } from "@bitwarden/common/abstractions/event/event-upload.service";
import { ExportService as ExportServiceAbstraction } from "@bitwarden/common/abstractions/export.service";
import { FileUploadService as FileUploadServiceAbstraction } from "@bitwarden/common/abstractions/fileUpload.service";
import { FolderApiServiceAbstraction } from "@bitwarden/common/abstractions/folder/folder-api.service.abstraction";
@@ -34,15 +36,19 @@ import { LogService } from "@bitwarden/common/abstractions/log.service";
import { LoginService as LoginServiceAbstraction } from "@bitwarden/common/abstractions/login.service";
import { MessagingService as MessagingServiceAbstraction } from "@bitwarden/common/abstractions/messaging.service";
import { NotificationsService as NotificationsServiceAbstraction } from "@bitwarden/common/abstractions/notifications.service";
import { OrganizationUserService } from "@bitwarden/common/abstractions/organization-user/organization-user.service";
import { OrganizationApiServiceAbstraction } from "@bitwarden/common/abstractions/organization/organization-api.service.abstraction";
import { OrganizationService as OrganizationServiceAbstraction } from "@bitwarden/common/abstractions/organization/organization.service.abstraction";
import {
InternalOrganizationService,
OrganizationService as OrganizationServiceAbstraction,
} from "@bitwarden/common/abstractions/organization/organization.service.abstraction";
import { PasswordGenerationService as PasswordGenerationServiceAbstraction } from "@bitwarden/common/abstractions/passwordGeneration.service";
import { PasswordRepromptService as PasswordRepromptServiceAbstraction } from "@bitwarden/common/abstractions/passwordReprompt.service";
import { PlatformUtilsService as PlatformUtilsServiceAbstraction } from "@bitwarden/common/abstractions/platformUtils.service";
import { PolicyApiServiceAbstraction } from "@bitwarden/common/abstractions/policy/policy-api.service.abstraction";
import {
PolicyService as PolicyServiceAbstraction,
InternalPolicyService,
PolicyService as PolicyServiceAbstraction,
} from "@bitwarden/common/abstractions/policy/policy.service.abstraction";
import { ProviderService as ProviderServiceAbstraction } from "@bitwarden/common/abstractions/provider.service";
import { SearchService as SearchServiceAbstraction } from "@bitwarden/common/abstractions/search.service";
@@ -68,6 +74,7 @@ import { Account } from "@bitwarden/common/models/domain/account";
import { GlobalState } from "@bitwarden/common/models/domain/global-state";
import { AccountApiServiceImplementation } from "@bitwarden/common/services/account/account-api.service";
import { AccountServiceImplementation } from "@bitwarden/common/services/account/account.service";
import { AvatarUpdateService } from "@bitwarden/common/services/account/avatar-update.service";
import { AnonymousHubService } from "@bitwarden/common/services/anonymousHub.service";
import { ApiService } from "@bitwarden/common/services/api.service";
import { AppIdService } from "@bitwarden/common/services/appId.service";
@@ -82,7 +89,8 @@ import { CryptoService } from "@bitwarden/common/services/crypto.service";
import { EncryptServiceImplementation } from "@bitwarden/common/services/cryptography/encrypt.service.implementation";
import { MultithreadEncryptServiceImplementation } from "@bitwarden/common/services/cryptography/multithread-encrypt.service.implementation";
import { EnvironmentService } from "@bitwarden/common/services/environment.service";
import { EventService } from "@bitwarden/common/services/event.service";
import { EventCollectionService } from "@bitwarden/common/services/event/event-collection.service";
import { EventUploadService } from "@bitwarden/common/services/event/event-upload.service";
import { ExportService } from "@bitwarden/common/services/export.service";
import { FileUploadService } from "@bitwarden/common/services/fileUpload.service";
import { FolderApiService } from "@bitwarden/common/services/folder/folder-api.service";
@@ -91,6 +99,7 @@ import { FormValidationErrorsService } from "@bitwarden/common/services/formVali
import { KeyConnectorService } from "@bitwarden/common/services/keyConnector.service";
import { LoginService } from "@bitwarden/common/services/login.service";
import { NotificationsService } from "@bitwarden/common/services/notifications.service";
import { OrganizationUserServiceImplementation } from "@bitwarden/common/services/organization-user/organization-user.service.implementation";
import { OrganizationApiService } from "@bitwarden/common/services/organization/organization-api.service";
import { OrganizationService } from "@bitwarden/common/services/organization/organization.service";
import { PasswordGenerationService } from "@bitwarden/common/services/passwordGeneration.service";
@@ -121,16 +130,16 @@ import { UnauthGuard } from "../guards/unauth.guard";
import { BroadcasterService } from "./broadcaster.service";
import {
WINDOW,
LOCALES_DIRECTORY,
LOCKED_CALLBACK,
LOG_MAC_FAILURES,
LOGOUT_CALLBACK,
MEMORY_STORAGE,
SECURE_STORAGE,
STATE_FACTORY,
STATE_SERVICE_USE_CACHE,
LOGOUT_CALLBACK,
LOCKED_CALLBACK,
LOCALES_DIRECTORY,
SYSTEM_LANGUAGE,
LOG_MAC_FAILURES,
WINDOW,
} from "./injection-tokens";
import { ModalService } from "./modal.service";
import { PasswordRepromptService } from "./passwordReprompt.service";
@@ -284,6 +293,11 @@ import { AbstractThemingService } from "./theming/theming.service.abstraction";
provide: InternalAccountService,
useExisting: AccountServiceAbstraction,
},
{
provide: AccountUpdateServiceAbstraction,
useClass: AvatarUpdateService,
deps: [ApiServiceAbstraction, StateServiceAbstraction],
},
{ provide: LogService, useFactory: () => new ConsoleLogService(false) },
{
provide: CollectionServiceAbstraction,
@@ -356,7 +370,7 @@ import { AbstractThemingService } from "./theming/theming.service.abstraction";
StateServiceAbstraction,
ProviderServiceAbstraction,
FolderApiServiceAbstraction,
SyncNotifierServiceAbstraction,
OrganizationServiceAbstraction,
LOGOUT_CALLBACK,
],
},
@@ -454,14 +468,18 @@ import { AbstractThemingService } from "./theming/theming.service.abstraction";
deps: [CryptoFunctionServiceAbstraction, LogService, LOG_MAC_FAILURES],
},
{
provide: EventServiceAbstraction,
useClass: EventService,
provide: EventUploadServiceAbstraction,
useClass: EventUploadService,
deps: [ApiServiceAbstraction, StateServiceAbstraction, LogService],
},
{
provide: EventCollectionServiceAbstraction,
useClass: EventCollectionService,
deps: [
ApiServiceAbstraction,
CipherServiceAbstraction,
StateServiceAbstraction,
LogService,
OrganizationServiceAbstraction,
EventUploadServiceAbstraction,
],
},
{
@@ -476,12 +494,7 @@ import { AbstractThemingService } from "./theming/theming.service.abstraction";
{
provide: PolicyApiServiceAbstraction,
useClass: PolicyApiService,
deps: [
PolicyServiceAbstraction,
ApiServiceAbstraction,
StateServiceAbstraction,
OrganizationServiceAbstraction,
],
deps: [PolicyServiceAbstraction, ApiServiceAbstraction, StateServiceAbstraction],
},
{
provide: SendServiceAbstraction,
@@ -506,6 +519,8 @@ import { AbstractThemingService } from "./theming/theming.service.abstraction";
LogService,
OrganizationServiceAbstraction,
CryptoFunctionServiceAbstraction,
SyncNotifierServiceAbstraction,
MessagingServiceAbstraction,
LOGOUT_CALLBACK,
],
},
@@ -522,7 +537,16 @@ import { AbstractThemingService } from "./theming/theming.service.abstraction";
{
provide: OrganizationServiceAbstraction,
useClass: OrganizationService,
deps: [StateServiceAbstraction, SyncNotifierServiceAbstraction],
deps: [StateServiceAbstraction],
},
{
provide: InternalOrganizationService,
useExisting: OrganizationServiceAbstraction,
},
{
provide: OrganizationUserService,
useClass: OrganizationUserServiceImplementation,
deps: [ApiServiceAbstraction],
},
{
provide: ProviderServiceAbstraction,
@@ -583,6 +607,7 @@ import { AbstractThemingService } from "./theming/theming.service.abstraction";
{
provide: LoginServiceAbstraction,
useClass: LoginService,
deps: [StateServiceAbstraction],
},
],
})

View File

@@ -6,10 +6,12 @@ import { ITreeNodeObject } from "@bitwarden/common/models/domain/tree-node";
import { CollectionView } from "@bitwarden/common/models/view/collection.view";
import { FolderView } from "@bitwarden/common/models/view/folder.view";
import { DeprecatedVaultFilterService } from "../../../abstractions/deprecated-vault-filter.service";
import { DynamicTreeNode } from "../models/dynamic-tree-node.model";
import { VaultFilter } from "../models/vault-filter.model";
import { VaultFilterService } from "../services/vault-filter.service";
// TODO: Replace with refactored web vault filter component
// and refactor desktop/browser vault filters
@Directive()
export class VaultFilterComponent implements OnInit {
@Input() activeFilter: VaultFilter = new VaultFilter();
@@ -31,7 +33,7 @@ export class VaultFilterComponent implements OnInit {
collections: DynamicTreeNode<CollectionView>;
folders$: Observable<DynamicTreeNode<FolderView>>;
constructor(protected vaultFilterService: VaultFilterService) {}
constructor(protected vaultFilterService: DeprecatedVaultFilterService) {}
get displayCollections() {
return this.collections?.fullList != null && this.collections.fullList.length > 0;

View File

@@ -1,8 +1,6 @@
import { TreeNode } from "@bitwarden/common/models/domain/tree-node";
import { CollectionView } from "@bitwarden/common/models/view/collection.view";
import { FolderView } from "@bitwarden/common/models/view/folder.view";
import { ITreeNodeObject, TreeNode } from "@bitwarden/common/models/domain/tree-node";
export class DynamicTreeNode<T extends CollectionView | FolderView> {
export class DynamicTreeNode<T extends ITreeNodeObject> {
fullList: T[];
nestedList: TreeNode<T>[];

View File

@@ -4,7 +4,10 @@ import { firstValueFrom, from, mergeMap, Observable } from "rxjs";
import { CipherService } from "@bitwarden/common/abstractions/cipher.service";
import { CollectionService } from "@bitwarden/common/abstractions/collection.service";
import { FolderService } from "@bitwarden/common/abstractions/folder/folder.service.abstraction";
import { OrganizationService } from "@bitwarden/common/abstractions/organization/organization.service.abstraction";
import {
isNotProviderUser,
OrganizationService,
} from "@bitwarden/common/abstractions/organization/organization.service.abstraction";
import { PolicyService } from "@bitwarden/common/abstractions/policy/policy.service.abstraction";
import { StateService } from "@bitwarden/common/abstractions/state.service";
import { PolicyType } from "@bitwarden/common/enums/policyType";
@@ -14,12 +17,13 @@ import { TreeNode } from "@bitwarden/common/models/domain/tree-node";
import { CollectionView } from "@bitwarden/common/models/view/collection.view";
import { FolderView } from "@bitwarden/common/models/view/folder.view";
import { DeprecatedVaultFilterService as DeprecatedVaultFilterServiceAbstraction } from "../../../abstractions/deprecated-vault-filter.service";
import { DynamicTreeNode } from "../models/dynamic-tree-node.model";
const NestingDelimiter = "/";
@Injectable()
export class VaultFilterService {
export class VaultFilterService implements DeprecatedVaultFilterServiceAbstraction {
constructor(
protected stateService: StateService,
protected organizationService: OrganizationService,
@@ -40,7 +44,9 @@ export class VaultFilterService {
async buildOrganizations(): Promise<Organization[]> {
let organizations = await this.organizationService.getAll();
if (organizations != null) {
organizations = organizations.sort((a, b) => a.name.localeCompare(b.name));
organizations = organizations
.filter(isNotProviderUser)
.sort((a, b) => a.name.localeCompare(b.name));
}
return organizations;
@@ -115,6 +121,6 @@ export class VaultFilterService {
const folders = await this.getAllFoldersNested(
await firstValueFrom(this.folderService.folderViews$)
);
return ServiceUtils.getTreeNodeObject(folders, id) as TreeNode<FolderView>;
return ServiceUtils.getTreeNodeObjectFromList(folders, id) as TreeNode<FolderView>;
}
}

View File

@@ -0,0 +1,3 @@
export async function awaitAsync(ms = 0) {
await new Promise((resolve) => setTimeout(resolve, ms));
}