mirror of
https://github.com/bitwarden/browser
synced 2025-12-17 16:53:34 +00:00
Merge branch 'EC-598-beeep-properly-store-passkeys-in-bitwarden' into PM-2207
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
<label class="environment-selector-btn">
|
||||
{{ "region" | i18n }}:
|
||||
{{ "loggingInOn" | i18n }}:
|
||||
<a
|
||||
(click)="toggle(null)"
|
||||
cdkOverlayOrigin
|
||||
@@ -8,8 +8,12 @@
|
||||
aria-controls="cdk-overlay-container"
|
||||
[ngSwitch]="selectedEnvironment"
|
||||
>
|
||||
<label *ngSwitchCase="ServerEnvironmentType.US" class="text-primary">{{ "us" | i18n }}</label>
|
||||
<label *ngSwitchCase="ServerEnvironmentType.EU" class="text-primary">{{ "eu" | i18n }}</label>
|
||||
<label *ngSwitchCase="ServerEnvironmentType.US" class="text-primary">{{
|
||||
"usDomain" | i18n
|
||||
}}</label>
|
||||
<label *ngSwitchCase="ServerEnvironmentType.EU" class="text-primary">{{
|
||||
"euDomain" | i18n
|
||||
}}</label>
|
||||
<label *ngSwitchCase="ServerEnvironmentType.SelfHosted" class="text-primary">{{
|
||||
"selfHosted" | i18n
|
||||
}}</label>
|
||||
@@ -23,7 +27,7 @@
|
||||
(backdropClick)="close()"
|
||||
(detach)="close()"
|
||||
[cdkConnectedOverlayOpen]="isOpen"
|
||||
[cdkConnectedOverlayPositions]="overlayPostition"
|
||||
[cdkConnectedOverlayPositions]="overlayPosition"
|
||||
>
|
||||
<div class="box-content">
|
||||
<div class="environment-selector-dialog" [@transformPanel]="'open'" role="dialog">
|
||||
@@ -41,7 +45,7 @@
|
||||
"
|
||||
></i>
|
||||
<img class="img-us" alt="" />
|
||||
<span>{{ "us" | i18n }}</span>
|
||||
<span>{{ "usDomain" | i18n }}</span>
|
||||
</button>
|
||||
<br />
|
||||
<button
|
||||
@@ -59,7 +63,7 @@
|
||||
"
|
||||
></i>
|
||||
<img class="img-eu" alt="" />
|
||||
<span>{{ "eu" | i18n }}</span>
|
||||
<span>{{ "euDomain" | i18n }}</span>
|
||||
</button>
|
||||
<br *ngIf="euServerFlagEnabled" />
|
||||
<button
|
||||
@@ -76,8 +80,8 @@
|
||||
"
|
||||
></i>
|
||||
<i
|
||||
class="bwi bwi-fw bwi-sm bwi-pencil-square"
|
||||
style="padding-bottom: 1px"
|
||||
class="bwi bwi-fw bwi-md bwi-pencil-square"
|
||||
style="padding-bottom: 1px; margin-right: 5px"
|
||||
aria-hidden="true"
|
||||
></i>
|
||||
<span>{{ "selfHosted" | i18n }}</span>
|
||||
|
||||
@@ -6,7 +6,10 @@ import { Subject, takeUntil } from "rxjs";
|
||||
|
||||
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
||||
import { ConfigServiceAbstraction } from "@bitwarden/common/platform/abstractions/config/config.service.abstraction";
|
||||
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service";
|
||||
import {
|
||||
EnvironmentService as EnvironmentServiceAbstraction,
|
||||
Region,
|
||||
} from "@bitwarden/common/platform/abstractions/environment.service";
|
||||
|
||||
@Component({
|
||||
selector: "environment-selector",
|
||||
@@ -37,9 +40,9 @@ export class EnvironmentSelectorComponent implements OnInit, OnDestroy {
|
||||
euServerFlagEnabled: boolean;
|
||||
isOpen = false;
|
||||
showingModal = false;
|
||||
selectedEnvironment: ServerEnvironment;
|
||||
ServerEnvironmentType = ServerEnvironment;
|
||||
overlayPostition: ConnectedPosition[] = [
|
||||
selectedEnvironment: Region;
|
||||
ServerEnvironmentType = Region;
|
||||
overlayPosition: ConnectedPosition[] = [
|
||||
{
|
||||
originX: "start",
|
||||
originY: "bottom",
|
||||
@@ -50,7 +53,7 @@ export class EnvironmentSelectorComponent implements OnInit, OnDestroy {
|
||||
protected componentDestroyed$: Subject<void> = new Subject();
|
||||
|
||||
constructor(
|
||||
protected environmentService: EnvironmentService,
|
||||
protected environmentService: EnvironmentServiceAbstraction,
|
||||
protected configService: ConfigServiceAbstraction,
|
||||
protected router: Router
|
||||
) {}
|
||||
@@ -67,33 +70,28 @@ export class EnvironmentSelectorComponent implements OnInit, OnDestroy {
|
||||
this.componentDestroyed$.complete();
|
||||
}
|
||||
|
||||
async toggle(option: ServerEnvironment) {
|
||||
async toggle(option: Region) {
|
||||
this.isOpen = !this.isOpen;
|
||||
if (option === null) {
|
||||
return;
|
||||
}
|
||||
if (option === ServerEnvironment.EU) {
|
||||
await this.environmentService.setUrls({ base: "https://vault.bitwarden.eu" });
|
||||
} else if (option === ServerEnvironment.US) {
|
||||
await this.environmentService.setUrls({ base: "https://vault.bitwarden.com" });
|
||||
} else if (option === ServerEnvironment.SelfHosted) {
|
||||
|
||||
this.updateEnvironmentInfo();
|
||||
|
||||
if (option === Region.SelfHosted) {
|
||||
this.onOpenSelfHostedSettings.emit();
|
||||
return;
|
||||
}
|
||||
|
||||
await this.environmentService.setRegion(option);
|
||||
this.updateEnvironmentInfo();
|
||||
}
|
||||
|
||||
async updateEnvironmentInfo() {
|
||||
this.selectedEnvironment = this.environmentService.selectedRegion;
|
||||
this.euServerFlagEnabled = await this.configService.getFeatureFlagBool(
|
||||
FeatureFlag.DisplayEuEnvironmentFlag
|
||||
);
|
||||
const webvaultUrl = this.environmentService.getWebVaultUrl();
|
||||
if (this.environmentService.isSelfHosted()) {
|
||||
this.selectedEnvironment = ServerEnvironment.SelfHosted;
|
||||
} else if (webvaultUrl != null && webvaultUrl.includes("bitwarden.eu")) {
|
||||
this.selectedEnvironment = ServerEnvironment.EU;
|
||||
} else {
|
||||
this.selectedEnvironment = ServerEnvironment.US;
|
||||
}
|
||||
}
|
||||
|
||||
close() {
|
||||
@@ -101,9 +99,3 @@ export class EnvironmentSelectorComponent implements OnInit, OnDestroy {
|
||||
this.updateEnvironmentInfo();
|
||||
}
|
||||
}
|
||||
|
||||
enum ServerEnvironment {
|
||||
US = "US",
|
||||
EU = "EU",
|
||||
SelfHosted = "Self-hosted",
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ export class LoginWithDeviceComponent
|
||||
protected successRoute = "vault";
|
||||
protected forcePasswordResetRoute = "update-temp-password";
|
||||
private resendTimeout = 12000;
|
||||
private authRequestKeyPair: [publicKey: ArrayBuffer, privateKey: ArrayBuffer];
|
||||
private authRequestKeyPair: [publicKey: Uint8Array, privateKey: Uint8Array];
|
||||
|
||||
constructor(
|
||||
protected router: Router,
|
||||
|
||||
@@ -2,9 +2,9 @@ import { Directive } from "@angular/core";
|
||||
import { Router } from "@angular/router";
|
||||
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { UserVerificationService } from "@bitwarden/common/abstractions/userVerification/userVerification.service.abstraction";
|
||||
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
|
||||
import { MasterPasswordPolicyOptions } from "@bitwarden/common/admin-console/models/domain/master-password-policy-options";
|
||||
import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction";
|
||||
import { VerificationType } from "@bitwarden/common/auth/enums/verification-type";
|
||||
import { PasswordRequest } from "@bitwarden/common/auth/models/request/password.request";
|
||||
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
|
||||
|
||||
@@ -2,9 +2,9 @@ import { Directive } from "@angular/core";
|
||||
import { Router } from "@angular/router";
|
||||
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { UserVerificationService } from "@bitwarden/common/abstractions/userVerification/userVerification.service.abstraction";
|
||||
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
|
||||
import { MasterPasswordPolicyOptions } from "@bitwarden/common/admin-console/models/domain/master-password-policy-options";
|
||||
import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction";
|
||||
import { VerificationType } from "@bitwarden/common/auth/enums/verification-type";
|
||||
import { ForceResetPasswordReason } from "@bitwarden/common/auth/models/domain/force-reset-password-reason";
|
||||
import { PasswordRequest } from "@bitwarden/common/auth/models/request/password.request";
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import { Directive } from "@angular/core";
|
||||
import { FormBuilder, FormControl } from "@angular/forms";
|
||||
import { FormBuilder } from "@angular/forms";
|
||||
|
||||
import { UserVerificationService } from "@bitwarden/common/abstractions/userVerification/userVerification.service.abstraction";
|
||||
import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
import { Verification } from "@bitwarden/common/types/verification";
|
||||
|
||||
import { ModalRef } from "../../components/modal/modal.ref";
|
||||
import { ModalConfig } from "../../services/modal.service";
|
||||
@@ -16,7 +17,12 @@ export class UserVerificationPromptComponent {
|
||||
confirmDescription = this.config.data.confirmDescription;
|
||||
confirmButtonText = this.config.data.confirmButtonText;
|
||||
modalTitle = this.config.data.modalTitle;
|
||||
secret = new FormControl();
|
||||
|
||||
formGroup = this.formBuilder.group({
|
||||
secret: this.formBuilder.control<Verification | null>(null),
|
||||
});
|
||||
|
||||
protected invalidSecret = false;
|
||||
|
||||
constructor(
|
||||
private modalRef: ModalRef,
|
||||
@@ -27,19 +33,31 @@ export class UserVerificationPromptComponent {
|
||||
private i18nService: I18nService
|
||||
) {}
|
||||
|
||||
async submit() {
|
||||
try {
|
||||
//Incorrect secret will throw an invalid password error.
|
||||
await this.userVerificationService.verifyUser(this.secret.value);
|
||||
} catch (e) {
|
||||
this.platformUtilsService.showToast(
|
||||
"error",
|
||||
this.i18nService.t("error"),
|
||||
this.i18nService.t("invalidMasterPassword")
|
||||
);
|
||||
get secret() {
|
||||
return this.formGroup.controls.secret;
|
||||
}
|
||||
|
||||
submit = async () => {
|
||||
this.formGroup.markAllAsTouched();
|
||||
|
||||
if (this.formGroup.invalid) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.modalRef.close(true);
|
||||
try {
|
||||
//Incorrect secret will throw an invalid password error.
|
||||
await this.userVerificationService.verifyUser(this.secret.value);
|
||||
this.invalidSecret = false;
|
||||
} catch (e) {
|
||||
this.invalidSecret = true;
|
||||
this.platformUtilsService.showToast("error", this.i18nService.t("error"), e.message);
|
||||
return;
|
||||
}
|
||||
|
||||
this.close(true);
|
||||
};
|
||||
|
||||
close(success: boolean) {
|
||||
this.modalRef.close(success);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import { Directive, OnInit } from "@angular/core";
|
||||
import { ControlValueAccessor, FormControl } from "@angular/forms";
|
||||
import { Directive, EventEmitter, Input, OnDestroy, OnInit, Output } from "@angular/core";
|
||||
import { ControlValueAccessor, FormControl, Validators } from "@angular/forms";
|
||||
import { Subject, takeUntil } from "rxjs";
|
||||
|
||||
import { UserVerificationService } from "@bitwarden/common/abstractions/userVerification/userVerification.service.abstraction";
|
||||
import { KeyConnectorService } from "@bitwarden/common/auth/abstractions/key-connector.service";
|
||||
import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction";
|
||||
import { VerificationType } from "@bitwarden/common/auth/enums/verification-type";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||
import { Verification } from "@bitwarden/common/types/verification";
|
||||
|
||||
@@ -17,29 +19,65 @@ import { Verification } from "@bitwarden/common/types/verification";
|
||||
selector: "app-user-verification",
|
||||
})
|
||||
// eslint-disable-next-line rxjs-angular/prefer-takeuntil
|
||||
export class UserVerificationComponent implements ControlValueAccessor, OnInit {
|
||||
usesKeyConnector = false;
|
||||
export class UserVerificationComponent implements ControlValueAccessor, OnInit, OnDestroy {
|
||||
private _invalidSecret = false;
|
||||
@Input()
|
||||
get invalidSecret() {
|
||||
return this._invalidSecret;
|
||||
}
|
||||
set invalidSecret(value: boolean) {
|
||||
this._invalidSecret = value;
|
||||
this.invalidSecretChange.emit(value);
|
||||
|
||||
// ISSUE: This is pretty hacky but unfortunately there is no way of knowing if the parent
|
||||
// control has been marked as touched, see: https://github.com/angular/angular/issues/10887
|
||||
// When that functionality has been added we should also look into forwarding reactive form
|
||||
// controls errors so that we don't need a separate input/output `invalidSecret`.
|
||||
if (value) {
|
||||
this.secret.markAsTouched();
|
||||
}
|
||||
this.secret.updateValueAndValidity({ emitEvent: false });
|
||||
}
|
||||
@Output() invalidSecretChange = new EventEmitter<boolean>();
|
||||
|
||||
usesKeyConnector = true;
|
||||
disableRequestOTP = false;
|
||||
sentCode = false;
|
||||
|
||||
secret = new FormControl("");
|
||||
secret = new FormControl("", [
|
||||
Validators.required,
|
||||
() => {
|
||||
if (this.invalidSecret) {
|
||||
return {
|
||||
invalidSecret: {
|
||||
message: this.usesKeyConnector
|
||||
? this.i18nService.t("incorrectCode")
|
||||
: this.i18nService.t("incorrectPassword"),
|
||||
},
|
||||
};
|
||||
}
|
||||
},
|
||||
]);
|
||||
|
||||
private onChange: (value: Verification) => void;
|
||||
private destroy$ = new Subject<void>();
|
||||
|
||||
constructor(
|
||||
private keyConnectorService: KeyConnectorService,
|
||||
private userVerificationService: UserVerificationService
|
||||
private userVerificationService: UserVerificationService,
|
||||
private i18nService: I18nService
|
||||
) {}
|
||||
|
||||
async ngOnInit() {
|
||||
this.usesKeyConnector = await this.keyConnectorService.getUsesKeyConnector();
|
||||
this.processChanges(this.secret.value);
|
||||
|
||||
// eslint-disable-next-line rxjs-angular/prefer-takeuntil
|
||||
this.secret.valueChanges.subscribe((secret: string) => this.processChanges(secret));
|
||||
this.secret.valueChanges
|
||||
.pipe(takeUntil(this.destroy$))
|
||||
.subscribe((secret: string) => this.processChanges(secret));
|
||||
}
|
||||
|
||||
async requestOTP() {
|
||||
requestOTP = async () => {
|
||||
if (this.usesKeyConnector) {
|
||||
this.disableRequestOTP = true;
|
||||
try {
|
||||
@@ -49,7 +87,7 @@ export class UserVerificationComponent implements ControlValueAccessor, OnInit {
|
||||
this.disableRequestOTP = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
writeValue(obj: any): void {
|
||||
this.secret.setValue(obj);
|
||||
@@ -72,7 +110,14 @@ export class UserVerificationComponent implements ControlValueAccessor, OnInit {
|
||||
}
|
||||
}
|
||||
|
||||
private processChanges(secret: string) {
|
||||
ngOnDestroy(): void {
|
||||
this.destroy$.next();
|
||||
this.destroy$.complete();
|
||||
}
|
||||
|
||||
protected processChanges(secret: string) {
|
||||
this.invalidSecret = false;
|
||||
|
||||
if (this.onChange == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user