1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-21 02:33:46 +00:00

Merge branch 'master' into copy-totp-on-auto-fill

This commit is contained in:
Thomas Rittson
2021-05-05 12:23:37 +10:00
committed by GitHub
123 changed files with 19534 additions and 10368 deletions

View File

@@ -1,18 +1,22 @@
import {
Component,
NgZone,
OnDestroy,
OnInit,
NgZone
} from '@angular/core';
import { Router } from '@angular/router';
import { ConstantsService } from 'jslib/services/constants.service';
import { I18nService } from 'jslib/abstractions/i18n.service';
import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service';
import { StorageService } from 'jslib/abstractions/storage.service';
import { ConstantsService } from 'jslib/services/constants.service';
import { BroadcasterService } from 'jslib/angular/services/broadcaster.service';
import { BrowserApi } from '../../browser/browserApi';
import { Utils } from 'jslib/misc/utils';
interface ExcludedDomain {
@@ -104,7 +108,7 @@ export class ExcludedDomainsComponent implements OnInit, OnDestroy {
async loadCurrentUris() {
const tabs = await BrowserApi.tabsQuery({ windowType: 'normal' });
if (tabs) {
const uriSet = new Set(tabs.map((tab) => Utils.getHostname(tab.url)));
const uriSet = new Set(tabs.map(tab => Utils.getHostname(tab.url)));
uriSet.delete(null);
this.currentUris = Array.from(uriSet);
}

View File

@@ -24,7 +24,7 @@ export class FolderAddEditComponent extends BaseFolderAddEditComponent {
}
async ngOnInit() {
const queryParamsSub = this.route.queryParams.subscribe(async (params) => {
const queryParamsSub = this.route.queryParams.subscribe(async params => {
if (params.folderId) {
this.folderId = params.folderId;
}

View File

@@ -127,6 +127,15 @@
</div>
<div class="box-footer">{{'disableFaviconDesc' | i18n}}</div>
</div>
<div class="box">
<div class="box-content">
<div class="box-content-row box-content-row-checkbox" appBoxRow>
<label for="badge">{{'disableBadgeCounter' | i18n}}</label>
<input id="badge" type="checkbox" (change)="updateDisableBadgeCounter()" [(ngModel)]="disableBadgeCounter">
</div>
</div>
<div class="box-footer">{{'disableBadgeCounterDesc' | i18n}}</div>
</div>
<div class="box">
<div class="box-content">
<div class="box-content-row" appBoxRow>

View File

@@ -3,8 +3,6 @@ import {
OnInit,
} from '@angular/core';
import { Angulartics2 } from 'angulartics2';
import { UriMatchType } from 'jslib/enums/uriMatchType';
import { I18nService } from 'jslib/abstractions/i18n.service';
@@ -22,6 +20,7 @@ import { ConstantsService } from 'jslib/services/constants.service';
})
export class OptionsComponent implements OnInit {
disableFavicon = false;
disableBadgeCounter = false;
enableAutoFillOnPageLoad = false;
enableAutoTotpCopyOnAutoFill = false;
disableAutoTotpCopy = false;
@@ -38,15 +37,14 @@ export class OptionsComponent implements OnInit {
clearClipboard: number;
clearClipboardOptions: any[];
constructor(private analytics: Angulartics2, private messagingService: MessagingService,
private platformUtilsService: PlatformUtilsService, private storageService: StorageService,
private stateService: StateService, private totpService: TotpService,
i18nService: I18nService) {
constructor(private messagingService: MessagingService, private storageService: StorageService,
private stateService: StateService, private totpService: TotpService, i18nService: I18nService) {
this.themeOptions = [
{ name: i18nService.t('default'), value: null },
{ name: i18nService.t('light'), value: 'light' },
{ name: i18nService.t('dark'), value: 'dark' },
{ name: 'Nord', value: 'nord' },
{ name: i18nService.t('solarizedDark'), value: 'solarizedDark' },
];
this.uriMatchOptions = [
{ name: i18nService.t('baseDomain'), value: UriMatchType.Domain },
@@ -89,6 +87,8 @@ export class OptionsComponent implements OnInit {
this.disableFavicon = await this.storageService.get<boolean>(ConstantsService.disableFaviconKey);
this.disableBadgeCounter = await this.storageService.get<boolean>(ConstantsService.disableBadgeCounterKey);
this.theme = await this.storageService.get<string>(ConstantsService.themeKey);
const defaultUriMatch = await this.storageService.get<UriMatchType>(ConstantsService.defaultUriMatch);
@@ -100,30 +100,25 @@ export class OptionsComponent implements OnInit {
async updateAddLoginNotification() {
await this.storageService.save(ConstantsService.disableAddLoginNotificationKey,
this.disableAddLoginNotification);
this.callAnalytics('Add Login Notification', !this.disableAddLoginNotification);
}
async updateChangedPasswordNotification() {
await this.storageService.save(ConstantsService.disableChangedPasswordNotificationKey,
this.disableChangedPasswordNotification);
this.callAnalytics('Changed Password Notification', !this.disableChangedPasswordNotification);
}
async updateDisableContextMenuItem() {
await this.storageService.save(ConstantsService.disableContextMenuItemKey,
this.disableContextMenuItem);
this.messagingService.send('bgUpdateContextMenu');
this.callAnalytics('Context Menu Item', !this.disableContextMenuItem);
}
async updateAutoTotpCopy() {
await this.storageService.save(ConstantsService.disableAutoTotpCopyKey, this.disableAutoTotpCopy);
this.callAnalytics('Auto Copy TOTP', !this.disableAutoTotpCopy);
}
async updateAutoFillOnPageLoad() {
await this.storageService.save(ConstantsService.enableAutoFillOnPageLoadKey, this.enableAutoFillOnPageLoad);
this.callAnalytics('Auto-fill Page Load', this.enableAutoFillOnPageLoad);
}
async updateAutoTotpCopyOnAutoFill() {
@@ -133,41 +128,34 @@ export class OptionsComponent implements OnInit {
async updateDisableFavicon() {
await this.storageService.save(ConstantsService.disableFaviconKey, this.disableFavicon);
await this.stateService.save(ConstantsService.disableFaviconKey, this.disableFavicon);
this.callAnalytics('Favicon', !this.disableFavicon);
}
async updateDisableBadgeCounter() {
await this.storageService.save(ConstantsService.disableBadgeCounterKey, this.disableBadgeCounter);
await this.stateService.save(ConstantsService.disableBadgeCounterKey, this.disableBadgeCounter);
this.messagingService.send('bgUpdateContextMenu');
}
async updateShowCards() {
await this.storageService.save(ConstantsService.dontShowCardsCurrentTab, this.dontShowCards);
await this.stateService.save(ConstantsService.dontShowCardsCurrentTab, this.dontShowCards);
this.callAnalytics('Show Cards on Current Tab', !this.dontShowCards);
}
async updateShowIdentities() {
await this.storageService.save(ConstantsService.dontShowIdentitiesCurrentTab, this.dontShowIdentities);
await this.stateService.save(ConstantsService.dontShowIdentitiesCurrentTab, this.dontShowIdentities);
this.callAnalytics('Show Identities on Current Tab', !this.dontShowIdentities);
}
async saveTheme() {
await this.storageService.save(ConstantsService.themeKey, this.theme);
this.analytics.eventTrack.next({ action: 'Set Theme ' + this.theme });
window.setTimeout(() => window.location.reload(), 200);
}
async saveDefaultUriMatch() {
await this.storageService.save(ConstantsService.defaultUriMatch, this.defaultUriMatch);
this.analytics.eventTrack.next({ action: 'Set Default URI Match ' + this.defaultUriMatch });
}
async saveClearClipboard() {
await this.storageService.save(ConstantsService.clearClipboardKey, this.clearClipboard);
this.analytics.eventTrack.next({
action: 'Set Clear Clipboard ' + (this.clearClipboard == null ? 'Disabled' : this.clearClipboard),
});
}
private callAnalytics(name: string, enabled: boolean) {
const status = enabled ? 'Enabled' : 'Disabled';
this.analytics.eventTrack.next({ action: `${status} ${name}` });
}
}

View File

@@ -4,7 +4,7 @@ import { Component } from '@angular/core';
import { ApiService } from 'jslib/abstractions/api.service';
import { I18nService } from 'jslib/abstractions/i18n.service';
import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service';
import { TokenService } from 'jslib/abstractions/token.service';
import { UserService } from 'jslib/abstractions/user.service';
import { PremiumComponent as BasePremiumComponent } from 'jslib/angular/components/premium.component';
@@ -16,9 +16,9 @@ export class PremiumComponent extends BasePremiumComponent {
priceString: string;
constructor(i18nService: I18nService, platformUtilsService: PlatformUtilsService,
tokenService: TokenService, apiService: ApiService,
apiService: ApiService, userService: UserService,
private currencyPipe: CurrencyPipe) {
super(i18nService, platformUtilsService, tokenService, apiService);
super(i18nService, platformUtilsService, apiService, userService);
// Support old price string. Can be removed in future once all translations are properly updated.
const thePrice = this.currencyPipe.transform(this.price, '$');

View File

@@ -1,4 +1,3 @@
import { Angulartics2 } from 'angulartics2';
import Swal from 'sweetalert2/src/sweetalert2.js';
import {
@@ -23,6 +22,7 @@ import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service';
import { StorageService } from 'jslib/abstractions/storage.service';
import { UserService } from 'jslib/abstractions/user.service';
import { VaultTimeoutService } from 'jslib/abstractions/vaultTimeout.service';
import { PopupUtilsService } from '../services/popup-utils.service';
const RateUrls = {
[DeviceType.ChromeExtension]:
@@ -56,10 +56,10 @@ export class SettingsComponent implements OnInit {
previousVaultTimeout: number = null;
constructor(private platformUtilsService: PlatformUtilsService, private i18nService: I18nService,
private analytics: Angulartics2, private vaultTimeoutService: VaultTimeoutService,
private storageService: StorageService, public messagingService: MessagingService,
private router: Router, private environmentService: EnvironmentService,
private cryptoService: CryptoService, private userService: UserService) {
private vaultTimeoutService: VaultTimeoutService, private storageService: StorageService,
public messagingService: MessagingService, private router: Router,
private environmentService: EnvironmentService, private cryptoService: CryptoService,
private userService: UserService, private popupUtilsService: PopupUtilsService) {
}
async ngOnInit() {
@@ -212,31 +212,30 @@ export class SettingsComponent implements OnInit {
async updateBiometric() {
if (this.biometric && this.supportsBiometric) {
// Request permission to use the optional permission for nativeMessaging
if (!this.platformUtilsService.isFirefox()) {
const hasPermission = await new Promise((resolve) => {
chrome.permissions.contains({permissions: ['nativeMessaging']}, resolve);
});
let granted;
try {
granted = await BrowserApi.requestPermission({ permissions: ['nativeMessaging'] });
} catch (e) {
// tslint:disable-next-line
console.error(e);
if (!hasPermission) {
if (this.platformUtilsService.isFirefox() && this.popupUtilsService.inSidebar(window)) {
await this.platformUtilsService.showDialog(
this.i18nService.t('nativeMessagingPermissionPromptDesc'), this.i18nService.t('nativeMessagingPermissionPromptTitle'),
this.i18nService.t('nativeMessaginPermissionSidebarDesc'), this.i18nService.t('nativeMessaginPermissionSidebarTitle'),
this.i18nService.t('ok'), null);
const granted = await new Promise((resolve, reject) => {
chrome.permissions.request({permissions: ['nativeMessaging']}, resolve);
});
if (!granted) {
await this.platformUtilsService.showDialog(
this.i18nService.t('nativeMessaginPermissionErrorDesc'), this.i18nService.t('nativeMessaginPermissionErrorTitle'),
this.i18nService.t('ok'), null);
this.biometric = false;
return;
}
this.biometric = false;
return;
}
}
if (!granted) {
await this.platformUtilsService.showDialog(
this.i18nService.t('nativeMessaginPermissionErrorDesc'), this.i18nService.t('nativeMessaginPermissionErrorTitle'),
this.i18nService.t('ok'), null);
this.biometric = false;
return;
}
const submitted = Swal.fire({
heightAuto: false,
buttonsStyling: false,
@@ -254,23 +253,23 @@ export class SettingsComponent implements OnInit {
await this.cryptoService.toggleKey();
await Promise.race([
submitted.then((result) => {
submitted.then(result => {
if (result.dismiss === Swal.DismissReason.cancel) {
this.biometric = false;
this.storageService.remove(ConstantsService.biometricAwaitingAcceptance);
}
}),
this.platformUtilsService.authenticateBiometric().then((result) => {
this.platformUtilsService.authenticateBiometric().then(result => {
this.biometric = result;
Swal.close();
if (this.biometric === false) {
this.platformUtilsService.showToast('error', this.i18nService.t('errorEnableBiometricTitle'), this.i18nService.t('errorEnableBiometricDesc'));
}
}).catch((e) => {
}).catch(e => {
// Handle connection errors
this.biometric = false;
})
}),
]);
} else {
await this.storageService.remove(ConstantsService.biometricUnlockKey);
@@ -279,7 +278,6 @@ export class SettingsComponent implements OnInit {
}
async lock() {
this.analytics.eventTrack.next({ action: 'Lock Now' });
await this.vaultTimeoutService.lock(true);
}
@@ -293,7 +291,6 @@ export class SettingsComponent implements OnInit {
}
async changePassword() {
this.analytics.eventTrack.next({ action: 'Clicked Change Password' });
const confirmed = await this.platformUtilsService.showDialog(
this.i18nService.t('changeMasterPasswordConfirmation'), this.i18nService.t('changeMasterPassword'),
this.i18nService.t('yes'), this.i18nService.t('cancel'));
@@ -303,7 +300,6 @@ export class SettingsComponent implements OnInit {
}
async twoStep() {
this.analytics.eventTrack.next({ action: 'Clicked Two-step Login' });
const confirmed = await this.platformUtilsService.showDialog(
this.i18nService.t('twoStepLoginConfirmation'), this.i18nService.t('twoStepLogin'),
this.i18nService.t('yes'), this.i18nService.t('cancel'));
@@ -313,7 +309,6 @@ export class SettingsComponent implements OnInit {
}
async share() {
this.analytics.eventTrack.next({ action: 'Clicked Share Vault' });
const confirmed = await this.platformUtilsService.showDialog(
this.i18nService.t('shareVaultConfirmation'), this.i18nService.t('shareVault'),
this.i18nService.t('yes'), this.i18nService.t('cancel'));
@@ -323,7 +318,6 @@ export class SettingsComponent implements OnInit {
}
async webVault() {
this.analytics.eventTrack.next({ action: 'Clicked Web Vault' });
let url = this.environmentService.getWebVaultUrl();
if (url == null) {
url = 'https://vault.bitwarden.com';
@@ -332,7 +326,6 @@ export class SettingsComponent implements OnInit {
}
import() {
this.analytics.eventTrack.next({ action: 'Clicked Import Items' });
BrowserApi.createNewTab('https://help.bitwarden.com/article/import-data/');
}
@@ -341,13 +334,10 @@ export class SettingsComponent implements OnInit {
}
help() {
this.analytics.eventTrack.next({ action: 'Clicked Help and Feedback' });
BrowserApi.createNewTab('https://help.bitwarden.com/');
}
about() {
this.analytics.eventTrack.next({ action: 'Clicked About' });
const year = (new Date()).getFullYear();
const versionText = document.createTextNode(
this.i18nService.t('version') + ': ' + BrowserApi.getApplicationVersion());
@@ -367,8 +357,6 @@ export class SettingsComponent implements OnInit {
}
async fingerprint() {
this.analytics.eventTrack.next({ action: 'Clicked Fingerprint' });
const fingerprint = await this.cryptoService.getFingerprint(await this.userService.getUserId());
const p = document.createElement('p');
p.innerText = this.i18nService.t('yourAccountsFingerprint') + ':';
@@ -394,7 +382,6 @@ export class SettingsComponent implements OnInit {
}
rate() {
this.analytics.eventTrack.next({ action: 'Rate Extension' });
const deviceType = this.platformUtilsService.getDevice();
BrowserApi.createNewTab((RateUrls as any)[deviceType]);
}

View File

@@ -1,11 +1,9 @@
import { ToasterService } from 'angular2-toaster';
import { Angulartics2 } from 'angulartics2';
import {
Component,
OnInit,
} from '@angular/core';
import { Router } from '@angular/router';
import { I18nService } from 'jslib/abstractions/i18n.service';
import { SyncService } from 'jslib/abstractions/sync.service';
@@ -18,8 +16,7 @@ export class SyncComponent implements OnInit {
lastSync = '--';
syncPromise: Promise<any>;
constructor(private syncService: SyncService, private router: Router,
private toasterService: ToasterService, private analytics: Angulartics2,
constructor(private syncService: SyncService, private toasterService: ToasterService,
private i18nService: I18nService) {
}
@@ -32,7 +29,6 @@ export class SyncComponent implements OnInit {
const success = await this.syncPromise;
if (success) {
await this.setLastSync();
this.analytics.eventTrack.next({ action: 'Synced Full' });
this.toasterService.popAsync('success', null, this.i18nService.t('syncingComplete'));
} else {
this.toasterService.popAsync('error', null, this.i18nService.t('syncingFailed'));