[PM-1019] Environment selection clients (#5480)

* [PM-169][PM-142][PM-191] Add Environments to Web and Desktop (#5294)

* [PM-1351] Add property to server-config.response. Change config to be able to fetch without being authed.

* [PM-1351] fetch every hour.

* [PM-1351] fetch on vault sync.

* [PM-1351] browser desktop fetch configs on sync complete.

* [PM-1351] Add methods to retrieve feature flags

* [PM-1351] Add enum to use as key to get values feature flag values

* [PM-1351] Remove debug code

* [PM-1351] Get flags when unauthed. Add enums as params. Hourly always fetch.

* [PM-1351] add check for authed user using auth service

* [PM-169] Web: add drop down to select environment

* [PM-169] Fix pop up menu margins. Add DisplayEuEnvironmentFlag.

* [PM-169] Change menu name.

* [PM-169] Add environment selector ts and html. Add declaration and import on login.module

* [PM-169] Add environment selector to desktop.

* [PM-169] Ignore lint error.

* [PM-169] add takeUntil to subscribes

* [PM-191] PR Fixes, code format

* [PM-168] Add Environments to extension login/registration (#5434)
This commit is contained in:
André Bispo 2023-05-19 17:35:42 +01:00 committed by GitHub
parent 6383d6ff8a
commit b9fe78796a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 463 additions and 42 deletions

View File

@ -2221,7 +2221,18 @@
}
}
},
"region": {
"message": "Region"
},
"opensInANewWindow": {
"message": "Opens in a new window"
},
"eu": {
"message": "EU",
"description": "European Union"
},
"us": {
"message": "US",
"description": "United States"
}
}

View File

@ -2221,6 +2221,9 @@
}
}
},
"region": {
"message": "Region"
},
"opensInANewWindow": {
"message": "Opens in a new window"
}

View File

@ -2,6 +2,7 @@ import { Component, OnInit } from "@angular/core";
import { Router } from "@angular/router";
import { EnvironmentComponent as BaseEnvironmentComponent } from "@bitwarden/angular/components/environment.component";
import { ModalService } from "@bitwarden/angular/services/modal.service";
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
@ -18,9 +19,10 @@ export class EnvironmentComponent extends BaseEnvironmentComponent implements On
platformUtilsService: PlatformUtilsService,
public environmentService: BrowserEnvironmentService,
i18nService: I18nService,
private router: Router
private router: Router,
modalService: ModalService
) {
super(platformUtilsService, environmentService, i18nService);
super(platformUtilsService, environmentService, i18nService, modalService);
this.showCustom = true;
}

View File

@ -9,9 +9,7 @@
<label for="email">{{ "emailAddress" | i18n }}</label>
<input id="email" type="email" formControlName="email" appInputVerbatim="false" />
</div>
<div class="box-footer no-margin" *ngIf="selfHostedDomain">
{{ "loggingInTo" | i18n : selfHostedDomain }}
</div>
<environment-selector class="environment-selector-padding"></environment-selector>
<div class="remember-email-check">
<input
id="rememberEmail"
@ -35,6 +33,3 @@
</p>
</div>
</div>
<button type="button" routerLink="/environment" class="settings-icon" (click)="setFormValues()">
<i class="bwi bwi-cog-f bwi-lg" aria-hidden="true"></i><span>&nbsp;{{ "settings" | i18n }}</span>
</button>

View File

