0">
-
+
{{ "accountSwitcherLimitReached" | i18n }}
diff --git a/apps/desktop/src/app/layout/account-switcher.component.ts b/apps/desktop/src/app/layout/account-switcher.component.ts
index e93eae8c8a6..031074e46e5 100644
--- a/apps/desktop/src/app/layout/account-switcher.component.ts
+++ b/apps/desktop/src/app/layout/account-switcher.component.ts
@@ -52,12 +52,12 @@ type InactiveAccount = ActiveAccount & {
],
})
export class AccountSwitcherComponent implements OnInit, OnDestroy {
- private destroy$ = new Subject
();
-
- isOpen = false;
- inactiveAccounts: { [userId: string]: InactiveAccount } = {};
activeAccount?: ActiveAccount;
+ inactiveAccounts: { [userId: string]: InactiveAccount } = {};
+
authStatus = AuthenticationStatus;
+
+ isOpen = false;
overlayPosition: ConnectedPosition[] = [
{
originX: "end",
@@ -67,6 +67,8 @@ export class AccountSwitcherComponent implements OnInit, OnDestroy {
},
];
+ private destroy$ = new Subject();
+
get showSwitcher() {
const userIsInAVault = !Utils.isNullOrWhitespace(this.activeAccount?.email);
const userIsAddingAnAdditionalAccount = Object.keys(this.inactiveAccounts).length > 0;
@@ -145,7 +147,7 @@ export class AccountSwitcherComponent implements OnInit, OnDestroy {
const inactiveAccounts: { [userId: string]: InactiveAccount } = {};
for (const userId in baseAccounts) {
- if (userId == null || userId === (await this.tokenService.getUserId())) {
+ if (userId == null || userId === (await this.stateService.getUserId())) {
continue;
}
From 755419f7d4117522949a5475391b92e3364e1a7f Mon Sep 17 00:00:00 2001
From: rr-bw <102181210+rr-bw@users.noreply.github.com>
Date: Thu, 12 Oct 2023 10:47:01 -0700
Subject: [PATCH 16/22] refactor to use environmentService insead of
getServerConfig
---
.../app/layout/account-switcher.component.ts | 28 +++++++++------
.../src/auth/components/lock.component.ts | 10 +++++-
.../abstractions/environment.service.ts | 4 ++-
.../platform/services/environment.service.ts | 34 ++++++++++---------
4 files changed, 47 insertions(+), 29 deletions(-)
diff --git a/apps/desktop/src/app/layout/account-switcher.component.ts b/apps/desktop/src/app/layout/account-switcher.component.ts
index 031074e46e5..58187965ef8 100644
--- a/apps/desktop/src/app/layout/account-switcher.component.ts
+++ b/apps/desktop/src/app/layout/account-switcher.component.ts
@@ -7,7 +7,6 @@ import { concatMap, Subject, takeUntil } from "rxjs";
import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service";
import { TokenService } from "@bitwarden/common/auth/abstractions/token.service";
import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status";
-import { EnvironmentUrls } from "@bitwarden/common/auth/models/domain/environment-urls";
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service";
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
@@ -24,7 +23,6 @@ type ActiveAccount = {
type InactiveAccount = ActiveAccount & {
authenticationStatus: AuthenticationStatus;
- environmentUrls: EnvironmentUrls;
};
@Component({
@@ -98,13 +96,20 @@ export class AccountSwitcherComponent implements OnInit, OnDestroy {
concatMap(async (accounts: { [userId: string]: Account }) => {
this.inactiveAccounts = await this.createInactiveAccounts(accounts);
+ const regionDomain = await this.environmentService.getRegionDomain();
+ let selfHostedDomain = "";
+
+ if (!regionDomain) {
+ selfHostedDomain = (await this.stateService.getEnvironmentUrls()).webVault;
+ }
+
try {
this.activeAccount = {
id: await this.tokenService.getUserId(),
name: (await this.tokenService.getName()) ?? (await this.tokenService.getEmail()),
email: await this.tokenService.getEmail(),
avatarColor: await this.stateService.getAvatarColor(),
- server: this.environmentService.getWebVaultHostname(),
+ server: regionDomain || Utils.getDomain(selfHostedDomain),
};
} catch {
this.activeAccount = undefined;
@@ -151,20 +156,21 @@ export class AccountSwitcherComponent implements OnInit, OnDestroy {
continue;
}
+ const regionDomain = await this.environmentService.getRegionDomain(userId);
+ let selfHostedDomain = "";
+
+ if (!regionDomain) {
+ selfHostedDomain = (await this.stateService.getEnvironmentUrls({ userId: userId }))
+ .webVault;
+ }
+
inactiveAccounts[userId] = {
id: userId,
name: baseAccounts[userId].profile.name,
email: baseAccounts[userId].profile.email,
authenticationStatus: await this.authService.getAuthStatus(userId),
avatarColor: await this.stateService.getAvatarColor({ userId: userId }),
- server: this.environmentService.getWebVaultHostname(
- (await this.stateService.getServerConfig({ userId: userId })).environment.vault
- ),
- /**
- * environmentUrls are stored on disk and must be retrieved separately from the
- * in memory state offered from subscribing to accounts
- */
- environmentUrls: await this.stateService.getEnvironmentUrls({ userId: userId }),
+ server: regionDomain || Utils.getDomain(selfHostedDomain),
};
}
diff --git a/libs/angular/src/auth/components/lock.component.ts b/libs/angular/src/auth/components/lock.component.ts
index 61c35ad3e3b..e6ff1c466fd 100644
--- a/libs/angular/src/auth/components/lock.component.ts
+++ b/libs/angular/src/auth/components/lock.component.ts
@@ -23,6 +23,7 @@ import { LogService } from "@bitwarden/common/platform/abstractions/log.service"
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
+import { Utils } from "@bitwarden/common/platform/misc/utils";
import { EncString } from "@bitwarden/common/platform/models/domain/enc-string";
import { UserKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
import { PinLockType } from "@bitwarden/common/services/vault-timeout/vault-timeout-settings.service";
@@ -376,7 +377,14 @@ export class LockComponent implements OnInit, OnDestroy {
this.biometricText = await this.stateService.getBiometricText();
this.email = await this.stateService.getEmail();
- this.webVaultHostname = this.environmentService.getWebVaultHostname();
+ const regionDomain = await this.environmentService.getRegionDomain();
+ let selfHostedDomain = "";
+
+ if (!regionDomain) {
+ selfHostedDomain = (await this.stateService.getEnvironmentUrls()).webVault;
+ }
+
+ this.webVaultHostname = regionDomain || Utils.getDomain(selfHostedDomain);
}
/**
diff --git a/libs/common/src/platform/abstractions/environment.service.ts b/libs/common/src/platform/abstractions/environment.service.ts
index 1316feb6d2a..7bd79a9dd01 100644
--- a/libs/common/src/platform/abstractions/environment.service.ts
+++ b/libs/common/src/platform/abstractions/environment.service.ts
@@ -39,7 +39,7 @@ export abstract class EnvironmentService {
hasBaseUrl: () => boolean;
getNotificationsUrl: () => string;
getWebVaultUrl: () => string;
- getWebVaultHostname: (url?: string) => string;
+ // getWebVaultHostname: (url?: string) => string;
/**
* Retrieves the URL of the cloud web vault app.
*
@@ -62,6 +62,8 @@ export abstract class EnvironmentService {
getScimUrl: () => string;
setUrlsFromStorage: () => Promise;
setUrls: (urls: Urls) => Promise;
+ getRegion: (userId: string) => Promise;
+ getRegionDomain: (userId?: string) => Promise;
setRegion: (region: Region) => Promise;
getUrls: () => Urls;
isCloud: () => boolean;
diff --git a/libs/common/src/platform/services/environment.service.ts b/libs/common/src/platform/services/environment.service.ts
index af192e92016..a126cfc062c 100644
--- a/libs/common/src/platform/services/environment.service.ts
+++ b/libs/common/src/platform/services/environment.service.ts
@@ -4,6 +4,7 @@ import { EnvironmentUrls } from "../../auth/models/domain/environment-urls";
import {
EnvironmentService as EnvironmentServiceAbstraction,
Region,
+ RegionDomain,
Urls,
} from "../abstractions/environment.service";
import { StateService } from "../abstractions/state.service";
@@ -88,22 +89,6 @@ export class EnvironmentService implements EnvironmentServiceAbstraction {
return "https://vault.bitwarden.com";
}
- getWebVaultHostname(url?: string) {
- if (url) {
- return this.removeVaultFromStringIfCloudUrl(url);
- }
-
- if (this.webVaultUrl != null) {
- return this.removeVaultFromStringIfCloudUrl(this.webVaultUrl);
- }
-
- if (this.baseUrl) {
- return this.removeVaultFromStringIfCloudUrl(this.baseUrl);
- }
-
- return "bitwarden.com";
- }
-
getCloudWebVaultUrl() {
if (this.cloudWebVaultUrl != null) {
return this.cloudWebVaultUrl;
@@ -300,6 +285,23 @@ export class EnvironmentService implements EnvironmentServiceAbstraction {
);
}
+ async getRegion(userId?: string) {
+ return this.stateService.getRegion(userId ? { userId: userId } : null);
+ }
+
+ async getRegionDomain(userId?: string) {
+ const region = await this.getRegion(userId ? userId : null);
+
+ switch (region) {
+ case Region.US:
+ return RegionDomain.US;
+ case Region.EU:
+ return RegionDomain.EU;
+ default:
+ return null;
+ }
+ }
+
async setRegion(region: Region) {
this.selectedRegion = region;
await this.stateService.setRegion(region);
From 9e93c979b76e6e494fa4b93960bdec2069f0980a Mon Sep 17 00:00:00 2001
From: rr-bw <102181210+rr-bw@users.noreply.github.com>
Date: Thu, 12 Oct 2023 10:58:55 -0700
Subject: [PATCH 17/22] use Utils.getHost() instead of Utils.getDomain()
---
apps/desktop/src/app/layout/account-switcher.component.ts | 4 ++--
libs/angular/src/auth/components/lock.component.ts | 2 +-
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/apps/desktop/src/app/layout/account-switcher.component.ts b/apps/desktop/src/app/layout/account-switcher.component.ts
index 58187965ef8..e0bf811868a 100644
--- a/apps/desktop/src/app/layout/account-switcher.component.ts
+++ b/apps/desktop/src/app/layout/account-switcher.component.ts
@@ -109,7 +109,7 @@ export class AccountSwitcherComponent implements OnInit, OnDestroy {
name: (await this.tokenService.getName()) ?? (await this.tokenService.getEmail()),
email: await this.tokenService.getEmail(),
avatarColor: await this.stateService.getAvatarColor(),
- server: regionDomain || Utils.getDomain(selfHostedDomain),
+ server: regionDomain || Utils.getHost(selfHostedDomain),
};
} catch {
this.activeAccount = undefined;
@@ -170,7 +170,7 @@ export class AccountSwitcherComponent implements OnInit, OnDestroy {
email: baseAccounts[userId].profile.email,
authenticationStatus: await this.authService.getAuthStatus(userId),
avatarColor: await this.stateService.getAvatarColor({ userId: userId }),
- server: regionDomain || Utils.getDomain(selfHostedDomain),
+ server: regionDomain || Utils.getHost(selfHostedDomain),
};
}
diff --git a/libs/angular/src/auth/components/lock.component.ts b/libs/angular/src/auth/components/lock.component.ts
index e6ff1c466fd..4d20e75f226 100644
--- a/libs/angular/src/auth/components/lock.component.ts
+++ b/libs/angular/src/auth/components/lock.component.ts
@@ -384,7 +384,7 @@ export class LockComponent implements OnInit, OnDestroy {
selfHostedDomain = (await this.stateService.getEnvironmentUrls()).webVault;
}
- this.webVaultHostname = regionDomain || Utils.getDomain(selfHostedDomain);
+ this.webVaultHostname = regionDomain || Utils.getHost(selfHostedDomain);
}
/**
From 96436e4bc24d3b950ab255ce5f8f9646ca7b7583 Mon Sep 17 00:00:00 2001
From: rr-bw <102181210+rr-bw@users.noreply.github.com>
Date: Thu, 12 Oct 2023 11:12:17 -0700
Subject: [PATCH 18/22] create getHost() method
---
.../app/layout/account-switcher.component.ts | 19 ++------------
.../src/auth/components/lock.component.ts | 10 +-------
.../abstractions/environment.service.ts | 2 +-
.../platform/services/environment.service.ts | 25 +++++++------------
4 files changed, 13 insertions(+), 43 deletions(-)
diff --git a/apps/desktop/src/app/layout/account-switcher.component.ts b/apps/desktop/src/app/layout/account-switcher.component.ts
index e0bf811868a..b603fde14e7 100644
--- a/apps/desktop/src/app/layout/account-switcher.component.ts
+++ b/apps/desktop/src/app/layout/account-switcher.component.ts
@@ -96,20 +96,13 @@ export class AccountSwitcherComponent implements OnInit, OnDestroy {
concatMap(async (accounts: { [userId: string]: Account }) => {
this.inactiveAccounts = await this.createInactiveAccounts(accounts);
- const regionDomain = await this.environmentService.getRegionDomain();
- let selfHostedDomain = "";
-
- if (!regionDomain) {
- selfHostedDomain = (await this.stateService.getEnvironmentUrls()).webVault;
- }
-
try {
this.activeAccount = {
id: await this.tokenService.getUserId(),
name: (await this.tokenService.getName()) ?? (await this.tokenService.getEmail()),
email: await this.tokenService.getEmail(),
avatarColor: await this.stateService.getAvatarColor(),
- server: regionDomain || Utils.getHost(selfHostedDomain),
+ server: await this.environmentService.getHost(),
};
} catch {
this.activeAccount = undefined;
@@ -156,21 +149,13 @@ export class AccountSwitcherComponent implements OnInit, OnDestroy {
continue;
}
- const regionDomain = await this.environmentService.getRegionDomain(userId);
- let selfHostedDomain = "";
-
- if (!regionDomain) {
- selfHostedDomain = (await this.stateService.getEnvironmentUrls({ userId: userId }))
- .webVault;
- }
-
inactiveAccounts[userId] = {
id: userId,
name: baseAccounts[userId].profile.name,
email: baseAccounts[userId].profile.email,
authenticationStatus: await this.authService.getAuthStatus(userId),
avatarColor: await this.stateService.getAvatarColor({ userId: userId }),
- server: regionDomain || Utils.getHost(selfHostedDomain),
+ server: await this.environmentService.getHost(userId),
};
}
diff --git a/libs/angular/src/auth/components/lock.component.ts b/libs/angular/src/auth/components/lock.component.ts
index 4d20e75f226..6c7c23e0ee5 100644
--- a/libs/angular/src/auth/components/lock.component.ts
+++ b/libs/angular/src/auth/components/lock.component.ts
@@ -23,7 +23,6 @@ import { LogService } from "@bitwarden/common/platform/abstractions/log.service"
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
-import { Utils } from "@bitwarden/common/platform/misc/utils";
import { EncString } from "@bitwarden/common/platform/models/domain/enc-string";
import { UserKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
import { PinLockType } from "@bitwarden/common/services/vault-timeout/vault-timeout-settings.service";
@@ -377,14 +376,7 @@ export class LockComponent implements OnInit, OnDestroy {
this.biometricText = await this.stateService.getBiometricText();
this.email = await this.stateService.getEmail();
- const regionDomain = await this.environmentService.getRegionDomain();
- let selfHostedDomain = "";
-
- if (!regionDomain) {
- selfHostedDomain = (await this.stateService.getEnvironmentUrls()).webVault;
- }
-
- this.webVaultHostname = regionDomain || Utils.getHost(selfHostedDomain);
+ this.webVaultHostname = await this.environmentService.getHost();
}
/**
diff --git a/libs/common/src/platform/abstractions/environment.service.ts b/libs/common/src/platform/abstractions/environment.service.ts
index 7bd79a9dd01..8e676991304 100644
--- a/libs/common/src/platform/abstractions/environment.service.ts
+++ b/libs/common/src/platform/abstractions/environment.service.ts
@@ -62,8 +62,8 @@ export abstract class EnvironmentService {
getScimUrl: () => string;
setUrlsFromStorage: () => Promise;
setUrls: (urls: Urls) => Promise;
+ getHost: (userId?: string) => Promise;
getRegion: (userId: string) => Promise;
- getRegionDomain: (userId?: string) => Promise;
setRegion: (region: Region) => Promise;
getUrls: () => Urls;
isCloud: () => boolean;
diff --git a/libs/common/src/platform/services/environment.service.ts b/libs/common/src/platform/services/environment.service.ts
index a126cfc062c..5e38f466fb6 100644
--- a/libs/common/src/platform/services/environment.service.ts
+++ b/libs/common/src/platform/services/environment.service.ts
@@ -285,11 +285,7 @@ export class EnvironmentService implements EnvironmentServiceAbstraction {
);
}
- async getRegion(userId?: string) {
- return this.stateService.getRegion(userId ? { userId: userId } : null);
- }
-
- async getRegionDomain(userId?: string) {
+ async getHost(userId?: string) {
const region = await this.getRegion(userId ? userId : null);
switch (region) {
@@ -298,10 +294,17 @@ export class EnvironmentService implements EnvironmentServiceAbstraction {
case Region.EU:
return RegionDomain.EU;
default:
- return null;
+ // self-hosted host
+ return Utils.getHost(
+ (await this.stateService.getEnvironmentUrls(userId ? { userId: userId } : null)).webVault
+ );
}
}
+ async getRegion(userId?: string) {
+ return this.stateService.getRegion(userId ? { userId: userId } : null);
+ }
+
async setRegion(region: Region) {
this.selectedRegion = region;
await this.stateService.setRegion(region);
@@ -350,16 +353,6 @@ export class EnvironmentService implements EnvironmentServiceAbstraction {
return url.trim();
}
- private removeVaultFromStringIfCloudUrl(url: string) {
- switch (url) {
- case this.usUrls.webVault:
- case this.euUrls.webVault:
- return Utils.getHostname(url).replace(/vault./g, "");
- default:
- return Utils.getHostname(url);
- }
- }
-
isCloud(): boolean {
return [
"https://api.bitwarden.com",
From 8514d960863a576e01728a27a0415f72cb5f5c58 Mon Sep 17 00:00:00 2001
From: rr-bw <102181210+rr-bw@users.noreply.github.com>
Date: Thu, 12 Oct 2023 11:25:51 -0700
Subject: [PATCH 19/22] remove comment
---
libs/common/src/platform/abstractions/environment.service.ts | 1 -
1 file changed, 1 deletion(-)
diff --git a/libs/common/src/platform/abstractions/environment.service.ts b/libs/common/src/platform/abstractions/environment.service.ts
index 8e676991304..143fe1a05a9 100644
--- a/libs/common/src/platform/abstractions/environment.service.ts
+++ b/libs/common/src/platform/abstractions/environment.service.ts
@@ -39,7 +39,6 @@ export abstract class EnvironmentService {
hasBaseUrl: () => boolean;
getNotificationsUrl: () => string;
getWebVaultUrl: () => string;
- // getWebVaultHostname: (url?: string) => string;
/**
* Retrieves the URL of the cloud web vault app.
*
From 8d6eee538c841cbcd111da249a3d301c2c788133 Mon Sep 17 00:00:00 2001
From: rr-bw <102181210+rr-bw@users.noreply.github.com>
Date: Mon, 16 Oct 2023 09:12:55 -0700
Subject: [PATCH 20/22] get base url as fallback
---
.../src/platform/abstractions/environment.service.ts | 1 -
libs/common/src/platform/services/environment.service.ts | 9 +++++----
2 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/libs/common/src/platform/abstractions/environment.service.ts b/libs/common/src/platform/abstractions/environment.service.ts
index 143fe1a05a9..6b8d40c86b7 100644
--- a/libs/common/src/platform/abstractions/environment.service.ts
+++ b/libs/common/src/platform/abstractions/environment.service.ts
@@ -62,7 +62,6 @@ export abstract class EnvironmentService {
setUrlsFromStorage: () => Promise;
setUrls: (urls: Urls) => Promise;
getHost: (userId?: string) => Promise;
- getRegion: (userId: string) => Promise;
setRegion: (region: Region) => Promise;
getUrls: () => Urls;
isCloud: () => boolean;
diff --git a/libs/common/src/platform/services/environment.service.ts b/libs/common/src/platform/services/environment.service.ts
index 5e38f466fb6..4b36467d186 100644
--- a/libs/common/src/platform/services/environment.service.ts
+++ b/libs/common/src/platform/services/environment.service.ts
@@ -288,6 +288,8 @@ export class EnvironmentService implements EnvironmentServiceAbstraction {
async getHost(userId?: string) {
const region = await this.getRegion(userId ? userId : null);
+ let envUrls;
+
switch (region) {
case Region.US:
return RegionDomain.US;
@@ -295,13 +297,12 @@ export class EnvironmentService implements EnvironmentServiceAbstraction {
return RegionDomain.EU;
default:
// self-hosted host
- return Utils.getHost(
- (await this.stateService.getEnvironmentUrls(userId ? { userId: userId } : null)).webVault
- );
+ envUrls = await this.stateService.getEnvironmentUrls(userId ? { userId: userId } : null);
+ return Utils.getHost(envUrls.webVault || envUrls.base);
}
}
- async getRegion(userId?: string) {
+ private async getRegion(userId?: string) {
return this.stateService.getRegion(userId ? { userId: userId } : null);
}
From 4d32a4abcbade5b04d15d3cb0231e58393119d32 Mon Sep 17 00:00:00 2001
From: rr-bw <102181210+rr-bw@users.noreply.github.com>
Date: Thu, 26 Oct 2023 09:35:08 -0700
Subject: [PATCH 21/22] resolve eslint error
---
.../src/platform/services/environment.service.ts | 11 ++++++-----
1 file changed, 6 insertions(+), 5 deletions(-)
diff --git a/libs/common/src/platform/services/environment.service.ts b/libs/common/src/platform/services/environment.service.ts
index 4b36467d186..ebe143e8e84 100644
--- a/libs/common/src/platform/services/environment.service.ts
+++ b/libs/common/src/platform/services/environment.service.ts
@@ -288,17 +288,18 @@ export class EnvironmentService implements EnvironmentServiceAbstraction {
async getHost(userId?: string) {
const region = await this.getRegion(userId ? userId : null);
- let envUrls;
-
switch (region) {
case Region.US:
return RegionDomain.US;
case Region.EU:
return RegionDomain.EU;
- default:
- // self-hosted host
- envUrls = await this.stateService.getEnvironmentUrls(userId ? { userId: userId } : null);
+ default: {
+ // Environment is self-hosted
+ const envUrls = await this.stateService.getEnvironmentUrls(
+ userId ? { userId: userId } : null
+ );
return Utils.getHost(envUrls.webVault || envUrls.base);
+ }
}
}
From 17554889251aa686fb5ef17d0924630317443098 Mon Sep 17 00:00:00 2001
From: rr-bw <102181210+rr-bw@users.noreply.github.com>
Date: Fri, 3 Nov 2023 12:37:01 -0700
Subject: [PATCH 22/22] Update
apps/desktop/src/app/layout/account-switcher.component.html
Co-authored-by: Oscar Hinton
---
apps/desktop/src/app/layout/account-switcher.component.html | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/apps/desktop/src/app/layout/account-switcher.component.html b/apps/desktop/src/app/layout/account-switcher.component.html
index da16f66f815..eedafbcfe0a 100644
--- a/apps/desktop/src/app/layout/account-switcher.component.html
+++ b/apps/desktop/src/app/layout/account-switcher.component.html
@@ -75,9 +75,9 @@
{{ "switchAccount" | i18n }}:
{{ account.value.email }}
- / {{ account.value.server }}
+
+ / {{ account.value.server }}
+
({{