mirror of
https://github.com/bitwarden/browser
synced 2025-12-14 07:13:32 +00:00
[PM-5979] Refactor EnvironmentService (#8040)
Refactor environment service to emit a single observable. This required significant changes to how the environment service behaves and tackles much of the tech debt planned for it.
This commit is contained in:
@@ -2386,12 +2386,6 @@
|
||||
"message": "EU",
|
||||
"description": "European Union"
|
||||
},
|
||||
"usDomain": {
|
||||
"message": "bitwarden.com"
|
||||
},
|
||||
"euDomain": {
|
||||
"message": "bitwarden.eu"
|
||||
},
|
||||
"accessDenied": {
|
||||
"message": "Access denied. You do not have permission to view this page."
|
||||
},
|
||||
|
||||
@@ -65,7 +65,7 @@ export class AccountSwitcherService {
|
||||
name: account.name ?? account.email,
|
||||
email: account.email,
|
||||
id: id,
|
||||
server: await this.environmentService.getHost(id),
|
||||
server: (await this.environmentService.getEnvironment(id))?.getHostname(),
|
||||
status: account.status,
|
||||
isActive: id === activeAccount?.id,
|
||||
avatarColor: await firstValueFrom(
|
||||
|
||||
@@ -94,10 +94,6 @@ export class HomeComponent implements OnInit, OnDestroy {
|
||||
this.router.navigate(["login"], { queryParams: { email: this.formGroup.value.email } });
|
||||
}
|
||||
|
||||
get selfHostedDomain() {
|
||||
return this.environmentService.hasBaseUrl() ? this.environmentService.getWebVaultUrl() : null;
|
||||
}
|
||||
|
||||
setFormValues() {
|
||||
this.loginService.setEmail(this.formGroup.value.email);
|
||||
this.loginService.setRememberEmail(this.formGroup.value.rememberEmail);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { Component, NgZone } from "@angular/core";
|
||||
import { FormBuilder } from "@angular/forms";
|
||||
import { ActivatedRoute, Router } from "@angular/router";
|
||||
import { firstValueFrom } from "rxjs";
|
||||
|
||||
import { LoginComponent as BaseLoginComponent } from "@bitwarden/angular/auth/components/login.component";
|
||||
import { FormValidationErrorsService } from "@bitwarden/angular/platform/abstractions/form-validation-errors.service";
|
||||
@@ -114,7 +115,8 @@ export class LoginComponent extends BaseLoginComponent {
|
||||
await this.ssoLoginService.setCodeVerifier(codeVerifier);
|
||||
await this.ssoLoginService.setSsoState(state);
|
||||
|
||||
let url = this.environmentService.getWebVaultUrl();
|
||||
const env = await firstValueFrom(this.environmentService.environment$);
|
||||
let url = env.getWebVaultUrl();
|
||||
if (url == null) {
|
||||
url = "https://vault.bitwarden.com";
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { Component, Inject } from "@angular/core";
|
||||
import { takeUntilDestroyed } from "@angular/core/rxjs-interop";
|
||||
import { ActivatedRoute, Router } from "@angular/router";
|
||||
|
||||
import { SsoComponent as BaseSsoComponent } from "@bitwarden/angular/auth/components/sso.component";
|
||||
@@ -64,9 +65,9 @@ export class SsoComponent extends BaseSsoComponent {
|
||||
configService,
|
||||
);
|
||||
|
||||
const url = this.environmentService.getWebVaultUrl();
|
||||
|
||||
this.redirectUri = url + "/sso-connector.html";
|
||||
environmentService.environment$.pipe(takeUntilDestroyed()).subscribe((env) => {
|
||||
this.redirectUri = env.getWebVaultUrl() + "/sso-connector.html";
|
||||
});
|
||||
this.clientId = "browser";
|
||||
|
||||
super.onSuccessfulLogin = async () => {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Component, Inject } from "@angular/core";
|
||||
import { ActivatedRoute, Router } from "@angular/router";
|
||||
import { Subject, Subscription } from "rxjs";
|
||||
import { Subject, Subscription, firstValueFrom } from "rxjs";
|
||||
import { filter, first, takeUntil } from "rxjs/operators";
|
||||
|
||||
import { TwoFactorComponent as BaseTwoFactorComponent } from "@bitwarden/angular/auth/components/two-factor.component";
|
||||
@@ -225,7 +225,7 @@ export class TwoFactorComponent extends BaseTwoFactorComponent {
|
||||
}
|
||||
}
|
||||
|
||||
override launchDuoFrameless() {
|
||||
override async launchDuoFrameless() {
|
||||
const duoHandOffMessage = {
|
||||
title: this.i18nService.t("youSuccessfullyLoggedIn"),
|
||||
message: this.i18nService.t("youMayCloseThisWindow"),
|
||||
@@ -234,8 +234,9 @@ export class TwoFactorComponent extends BaseTwoFactorComponent {
|
||||
|
||||
// we're using the connector here as a way to set a cookie with translations
|
||||
// before continuing to the duo frameless url
|
||||
const env = await firstValueFrom(this.environmentService.environment$);
|
||||
const launchUrl =
|
||||
this.environmentService.getWebVaultUrl() +
|
||||
env.getWebVaultUrl() +
|
||||
"/duo-redirect-connector.html" +
|
||||
"?duoFramelessUrl=" +
|
||||
encodeURIComponent(this.duoFramelessUrl) +
|
||||
|
||||
@@ -113,7 +113,7 @@ type NotificationBackgroundExtensionMessageHandlers = {
|
||||
bgGetEnableChangedPasswordPrompt: () => Promise<boolean>;
|
||||
bgGetEnableAddedLoginPrompt: () => Promise<boolean>;
|
||||
bgGetExcludedDomains: () => Promise<NeverDomains>;
|
||||
getWebVaultUrlForNotification: () => string;
|
||||
getWebVaultUrlForNotification: () => Promise<string>;
|
||||
};
|
||||
|
||||
export {
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
import { mock } from "jest-mock-extended";
|
||||
import { firstValueFrom } from "rxjs";
|
||||
import { BehaviorSubject, firstValueFrom } from "rxjs";
|
||||
|
||||
import { PolicyService } from "@bitwarden/common/admin-console/services/policy/policy.service";
|
||||
import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status";
|
||||
import { AuthService } from "@bitwarden/common/auth/services/auth.service";
|
||||
import { DomainSettingsService } from "@bitwarden/common/autofill/services/domain-settings.service";
|
||||
import { UserNotificationSettingsService } from "@bitwarden/common/autofill/services/user-notification-settings.service";
|
||||
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service";
|
||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||
import { EnvironmentService } from "@bitwarden/common/platform/services/environment.service";
|
||||
import { SelfHostedEnvironment } from "@bitwarden/common/platform/services/default-environment.service";
|
||||
import { ThemeStateService } from "@bitwarden/common/platform/theming/theme-state.service";
|
||||
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
||||
import { FolderView } from "@bitwarden/common/vault/models/view/folder.view";
|
||||
@@ -1348,16 +1349,21 @@ describe("NotificationBackground", () => {
|
||||
const message: NotificationBackgroundExtensionMessage = {
|
||||
command: "getWebVaultUrlForNotification",
|
||||
};
|
||||
const webVaultUrl = "https://example.com";
|
||||
const env = new SelfHostedEnvironment({ webVault: "https://example.com" });
|
||||
|
||||
Object.defineProperty(environmentService, "environment$", {
|
||||
configurable: true,
|
||||
get: () => null,
|
||||
});
|
||||
|
||||
const environmentServiceSpy = jest
|
||||
.spyOn(environmentService, "getWebVaultUrl")
|
||||
.mockReturnValueOnce(webVaultUrl);
|
||||
.spyOn(environmentService as any, "environment$", "get")
|
||||
.mockReturnValue(new BehaviorSubject(env).asObservable());
|
||||
|
||||
sendExtensionRuntimeMessage(message);
|
||||
await flushPromises();
|
||||
|
||||
expect(environmentServiceSpy).toHaveBeenCalled();
|
||||
expect(environmentServiceSpy).toHaveReturnedWith(webVaultUrl);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -165,6 +165,7 @@ export default class NotificationBackground {
|
||||
notificationQueueMessage: NotificationQueueMessageItem,
|
||||
) {
|
||||
const notificationType = notificationQueueMessage.type;
|
||||
|
||||
const typeData: Record<string, any> = {
|
||||
isVaultLocked: notificationQueueMessage.wasVaultLocked,
|
||||
theme: await firstValueFrom(this.themeStateService.selectedTheme$),
|
||||
@@ -655,8 +656,9 @@ export default class NotificationBackground {
|
||||
return await firstValueFrom(this.folderService.folderViews$);
|
||||
}
|
||||
|
||||
private getWebVaultUrl(): string {
|
||||
return this.environmentService.getWebVaultUrl();
|
||||
private async getWebVaultUrl(): Promise<string> {
|
||||
const env = await firstValueFrom(this.environmentService.environment$);
|
||||
return env.getWebVaultUrl();
|
||||
}
|
||||
|
||||
private async removeIndividualVault(): Promise<boolean> {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { mock, mockReset } from "jest-mock-extended";
|
||||
import { of } from "rxjs";
|
||||
import { BehaviorSubject, of } from "rxjs";
|
||||
|
||||
import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status";
|
||||
import { AuthService } from "@bitwarden/common/auth/services/auth.service";
|
||||
@@ -12,9 +12,13 @@ import {
|
||||
DefaultDomainSettingsService,
|
||||
DomainSettingsService,
|
||||
} from "@bitwarden/common/autofill/services/domain-settings.service";
|
||||
import {
|
||||
EnvironmentService,
|
||||
Region,
|
||||
} from "@bitwarden/common/platform/abstractions/environment.service";
|
||||
import { ThemeType } from "@bitwarden/common/platform/enums";
|
||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||
import { EnvironmentService } from "@bitwarden/common/platform/services/environment.service";
|
||||
import { CloudEnvironment } from "@bitwarden/common/platform/services/default-environment.service";
|
||||
import { I18nService } from "@bitwarden/common/platform/services/i18n.service";
|
||||
import { ThemeStateService } from "@bitwarden/common/platform/theming/theme-state.service";
|
||||
import {
|
||||
@@ -48,8 +52,6 @@ import {
|
||||
|
||||
import OverlayBackground from "./overlay.background";
|
||||
|
||||
const iconServerUrl = "https://icons.bitwarden.com/";
|
||||
|
||||
describe("OverlayBackground", () => {
|
||||
const mockUserId = Utils.newGuid() as UserId;
|
||||
const accountService: FakeAccountService = mockAccountServiceWith(mockUserId);
|
||||
@@ -61,9 +63,15 @@ describe("OverlayBackground", () => {
|
||||
const cipherService = mock<CipherService>();
|
||||
const autofillService = mock<AutofillService>();
|
||||
const authService = mock<AuthService>();
|
||||
const environmentService = mock<EnvironmentService>({
|
||||
getIconsUrl: () => iconServerUrl,
|
||||
});
|
||||
|
||||
const environmentService = mock<EnvironmentService>();
|
||||
environmentService.environment$ = new BehaviorSubject(
|
||||
new CloudEnvironment({
|
||||
key: Region.US,
|
||||
domain: "bitwarden.com",
|
||||
urls: { icons: "https://icons.bitwarden.com/" },
|
||||
}),
|
||||
);
|
||||
const stateService = mock<BrowserStateService>();
|
||||
const autofillSettingsService = mock<AutofillSettingsService>();
|
||||
const i18nService = mock<I18nService>();
|
||||
|
||||
@@ -53,7 +53,7 @@ class OverlayBackground implements OverlayBackgroundInterface {
|
||||
private overlayListPort: chrome.runtime.Port;
|
||||
private focusedFieldData: FocusedFieldData;
|
||||
private overlayPageTranslations: Record<string, string>;
|
||||
private readonly iconsServerUrl: string;
|
||||
private iconsServerUrl: string;
|
||||
private readonly extensionMessageHandlers: OverlayBackgroundExtensionMessageHandlers = {
|
||||
openAutofillOverlay: () => this.openOverlay(false),
|
||||
autofillOverlayElementClosed: ({ message }) => this.overlayElementClosed(message),
|
||||
@@ -98,9 +98,7 @@ class OverlayBackground implements OverlayBackgroundInterface {
|
||||
private i18nService: I18nService,
|
||||
private platformUtilsService: PlatformUtilsService,
|
||||
private themeStateService: ThemeStateService,
|
||||
) {
|
||||
this.iconsServerUrl = this.environmentService.getIconsUrl();
|
||||
}
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Removes cached page details for a tab
|
||||
@@ -118,6 +116,8 @@ class OverlayBackground implements OverlayBackgroundInterface {
|
||||
*/
|
||||
async init() {
|
||||
this.setupExtensionMessageListeners();
|
||||
const env = await firstValueFrom(this.environmentService.environment$);
|
||||
this.iconsServerUrl = env.getIconsUrl();
|
||||
await this.getOverlayVisibility();
|
||||
await this.getAuthStatus();
|
||||
}
|
||||
|
||||
@@ -613,6 +613,7 @@ export default class MainBackground {
|
||||
this.authService,
|
||||
this.environmentService,
|
||||
this.logService,
|
||||
this.stateProvider,
|
||||
true,
|
||||
);
|
||||
|
||||
@@ -1032,10 +1033,6 @@ export default class MainBackground {
|
||||
|
||||
return new Promise<void>((resolve) => {
|
||||
setTimeout(async () => {
|
||||
await this.environmentService.setUrlsFromStorage();
|
||||
// Workaround to ignore stateService.activeAccount until URLs are set
|
||||
// TODO: Remove this when implementing ticket PM-2637
|
||||
this.environmentService.initialized = true;
|
||||
if (!this.isPrivateMode) {
|
||||
await this.refreshBadge();
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { firstValueFrom } from "rxjs";
|
||||
|
||||
import { NotificationsService } from "@bitwarden/common/abstractions/notifications.service";
|
||||
import { AutofillOverlayVisibility } from "@bitwarden/common/autofill/constants";
|
||||
import { AutofillSettingsServiceAbstraction } from "@bitwarden/common/autofill/services/autofill-settings.service";
|
||||
@@ -220,7 +222,8 @@ export default class RuntimeBackground {
|
||||
}
|
||||
break;
|
||||
case "authResult": {
|
||||
const vaultUrl = this.environmentService.getWebVaultUrl();
|
||||
const env = await firstValueFrom(this.environmentService.environment$);
|
||||
const vaultUrl = env.getWebVaultUrl();
|
||||
|
||||
if (msg.referrer == null || Utils.getHostname(vaultUrl) !== msg.referrer) {
|
||||
return;
|
||||
@@ -241,7 +244,8 @@ export default class RuntimeBackground {
|
||||
break;
|
||||
}
|
||||
case "webAuthnResult": {
|
||||
const vaultUrl = this.environmentService.getWebVaultUrl();
|
||||
const env = await firstValueFrom(this.environmentService.environment$);
|
||||
const vaultUrl = env.getWebVaultUrl();
|
||||
|
||||
if (msg.referrer == null || Utils.getHostname(vaultUrl) !== msg.referrer) {
|
||||
return;
|
||||
@@ -364,7 +368,8 @@ export default class RuntimeBackground {
|
||||
|
||||
async sendBwInstalledMessageToVault() {
|
||||
try {
|
||||
const vaultUrl = this.environmentService.getWebVaultUrl();
|
||||
const env = await firstValueFrom(this.environmentService.environment$);
|
||||
const vaultUrl = env.getWebVaultUrl();
|
||||
const urlObj = new URL(vaultUrl);
|
||||
|
||||
const tabs = await BrowserApi.tabsQuery({ url: `${urlObj.href}*` });
|
||||
|
||||
@@ -13,6 +13,7 @@ import {
|
||||
} from "./environment-service.factory";
|
||||
import { FactoryOptions, CachedServices, factory } from "./factory-options";
|
||||
import { logServiceFactory, LogServiceInitOptions } from "./log-service.factory";
|
||||
import { stateProviderFactory } from "./state-provider.factory";
|
||||
import { stateServiceFactory, StateServiceInitOptions } from "./state-service.factory";
|
||||
|
||||
type ConfigServiceFactoryOptions = FactoryOptions & {
|
||||
@@ -43,6 +44,7 @@ export function configServiceFactory(
|
||||
await authServiceFactory(cache, opts),
|
||||
await environmentServiceFactory(cache, opts),
|
||||
await logServiceFactory(cache, opts),
|
||||
await stateProviderFactory(cache, opts),
|
||||
opts.configServiceOptions?.subscribe ?? true,
|
||||
),
|
||||
);
|
||||
|
||||
@@ -7,6 +7,7 @@ import { EnvironmentService } from "@bitwarden/common/platform/abstractions/envi
|
||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
|
||||
import { ConfigService } from "@bitwarden/common/platform/services/config/config.service";
|
||||
import { StateProvider } from "@bitwarden/common/platform/state";
|
||||
|
||||
import { browserSession, sessionSync } from "../decorators/session-sync-observable";
|
||||
|
||||
@@ -21,8 +22,17 @@ export class BrowserConfigService extends ConfigService {
|
||||
authService: AuthService,
|
||||
environmentService: EnvironmentService,
|
||||
logService: LogService,
|
||||
stateProvider: StateProvider,
|
||||
subscribe = false,
|
||||
) {
|
||||
super(stateService, configApiService, authService, environmentService, logService, subscribe);
|
||||
super(
|
||||
stateService,
|
||||
configApiService,
|
||||
authService,
|
||||
environmentService,
|
||||
logService,
|
||||
stateProvider,
|
||||
subscribe,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
import { firstValueFrom } from "rxjs";
|
||||
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { Region } from "@bitwarden/common/platform/abstractions/environment.service";
|
||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||
import { EnvironmentService } from "@bitwarden/common/platform/services/environment.service";
|
||||
import { DefaultEnvironmentService } from "@bitwarden/common/platform/services/default-environment.service";
|
||||
import { StateProvider } from "@bitwarden/common/platform/state";
|
||||
|
||||
import { GroupPolicyEnvironment } from "../../admin-console/types/group-policy-environment";
|
||||
import { devFlagEnabled, devFlagValue } from "../flags";
|
||||
|
||||
export class BrowserEnvironmentService extends EnvironmentService {
|
||||
export class BrowserEnvironmentService extends DefaultEnvironmentService {
|
||||
constructor(
|
||||
private logService: LogService,
|
||||
stateProvider: StateProvider,
|
||||
@@ -29,16 +32,18 @@ export class BrowserEnvironmentService extends EnvironmentService {
|
||||
return false;
|
||||
}
|
||||
|
||||
const env = await this.getManagedEnvironment();
|
||||
const managedEnv = await this.getManagedEnvironment();
|
||||
const env = await firstValueFrom(this.environment$);
|
||||
const urls = env.getUrls();
|
||||
|
||||
return (
|
||||
env.base != this.baseUrl ||
|
||||
env.webVault != this.webVaultUrl ||
|
||||
env.api != this.webVaultUrl ||
|
||||
env.identity != this.identityUrl ||
|
||||
env.icons != this.iconsUrl ||
|
||||
env.notifications != this.notificationsUrl ||
|
||||
env.events != this.eventsUrl
|
||||
managedEnv.base != urls.base ||
|
||||
managedEnv.webVault != urls.webVault ||
|
||||
managedEnv.api != urls.api ||
|
||||
managedEnv.identity != urls.identity ||
|
||||
managedEnv.icons != urls.icons ||
|
||||
managedEnv.notifications != urls.notifications ||
|
||||
managedEnv.events != urls.events
|
||||
);
|
||||
}
|
||||
|
||||
@@ -62,7 +67,7 @@ export class BrowserEnvironmentService extends EnvironmentService {
|
||||
|
||||
async setUrlsToManagedEnvironment() {
|
||||
const env = await this.getManagedEnvironment();
|
||||
await this.setUrls({
|
||||
await this.setEnvironment(Region.SelfHosted, {
|
||||
base: env.base,
|
||||
webVault: env.webVault,
|
||||
api: env.api,
|
||||
|
||||
@@ -222,12 +222,12 @@ function getBgService<T>(service: keyof MainBackground) {
|
||||
},
|
||||
{
|
||||
provide: BrowserEnvironmentService,
|
||||
useExisting: EnvironmentService,
|
||||
useClass: BrowserEnvironmentService,
|
||||
deps: [LogService, StateProvider, AccountServiceAbstraction],
|
||||
},
|
||||
{
|
||||
provide: EnvironmentService,
|
||||
useFactory: getBgService<EnvironmentService>("environmentService"),
|
||||
deps: [],
|
||||
useExisting: BrowserEnvironmentService,
|
||||
},
|
||||
{ provide: TotpService, useFactory: getBgService<TotpService>("totpService"), deps: [] },
|
||||
{
|
||||
@@ -480,6 +480,7 @@ function getBgService<T>(service: keyof MainBackground) {
|
||||
ConfigApiServiceAbstraction,
|
||||
AuthServiceAbstraction,
|
||||
EnvironmentService,
|
||||
StateProvider,
|
||||
LogService,
|
||||
],
|
||||
},
|
||||
|
||||
@@ -6,33 +6,33 @@
|
||||
<div bitDialogContent>
|
||||
<p>© Bitwarden Inc. 2015-{{ year }}</p>
|
||||
<p>{{ "version" | i18n }}: {{ version }}</p>
|
||||
<ng-container *ngIf="serverConfig$ | async as serverConfig">
|
||||
<p *ngIf="isCloud">
|
||||
{{ "serverVersion" | i18n }}: {{ this.serverConfig?.version }}
|
||||
<span *ngIf="!serverConfig.isValid()">
|
||||
({{ "lastSeenOn" | i18n: (serverConfig.utcDate | date: "mediumDate") }})
|
||||
<ng-container *ngIf="data$ | async as data">
|
||||
<p *ngIf="data.isCloud">
|
||||
{{ "serverVersion" | i18n }}: {{ data.serverConfig?.version }}
|
||||
<span *ngIf="!data.serverConfig.isValid()">
|
||||
({{ "lastSeenOn" | i18n: (data.serverConfig.utcDate | date: "mediumDate") }})
|
||||
</span>
|
||||
</p>
|
||||
|
||||
<ng-container *ngIf="!isCloud">
|
||||
<ng-container *ngIf="serverConfig.server">
|
||||
<ng-container *ngIf="!data.isCloud">
|
||||
<ng-container *ngIf="data.serverConfig.server">
|
||||
<p>
|
||||
{{ "serverVersion" | i18n }} <small>({{ "thirdParty" | i18n }})</small>:
|
||||
{{ this.serverConfig?.version }}
|
||||
<span *ngIf="!serverConfig.isValid()">
|
||||
({{ "lastSeenOn" | i18n: (serverConfig.utcDate | date: "mediumDate") }})
|
||||
{{ data.serverConfig?.version }}
|
||||
<span *ngIf="!data.serverConfig.isValid()">
|
||||
({{ "lastSeenOn" | i18n: (data.serverConfig.utcDate | date: "mediumDate") }})
|
||||
</span>
|
||||
</p>
|
||||
<div>
|
||||
<small>{{ "thirdPartyServerMessage" | i18n: serverConfig.server?.name }}</small>
|
||||
<small>{{ "thirdPartyServerMessage" | i18n: data.serverConfig.server?.name }}</small>
|
||||
</div>
|
||||
</ng-container>
|
||||
|
||||
<p *ngIf="!serverConfig.server">
|
||||
<p *ngIf="!data.serverConfig.server">
|
||||
{{ "serverVersion" | i18n }} <small>({{ "selfHostedServer" | i18n }})</small>:
|
||||
{{ this.serverConfig?.version }}
|
||||
<span *ngIf="!serverConfig.isValid()">
|
||||
({{ "lastSeenOn" | i18n: (serverConfig.utcDate | date: "mediumDate") }})
|
||||
{{ data.serverConfig?.version }}
|
||||
<span *ngIf="!data.serverConfig.isValid()">
|
||||
({{ "lastSeenOn" | i18n: (data.serverConfig.utcDate | date: "mediumDate") }})
|
||||
</span>
|
||||
</p>
|
||||
</ng-container>
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
import { CommonModule } from "@angular/common";
|
||||
import { Component } from "@angular/core";
|
||||
import { Observable } from "rxjs";
|
||||
import { combineLatest, map } from "rxjs";
|
||||
|
||||
import { JslibModule } from "@bitwarden/angular/jslib.module";
|
||||
import { ConfigServiceAbstraction } from "@bitwarden/common/platform/abstractions/config/config.service.abstraction";
|
||||
import { ServerConfig } from "@bitwarden/common/platform/abstractions/config/server-config";
|
||||
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service";
|
||||
import { ButtonModule, DialogModule } from "@bitwarden/components";
|
||||
|
||||
@@ -16,11 +15,13 @@ import { BrowserApi } from "../../platform/browser/browser-api";
|
||||
imports: [CommonModule, JslibModule, DialogModule, ButtonModule],
|
||||
})
|
||||
export class AboutComponent {
|
||||
protected serverConfig$: Observable<ServerConfig> = this.configService.serverConfig$;
|
||||
|
||||
protected year = new Date().getFullYear();
|
||||
protected version = BrowserApi.getApplicationVersion();
|
||||
protected isCloud = this.environmentService.isCloud();
|
||||
|
||||
protected data$ = combineLatest([
|
||||
this.configService.serverConfig$,
|
||||
this.environmentService.environment$.pipe(map((env) => env.isCloud())),
|
||||
]).pipe(map(([serverConfig, isCloud]) => ({ serverConfig, isCloud })));
|
||||
|
||||
constructor(
|
||||
private configService: ConfigServiceAbstraction,
|
||||
|
||||
@@ -446,9 +446,8 @@ export class SettingsComponent implements OnInit {
|
||||
type: "info",
|
||||
});
|
||||
if (confirmed) {
|
||||
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
BrowserApi.createNewTab(this.environmentService.getWebVaultUrl());
|
||||
const env = await firstValueFrom(this.environmentService.environment$);
|
||||
await BrowserApi.createNewTab(env.getWebVaultUrl());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -479,10 +478,9 @@ export class SettingsComponent implements OnInit {
|
||||
}
|
||||
|
||||
async webVault() {
|
||||
const url = this.environmentService.getWebVaultUrl();
|
||||
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
BrowserApi.createNewTab(url);
|
||||
const env = await firstValueFrom(this.environmentService.environment$);
|
||||
const url = env.getWebVaultUrl();
|
||||
await BrowserApi.createNewTab(url);
|
||||
}
|
||||
|
||||
async import() {
|
||||
|
||||
@@ -690,6 +690,8 @@ export class LoginCommand {
|
||||
codeChallenge: string,
|
||||
state: string,
|
||||
): Promise<{ ssoCode: string; orgIdentifier: string }> {
|
||||
const env = await firstValueFrom(this.environmentService.environment$);
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
const callbackServer = http.createServer((req, res) => {
|
||||
const urlString = "http://localhost" + req.url;
|
||||
@@ -724,7 +726,7 @@ export class LoginCommand {
|
||||
}
|
||||
});
|
||||
let foundPort = false;
|
||||
const webUrl = this.environmentService.getWebVaultUrl();
|
||||
const webUrl = env.getWebVaultUrl();
|
||||
for (let port = 8065; port <= 8070; port++) {
|
||||
try {
|
||||
this.ssoRedirectUri = "http://localhost:" + port;
|
||||
|
||||
@@ -47,6 +47,7 @@ import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abs
|
||||
import { DefaultBillingAccountProfileStateService } from "@bitwarden/common/billing/services/account/billing-account-profile-state.service";
|
||||
import { ClientType } from "@bitwarden/common/enums";
|
||||
import { ConfigApiServiceAbstraction } from "@bitwarden/common/platform/abstractions/config/config-api.service.abstraction";
|
||||
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service";
|
||||
import { KeyGenerationService as KeyGenerationServiceAbstraction } from "@bitwarden/common/platform/abstractions/key-generation.service";
|
||||
import {
|
||||
BiometricStateService,
|
||||
@@ -62,7 +63,7 @@ import { ConfigApiService } from "@bitwarden/common/platform/services/config/con
|
||||
import { ContainerService } from "@bitwarden/common/platform/services/container.service";
|
||||
import { CryptoService } from "@bitwarden/common/platform/services/crypto.service";
|
||||
import { EncryptServiceImplementation } from "@bitwarden/common/platform/services/cryptography/encrypt.service.implementation";
|
||||
import { EnvironmentService } from "@bitwarden/common/platform/services/environment.service";
|
||||
import { DefaultEnvironmentService } from "@bitwarden/common/platform/services/default-environment.service";
|
||||
import { FileUploadService } from "@bitwarden/common/platform/services/file-upload/file-upload.service";
|
||||
import { KeyGenerationService } from "@bitwarden/common/platform/services/key-generation.service";
|
||||
import { MemoryStorageService } from "@bitwarden/common/platform/services/memory-storage.service";
|
||||
@@ -312,7 +313,10 @@ export class Main {
|
||||
this.derivedStateProvider,
|
||||
);
|
||||
|
||||
this.environmentService = new EnvironmentService(this.stateProvider, this.accountService);
|
||||
this.environmentService = new DefaultEnvironmentService(
|
||||
this.stateProvider,
|
||||
this.accountService,
|
||||
);
|
||||
|
||||
this.tokenService = new TokenService(
|
||||
this.singleUserStateProvider,
|
||||
@@ -504,6 +508,7 @@ export class Main {
|
||||
this.authService,
|
||||
this.environmentService,
|
||||
this.logService,
|
||||
this.stateProvider,
|
||||
true,
|
||||
);
|
||||
|
||||
@@ -703,7 +708,6 @@ export class Main {
|
||||
await this.storageService.init();
|
||||
await this.stateService.init();
|
||||
this.containerService.attachToGlobal(global);
|
||||
await this.environmentService.setUrlsFromStorage();
|
||||
await this.i18nService.init();
|
||||
this.twoFactorService.init();
|
||||
this.configService.init();
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
import { OptionValues } from "commander";
|
||||
import { firstValueFrom } from "rxjs";
|
||||
|
||||
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service";
|
||||
import {
|
||||
EnvironmentService,
|
||||
Region,
|
||||
} from "@bitwarden/common/platform/abstractions/environment.service";
|
||||
|
||||
import { Response } from "../models/response";
|
||||
import { MessageResponse } from "../models/response/message.response";
|
||||
@@ -29,16 +33,15 @@ export class ConfigCommand {
|
||||
!options.notifications &&
|
||||
!options.events
|
||||
) {
|
||||
const env = await firstValueFrom(this.environmentService.environment$);
|
||||
const stringRes = new StringResponse(
|
||||
this.environmentService.hasBaseUrl()
|
||||
? this.environmentService.getUrls().base
|
||||
: "https://bitwarden.com",
|
||||
env.hasBaseUrl() ? env.getUrls().base : "https://bitwarden.com",
|
||||
);
|
||||
return Response.success(stringRes);
|
||||
}
|
||||
|
||||
url = url === "null" || url === "bitwarden.com" || url === "https://bitwarden.com" ? null : url;
|
||||
await this.environmentService.setUrls({
|
||||
await this.environmentService.setEnvironment(Region.SelfHosted, {
|
||||
base: url,
|
||||
webVault: options.webVault || null,
|
||||
api: options.api || null,
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
import * as inquirer from "inquirer";
|
||||
import { firstValueFrom } from "rxjs";
|
||||
|
||||
import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction";
|
||||
import { KeyConnectorService } from "@bitwarden/common/auth/abstractions/key-connector.service";
|
||||
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service";
|
||||
import {
|
||||
EnvironmentService,
|
||||
Region,
|
||||
} from "@bitwarden/common/platform/abstractions/environment.service";
|
||||
import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction";
|
||||
|
||||
import { Response } from "../models/response";
|
||||
@@ -67,9 +71,10 @@ export class ConvertToKeyConnectorCommand {
|
||||
await this.keyConnectorService.setUsesKeyConnector(true);
|
||||
|
||||
// Update environment URL - required for api key login
|
||||
const urls = this.environmentService.getUrls();
|
||||
const env = await firstValueFrom(this.environmentService.environment$);
|
||||
const urls = env.getUrls();
|
||||
urls.keyConnector = organization.keyConnectorUrl;
|
||||
await this.environmentService.setUrls(urls);
|
||||
await this.environmentService.setEnvironment(Region.SelfHosted, urls);
|
||||
|
||||
return Response.success();
|
||||
} else if (answer.convert === "leave") {
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { firstValueFrom } from "rxjs";
|
||||
|
||||
import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service";
|
||||
import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status";
|
||||
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service";
|
||||
@@ -17,7 +19,7 @@ export class StatusCommand {
|
||||
|
||||
async run(): Promise<Response> {
|
||||
try {
|
||||
const baseUrl = this.baseUrl();
|
||||
const baseUrl = await this.baseUrl();
|
||||
const status = await this.status();
|
||||
const lastSync = await this.syncService.getLastSync();
|
||||
const userId = await this.stateService.getUserId();
|
||||
@@ -37,8 +39,9 @@ export class StatusCommand {
|
||||
}
|
||||
}
|
||||
|
||||
private baseUrl(): string {
|
||||
return this.envService.getUrls().base;
|
||||
private async baseUrl(): Promise<string> {
|
||||
const env = await firstValueFrom(this.envService.environment$);
|
||||
return env.getUrls().base;
|
||||
}
|
||||
|
||||
private async status(): Promise<"unauthenticated" | "locked" | "unlocked"> {
|
||||
|
||||
@@ -127,7 +127,8 @@ export class SendCreateCommand {
|
||||
await this.sendApiService.save([encSend, fileData]);
|
||||
const newSend = await this.sendService.getFromState(encSend.id);
|
||||
const decSend = await newSend.decrypt();
|
||||
const res = new SendResponse(decSend, this.environmentService.getWebVaultUrl());
|
||||
const env = await firstValueFrom(this.environmentService.environment$);
|
||||
const res = new SendResponse(decSend, env.getWebVaultUrl());
|
||||
return Response.success(res);
|
||||
} catch (e) {
|
||||
return Response.error(e);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { OptionValues } from "commander";
|
||||
import { firstValueFrom } from "rxjs";
|
||||
|
||||
import { SearchService } from "@bitwarden/common/abstractions/search.service";
|
||||
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
|
||||
@@ -32,7 +33,8 @@ export class SendGetCommand extends DownloadCommand {
|
||||
return Response.notFound();
|
||||
}
|
||||
|
||||
const webVaultUrl = this.environmentService.getWebVaultUrl();
|
||||
const env = await firstValueFrom(this.environmentService.environment$);
|
||||
const webVaultUrl = env.getWebVaultUrl();
|
||||
let filter = (s: SendView) => true;
|
||||
let selector = async (s: SendView): Promise<Response> =>
|
||||
Response.success(new SendResponse(s, webVaultUrl));
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { firstValueFrom } from "rxjs";
|
||||
|
||||
import { SearchService } from "@bitwarden/common/abstractions/search.service";
|
||||
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service";
|
||||
import { SendService } from "@bitwarden/common/tools/send/services/send.service.abstraction";
|
||||
@@ -21,7 +23,8 @@ export class SendListCommand {
|
||||
sends = this.searchService.searchSends(sends, normalizedOptions.search);
|
||||
}
|
||||
|
||||
const webVaultUrl = this.environmentService.getWebVaultUrl();
|
||||
const env = await firstValueFrom(this.environmentService.environment$);
|
||||
const webVaultUrl = env.getWebVaultUrl();
|
||||
const res = new ListResponse(sends.map((s) => new SendResponse(s, webVaultUrl)));
|
||||
return Response.success(res);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { OptionValues } from "commander";
|
||||
import * as inquirer from "inquirer";
|
||||
import { firstValueFrom } from "rxjs";
|
||||
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { ErrorResponse } from "@bitwarden/common/models/response/error.response";
|
||||
@@ -46,7 +47,7 @@ export class SendReceiveCommand extends DownloadCommand {
|
||||
return Response.badRequest("Failed to parse the provided Send url");
|
||||
}
|
||||
|
||||
const apiUrl = this.getApiUrl(urlObject);
|
||||
const apiUrl = await this.getApiUrl(urlObject);
|
||||
const [id, key] = this.getIdAndKey(urlObject);
|
||||
|
||||
if (Utils.isNullOrWhitespace(id) || Utils.isNullOrWhitespace(key)) {
|
||||
@@ -108,8 +109,9 @@ export class SendReceiveCommand extends DownloadCommand {
|
||||
return [result[0], result[1]];
|
||||
}
|
||||
|
||||
private getApiUrl(url: URL) {
|
||||
const urls = this.environmentService.getUrls();
|
||||
private async getApiUrl(url: URL) {
|
||||
const env = await firstValueFrom(this.environmentService.environment$);
|
||||
const urls = env.getUrls();
|
||||
if (url.origin === "https://send.bitwarden.com") {
|
||||
return "https://api.bitwarden.com";
|
||||
} else if (url.origin === urls.api) {
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { firstValueFrom } from "rxjs";
|
||||
|
||||
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service";
|
||||
import { SendService } from "@bitwarden/common/tools/send/services//send.service.abstraction";
|
||||
import { SendApiService } from "@bitwarden/common/tools/send/services/send-api.service.abstraction";
|
||||
@@ -18,7 +20,8 @@ export class SendRemovePasswordCommand {
|
||||
|
||||
const updatedSend = await this.sendService.get(id);
|
||||
const decSend = await updatedSend.decrypt();
|
||||
const webVaultUrl = this.environmentService.getWebVaultUrl();
|
||||
const env = await firstValueFrom(this.environmentService.environment$);
|
||||
const webVaultUrl = env.getWebVaultUrl();
|
||||
const res = new SendResponse(decSend, webVaultUrl);
|
||||
return Response.success(res);
|
||||
} catch (e) {
|
||||
|
||||
@@ -105,7 +105,7 @@ export class AccountSwitcherComponent implements OnInit, OnDestroy {
|
||||
name: (await this.tokenService.getName()) ?? (await this.tokenService.getEmail()),
|
||||
email: await this.tokenService.getEmail(),
|
||||
avatarColor: await firstValueFrom(this.avatarService.avatarColor$),
|
||||
server: await this.environmentService.getHost(),
|
||||
server: (await this.environmentService.getEnvironment())?.getHostname(),
|
||||
};
|
||||
} catch {
|
||||
this.activeAccount = undefined;
|
||||
@@ -158,7 +158,7 @@ export class AccountSwitcherComponent implements OnInit, OnDestroy {
|
||||
email: baseAccounts[userId].profile.email,
|
||||
authenticationStatus: await this.authService.getAuthStatus(userId),
|
||||
avatarColor: await firstValueFrom(this.avatarService.getUserAvatarColor$(userId as UserId)),
|
||||
server: await this.environmentService.getHost(userId),
|
||||
server: (await this.environmentService.getEnvironment(userId))?.getHostname(),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,6 @@ import { NotificationsService as NotificationsServiceAbstraction } from "@bitwar
|
||||
import { TwoFactorService as TwoFactorServiceAbstraction } from "@bitwarden/common/auth/abstractions/two-factor.service";
|
||||
import { CryptoService as CryptoServiceAbstraction } from "@bitwarden/common/platform/abstractions/crypto.service";
|
||||
import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.service";
|
||||
import { EnvironmentService as EnvironmentServiceAbstraction } from "@bitwarden/common/platform/abstractions/environment.service";
|
||||
import { I18nService as I18nServiceAbstraction } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { PlatformUtilsService as PlatformUtilsServiceAbstraction } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
import { StateService as StateServiceAbstraction } from "@bitwarden/common/platform/abstractions/state.service";
|
||||
@@ -25,7 +24,6 @@ import { NativeMessagingService } from "../../services/native-messaging.service"
|
||||
export class InitService {
|
||||
constructor(
|
||||
@Inject(WINDOW) private win: Window,
|
||||
private environmentService: EnvironmentServiceAbstraction,
|
||||
private syncService: SyncServiceAbstraction,
|
||||
private vaultTimeoutService: VaultTimeoutService,
|
||||
private i18nService: I18nServiceAbstraction,
|
||||
@@ -46,10 +44,6 @@ export class InitService {
|
||||
return async () => {
|
||||
this.nativeMessagingService.init();
|
||||
await this.stateService.init({ runMigrations: false }); // Desktop will run them in main process
|
||||
await this.environmentService.setUrlsFromStorage();
|
||||
// Workaround to ignore stateService.activeAccount until URLs are set
|
||||
// TODO: Remove this when implementing ticket PM-2637
|
||||
this.environmentService.initialized = true;
|
||||
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
this.syncService.fullSync(true);
|
||||
|
||||
@@ -49,10 +49,6 @@ export class LoginComponent extends BaseLoginComponent implements OnDestroy {
|
||||
return this.formGroup.value.email;
|
||||
}
|
||||
|
||||
get selfHostedDomain() {
|
||||
return this.environmentService.hasBaseUrl() ? this.environmentService.getWebVaultUrl() : null;
|
||||
}
|
||||
|
||||
constructor(
|
||||
devicesApiService: DevicesApiServiceAbstraction,
|
||||
appIdService: AppIdService,
|
||||
@@ -152,9 +148,6 @@ export class LoginComponent extends BaseLoginComponent implements OnDestroy {
|
||||
// eslint-disable-next-line rxjs/no-async-subscribe
|
||||
childComponent.onSaved.pipe(takeUntil(this.componentDestroyed$)).subscribe(async () => {
|
||||
modal.close();
|
||||
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
this.environmentSelector.updateEnvironmentInfo();
|
||||
await this.getLoginWithDevice(this.loggedEmail);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { Component, Inject, NgZone, ViewChild, ViewContainerRef } from "@angular/core";
|
||||
import { ActivatedRoute, Router } from "@angular/router";
|
||||
import { firstValueFrom } from "rxjs";
|
||||
|
||||
import { TwoFactorComponent as BaseTwoFactorComponent } from "@bitwarden/angular/auth/components/two-factor.component";
|
||||
import { WINDOW } from "@bitwarden/angular/services/injection-tokens";
|
||||
@@ -141,7 +142,7 @@ export class TwoFactorComponent extends BaseTwoFactorComponent {
|
||||
}
|
||||
}
|
||||
|
||||
override launchDuoFrameless() {
|
||||
override async launchDuoFrameless() {
|
||||
const duoHandOffMessage = {
|
||||
title: this.i18nService.t("youSuccessfullyLoggedIn"),
|
||||
message: this.i18nService.t("youMayCloseThisWindow"),
|
||||
@@ -150,8 +151,9 @@ export class TwoFactorComponent extends BaseTwoFactorComponent {
|
||||
|
||||
// we're using the connector here as a way to set a cookie with translations
|
||||
// before continuing to the duo frameless url
|
||||
const env = await firstValueFrom(this.environmentService.environment$);
|
||||
const launchUrl =
|
||||
this.environmentService.getWebVaultUrl() +
|
||||
env.getWebVaultUrl() +
|
||||
"/duo-redirect-connector.html" +
|
||||
"?duoFramelessUrl=" +
|
||||
encodeURIComponent(this.duoFramelessUrl) +
|
||||
|
||||
@@ -2346,12 +2346,6 @@
|
||||
"loggingInOn": {
|
||||
"message": "Logging in on"
|
||||
},
|
||||
"usDomain": {
|
||||
"message": "bitwarden.com"
|
||||
},
|
||||
"euDomain": {
|
||||
"message": "bitwarden.eu"
|
||||
},
|
||||
"selfHostedServer": {
|
||||
"message": "self-hosted"
|
||||
},
|
||||
|
||||
@@ -10,7 +10,7 @@ import { StateService } from "@bitwarden/common/platform/abstractions/state.serv
|
||||
import { DefaultBiometricStateService } from "@bitwarden/common/platform/biometrics/biometric-state.service";
|
||||
import { StateFactory } from "@bitwarden/common/platform/factories/state-factory";
|
||||
import { GlobalState } from "@bitwarden/common/platform/models/domain/global-state";
|
||||
import { EnvironmentService } from "@bitwarden/common/platform/services/environment.service";
|
||||
import { DefaultEnvironmentService } from "@bitwarden/common/platform/services/default-environment.service";
|
||||
import { MemoryStorageService } from "@bitwarden/common/platform/services/memory-storage.service";
|
||||
import { MigrationBuilderService } from "@bitwarden/common/platform/services/migration-builder.service";
|
||||
import { MigrationRunner } from "@bitwarden/common/platform/services/migration-runner";
|
||||
@@ -54,7 +54,7 @@ export class Main {
|
||||
memoryStorageForStateProviders: MemoryStorageServiceForStateProviders;
|
||||
messagingService: ElectronMainMessagingService;
|
||||
stateService: StateService;
|
||||
environmentService: EnvironmentService;
|
||||
environmentService: DefaultEnvironmentService;
|
||||
mainCryptoFunctionService: MainCryptoFunctionService;
|
||||
desktopCredentialStorageListener: DesktopCredentialStorageListener;
|
||||
migrationRunner: MigrationRunner;
|
||||
@@ -148,7 +148,7 @@ export class Main {
|
||||
new DefaultDerivedStateProvider(this.memoryStorageForStateProviders),
|
||||
);
|
||||
|
||||
this.environmentService = new EnvironmentService(stateProvider, accountService);
|
||||
this.environmentService = new DefaultEnvironmentService(stateProvider, accountService);
|
||||
|
||||
this.tokenService = new TokenService(
|
||||
singleUserStateProvider,
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { app, Menu } from "electron";
|
||||
import { firstValueFrom } from "rxjs";
|
||||
|
||||
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
@@ -45,7 +46,8 @@ export class MenuMain {
|
||||
}
|
||||
|
||||
private async getWebVaultUrl() {
|
||||
return this.environmentService.getWebVaultUrl() ?? cloudWebVaultUrl;
|
||||
const env = await firstValueFrom(this.environmentService.environment$);
|
||||
return env.getWebVaultUrl() ?? cloudWebVaultUrl;
|
||||
}
|
||||
|
||||
private initContextMenu() {
|
||||
|
||||
@@ -177,6 +177,7 @@ const renderer = {
|
||||
ENV: ENV,
|
||||
FLAGS: envConfig.flags,
|
||||
DEV_FLAGS: NODE_ENV === "development" ? envConfig.devFlags : {},
|
||||
ADDITIONAL_REGIONS: envConfig.additionalRegions ?? [],
|
||||
}),
|
||||
],
|
||||
};
|
||||
|
||||
@@ -10,6 +10,15 @@
|
||||
"proxyNotifications": "http://localhost:61840",
|
||||
"wsConnectSrc": "ws://localhost:61840"
|
||||
},
|
||||
"additionalRegions": [
|
||||
{
|
||||
"key": "LOCAL",
|
||||
"domain": "localhost",
|
||||
"urls": {
|
||||
"webVault": "https://localhost:8080"
|
||||
}
|
||||
}
|
||||
],
|
||||
"flags": {
|
||||
"secretsManager": true,
|
||||
"showPasswordless": true,
|
||||
|
||||
@@ -4,6 +4,22 @@
|
||||
"notifications": "https://notifications.euqa.bitwarden.pw",
|
||||
"scim": "https://scim.euqa.bitwarden.pw"
|
||||
},
|
||||
"additionalRegions": [
|
||||
{
|
||||
"key": "USQA",
|
||||
"domain": "qa.bitwarden.pw",
|
||||
"urls": {
|
||||
"webVault": "https://vault.qa.bitwarden.pw"
|
||||
}
|
||||
},
|
||||
{
|
||||
"key": "EUQA",
|
||||
"domain": "euqa.bitwarden.pw",
|
||||
"urls": {
|
||||
"webVault": "https://vault.euqa.bitwarden.pw"
|
||||
}
|
||||
}
|
||||
],
|
||||
"flags": {
|
||||
"secretsManager": true,
|
||||
"showPasswordless": true
|
||||
|
||||
@@ -10,6 +10,22 @@
|
||||
"proxyEvents": "https://events.qa.bitwarden.pw",
|
||||
"proxyNotifications": "https://notifications.qa.bitwarden.pw"
|
||||
},
|
||||
"additionalRegions": [
|
||||
{
|
||||
"key": "USQA",
|
||||
"domain": "qa.bitwarden.pw",
|
||||
"urls": {
|
||||
"webVault": "https://vault.qa.bitwarden.pw"
|
||||
}
|
||||
},
|
||||
{
|
||||
"key": "EUQA",
|
||||
"domain": "euqa.bitwarden.pw",
|
||||
"urls": {
|
||||
"webVault": "https://vault.euqa.bitwarden.pw"
|
||||
}
|
||||
}
|
||||
],
|
||||
"flags": {
|
||||
"secretsManager": true,
|
||||
"showPasswordless": true,
|
||||
|
||||
@@ -127,7 +127,7 @@ export class TwoFactorComponent extends BaseTwoFactorComponent implements OnDest
|
||||
await this.submit();
|
||||
};
|
||||
|
||||
override launchDuoFrameless() {
|
||||
override async launchDuoFrameless() {
|
||||
const duoHandOffMessage = {
|
||||
title: this.i18nService.t("youSuccessfullyLoggedIn"),
|
||||
message: this.i18nService.t("thisWindowWillCloseIn5Seconds"),
|
||||
|
||||
@@ -44,11 +44,11 @@ export class PremiumComponent implements OnInit {
|
||||
private billingAccountProfileStateService: BillingAccountProfileStateService,
|
||||
) {
|
||||
this.selfHosted = platformUtilsService.isSelfHost();
|
||||
this.cloudWebVaultUrl = this.environmentService.getCloudWebVaultUrl();
|
||||
this.canAccessPremium$ = billingAccountProfileStateService.hasPremiumFromAnySource$;
|
||||
}
|
||||
|
||||
async ngOnInit() {
|
||||
this.cloudWebVaultUrl = await firstValueFrom(this.environmentService.cloudWebVaultUrl$);
|
||||
if (await firstValueFrom(this.billingAccountProfileStateService.hasPremiumPersonally$)) {
|
||||
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
|
||||
@@ -49,10 +49,10 @@ export class UserSubscriptionComponent implements OnInit {
|
||||
private billingAccountProfileStateService: BillingAccountProfileStateService,
|
||||
) {
|
||||
this.selfHosted = platformUtilsService.isSelfHost();
|
||||
this.cloudWebVaultUrl = this.environmentService.getCloudWebVaultUrl();
|
||||
}
|
||||
|
||||
async ngOnInit() {
|
||||
this.cloudWebVaultUrl = await firstValueFrom(this.environmentService.cloudWebVaultUrl$);
|
||||
this.presentUserWithOffboardingSurvey$ = this.configService.getFeatureFlag$<boolean>(
|
||||
FeatureFlag.AC1607_PresentUserOffboardingSurvey,
|
||||
);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Component, OnDestroy, OnInit } from "@angular/core";
|
||||
import { FormControl, FormGroup } from "@angular/forms";
|
||||
import { ActivatedRoute } from "@angular/router";
|
||||
import { concatMap, Subject, takeUntil } from "rxjs";
|
||||
import { concatMap, firstValueFrom, Subject, takeUntil } from "rxjs";
|
||||
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction";
|
||||
@@ -82,11 +82,11 @@ export class OrganizationSubscriptionSelfhostComponent implements OnInit, OnDest
|
||||
private i18nService: I18nService,
|
||||
private environmentService: EnvironmentService,
|
||||
private dialogService: DialogService,
|
||||
) {
|
||||
this.cloudWebVaultUrl = this.environmentService.getCloudWebVaultUrl();
|
||||
}
|
||||
) {}
|
||||
|
||||
async ngOnInit() {
|
||||
this.cloudWebVaultUrl = await firstValueFrom(this.environmentService.cloudWebVaultUrl$);
|
||||
|
||||
this.route.params
|
||||
.pipe(
|
||||
concatMap(async (params) => {
|
||||
|
||||
@@ -14,11 +14,15 @@ import { OrganizationService } from "@bitwarden/common/admin-console/abstraction
|
||||
import { PaymentMethodType } from "@bitwarden/common/billing/enums";
|
||||
import { BitPayInvoiceRequest } from "@bitwarden/common/billing/models/request/bit-pay-invoice.request";
|
||||
import { ConfigServiceAbstraction } from "@bitwarden/common/platform/abstractions/config/config.service.abstraction";
|
||||
import { PayPalConfig } from "@bitwarden/common/platform/abstractions/environment.service";
|
||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
|
||||
|
||||
export type PayPalConfig = {
|
||||
businessId?: string;
|
||||
buttonAction?: string;
|
||||
};
|
||||
|
||||
@Component({
|
||||
selector: "app-add-credit",
|
||||
templateUrl: "add-credit.component.html",
|
||||
|
||||
@@ -1,38 +1,25 @@
|
||||
<div class="tw-mb-1" *ngIf="showRegionSelector">
|
||||
<bit-menu #environmentOptions>
|
||||
<a
|
||||
*ngFor="let region of availableRegions"
|
||||
bitMenuItem
|
||||
[attr.href]="
|
||||
isUsServer ? 'javascript:void(0)' : 'https://vault.bitwarden.com' + routeAndParams
|
||||
region == currentRegion ? 'javascript:void(0)' : region.urls.webVault + routeAndParams
|
||||
"
|
||||
class="pr-4"
|
||||
>
|
||||
<i
|
||||
class="bwi bwi-fw bwi-sm bwi-check pb-1"
|
||||
aria-hidden="true"
|
||||
[style.visibility]="isUsServer ? 'visible' : 'hidden'"
|
||||
[style.visibility]="region == currentRegion ? 'visible' : 'hidden'"
|
||||
></i>
|
||||
{{ "usDomain" | i18n }}
|
||||
</a>
|
||||
<a
|
||||
bitMenuItem
|
||||
[attr.href]="
|
||||
isEuServer ? 'javascript:void(0)' : 'https://vault.bitwarden.eu' + routeAndParams
|
||||
"
|
||||
class="pr-4"
|
||||
>
|
||||
<i
|
||||
class="bwi bwi-fw bwi-sm bwi-check pb-1"
|
||||
aria-hidden="true"
|
||||
[style.visibility]="isEuServer ? 'visible' : 'hidden'"
|
||||
></i>
|
||||
{{ "euDomain" | i18n }}
|
||||
{{ region.domain }}
|
||||
</a>
|
||||
</bit-menu>
|
||||
<div>
|
||||
{{ "server" | i18n }}:
|
||||
<a [routerLink]="[]" [bitMenuTriggerFor]="environmentOptions">
|
||||
<b>{{ isEuServer ? ("euDomain" | i18n) : ("usDomain" | i18n) }}</b
|
||||
<b>{{ currentRegion?.domain }}</b
|
||||
><i class="bwi bwi-fw bwi-sm bwi-angle-down" aria-hidden="true"></i>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
import { Component, OnInit } from "@angular/core";
|
||||
import { Router } from "@angular/router";
|
||||
|
||||
import { RegionDomain } from "@bitwarden/common/platform/abstractions/environment.service";
|
||||
import {
|
||||
EnvironmentService,
|
||||
RegionConfig,
|
||||
} from "@bitwarden/common/platform/abstractions/environment.service";
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||
|
||||
@@ -12,19 +15,21 @@ import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||
export class EnvironmentSelectorComponent implements OnInit {
|
||||
constructor(
|
||||
private platformUtilsService: PlatformUtilsService,
|
||||
private environmentService: EnvironmentService,
|
||||
private router: Router,
|
||||
) {}
|
||||
|
||||
isEuServer: boolean;
|
||||
isUsServer: boolean;
|
||||
showRegionSelector = false;
|
||||
routeAndParams: string;
|
||||
protected availableRegions = this.environmentService.availableRegions();
|
||||
protected currentRegion?: RegionConfig;
|
||||
|
||||
protected showRegionSelector = false;
|
||||
protected routeAndParams: string;
|
||||
|
||||
async ngOnInit() {
|
||||
const domain = Utils.getDomain(window.location.href);
|
||||
this.isEuServer = domain.includes(RegionDomain.EU);
|
||||
this.isUsServer = domain.includes(RegionDomain.US) || domain.includes(RegionDomain.USQA);
|
||||
this.showRegionSelector = !this.platformUtilsService.isSelfHost();
|
||||
this.routeAndParams = `/#${this.router.url}`;
|
||||
|
||||
const host = Utils.getHost(window.location.href);
|
||||
this.currentRegion = this.availableRegions.find((r) => Utils.getHost(r.urls.webVault) === host);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,11 +11,14 @@ import {
|
||||
OBSERVABLE_MEMORY_STORAGE,
|
||||
OBSERVABLE_DISK_STORAGE,
|
||||
OBSERVABLE_DISK_LOCAL_STORAGE,
|
||||
WINDOW,
|
||||
} from "@bitwarden/angular/services/injection-tokens";
|
||||
import { JslibServicesModule } from "@bitwarden/angular/services/jslib-services.module";
|
||||
import { ModalService as ModalServiceAbstraction } from "@bitwarden/angular/services/modal.service";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { LoginService as LoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/login.service";
|
||||
import { LoginService } from "@bitwarden/common/auth/services/login.service";
|
||||
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service";
|
||||
import { FileDownloadService } from "@bitwarden/common/platform/abstractions/file-download/file-download.service";
|
||||
import { I18nService as I18nServiceAbstraction } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||
@@ -28,9 +31,9 @@ import { StateFactory } from "@bitwarden/common/platform/factories/state-factory
|
||||
import { MemoryStorageService } from "@bitwarden/common/platform/services/memory-storage.service";
|
||||
import { MigrationBuilderService } from "@bitwarden/common/platform/services/migration-builder.service";
|
||||
import { MigrationRunner } from "@bitwarden/common/platform/services/migration-runner";
|
||||
/* eslint-disable import/no-restricted-paths -- Implementation for memory storage */
|
||||
import { StorageServiceProvider } from "@bitwarden/common/platform/services/storage-service.provider";
|
||||
import { GlobalStateProvider } from "@bitwarden/common/platform/state";
|
||||
/* eslint-disable import/no-restricted-paths -- Implementation for memory storage */
|
||||
import { GlobalStateProvider, StateProvider } from "@bitwarden/common/platform/state";
|
||||
import { MemoryStorageService as MemoryStorageServiceForStateProviders } from "@bitwarden/common/platform/state/storage/memory-storage.service";
|
||||
/* eslint-enable import/no-restricted-paths -- Implementation for memory storage */
|
||||
import {
|
||||
@@ -41,6 +44,7 @@ import {
|
||||
import { PolicyListService } from "../admin-console/core/policy-list.service";
|
||||
import { HtmlStorageService } from "../core/html-storage.service";
|
||||
import { I18nService } from "../core/i18n.service";
|
||||
import { WebEnvironmentService } from "../platform/web-environment.service";
|
||||
import { WebMigrationRunner } from "../platform/web-migration-runner";
|
||||
import { WebStorageServiceProvider } from "../platform/web-storage-service.provider";
|
||||
import { WindowStorageService } from "../platform/window-storage.service";
|
||||
@@ -138,6 +142,11 @@ import { WebPlatformUtilsService } from "./web-platform-utils.service";
|
||||
OBSERVABLE_DISK_LOCAL_STORAGE,
|
||||
],
|
||||
},
|
||||
{
|
||||
provide: EnvironmentService,
|
||||
useClass: WebEnvironmentService,
|
||||
deps: [WINDOW, StateProvider, AccountService],
|
||||
},
|
||||
{
|
||||
provide: ThemeStateService,
|
||||
useFactory: (globalStateProvider: GlobalStateProvider) =>
|
||||
|
||||
@@ -8,10 +8,6 @@ import { NotificationsService as NotificationsServiceAbstraction } from "@bitwar
|
||||
import { TwoFactorService as TwoFactorServiceAbstraction } from "@bitwarden/common/auth/abstractions/two-factor.service";
|
||||
import { CryptoService as CryptoServiceAbstraction } from "@bitwarden/common/platform/abstractions/crypto.service";
|
||||
import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.service";
|
||||
import {
|
||||
EnvironmentService as EnvironmentServiceAbstraction,
|
||||
Urls,
|
||||
} from "@bitwarden/common/platform/abstractions/environment.service";
|
||||
import { I18nService as I18nServiceAbstraction } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { StateService as StateServiceAbstraction } from "@bitwarden/common/platform/abstractions/state.service";
|
||||
import { ConfigService } from "@bitwarden/common/platform/services/config/config.service";
|
||||
@@ -23,7 +19,6 @@ import { VaultTimeoutService } from "@bitwarden/common/services/vault-timeout/va
|
||||
export class InitService {
|
||||
constructor(
|
||||
@Inject(WINDOW) private win: Window,
|
||||
private environmentService: EnvironmentServiceAbstraction,
|
||||
private notificationsService: NotificationsServiceAbstraction,
|
||||
private vaultTimeoutService: VaultTimeoutService,
|
||||
private i18nService: I18nServiceAbstraction,
|
||||
@@ -41,13 +36,6 @@ export class InitService {
|
||||
return async () => {
|
||||
await this.stateService.init();
|
||||
|
||||
const urls = process.env.URLS as Urls;
|
||||
urls.base ??= this.win.location.origin;
|
||||
await this.environmentService.setUrls(urls);
|
||||
// Workaround to ignore stateService.activeAccount until process.env.URLS are set
|
||||
// TODO: Remove this when implementing ticket PM-2637
|
||||
this.environmentService.initialized = true;
|
||||
|
||||
setTimeout(() => this.notificationsService.init(), 3000);
|
||||
await this.vaultTimeoutService.init(true);
|
||||
await this.i18nService.init();
|
||||
|
||||
62
apps/web/src/app/platform/web-environment.service.ts
Normal file
62
apps/web/src/app/platform/web-environment.service.ts
Normal file
@@ -0,0 +1,62 @@
|
||||
import { ReplaySubject } from "rxjs";
|
||||
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import {
|
||||
Environment,
|
||||
Region,
|
||||
RegionConfig,
|
||||
Urls,
|
||||
} from "@bitwarden/common/platform/abstractions/environment.service";
|
||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||
import {
|
||||
CloudEnvironment,
|
||||
DefaultEnvironmentService,
|
||||
SelfHostedEnvironment,
|
||||
} from "@bitwarden/common/platform/services/default-environment.service";
|
||||
import { StateProvider } from "@bitwarden/common/platform/state";
|
||||
|
||||
/**
|
||||
* Web specific environment service. Ensures that the urls are set from the window location.
|
||||
*/
|
||||
export class WebEnvironmentService extends DefaultEnvironmentService {
|
||||
constructor(
|
||||
private win: Window,
|
||||
stateProvider: StateProvider,
|
||||
accountService: AccountService,
|
||||
) {
|
||||
super(stateProvider, accountService);
|
||||
|
||||
// The web vault always uses the current location as the base url
|
||||
const urls = process.env.URLS as Urls;
|
||||
urls.base ??= this.win.location.origin;
|
||||
|
||||
// Find the region
|
||||
const domain = Utils.getDomain(this.win.location.href);
|
||||
const region = this.availableRegions().find((r) => Utils.getDomain(r.urls.webVault) === domain);
|
||||
|
||||
let environment: Environment;
|
||||
if (region) {
|
||||
environment = new WebCloudEnvironment(region, urls);
|
||||
} else {
|
||||
environment = new SelfHostedEnvironment(urls);
|
||||
}
|
||||
|
||||
// Override the environment observable with a replay subject
|
||||
const subject = new ReplaySubject<Environment>(1);
|
||||
subject.next(environment);
|
||||
this.environment$ = subject.asObservable();
|
||||
}
|
||||
|
||||
// Web cannot set environment
|
||||
async setEnvironment(region: Region, urls?: Urls): Promise<Urls> {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
class WebCloudEnvironment extends CloudEnvironment {
|
||||
constructor(config: RegionConfig, urls: Urls) {
|
||||
super(config);
|
||||
// We override the urls to avoid CORS issues
|
||||
this.urls = urls;
|
||||
}
|
||||
}
|
||||
@@ -7063,12 +7063,6 @@
|
||||
"enforceOnLoginDesc": {
|
||||
"message": "Require existing members to change their passwords"
|
||||
},
|
||||
"usDomain": {
|
||||
"message": "bitwarden.com"
|
||||
},
|
||||
"euDomain": {
|
||||
"message": "bitwarden.eu"
|
||||
},
|
||||
"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."
|
||||
|
||||
@@ -171,6 +171,7 @@ const plugins = [
|
||||
PAYPAL_CONFIG: envConfig["paypal"] ?? {},
|
||||
FLAGS: envConfig["flags"] ?? {},
|
||||
DEV_FLAGS: NODE_ENV === "development" ? envConfig["devFlags"] : {},
|
||||
ADDITIONAL_REGIONS: envConfig["additionalRegions"] ?? [],
|
||||
}),
|
||||
new AngularWebpackPlugin({
|
||||
tsConfigPath: "tsconfig.json",
|
||||
|
||||
Reference in New Issue
Block a user