@ -1,7 +1,9 @@
import { Component, OnInit } from "@angular/core";
import { Component, OnDestroy, OnInit, ViewChild } from "@angular/core";
import { FormBuilder, Validators } from "@angular/forms";
import { ActivatedRoute, Router } from "@angular/router";
import { Router } from "@angular/router";
import { Subject, takeUntil } from "rxjs";
import { EnvironmentSelectorComponent } from "@bitwarden/angular/auth/components/environment-selector.component";
import { EnvironmentService } from "@bitwarden/common/abstractions/environment.service";
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
@ -12,9 +14,12 @@ import { LoginService } from "@bitwarden/common/auth/abstractions/login.service"
selector: "app-home",
templateUrl: "home.component.html",
})
export class HomeComponent implements OnInit {
loginInitiated = false;
export class HomeComponent implements OnInit, OnDestroy {
@ViewChild(EnvironmentSelectorComponent, { static: true })
environmentSelector!: EnvironmentSelectorComponent;
private destroyed$: Subject<void> = new Subject();
loginInitiated = false;
formGroup = this.formBuilder.group({
email: ["", [Validators.required, Validators.email]],
rememberEmail: [false],
@ -27,9 +32,9 @@ export class HomeComponent implements OnInit {
private router: Router,
private i18nService: I18nService,
private environmentService: EnvironmentService,
private route: ActivatedRoute,
private loginService: LoginService
) {}
async ngOnInit(): Promise<void> {
let savedEmail = this.loginService.getEmail();
const rememberEmail = this.loginService.getRememberEmail();
@ -48,6 +53,18 @@ export class HomeComponent implements OnInit {
});
}
}
this.environmentSelector.onOpenSelfHostedSettings
.pipe(takeUntil(this.destroyed$))
.subscribe(() => {
this.setFormValues();
this.router.navigate(["environment"]);
});
}
ngOnDestroy(): void {
this.destroyed$.next();
this.destroyed$.complete();
}
submit() {

View File

@ -10,6 +10,7 @@ import { FormsModule, ReactiveFormsModule } from "@angular/forms";
import { BrowserModule } from "@angular/platform-browser";
import { BrowserAnimationsModule } from "@angular/platform-browser/animations";
import { EnvironmentSelectorComponent } from "@bitwarden/angular/auth/components/environment-selector.component";
import { BitwardenToastModule } from "@bitwarden/angular/components/toastr.component";
import { JslibModule } from "@bitwarden/angular/jslib.module";
import { ColorPasswordCountPipe } from "@bitwarden/angular/pipes/color-password-count.pipe";
@ -153,6 +154,7 @@ import "./locales";
AboutComponent,
HelpAndFeedbackComponent,
AutofillComponent,
EnvironmentSelectorComponent,
],
providers: [CurrencyPipe, DatePipe],
bootstrap: [AppComponent],

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

View File

@ -45,3 +45,67 @@ html.browser_safari {
border-color: #2e3440;
}
}
.environment-selector-btn {
font-size: $font-size-small;
color: $text-muted;
line-height: 25px;
font-weight: 400;
padding-left: 5px;
label {
font-weight: 600;
}
a,
a label:hover {
cursor: pointer;
}
}
.environment-selector-dialog {
@include themify($themes) {
background-color: themed("boxBackgroundColor");
}
padding: 5px;
width: 100%;
box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 3px 1px -2px rgba(0, 0, 0, 0.12),
0 1px 5px 0 rgba(0, 0, 0, 0.2);
border-radius: $border-radius;
}
.environment-selector-dialog-item {
@include themify($themes) {
color: themed("textColor") !important;
}
width: 100%;
text-align: left;
padding: 0px 15px 0px 5px;
border-radius: 3px;
border: 1px solid transparent;
transition: all 0.2s ease-in-out;
&:hover {
@include themify($themes) {
background-color: themed("listItemBackgroundHoverColor") !important;
}
}
img {
margin-bottom: -2px;
width: 22px;
height: 14px;
}
.img-us {
content: url("../images/us-flag.png");
}
.img-eu {
content: url("../images/eu-flag.png");
}
}
.environment-selector-padding {
padding-left: 10px;
}

View File

@ -144,7 +144,7 @@ body.body-full {
}
.remember-email-check {
padding-top: 8px;
padding-top: 18px;
padding-left: 10px;
padding-bottom: 18px;
}

View File

