1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-16 08:13:42 +00:00

Add helper methods to EnvironmentService for retrieving urls (#435)

This commit is contained in:
Oscar Hinton
2021-07-23 20:03:52 +02:00
committed by GitHub
parent c77441b353
commit de288913e4
19 changed files with 234 additions and 158 deletions

View File

@@ -153,12 +153,6 @@ import { UserKeyResponse } from '../models/response/userKeyResponse';
import { SendAccessView } from '../models/view/sendAccessView';
export abstract class ApiService {
urlsSet: boolean;
apiBaseUrl: string;
identityBaseUrl: string;
eventsBaseUrl: string;
setUrls: (urls: EnvironmentUrls) => void;
postIdentityToken: (request: TokenRequest) => Promise<IdentityTokenResponse | IdentityTwoFactorResponse | IdentityCaptchaResponse>;
refreshIdentityToken: () => Promise<any>;

View File

@@ -1,14 +1,29 @@
export abstract class EnvironmentService {
baseUrl: string;
webVaultUrl: string;
apiUrl: string;
identityUrl: string;
iconsUrl: string;
notificationsUrl: string;
eventsUrl: string;
enterpriseUrl: string;
import { Observable } from 'rxjs';
export type Urls = {
base?: string;
webVault?: string;
api?: string;
identity?: string;
icons?: string;
notifications?: string;
events?: string;
enterprise?: string;
};
export abstract class EnvironmentService {
urls: Observable<Urls>;
hasBaseUrl: () => boolean;
getNotificationsUrl: () => string;
getEnterpriseUrl: () => string;
getWebVaultUrl: () => string;
getSendUrl: () => string;
getIconsUrl: () => string;
getApiUrl: () => string;
getIdentityUrl: () => string;
getEventsUrl: () => string;
setUrlsFromStorage: () => Promise<void>;
setUrls: (urls: any) => Promise<any>;
setUrls: (urls: any, saveSettings?: boolean) => Promise<Urls>;
getUrls: () => Urls;
}

View File

@@ -1,7 +1,5 @@
import { EnvironmentService } from './environment.service';
export abstract class NotificationsService {
init: (environmentService: EnvironmentService) => Promise<void>;
init: () => Promise<void>;
updateConnection: (sync?: boolean) => Promise<void>;
reconnectFromActivity: () => Promise<void>;
disconnectFromInactivity: () => Promise<void>;

View File

@@ -5,8 +5,6 @@ import { ApiService as ApiServiceAbstraction } from '../abstractions/api.service
import { PlatformUtilsService } from '../abstractions/platformUtils.service';
import { TokenService } from '../abstractions/token.service';
import { EnvironmentUrls } from '../models/domain/environmentUrls';
import { AttachmentRequest } from '../models/request/attachmentRequest';
import { BitPayInvoiceRequest } from '../models/request/bitPayInvoiceRequest';
import { CipherBulkDeleteRequest } from '../models/request/cipherBulkDeleteRequest';
@@ -160,23 +158,19 @@ import { ChallengeResponse } from '../models/response/twoFactorWebAuthnResponse'
import { TwoFactorYubiKeyResponse } from '../models/response/twoFactorYubiKeyResponse';
import { UserKeyResponse } from '../models/response/userKeyResponse';
import { EnvironmentService } from '../abstractions';
import { IdentityCaptchaResponse } from '../models/response/identityCaptchaResponse';
import { SendAccessView } from '../models/view/sendAccessView';
export class ApiService implements ApiServiceAbstraction {
urlsSet: boolean = false;
apiBaseUrl: string;
identityBaseUrl: string;
eventsBaseUrl: string;
private device: DeviceType;
private deviceType: string;
private isWebClient = false;
private isDesktopClient = false;
private usingBaseUrl = false;
constructor(private tokenService: TokenService, private platformUtilsService: PlatformUtilsService,
private logoutCallback: (expired: boolean) => Promise<void>, private customUserAgent: string = null) {
private environmentService: EnvironmentService, private logoutCallback: (expired: boolean) => Promise<void>,
private customUserAgent: string = null) {
this.device = platformUtilsService.getDevice();
this.deviceType = this.device.toString();
this.isWebClient = this.device === DeviceType.IEBrowser || this.device === DeviceType.ChromeBrowser ||
@@ -187,33 +181,6 @@ export class ApiService implements ApiServiceAbstraction {
this.device === DeviceType.LinuxDesktop;
}
setUrls(urls: EnvironmentUrls): void {
this.urlsSet = true;
if (urls.base != null) {
this.usingBaseUrl = true;
this.apiBaseUrl = urls.base + '/api';
this.identityBaseUrl = urls.base + '/identity';
this.eventsBaseUrl = urls.base + '/events';
return;
}
this.apiBaseUrl = urls.api;
this.identityBaseUrl = urls.identity;
this.eventsBaseUrl = urls.events;
// Production
if (this.apiBaseUrl == null) {
this.apiBaseUrl = 'https://api.bitwarden.com';
}
if (this.identityBaseUrl == null) {
this.identityBaseUrl = 'https://identity.bitwarden.com';
}
if (this.eventsBaseUrl == null) {
this.eventsBaseUrl = 'https://events.bitwarden.com';
}
}
// Auth APIs
async postIdentityToken(request: TokenRequest): Promise<IdentityTokenResponse | IdentityTwoFactorResponse | IdentityCaptchaResponse> {
@@ -226,7 +193,7 @@ export class ApiService implements ApiServiceAbstraction {
headers.set('User-Agent', this.customUserAgent);
}
request.alterIdentityTokenHeaders(headers);
const response = await this.fetch(new Request(this.identityBaseUrl + '/connect/token', {
const response = await this.fetch(new Request(this.environmentService.getIdentityUrl() + '/connect/token', {
body: this.qsStringify(request.toIdentityToken(request.clientId ?? this.platformUtilsService.identityClientId)),
credentials: this.getCredentials(),
cache: 'no-store',
@@ -1399,7 +1366,7 @@ export class ApiService implements ApiServiceAbstraction {
if (this.customUserAgent != null) {
headers.set('User-Agent', this.customUserAgent);
}
const response = await this.fetch(new Request(this.eventsBaseUrl + '/collect', {
const response = await this.fetch(new Request(this.environmentService.getEventsUrl() + '/collect', {
cache: 'no-store',
credentials: this.getCredentials(),
method: 'POST',
@@ -1473,7 +1440,7 @@ export class ApiService implements ApiServiceAbstraction {
}
const path = `/account/prevalidate?domainHint=${encodeURIComponent(identifier)}`;
const response = await this.fetch(new Request(this.identityBaseUrl + path, {
const response = await this.fetch(new Request(this.environmentService.getIdentityUrl() + path, {
cache: 'no-store',
credentials: this.getCredentials(),
headers: headers,
@@ -1503,7 +1470,7 @@ export class ApiService implements ApiServiceAbstraction {
}
const decodedToken = this.tokenService.decodeToken();
const response = await this.fetch(new Request(this.identityBaseUrl + '/connect/token', {
const response = await this.fetch(new Request(this.environmentService.getIdentityUrl() + '/connect/token', {
body: this.qsStringify({
grant_type: 'refresh_token',
client_id: decodedToken.client_id,
@@ -1528,7 +1495,7 @@ export class ApiService implements ApiServiceAbstraction {
private async send(method: 'GET' | 'POST' | 'PUT' | 'DELETE', path: string, body: any,
authed: boolean, hasResponse: boolean, apiUrl?: string,
alterHeaders?: (headers: Headers) => void): Promise<any> {
apiUrl = Utils.isNullOrWhitespace(apiUrl) ? this.apiBaseUrl : apiUrl;
apiUrl = Utils.isNullOrWhitespace(apiUrl) ? this.environmentService.getApiUrl() : apiUrl;
const headers = new Headers({
'Device-Type': this.deviceType,
});
@@ -1601,7 +1568,7 @@ export class ApiService implements ApiServiceAbstraction {
}
private getCredentials(): RequestCredentials {
if (!this.isWebClient || this.usingBaseUrl) {
if (!this.isWebClient || this.environmentService.hasBaseUrl()) {
return 'include';
}
return undefined;

View File

@@ -1,32 +1,119 @@
import { Observable, Subject } from 'rxjs';
import { EnvironmentUrls } from '../models/domain/environmentUrls';
import { ConstantsService } from './constants.service';
import { ApiService } from '../abstractions/api.service';
import { EnvironmentService as EnvironmentServiceAbstraction } from '../abstractions/environment.service';
import { NotificationsService } from '../abstractions/notifications.service';
import { EnvironmentService as EnvironmentServiceAbstraction, Urls } from '../abstractions/environment.service';
import { StorageService } from '../abstractions/storage.service';
export class EnvironmentService implements EnvironmentServiceAbstraction {
baseUrl: string;
webVaultUrl: string;
apiUrl: string;
identityUrl: string;
iconsUrl: string;
notificationsUrl: string;
eventsUrl: string;
enterpriseUrl: string;
constructor(private apiService: ApiService, private storageService: StorageService,
private notificationsService: NotificationsService) { }
private readonly urlsSubject = new Subject<Urls>();
urls: Observable<Urls> = this.urlsSubject; // tslint:disable-line
getWebVaultUrl(): string {
private baseUrl: string;
private webVaultUrl: string;
private apiUrl: string;
private identityUrl: string;
private iconsUrl: string;
private notificationsUrl: string;
private eventsUrl: string;
private enterpriseUrl: string;
constructor(private storageService: StorageService) {}
hasBaseUrl() {
return this.baseUrl != null;
}
getNotificationsUrl() {
if (this.notificationsUrl != null) {
return this.notificationsUrl;
}
if (this.baseUrl != null) {
return this.baseUrl + '/notifications';
}
return 'https://notifications.bitwarden.com';
}
getEnterpriseUrl() {
if (this.enterpriseUrl != null) {
return this.enterpriseUrl;
}
if (this.baseUrl != null) {
return this.baseUrl + '/portal';
}
return 'https://portal.bitwarden.com';
}
getWebVaultUrl() {
if (this.webVaultUrl != null) {
return this.webVaultUrl;
} else if (this.baseUrl) {
}
if (this.baseUrl) {
return this.baseUrl;
}
return null;
return 'https://vault.bitwarden.com';
}
getSendUrl() {
return this.getWebVaultUrl() === 'https://vault.bitwarden.com'
? 'https://send.bitwarden.com/#'
: this.getWebVaultUrl() + '/#/send/';
}
getIconsUrl() {
if (this.iconsUrl != null) {
return this.iconsUrl;
}
if (this.baseUrl) {
return this.baseUrl + '/icons';
}
return 'https://icons.bitwarden.net';
}
getApiUrl() {
if (this.apiUrl != null) {
return this.apiUrl;
}
if (this.baseUrl) {
return this.baseUrl + '/api';
}
return 'https://api.bitwarden.com';
}
getIdentityUrl() {
if (this.identityUrl != null) {
return this.identityUrl;
}
if (this.baseUrl) {
return this.baseUrl + '/identity';
}
return 'https://identity.bitwarden.com';
}
getEventsUrl() {
if (this.eventsUrl != null) {
return this.eventsUrl;
}
if (this.baseUrl) {
return this.baseUrl + '/events';
}
return 'https://events.bitwarden.com';
}
async setUrlsFromStorage(): Promise<void> {
@@ -46,7 +133,6 @@ export class EnvironmentService implements EnvironmentServiceAbstraction {
if (urls.base) {
this.baseUrl = envUrls.base = urls.base;
this.apiService.setUrls(envUrls);
return;
}
@@ -57,10 +143,9 @@ export class EnvironmentService implements EnvironmentServiceAbstraction {
this.notificationsUrl = urls.notifications;
this.eventsUrl = envUrls.events = urls.events;
this.enterpriseUrl = urls.enterprise;
this.apiService.setUrls(envUrls);
}
async setUrls(urls: any): Promise<any> {
async setUrls(urls: Urls, saveSettings: boolean = true): Promise<any> {
urls.base = this.formatUrl(urls.base);
urls.webVault = this.formatUrl(urls.webVault);
urls.api = this.formatUrl(urls.api);
@@ -70,16 +155,18 @@ export class EnvironmentService implements EnvironmentServiceAbstraction {
urls.events = this.formatUrl(urls.events);
urls.enterprise = this.formatUrl(urls.enterprise);
await this.storageService.save(ConstantsService.environmentUrlsKey, {
base: urls.base,
api: urls.api,
identity: urls.identity,
webVault: urls.webVault,
icons: urls.icons,
notifications: urls.notifications,
events: urls.events,
enterprise: urls.enterprise,
});
if (saveSettings) {
await this.storageService.save(ConstantsService.environmentUrlsKey, {
base: urls.base,
api: urls.api,
identity: urls.identity,
webVault: urls.webVault,
icons: urls.icons,
notifications: urls.notifications,
events: urls.events,
enterprise: urls.enterprise,
});
}
this.baseUrl = urls.base;
this.webVaultUrl = urls.webVault;
@@ -90,22 +177,24 @@ export class EnvironmentService implements EnvironmentServiceAbstraction {
this.eventsUrl = urls.events;
this.enterpriseUrl = urls.enterprise;
const envUrls = new EnvironmentUrls();
if (this.baseUrl) {
envUrls.base = this.baseUrl;
} else {
envUrls.api = this.apiUrl;
envUrls.identity = this.identityUrl;
envUrls.events = this.eventsUrl;
}
this.urlsSubject.next(urls);
this.apiService.setUrls(envUrls);
if (this.notificationsService != null) {
this.notificationsService.init(this);
}
return urls;
}
getUrls() {
return {
base: this.baseUrl,
webVault: this.webVaultUrl,
api: this.apiUrl,
identity: this.identityUrl,
icons: this.iconsUrl,
notifications: this.notificationsUrl,
events: this.eventsUrl,
enterprise: this.enterpriseUrl,
};
}
private formatUrl(url: string): string {
if (url == null || url === '') {
return null;

View File

@@ -29,18 +29,20 @@ export class NotificationsService implements NotificationsServiceAbstraction {
constructor(private userService: UserService, private syncService: SyncService,
private appIdService: AppIdService, private apiService: ApiService,
private vaultTimeoutService: VaultTimeoutService,
private vaultTimeoutService: VaultTimeoutService, private environmentService: EnvironmentService,
private logoutCallback: () => Promise<void>, private logService: LogService) {
this.environmentService.urls.subscribe(() => {
if (!this.inited) {
return;
}
this.init();
});
}
async init(environmentService: EnvironmentService): Promise<void> {
async init(): Promise<void> {
this.inited = false;
this.url = 'https://notifications.bitwarden.com';
if (environmentService.notificationsUrl != null) {
this.url = environmentService.notificationsUrl;
} else if (environmentService.baseUrl != null) {
this.url = environmentService.baseUrl + '/notifications';
}
this.url = this.environmentService.getNotificationsUrl();
// Set notifications server URL to `https://-` to effectively disable communication
// with the notifications server from the client app