@ -1,6 +1,7 @@
import { Component } from "@angular/core";
import { EnvironmentComponent as BaseEnvironmentComponent } from "@bitwarden/angular/components/environment.component";
import { ModalService } from "@bitwarden/angular/services/modal.service";
import { EnvironmentService } from "@bitwarden/common/abstractions/environment.service";
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
@ -13,8 +14,9 @@ export class EnvironmentComponent extends BaseEnvironmentComponent {
constructor(
platformUtilsService: PlatformUtilsService,
environmentService: EnvironmentService,
i18nService: I18nService
i18nService: I18nService,
modalService: ModalService
) {
super(platformUtilsService, environmentService, i18nService);
super(platformUtilsService, environmentService, i18nService, modalService);
}
}

View File

@ -1,16 +1,4 @@
<div id="login-page">
<div class="login-header">
<button
type="button"
appStopClick
(click)="settings()"
class="environment-urls-settings-icon"
attr.aria-label="{{ 'settings' | i18n }}"
>
<i class="bwi bwi-cog bwi-lg" aria-hidden="true"></i>
{{ "settings" | i18n }}
</button>
</div>
<div id="login-page" class="page-top-padding">
<form
id="login-page"
#form
@ -19,7 +7,7 @@
[formGroup]="formGroup"
attr.aria-hidden="{{ showingModal }}"
>
<div id="content" class="content">
<div id="content" class="content" style="padding-top: 50px">
<img class="logo-image" alt="Bitwarden" />
<p class="lead">{{ "loginOrCreateNewAccount" | i18n }}</p>
<!-- start email -->
@ -37,9 +25,7 @@
/>
</div>
</div>
<div class="box-footer" *ngIf="selfHostedDomain">
{{ "loggingInTo" | i18n : selfHostedDomain }}
</div>
<environment-selector></environment-selector>
</div>
<div class="checkbox remember-email">
<label for="rememberEmail">

View File

@ -1,7 +1,9 @@
import { Component, NgZone, OnDestroy, ViewChild, ViewContainerRef } from "@angular/core";
import { FormBuilder } from "@angular/forms";
import { ActivatedRoute, Router } from "@angular/router";
import { Subject, takeUntil } from "rxjs";
import { EnvironmentSelectorComponent } from "@bitwarden/angular/auth/components/environment-selector.component";
import { LoginComponent as BaseLoginComponent } from "@bitwarden/angular/auth/components/login.component";
import { ModalService } from "@bitwarden/angular/services/modal.service";
import { ApiService } from "@bitwarden/common/abstractions/api.service";
@ -31,7 +33,10 @@ const BroadcasterSubscriptionId = "LoginComponent";
export class LoginComponent extends BaseLoginComponent implements OnDestroy {
@ViewChild("environment", { read: ViewContainerRef, static: true })
environmentModal: ViewContainerRef;
@ViewChild(EnvironmentSelectorComponent)
environmentSelector!: EnvironmentSelectorComponent;
protected componentDestroyed$: Subject<void> = new Subject();
webVaultHostname = "";
showingModal = false;
@ -116,10 +121,17 @@ export class LoginComponent extends BaseLoginComponent implements OnDestroy {
});
});
this.messagingService.send("getWindowIsFocused");
this.environmentSelector.onOpenSelfHostedSettings
.pipe(takeUntil(this.componentDestroyed$))
.subscribe(() => {
this.settings();
});
}
ngOnDestroy() {
this.broadcasterService.unsubscribe(BroadcasterSubscriptionId);
this.componentDestroyed$.next();
this.componentDestroyed$.complete();
}
async settings() {
@ -128,17 +140,16 @@ export class LoginComponent extends BaseLoginComponent implements OnDestroy {
this.environmentModal
);
// eslint-disable-next-line rxjs-angular/prefer-takeuntil
modal.onShown.subscribe(() => {
modal.onShown.pipe(takeUntil(this.componentDestroyed$)).subscribe(() => {
this.showingModal = true;
});
// eslint-disable-next-line rxjs-angular/prefer-takeuntil
modal.onClosed.subscribe(() => {
modal.onClosed.pipe(takeUntil(this.componentDestroyed$)).subscribe(() => {
this.showingModal = false;
});
// eslint-disable-next-line rxjs-angular/prefer-takeuntil, rxjs/no-async-subscribe
childComponent.onSaved.subscribe(async () => {
// eslint-disable-next-line rxjs/no-async-subscribe
childComponent.onSaved.pipe(takeUntil(this.componentDestroyed$)).subscribe(async () => {
modal.close();
await this.checkSelfHosted();
});

View File

@ -1,6 +1,8 @@
import { NgModule } from "@angular/core";
import { RouterModule } from "@angular/router";
import { EnvironmentSelectorComponent } from "@bitwarden/angular/auth/components/environment-selector.component";
import { SharedModule } from "../../app/shared/shared.module";
import { LoginWithDeviceComponent } from "./login-with-device.component";
@ -8,7 +10,7 @@ import { LoginComponent } from "./login.component";
@NgModule({
imports: [SharedModule, RouterModule],
declarations: [LoginComponent, LoginWithDeviceComponent],
declarations: [LoginComponent, LoginWithDeviceComponent, EnvironmentSelectorComponent],
exports: [LoginComponent, LoginWithDeviceComponent],
})
export class LoginModule {}

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

View File

@ -2251,5 +2251,19 @@
},
"windowsBiometricUpdateWarningTitle": {
"message": "Recommended Settings Update"
},
"region": {
"message": "Region"
},
"eu": {
"message": "EU",
"description": "European Union"
},
"us": {
"message": "US",
"description": "United States"
},
"selfHosted": {
"message": "Self-hosted"
}
}

View File

@ -38,3 +38,63 @@
padding-top: 0;
}
}
.environment-selector-btn {
font-size: $font-size-small;
color: $text-muted;
line-height: 25px;
font-weight: 400;
padding-left: 5px;
label {
font-weight: 600;
}
a,
a label:hover {
cursor: pointer;
}
}
.environment-selector-dialog {
@include themify($themes) {
background-color: themed("boxBackgroundColor");
}
padding: 5px;
width: 100%;
box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 3px 1px -2px rgba(0, 0, 0, 0.12),
0 1px 5px 0 rgba(0, 0, 0, 0.2);
border-radius: $border-radius;
}
.environment-selector-dialog-item {
@include themify($themes) {
color: themed("textColor") !important;
}
width: 100%;
text-align: left;
padding: 0px 15px 0px 5px;
border-radius: 3px;
border: 1px solid transparent;
transition: all 0.2s ease-in-out;
&:hover {
@include themify($themes) {
background-color: themed("listItemBackgroundHoverColor") !important;
}
}
img {
margin-bottom: -2px;
width: 22px;
height: 14px;
}
.img-us {
content: url("../images/us-flag.png");
}
.img-eu {
content: url("../images/eu-flag.png");
}
}

View File

@ -421,6 +421,10 @@ app-root > #loading,
}
}
.page-top-padding {
padding-top: 50px;
}
.logo-image {
@include themify($themes) {
content: url("../images/logo-" + themed("logoSuffix") + "@2x.png");

View File

@ -1,5 +1,34 @@
<router-outlet></router-outlet>
<div class="container my-5 text-muted text-center">
<div class="tw-mb-1">
<bit-menu #environmentOptions>
<a bitMenuItem href="https://vault.bitwarden.com" class="pr-4">
<i
class="bwi bwi-fw bwi-sm bwi-check pb-1"
aria-hidden="true"
[style.visibility]="isEuServer ? 'hidden' : 'visible'"
></i>
<img src="../../images/us_flag.png" alt="" class="pb-1 mr-1" />
{{ "us" | i18n }}
</a>
<a bitMenuItem href="https://vault.bitwarden.eu" class="pr-4" *ngIf="euServerFlagEnabled">
<i
class="bwi bwi-fw bwi-sm bwi-check pb-1"
aria-hidden="true"
[style.visibility]="isEuServer ? 'visible' : 'hidden'"
></i>
<img src="../../images/eu_flag.png" alt="" class="pb-1 mr-1" />
{{ "eu" | i18n }}
</a>
</bit-menu>
{{ "region" | i18n }}:
<a [routerLink]="[]" [bitMenuTriggerFor]="environmentOptions">
<b>{{ isEuServer ? ("eu" | i18n) : ("us" | i18n) }}</b
><i class="bwi bwi-fw bwi-sm bwi-angle-down" aria-hidden="true"></i>
</a>
<br />
</div>
&copy; {{ year }} Bitwarden Inc. <br />
{{ "versionNumber" | i18n : version }}
</div>

View File

@ -1,6 +1,9 @@
import { Component, OnDestroy, OnInit } from "@angular/core";
import { ConfigServiceAbstraction } from "@bitwarden/common/abstractions/config/config.service.abstraction";
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
import { Utils } from "@bitwarden/common/misc/utils";
@Component({
selector: "app-frontend-layout",
@ -9,12 +12,22 @@ import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUti
export class FrontendLayoutComponent implements OnInit, OnDestroy {
version: string;
year = "2015";
isEuServer = true;
euServerFlagEnabled: boolean;
constructor(private platformUtilsService: PlatformUtilsService) {}
constructor(
private platformUtilsService: PlatformUtilsService,
private configService: ConfigServiceAbstraction
) {}
async ngOnInit() {
this.year = new Date().getFullYear().toString();
this.version = await this.platformUtilsService.getApplicationVersion();
this.euServerFlagEnabled = await this.configService.getFeatureFlagBool(
FeatureFlag.DisplayEuEnvironmentFlag
);
this.isEuServer = Utils.getDomain(window.location.href).includes(".eu");
document.body.classList.add("layout_frontend");
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

View File

@ -6789,6 +6789,17 @@
"enforceOnLoginDesc": {
"message": "Require existing members to change their passwords"
},
"region": {
"message": "Region"
},
"eu": {
"message": "EU",
"description": "European Union"
},
"us": {
"message": "US",
"description": "United States"
},
"smProjectDeleteAccessRestricted": {
"message": "You don't have permissions to delete this project",
"description": "The individual description shown to the user when the user doesn't have access to delete a project."

View File

@ -0,0 +1,86 @@
<label class="environment-selector-btn">
{{ "region" | i18n }}:
<a
(click)="toggle(null)"
cdkOverlayOrigin
#trigger="cdkOverlayOrigin"
aria-haspopup="menu"
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.SelfHosted" class="text-primary">{{
"selfHosted" | i18n
}}</label>
<i class="bwi bwi-fw bwi-sm bwi-angle-down" aria-hidden="true"></i>
</a>
</label>
<ng-template
cdkConnectedOverlay
[cdkConnectedOverlayOrigin]="trigger"
(backdropClick)="close()"
(detach)="close()"
[cdkConnectedOverlayOpen]="isOpen"
[cdkConnectedOverlayPositions]="overlayPostition"
>
<div class="box-content">
<div class="environment-selector-dialog" [@transformPanel]="'open'" role="dialog">
<button
type="button"
class="environment-selector-dialog-item"
(click)="toggle(ServerEnvironmentType.US)"
>
<i
class="bwi bwi-fw bwi-sm bwi-check"
style="padding-bottom: 1px"
aria-hidden="true"
[style.visibility]="
selectedEnvironment === ServerEnvironmentType.US ? 'visible' : 'hidden'
"
></i>
<img class="img-us" alt="" />
<span>{{ "us" | i18n }}</span>
</button>
<br />
<button
type="button"
class="environment-selector-dialog-item"
(click)="toggle(ServerEnvironmentType.EU)"
>
<i
class="bwi bwi-fw bwi-sm bwi-check"
style="padding-bottom: 1px"
aria-hidden="true"
[style.visibility]="
selectedEnvironment === ServerEnvironmentType.EU ? 'visible' : 'hidden'
"
></i>
<img class="img-eu" alt="" />
<span>{{ "eu" | i18n }}</span>
</button>
<br />
<button
type="button"
class="environment-selector-dialog-item"
(click)="toggle(ServerEnvironmentType.SelfHosted)"
>
<i
class="bwi bwi-fw bwi-sm bwi-check"
style="padding-bottom: 1px"
aria-hidden="true"
[style.visibility]="
selectedEnvironment === ServerEnvironmentType.SelfHosted ? 'visible' : 'hidden'
"
></i>
<i
class="bwi bwi-fw bwi-sm bwi-pencil-square"
style="padding-bottom: 1px"
aria-hidden="true"
></i>
<span>{{ "selfHosted" | i18n }}</span>
</button>
</div>
</div>
</ng-template>

View File

@ -0,0 +1,103 @@
import { animate, state, style, transition, trigger } from "@angular/animations";
import { ConnectedPosition } from "@angular/cdk/overlay";
import { Component, EventEmitter, OnDestroy, OnInit, Output } from "@angular/core";
import { Router } from "@angular/router";
import { Subject } from "rxjs";
import { ConfigServiceAbstraction } from "@bitwarden/common/abstractions/config/config.service.abstraction";
import { EnvironmentService } from "@bitwarden/common/abstractions/environment.service";
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
@Component({
selector: "environment-selector",
templateUrl: "environment-selector.component.html",
animations: [
trigger("transformPanel", [
state(
"void",
style({
opacity: 0,
})
),
transition(
"void => open",
animate(
"100ms linear",
style({
opacity: 1,
})
)
),
transition("* => void", animate("100ms linear", style({ opacity: 0 }))),
]),
],
})
export class EnvironmentSelectorComponent implements OnInit, OnDestroy {
@Output() onOpenSelfHostedSettings = new EventEmitter();
isOpen = false;
showingModal = false;
selectedEnvironment: ServerEnvironment;
ServerEnvironmentType = ServerEnvironment;
euServerFlagEnabled: boolean;
overlayPostition: ConnectedPosition[] = [
{
originX: "start",
originY: "bottom",
overlayX: "start",
overlayY: "top",
},
];
protected componentDestroyed$: Subject<void> = new Subject();
constructor(
protected environmentService: EnvironmentService,
protected configService: ConfigServiceAbstraction,
protected router: Router
) {}
async ngOnInit() {
this.euServerFlagEnabled = await this.configService.getFeatureFlagBool(
FeatureFlag.DisplayEuEnvironmentFlag
);
this.updateEnvironmentInfo();
}
ngOnDestroy(): void {
this.componentDestroyed$.next();
this.componentDestroyed$.complete();
}
async toggle(option: ServerEnvironment) {
this.isOpen = !this.isOpen;
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.onOpenSelfHostedSettings.emit();
}
this.updateEnvironmentInfo();
}
updateEnvironmentInfo() {
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() {
this.isOpen = false;
this.updateEnvironmentInfo();
}
}
enum ServerEnvironment {
US = "US",
EU = "EU",
SelfHosted = "Self-hosted",
}

View File

@ -4,6 +4,8 @@ import { EnvironmentService } from "@bitwarden/common/abstractions/environment.s
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
import { ModalService } from "../services/modal.service";
@Directive()
export class EnvironmentComponent {
@Output() onSaved = new EventEmitter();
@ -19,7 +21,8 @@ export class EnvironmentComponent {
constructor(
protected platformUtilsService: PlatformUtilsService,
protected environmentService: EnvironmentService,
protected i18nService: I18nService
protected i18nService: I18nService,
private modalService: ModalService
) {
const urls = this.environmentService.getUrls();
@ -59,5 +62,6 @@ export class EnvironmentComponent {
protected saved() {
this.onSaved.emit();
this.modalService.closeAll();
}
}

View File

@ -218,6 +218,8 @@ export class EnvironmentService implements EnvironmentServiceAbstraction {
return ![
"http://vault.bitwarden.com",
"https://vault.bitwarden.com",
"http://vault.bitwarden.eu",
"https://vault.bitwarden.eu",
"http://vault.qa.bitwarden.pw",
"https://vault.qa.bitwarden.pw",
].includes(this.getWebVaultUrl());