1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-23 11:43:46 +00:00

Merge branch 'master' into patrickhlauke-issue1987

This commit is contained in:
Patrick H. Lauke
2021-12-13 17:37:42 +00:00
111 changed files with 6395 additions and 7969 deletions

View File

@@ -2,16 +2,16 @@
<header>
<div class="left"></div>
<h1 class="center">
<span class="title">{{(pinLock ? 'verifyPin' : 'verifyMasterPassword') | i18n}}</span>
<span class="title">{{'verifyIdentity' | i18n}}</span>
</h1>
<div class="right">
<button type="submit" appBlurClick>{{'unlock' | i18n}}</button>
<button type="submit" appBlurClick *ngIf="!hideInput">{{'unlock' | i18n}}</button>
</div>
</header>
<content>
<div class="box">
<div class="box-content">
<div class="box-content-row box-content-row-flex" appBoxRow>
<div class="box-content-row box-content-row-flex" appBoxRow *ngIf="!hideInput">
<div class="row-main" *ngIf="pinLock">
<label for="pin">{{'pin' | i18n}}</label>
<input id="pin" type="{{showPassword ? 'text' : 'password'}}" name="PIN" class="monospaced"
@@ -32,13 +32,14 @@
</div>
</div>
<div class="box-footer">
<p>{{(pinLock ? 'yourVaultIsLockedPinCode' : 'yourVaultIsLocked') | i18n}}</p>
<p>{{'yourVaultIsLocked' | i18n}}</p>
{{'loggedInAsOn' | i18n : email : webVaultHostname}}
</div>
</div>
<div class="box" *ngIf="biometricLock">
<div class="box-footer">
<button type="button" class="btn primary block" (click)="unlockBiometric()" appStopClick>{{'unlockWithBiometrics' | i18n}}</button>
<button type="button" class="btn primary block" (click)="unlockBiometric()"
appStopClick>{{'unlockWithBiometrics' | i18n}}</button>
</div>
</div>
<p class="text-center">

View File

@@ -1,4 +1,7 @@
import { Component } from '@angular/core';
import {
Component,
NgZone,
} from '@angular/core';
import { Router } from '@angular/router';
import Swal from 'sweetalert2';
@@ -8,6 +11,7 @@ import { ApiService } from 'jslib-common/abstractions/api.service';
import { CryptoService } from 'jslib-common/abstractions/crypto.service';
import { EnvironmentService } from 'jslib-common/abstractions/environment.service';
import { I18nService } from 'jslib-common/abstractions/i18n.service';
import { KeyConnectorService } from 'jslib-common/abstractions/keyConnector.service';
import { LogService } from 'jslib-common/abstractions/log.service';
import { MessagingService } from 'jslib-common/abstractions/messaging.service';
import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
@@ -30,9 +34,11 @@ export class LockComponent extends BaseLockComponent {
userService: UserService, cryptoService: CryptoService,
storageService: StorageService, vaultTimeoutService: VaultTimeoutService,
environmentService: EnvironmentService, stateService: StateService,
apiService: ApiService, logService: LogService) {
apiService: ApiService, logService: LogService, keyConnectorService: KeyConnectorService,
ngZone: NgZone) {
super(router, i18nService, platformUtilsService, messagingService, userService, cryptoService,
storageService, vaultTimeoutService, environmentService, stateService, apiService, logService);
storageService, vaultTimeoutService, environmentService, stateService, apiService, logService,
keyConnectorService, ngZone);
this.successRoute = '/tabs/current';
this.isInitialLockScreen = (window as any).previousPopupUrl == null;
}

View File

@@ -1,4 +1,7 @@
import { Component } from '@angular/core';
import {
Component,
NgZone,
} from '@angular/core';
import { Router } from '@angular/router';
import { AuthService } from 'jslib-common/abstractions/auth.service';
@@ -24,9 +27,9 @@ export class LoginComponent extends BaseLoginComponent {
protected stateService: StateService, protected environmentService: EnvironmentService,
protected passwordGenerationService: PasswordGenerationService,
protected cryptoFunctionService: CryptoFunctionService, storageService: StorageService,
syncService: SyncService, logService: LogService) {
syncService: SyncService, logService: LogService, ngZone: NgZone) {
super(authService, router, platformUtilsService, i18nService, stateService, environmentService,
passwordGenerationService, cryptoFunctionService, storageService, logService);
passwordGenerationService, cryptoFunctionService, storageService, logService, ngZone);
super.onSuccessfulLogin = async () => {
await syncService.fullSync(true);
};

View File

@@ -0,0 +1,29 @@
<header>
<div class="left"></div>
<div class="center">
<span class="title">{{'removeMasterPassword' | i18n}}</span>
</div>
<div class="right"></div>
</header>
<content>
<div class="box">
<div class="box-content">
<div class="box-content-row" appBoxRow>
<p>{{'convertOrganizationEncryptionDesc' | i18n : organization.name}}</p>
</div>
<div class="box-content-row">
<button type="button" class="btn block primary" (click)="convert()" [disabled]="actionPromise">
<i class="fa fa-spinner fa-spin" title="{{'loading' | i18n}}" aria-hidden="true" *ngIf="continuing"></i>
{{'removeMasterPassword' | i18n}}
</button>
</div>
<div class="box-content-row">
<button type="button" class="btn btn-outline-secondary block" (click)="leave()" [disabled]="actionPromise">
<i class="fa fa-spinner fa-spin" title="{{'loading' | i18n}}" aria-hidden="true" *ngIf="leaving"></i>
{{'leaveOrganization' | i18n}}
</button>
</div>
</div>
</div>
</content>

View File

@@ -0,0 +1,10 @@
import { Component } from '@angular/core';
import { RemovePasswordComponent as BaseRemovePasswordComponent } from 'jslib-angular/components/remove-password.component';
@Component({
selector: 'app-remove-password',
templateUrl: 'remove-password.component.html',
})
export class RemovePasswordComponent extends BaseRemovePasswordComponent {
}

View File

@@ -16,6 +16,7 @@ import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.se
import { StateService } from 'jslib-common/abstractions/state.service';
import { StorageService } from 'jslib-common/abstractions/storage.service';
import { SyncService } from 'jslib-common/abstractions/sync.service';
import { VaultTimeoutService } from 'jslib-common/abstractions/vaultTimeout.service';
import { SsoComponent as BaseSsoComponent } from 'jslib-angular/components/sso.component';
import { BrowserApi } from '../../browser/browserApi';
@@ -30,7 +31,8 @@ export class SsoComponent extends BaseSsoComponent {
storageService: StorageService, stateService: StateService,
platformUtilsService: PlatformUtilsService, apiService: ApiService,
cryptoFunctionService: CryptoFunctionService, passwordGenerationService: PasswordGenerationService,
syncService: SyncService, environmentService: EnvironmentService, logService: LogService) {
syncService: SyncService, environmentService: EnvironmentService, logService: LogService,
private vaultTimeoutService: VaultTimeoutService) {
super(authService, router, i18nService, route, storageService, stateService, platformUtilsService,
apiService, cryptoFunctionService, environmentService, passwordGenerationService, logService);
@@ -41,7 +43,11 @@ export class SsoComponent extends BaseSsoComponent {
super.onSuccessfulLogin = async () => {
await syncService.fullSync(true);
BrowserApi.reloadOpenWindows();
if (await this.vaultTimeoutService.isLocked()) {
// If the vault is unlocked then this will clear keys from memory, which we don't want to do
BrowserApi.reloadOpenWindows();
}
const thisWindow = window.open('', '_self');
thisWindow.close();
};

View File

@@ -9,6 +9,7 @@ import { TwoFactorProviderType } from 'jslib-common/enums/twoFactorProviderType'
import { ApiService } from 'jslib-common/abstractions/api.service';
import { AuthService } from 'jslib-common/abstractions/auth.service';
import { BroadcasterService } from 'jslib-common/abstractions/broadcaster.service';
import { EnvironmentService } from 'jslib-common/abstractions/environment.service';
import { I18nService } from 'jslib-common/abstractions/i18n.service';
import { LogService } from 'jslib-common/abstractions/log.service';
@@ -18,8 +19,6 @@ import { StateService } from 'jslib-common/abstractions/state.service';
import { StorageService } from 'jslib-common/abstractions/storage.service';
import { SyncService } from 'jslib-common/abstractions/sync.service';
import { BroadcasterService } from 'jslib-angular/services/broadcaster.service';
import { TwoFactorComponent as BaseTwoFactorComponent } from 'jslib-angular/components/two-factor.component';
import { PopupUtilsService } from '../services/popup-utils.service';

View File

@@ -7,10 +7,10 @@ import {
} from '@angular/router';
import { AuthGuardService } from 'jslib-angular/services/auth-guard.service';
import { LockGuardService } from 'jslib-angular/services/lock-guard.service';
import { DebounceNavigationService } from './services/debounceNavigationService';
import { LaunchGuardService } from './services/launch-guard.service';
import { LockGuardService } from './services/lock-guard.service';
import { EnvironmentComponent } from './accounts/environment.component';
import { HintComponent } from './accounts/hint.component';
@@ -18,6 +18,7 @@ import { HomeComponent } from './accounts/home.component';
import { LockComponent } from './accounts/lock.component';
import { LoginComponent } from './accounts/login.component';
import { RegisterComponent } from './accounts/register.component';
import { RemovePasswordComponent } from './accounts/remove-password.component';
import { SetPasswordComponent } from './accounts/set-password.component';
import { SsoComponent } from './accounts/sso.component';
import { TwoFactorOptionsComponent } from './accounts/two-factor-options.component';
@@ -105,6 +106,12 @@ const routes: Routes = [
component: SetPasswordComponent,
data: { state: 'set-password' },
},
{
path: 'remove-password',
component: RemovePasswordComponent,
canActivate: [AuthGuardService],
data: { state: 'remove-password' },
},
{
path: 'register',
component: RegisterComponent,

View File

@@ -1,13 +1,3 @@
import { BrowserApi } from '../browser/browserApi';
import {
BodyOutputType,
Toast,
ToasterConfig,
ToasterService,
} from 'angular2-toaster';
import Swal, { SweetAlertIcon } from 'sweetalert2/src/sweetalert2.js';
import {
ChangeDetectorRef,
Component,
@@ -21,11 +11,17 @@ import {
Router,
RouterOutlet,
} from '@angular/router';
import { BroadcasterService } from 'jslib-angular/services/broadcaster.service';
import {
IndividualConfig,
ToastrService,
} from 'ngx-toastr';
import Swal, { SweetAlertIcon } from 'sweetalert2/src/sweetalert2.js';
import { BrowserApi } from '../browser/browserApi';
import { AuthService } from 'jslib-common/abstractions/auth.service';
import { BroadcasterService } from 'jslib-common/abstractions/broadcaster.service';
import { I18nService } from 'jslib-common/abstractions/i18n.service';
import { KeyConnectorService } from 'jslib-common/abstractions/keyConnector.service';
import { MessagingService } from 'jslib-common/abstractions/messaging.service';
import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
import { StateService } from 'jslib-common/abstractions/state.service';
@@ -33,7 +29,6 @@ import { StorageService } from 'jslib-common/abstractions/storage.service';
import { ConstantsService } from 'jslib-common/services/constants.service';
import BrowserPlatformUtilsService from 'src/services/browserPlatformUtils.service';
import { routerTransition } from './app-routing.animations';
@Component({
@@ -41,29 +36,21 @@ import { routerTransition } from './app-routing.animations';
styles: [],
animations: [routerTransition],
template: `
<toaster-container [toasterconfig]="toasterConfig" aria-live="polite"></toaster-container>
<main [@routerTransition]="getState(o)">
<router-outlet #o="outlet"></router-outlet>
</main>`,
})
export class AppComponent implements OnInit {
toasterConfig: ToasterConfig = new ToasterConfig({
showCloseButton: false,
mouseoverTimerStop: true,
animation: 'slideUp',
limit: 2,
positionClass: 'toast-bottom-full-width',
newestOnTop: false,
});
private lastActivity: number = null;
constructor(private toasterService: ToasterService, private storageService: StorageService,
constructor(private toastrService: ToastrService, private storageService: StorageService,
private broadcasterService: BroadcasterService, private authService: AuthService,
private i18nService: I18nService, private router: Router,
private stateService: StateService, private messagingService: MessagingService,
private changeDetectorRef: ChangeDetectorRef, private ngZone: NgZone,
private sanitizer: DomSanitizer, private platformUtilsService: PlatformUtilsService) { }
private sanitizer: DomSanitizer, private platformUtilsService: PlatformUtilsService,
private keyConnectoService: KeyConnectorService) { }
ngOnInit() {
if (BrowserApi.getBackgroundPage() == null) {
@@ -121,6 +108,11 @@ export class AppComponent implements OnInit {
this.ngZone.run(() => {
this.router.navigate(['/']);
});
} else if (msg.command === 'convertAccountToKeyConnector') {
this.ngZone.run(async () => {
await this.keyConnectoService.setConvertAccountRequired(true);
this.router.navigate(['/remove-password']);
});
} else {
msg.webExtSender = sender;
this.broadcasterService.send(msg);
@@ -178,30 +170,29 @@ export class AppComponent implements OnInit {
}
private showToast(msg: any) {
const toast: Toast = {
type: msg.type,
title: msg.title,
};
let message = '';
const options: Partial<IndividualConfig> = {};
if (typeof (msg.text) === 'string') {
toast.body = msg.text;
message = msg.text;
} else if (msg.text.length === 1) {
toast.body = msg.text[0];
message = msg.text[0];
} else {
let message = '';
msg.text.forEach((t: string) =>
message += ('<p>' + this.sanitizer.sanitize(SecurityContext.HTML, t) + '</p>'));
toast.body = message;
toast.bodyOutputType = BodyOutputType.TrustedHtml;
options.enableHtml = true;
}
if (msg.options != null) {
if (msg.options.trustedHtml === true) {
toast.bodyOutputType = BodyOutputType.TrustedHtml;
options.enableHtml = true;
}
if (msg.options.timeout != null && msg.options.timeout > 0) {
toast.timeout = msg.options.timeout;
options.timeOut = msg.options.timeout;
}
}
this.toasterService.popAsync(toast);
this.toastrService.show(message, msg.title, options, 'toast-' + msg.type);
}
private async showDialog(msg: any) {

View File

@@ -1,7 +1,6 @@
import { A11yModule } from '@angular/cdk/a11y';
import { DragDropModule } from '@angular/cdk/drag-drop';
import { ScrollingModule } from '@angular/cdk/scrolling';
import { ToasterModule } from 'angular2-toaster';
import { AppRoutingModule } from './app-routing.module';
import { ServicesModule } from './services/services.module';
@@ -17,6 +16,7 @@ import { HomeComponent } from './accounts/home.component';
import { LockComponent } from './accounts/lock.component';
import { LoginComponent } from './accounts/login.component';
import { RegisterComponent } from './accounts/register.component';
import { RemovePasswordComponent } from './accounts/remove-password.component';
import { SetPasswordComponent } from './accounts/set-password.component';
import { SsoComponent } from './accounts/sso.component';
import { TwoFactorOptionsComponent } from './accounts/two-factor-options.component';
@@ -80,9 +80,11 @@ import { PasswordRepromptComponent } from './components/password-reprompt.compon
import { PopOutComponent } from './components/pop-out.component';
import { SendListComponent } from './components/send-list.component';
import { SetPinComponent } from './components/set-pin.component';
import { VerifyMasterPasswordComponent } from './components/verify-master-password.component';
import { CalloutComponent } from 'jslib-angular/components/callout.component';
import { IconComponent } from 'jslib-angular/components/icon.component';
import { BitwardenToastModule } from 'jslib-angular/components/toastr.component';
import {
CurrencyPipe,
@@ -186,12 +188,18 @@ registerLocaleData(localeZhTw, 'zh-TW');
ReactiveFormsModule,
ScrollingModule,
ServicesModule,
ToasterModule.forRoot(),
BitwardenToastModule.forRoot({
maxOpened: 2,
autoDismiss: true,
closeButton: true,
positionClass: 'toast-bottom-full-width',
}),
],
declarations: [
A11yTitleDirective,
ActionButtonsComponent,
AddEditComponent,
AddEditCustomFieldsComponent,
ApiActionDirective,
AppComponent,
AttachmentsComponent,
@@ -212,8 +220,8 @@ registerLocaleData(localeZhTw, 'zh-TW');
FolderAddEditComponent,
FoldersComponent,
GroupingsComponent,
HomeComponent,
HintComponent,
HomeComponent,
I18nPipe,
IconComponent,
InputVerbatimDirective,
@@ -223,6 +231,7 @@ registerLocaleData(localeZhTw, 'zh-TW');
PasswordGeneratorComponent,
PasswordGeneratorHistoryComponent,
PasswordHistoryComponent,
PasswordRepromptComponent,
PopOutComponent,
PremiumComponent,
PrivateModeComponent,
@@ -235,6 +244,7 @@ registerLocaleData(localeZhTw, 'zh-TW');
SendListComponent,
SendTypeComponent,
SetPasswordComponent,
SetPinComponent,
SettingsComponent,
ShareComponent,
SsoComponent,
@@ -243,15 +253,14 @@ registerLocaleData(localeZhTw, 'zh-TW');
SyncComponent,
TabsComponent,
TrueFalseValueDirective,
TwoFactorOptionsComponent,
TwoFactorComponent,
TwoFactorOptionsComponent,
UpdateTempPasswordComponent,
ViewComponent,
PasswordRepromptComponent,
SetPinComponent,
VaultTimeoutInputComponent,
AddEditCustomFieldsComponent,
VerifyMasterPasswordComponent,
ViewComponent,
ViewCustomFieldsComponent,
RemovePasswordComponent,
],
entryComponents: [],
providers: [

View File

@@ -5,8 +5,6 @@ import {
Output,
} from '@angular/core';
import { ToasterService } from 'angular2-toaster';
import { CipherRepromptType } from 'jslib-common/enums/cipherRepromptType';
import { CipherType } from 'jslib-common/enums/cipherType';
import { EventType } from 'jslib-common/enums/eventType';
@@ -33,7 +31,7 @@ export class ActionButtonsComponent {
cipherType = CipherType;
userHasPremiumAccess = false;
constructor(private toasterService: ToasterService, private i18nService: I18nService,
constructor(private i18nService: I18nService,
private platformUtilsService: PlatformUtilsService, private eventService: EventService,
private totpService: TotpService, private userService: UserService,
private passwordRepromptService: PasswordRepromptService) { }
@@ -63,7 +61,7 @@ export class ActionButtonsComponent {
}
this.platformUtilsService.copyToClipboard(value, { window: window });
this.toasterService.popAsync('info', null,
this.platformUtilsService.showToast('info', null,
this.i18nService.t('valueCopied', this.i18nService.t(typeI18nKey)));
if (typeI18nKey === 'password' || typeI18nKey === 'verificationCodeTotp') {

View File

@@ -23,7 +23,7 @@
</div>
</div>
</div>
<div class="checkbox">
<div class="checkbox" *ngIf="showMasterPassOnRestart">
<label for="masterPasswordOnRestart">
<input type="checkbox" id="masterPasswordOnRestart" name="MasterPasswordOnRestart"
[(ngModel)]="masterPassOnRestart">

View File

@@ -0,0 +1,25 @@
<ng-container *ngIf="!usesKeyConnector">
<div class="box-content-row" appBoxRow>
<label for="masterPassword">{{'masterPass' | i18n}}</label>
<input id="masterPassword" type="password" name="MasterPasswordHash" class="form-control"
[formControl]="secret" required appAutofocus appInputVerbatim>
</div>
</ng-container>
<ng-container *ngIf="usesKeyConnector">
<div class="box-content-row" appBoxRow>
<label class="d-block">{{'sendVerificationCode' | i18n}}</label>
<button type="button" class="btn btn-outline-secondary" (click)="requestOTP()" [disabled]="disableRequestOTP">
{{'sendCode' | i18n}}
</button>
<span class="ml-2 text-success" role="alert" @sent *ngIf="sentCode">
<i class="fa fa-check-circle-o" aria-hidden="true"></i>
{{'codeSent' | i18n}}
</span>
</div>
<div class="box-content-row" appBoxRow>
<label for="verificationCode">{{'verificationCode' | i18n}}</label>
<input id="verificationCode" type="input" name="verificationCode" class="form-control"
[formControl]="secret" required appAutofocus appInputVerbatim>
</div>
</ng-container>

View File

@@ -0,0 +1,31 @@
import {
animate,
style,
transition,
trigger,
} from '@angular/animations';
import { Component } from '@angular/core';
import { NG_VALUE_ACCESSOR } from '@angular/forms';
import { VerifyMasterPasswordComponent as BaseComponent } from 'jslib-angular/components/verify-master-password.component';
@Component({
selector: 'app-verify-master-password',
templateUrl: 'verify-master-password.component.html',
providers: [
{
provide: NG_VALUE_ACCESSOR,
multi: true,
useExisting: VerifyMasterPasswordComponent,
},
],
animations: [
trigger('sent', [
transition(':enter', [
style({ opacity: 0 }),
animate('100ms', style({ opacity: 1 })),
]),
]),
],
})
export class VerifyMasterPasswordComponent extends BaseComponent { }

View File

@@ -347,6 +347,22 @@ app-root {
}
@media only screen and (min-width: 601px) {
app-login header {
padding: 0 calc((100% - 500px) / 2);
}
app-login content {
padding: 0 calc((100% - 500px) / 2);
}
app-two-factor header {
padding: 0 calc((100% - 500px) / 2);
}
app-two-factor content {
padding: 0 calc((100% - 500px) / 2);
}
app-lock header {
padding: 0 calc((100% - 500px) / 2);
}

View File

@@ -531,6 +531,10 @@
color: themed('mutedColor');
}
&.icon-small {
min-width: 25px;
}
img {
border-radius: $border-radius;
max-height: 20px;

View File

@@ -146,7 +146,7 @@ p.lead {
}
.password-wrapper {
word-break: break-all;
overflow-wrap: break-word;
white-space: pre-wrap;
min-width: 0;
}
@@ -360,14 +360,6 @@ input[type="password"]::-ms-reveal {
}
}
// Workaround for rendering error in Firefox sidebar
// option elements will not render background-color correctly if identical to parent background-color
select option {
@include themify($themes) {
background-color: darken(themed('inputBackgroundColor'), +1);
}
}
// Workaround for slow performance on external monitors on Chrome + MacOS
// See: https://bugs.chromium.org/p/chromium/issues/detail?id=971701#c64
@keyframes redraw {

View File

@@ -1,6 +1,6 @@
$fa-font-path: "~font-awesome/fonts";
@import "~font-awesome/scss/font-awesome.scss";
@import "~angular2-toaster/toaster";
@import '~ngx-toastr/toastr';
@import "~sweetalert2/src/sweetalert2.scss";
@import "variables.scss";
@@ -9,32 +9,36 @@ $fa-font-path: "~font-awesome/fonts";
// Toaster
.toast-container {
&.toast-bottom-full-width div.toast {
margin: 0 10px 10px;
width: calc(100% - 20px);
box-shadow: 0 0 8px rgba(0, 0, 0, 0.35);
&:hover {
box-shadow: 0 0 10px rgba(0, 0, 0, 0.6);
}
.toast-close-button {
font-size: 18px;
margin-right: 4px;
}
.toast {
&:before {
.ngx-toastr {
align-items: center;
background-image: none !important;
border-radius: $border-radius;
box-shadow: 0 0 8px rgba(0, 0, 0, 0.35);
display: flex;
padding: 15px;
.toast-close-button {
position: absolute;
right: 5px;
top: 0;
}
&:hover {
box-shadow: 0 0 10px rgba(0, 0, 0, 0.6);
}
.icon i::before {
float: left;
font-style: normal;
font-family: FontAwesome;
font-size: 25px;
line-height: 20px;
float: left;
color: #ffffff;
margin: auto 0 auto 15px;
}
.toast-content {
padding: 15px;
}
.toaster-icon {
display: none;
padding-right: 15px;
}
.toast-message {
@@ -48,49 +52,41 @@ $fa-font-path: "~font-awesome/fonts";
}
&.toast-danger, &.toast-error {
background-image: none !important;
@include themify($themes) {
background-color: themed('dangerColor');
}
&:before {
.icon i::before {
content: "\f0e7";
}
}
&.toast-warning {
background-image: none !important;
@include themify($themes) {
background-color: themed('warningColor');
}
&:before {
.icon i::before {
content: "\f071";
}
}
&.toast-info {
background-image: none !important;
@include themify($themes) {
background-color: themed('infoColor');
}
&:before {
.icon i:before {
content: "\f05a";
}
}
&.toast-success {
background-image: none !important;
@include themify($themes) {
background-color: themed('successColor');
}
&:before {
.icon i:before {
content: "\f00C";
}
}

View File

@@ -12,6 +12,7 @@ import { SendView } from 'jslib-common/models/view/sendView';
import { SendComponent as BaseSendComponent } from 'jslib-angular/components/send/send.component';
import { BroadcasterService } from 'jslib-common/abstractions/broadcaster.service';
import { EnvironmentService } from 'jslib-common/abstractions/environment.service';
import { I18nService } from 'jslib-common/abstractions/i18n.service';
import { LogService } from 'jslib-common/abstractions/log.service';
@@ -23,8 +24,6 @@ import { StateService } from 'jslib-common/abstractions/state.service';
import { SyncService } from 'jslib-common/abstractions/sync.service';
import { UserService } from 'jslib-common/abstractions/user.service';
import { BroadcasterService } from 'jslib-angular/services/broadcaster.service';
import { PopupUtilsService } from '../services/popup-utils.service';
import { SendType } from 'jslib-common/enums/sendType';

View File

@@ -17,6 +17,7 @@ import { SendView } from 'jslib-common/models/view/sendView';
import { SendComponent as BaseSendComponent } from 'jslib-angular/components/send/send.component';
import { BroadcasterService } from 'jslib-common/abstractions/broadcaster.service';
import { EnvironmentService } from 'jslib-common/abstractions/environment.service';
import { I18nService } from 'jslib-common/abstractions/i18n.service';
import { LogService } from 'jslib-common/abstractions/log.service';
@@ -27,8 +28,6 @@ import { SendService } from 'jslib-common/abstractions/send.service';
import { StateService } from 'jslib-common/abstractions/state.service';
import { UserService } from 'jslib-common/abstractions/user.service';
import { BroadcasterService } from 'jslib-angular/services/broadcaster.service';
import { PopupUtilsService } from '../services/popup-utils.service';
import { SendType } from 'jslib-common/enums/sendType';

View File

@@ -6,7 +6,7 @@ import {
Router,
} from '@angular/router';
import { UnauthGuardService } from './unauth-guard.service';
import { UnauthGuardService } from 'jslib-angular/services/unauth-guard.service';
@Injectable()
export class LaunchGuardService implements CanActivate {

View File

@@ -4,18 +4,15 @@ import {
NgModule,
} from '@angular/core';
import { ToasterModule } from 'angular2-toaster';
import { DebounceNavigationService } from './debounceNavigationService';
import { LaunchGuardService } from './launch-guard.service';
import { LockGuardService } from './lock-guard.service';
import { PasswordRepromptService } from './password-reprompt.service';
import { UnauthGuardService } from './unauth-guard.service';
import { AuthGuardService } from 'jslib-angular/services/auth-guard.service';
import { BroadcasterService } from 'jslib-angular/services/broadcaster.service';
import { ModalService } from 'jslib-angular/services/modal.service';
import { ValidationService } from 'jslib-angular/services/validation.service';
import { JslibServicesModule } from 'jslib-angular/services/jslib-services.module';
import { LockGuardService as BaseLockGuardService } from 'jslib-angular/services/lock-guard.service';
import { UnauthGuardService as BaseUnauthGuardService } from 'jslib-angular/services/unauth-guard.service';
import { BrowserApi } from '../../browser/browserApi';
@@ -33,6 +30,7 @@ import { ExportService } from 'jslib-common/abstractions/export.service';
import { FileUploadService } from 'jslib-common/abstractions/fileUpload.service';
import { FolderService } from 'jslib-common/abstractions/folder.service';
import { I18nService } from 'jslib-common/abstractions/i18n.service';
import { KeyConnectorService } from 'jslib-common/abstractions/keyConnector.service';
import { LogService as LogServiceAbstraction } from 'jslib-common/abstractions/log.service';
import { MessagingService } from 'jslib-common/abstractions/messaging.service';
import { NotificationsService } from 'jslib-common/abstractions/notifications.service';
@@ -49,6 +47,7 @@ import { SyncService } from 'jslib-common/abstractions/sync.service';
import { TokenService } from 'jslib-common/abstractions/token.service';
import { TotpService } from 'jslib-common/abstractions/totp.service';
import { UserService } from 'jslib-common/abstractions/user.service';
import { UserVerificationService } from 'jslib-common/abstractions/userVerification.service';
import { VaultTimeoutService } from 'jslib-common/abstractions/vaultTimeout.service';
import { AutofillService } from '../../services/abstractions/autofill.service';
@@ -74,14 +73,9 @@ function getBgService<T>(service: string) {
const isPrivateMode = BrowserApi.getBackgroundPage() == null;
const stateService = new StateService();
const messagingService = new BrowserMessagingService();
const logService = getBgService<ConsoleLogService>('logService')();
const searchService = isPrivateMode ? null : new PopupSearchService(getBgService<SearchService>('searchService')(),
getBgService<CipherService>('cipherService')(), logService, getBgService<I18nService>('i18nService')());
export function initFactory(platformUtilsService: PlatformUtilsService, i18nService: I18nService, storageService: StorageService,
popupUtilsService: PopupUtilsService): Function {
export function initFactory(platformUtilsService: PlatformUtilsService, i18nService: I18nService,
storageService: StorageService, popupUtilsService: PopupUtilsService, stateService: StateServiceAbstraction,
logService: LogServiceAbstraction): Function {
return async () => {
if (!popupUtilsService.inPopup(window)) {
window.document.body.classList.add('body-full');
@@ -128,23 +122,48 @@ export function initFactory(platformUtilsService: PlatformUtilsService, i18nServ
@NgModule({
imports: [
ToasterModule,
JslibServicesModule,
],
declarations: [],
providers: [
ValidationService,
AuthGuardService,
LockGuardService,
{
provide: LOCALE_ID,
useFactory: () => isPrivateMode ? null : getBgService<I18nService>('i18nService')().translationLocale,
deps: [],
},
{
provide: APP_INITIALIZER,
useFactory: initFactory,
deps: [
PlatformUtilsService,
I18nService,
StorageService,
PopupUtilsService,
StateServiceAbstraction,
LogServiceAbstraction,
],
multi: true,
},
LaunchGuardService,
UnauthGuardService,
{ provide: BaseLockGuardService, useClass: LockGuardService },
{ provide: BaseUnauthGuardService, useClass: UnauthGuardService },
DebounceNavigationService,
PopupUtilsService,
BroadcasterService,
ModalService,
{ provide: MessagingService, useValue: messagingService },
{ provide: MessagingService, useClass: BrowserMessagingService },
{ provide: AuthServiceAbstraction, useFactory: getBgService<AuthService>('authService'), deps: [] },
{ provide: StateServiceAbstraction, useValue: stateService },
{ provide: SearchServiceAbstraction, useValue: searchService },
{ provide: StateServiceAbstraction, useClass: StateService },
{
provide: SearchServiceAbstraction,
useFactory: (cipherService: CipherService, logService: ConsoleLogService, i18nService: I18nService) => {
return isPrivateMode ? null : new PopupSearchService(getBgService<SearchService>('searchService')(),
cipherService, logService, i18nService);
},
deps: [
CipherService,
LogServiceAbstraction,
I18nService,
],
},
{ provide: AuditService, useFactory: getBgService<AuditService>('auditService'), deps: [] },
{ provide: FileUploadService, useFactory: getBgService<FileUploadService>('fileUploadService'), deps: [] },
{ provide: CipherService, useFactory: getBgService<CipherService>('cipherService'), deps: [] },
@@ -182,6 +201,12 @@ export function initFactory(platformUtilsService: PlatformUtilsService, i18nServ
{ provide: AutofillService, useFactory: getBgService<AutofillService>('autofillService'), deps: [] },
{ provide: ExportService, useFactory: getBgService<ExportService>('exportService'), deps: [] },
{ provide: SendService, useFactory: getBgService<SendService>('sendService'), deps: [] },
{ provide: KeyConnectorService, useFactory: getBgService<KeyConnectorService>('keyConnectorService'), deps: [] },
{
provide: UserVerificationService,
useFactory: getBgService<UserVerificationService>('userVerificationService'),
deps: [],
},
{
provide: VaultTimeoutService,
useFactory: getBgService<VaultTimeoutService>('vaultTimeoutService'),
@@ -192,17 +217,7 @@ export function initFactory(platformUtilsService: PlatformUtilsService, i18nServ
useFactory: getBgService<NotificationsService>('notificationsService'),
deps: [],
},
{
provide: APP_INITIALIZER,
useFactory: initFactory,
deps: [PlatformUtilsService, I18nService, StorageService, PopupUtilsService],
multi: true,
},
{
provide: LOCALE_ID,
useFactory: () => isPrivateMode ? null : getBgService<I18nService>('i18nService')().translationLocale,
deps: [],
},
{ provide: LogServiceAbstraction, useFactory: getBgService<ConsoleLogService>('logService'), deps: [] },
{ provide: PasswordRepromptServiceAbstraction, useClass: PasswordRepromptService },
],
})

View File

@@ -9,12 +9,11 @@ import { Router } from '@angular/router';
import { ConstantsService } from 'jslib-common/services/constants.service';
import { BroadcasterService } from 'jslib-common/abstractions/broadcaster.service';
import { I18nService } from 'jslib-common/abstractions/i18n.service';
import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
import { StorageService } from 'jslib-common/abstractions/storage.service';
import { BroadcasterService } from 'jslib-angular/services/broadcaster.service';
import { BrowserApi } from '../../browser/browserApi';
import { Utils } from 'jslib-common/misc/utils';

View File

@@ -1,4 +1,4 @@
<form (ngSubmit)="submit()">
<form (ngSubmit)="submit()" [formGroup]="exportForm">
<header>
<div class="left">
<a routerLink="/tabs/settings">
@@ -10,7 +10,7 @@
<span class="title">{{'exportVault' | i18n}}</span>
</h1>
<div class="right">
<button appBlurClick type="submit" [disabled]="disabledByPolicy">{{'submit' | i18n}}</button>
<button appBlurClick type="submit" [disabled]="!exportForm.enabled">{{'submit' | i18n}}</button>
</div>
</header>
<content>
@@ -22,30 +22,15 @@
<div class="box-content">
<div class="box-content-row" appBoxRow>
<label for="format">{{'fileFormat' | i18n}}</label>
<select id="format" name="Format" [(ngModel)]="format" [disabled]="disabledByPolicy">
<option value="json">.json</option>
<option value="csv">.csv</option>
<option value="encrypted_json">.json (Encrypted)</option>
<select id="format" name="Format" formControlName="format">
<option *ngFor="let f of formatOptions" [value]="f.value">{{f.name}}</option>
</select>
</div>
<div class="box-content-row box-content-row-flex" appBoxRow>
<div class="row-main">
<label for="masterPassword">{{'masterPass' | i18n}}</label>
<input id="masterPassword" type="{{showPassword ? 'text' : 'password'}}" name="MasterPassword"
class="monospaced" [(ngModel)]="masterPassword" required appInputVerbatim appAutofocus
[disabled]="disabledByPolicy">
</div>
<div class="action-buttons">
<button type="button" class="row-btn" appStopClick appBlurClick
appA11yTitle="{{'toggleVisibility' | i18n}}" (click)="togglePassword()">
<i class="fa fa-lg" aria-hidden="true"
[ngClass]="{'fa-eye': !showPassword, 'fa-eye-slash': showPassword}"></i>
</button>
</div>
</div>
<app-verify-master-password ngDefaultControl formControlName="secret" name="Secret">
</app-verify-master-password>
</div>
<div class="box-footer">
<p>{{'exportMasterPassword' | i18n}}</p>
<p>{{'confirmIdentity' | i18n}}</p>
</div>
</div>
</content>

View File

@@ -1,4 +1,5 @@
import { Component } from '@angular/core';
import { FormBuilder } from '@angular/forms';
import { Router } from '@angular/router';
import { CryptoService } from 'jslib-common/abstractions/crypto.service';
@@ -8,6 +9,7 @@ import { I18nService } from 'jslib-common/abstractions/i18n.service';
import { LogService } from 'jslib-common/abstractions/log.service';
import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
import { PolicyService } from 'jslib-common/abstractions/policy.service';
import { UserVerificationService } from 'jslib-common/abstractions/userVerification.service';
import { ExportComponent as BaseExportComponent } from 'jslib-angular/components/export.component';
@@ -19,9 +21,9 @@ export class ExportComponent extends BaseExportComponent {
constructor(cryptoService: CryptoService, i18nService: I18nService,
platformUtilsService: PlatformUtilsService, exportService: ExportService,
eventService: EventService, policyService: PolicyService, private router: Router,
logService: LogService) {
logService: LogService, userVerificationService: UserVerificationService, fb: FormBuilder) {
super(cryptoService, i18nService, platformUtilsService, exportService, eventService, policyService, window,
logService);
logService, userVerificationService, fb);
}
protected saved() {

View File

@@ -71,7 +71,7 @@
<span><i class="fa fa-chevron-right fa-lg row-sub-icon" aria-hidden="true"></i></span>
</a>
<button type="button" class="box-content-row box-content-row-flex text-default" appStopClick appBlurClick
(click)="changePassword()">
(click)="changePassword()" *ngIf="showChangeMasterPass">
<div class="row-main">{{'changeMasterPassword' | i18n}}</div>
<i class="fa fa-chevron-right fa-lg row-sub-icon" aria-hidden="true"></i>
</button>

View File

@@ -6,7 +6,6 @@ import {
} from '@angular/core';
import { FormControl } from '@angular/forms';
import { Router } from '@angular/router';
import { ToasterService } from 'angular2-toaster';
import Swal from 'sweetalert2/src/sweetalert2.js';
import { BrowserApi } from '../../browser/browserApi';
@@ -18,6 +17,7 @@ import { ConstantsService } from 'jslib-common/services/constants.service';
import { CryptoService } from 'jslib-common/abstractions/crypto.service';
import { EnvironmentService } from 'jslib-common/abstractions/environment.service';
import { I18nService } from 'jslib-common/abstractions/i18n.service';
import { KeyConnectorService } from 'jslib-common/abstractions/keyConnector.service';
import { MessagingService } from 'jslib-common/abstractions/messaging.service';
import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
import { StorageService } from 'jslib-common/abstractions/storage.service';
@@ -58,6 +58,7 @@ export class SettingsComponent implements OnInit {
biometric: boolean = false;
disableAutoBiometricsPrompt = true;
previousVaultTimeout: number = null;
showChangeMasterPass = true;
vaultTimeout: FormControl = new FormControl(null);
@@ -66,7 +67,8 @@ export class SettingsComponent implements OnInit {
public messagingService: MessagingService, private router: Router,
private environmentService: EnvironmentService, private cryptoService: CryptoService,
private userService: UserService, private popupUtilsService: PopupUtilsService,
private modalService: ModalService, private toasterService: ToasterService) {
private modalService: ModalService,
private keyConnectorService: KeyConnectorService) {
}
async ngOnInit() {
@@ -118,6 +120,7 @@ export class SettingsComponent implements OnInit {
this.biometric = await this.vaultTimeoutService.isBiometricLockSet();
this.disableAutoBiometricsPrompt = await this.storageService.get<boolean>(
ConstantsService.disableAutoBiometricsPromptKey) ?? true;
this.showChangeMasterPass = !await this.keyConnectorService.getUsesKeyConnector();
}
async saveVaultTimeout(newValue: number) {
@@ -132,7 +135,7 @@ export class SettingsComponent implements OnInit {
}
if (!this.vaultTimeout.valid) {
this.toasterService.popAsync('error', null, this.i18nService.t('vaultTimeoutToLarge'));
this.platformUtilsService.showToast('error', null, this.i18nService.t('vaultTimeoutToLarge'));
return;
}
@@ -161,7 +164,7 @@ export class SettingsComponent implements OnInit {
}
if (!this.vaultTimeout.valid) {
this.toasterService.popAsync('error', null, this.i18nService.t('vaultTimeoutToLarge'));
this.platformUtilsService.showToast('error', null, this.i18nService.t('vaultTimeoutToLarge'));
return;
}

View File

@@ -1,11 +1,10 @@
import { ToasterService } from 'angular2-toaster';
import {
Component,
OnInit,
} from '@angular/core';
import { I18nService } from 'jslib-common/abstractions/i18n.service';
import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
import { SyncService } from 'jslib-common/abstractions/sync.service';
@Component({
@@ -16,7 +15,7 @@ export class SyncComponent implements OnInit {
lastSync = '--';
syncPromise: Promise<any>;
constructor(private syncService: SyncService, private toasterService: ToasterService,
constructor(private syncService: SyncService, private platformUtilsService: PlatformUtilsService,
private i18nService: I18nService) {
}
@@ -29,9 +28,9 @@ export class SyncComponent implements OnInit {
const success = await this.syncPromise;
if (success) {
await this.setLastSync();
this.toasterService.popAsync('success', null, this.i18nService.t('syncingComplete'));
this.platformUtilsService.showToast('success', null, this.i18nService.t('syncingComplete'));
} else {
this.toasterService.popAsync('error', null, this.i18nService.t('syncingFailed'));
this.platformUtilsService.showToast('error', null, this.i18nService.t('syncingFailed'));
}
}

View File

@@ -16,15 +16,20 @@
<div class="row-main">
<input id="fieldName{{i}}" type="text" name="Field.Name{{i}}" [(ngModel)]="f.name" class="row-label"
placeholder="{{'name' | i18n}}" appInputVerbatim>
<!--Custom Field: Text-->
<!-- Text -->
<input id="fieldValue{{i}}" type="text" name="Field.Value{{i}}" [(ngModel)]="f.value"
*ngIf="f.type === fieldType.Text" placeholder="{{'value' | i18n}}" appInputVerbatim>
<!--Custom Field: Hidden-->
<!-- Hidden -->
<input id="fieldValue{{i}}" type="{{f.showValue ? 'text' : 'password'}}" name="Field.Value{{i}}"
[(ngModel)]="f.value" class="monospaced" appInputVerbatim *ngIf="f.type === fieldType.Hidden"
placeholder="{{'value' | i18n}}" [disabled]="!cipher.viewPassword && !f.newField">
<!-- Linked -->
<select id="fieldValue{{i}}" name="Field.Value{{i}}" [(ngModel)]="f.linkedId"
*ngIf="f.type === fieldType.Linked && cipher.linkedFieldOptions != null">
<option *ngFor="let o of linkedFieldOptions" [ngValue]="o.value">{{o.name}}</option>
</select>
</div>
<!--Custom Field: Boolean-->
<!-- Boolean -->
<input id="fieldValue{{i}}" name="Field.Value{{i}}" type="checkbox" [(ngModel)]="f.value"
*ngIf="f.type === fieldType.Boolean" appTrueFalseValue trueValue="true" falseValue="false">
<div class="action-buttons" *ngIf="f.type === fieldType.Hidden && (cipher.viewPassword || f.newField)">
@@ -47,6 +52,9 @@
<label for="addFieldType" class="sr-only">{{'type' | i18n}}</label>
<select id="addFieldType" name="AddFieldType" [(ngModel)]="addFieldType" class="field-type">
<option *ngFor="let o of addFieldTypeOptions" [ngValue]="o.value">{{o.name}}</option>
<option *ngIf="cipher.linkedFieldOptions != null" [ngValue]="addFieldLinkedTypeOption.value">
{{addFieldLinkedTypeOption.name}}
</option>
</select>
</div>
</div>

View File

@@ -290,7 +290,7 @@
<label for="favorite">{{'favorite' | i18n}}</label>
<input id="favorite" type="checkbox" name="Favorite" [(ngModel)]="cipher.favorite">
</div>
<div class="box-content-row box-content-row-checkbox" appBoxRow>
<div class="box-content-row box-content-row-checkbox" appBoxRow *ngIf="canUseReprompt">
<label for="passwordPrompt">
{{'passwordPrompt' | i18n}}
<a target="_blank" rel="noopener" appA11yTitle="{{'learnMore' | i18n}}"
@@ -298,8 +298,7 @@
<i class="fa fa-question-circle-o" aria-hidden="true"></i>
</a>
</label>
<input id="passwordPrompt" type="checkbox" name="PasswordPrompt" [ngModel]="reprompt"
(change)="repromptChanged()">
<input id="passwordPrompt" type="checkbox" name="PasswordPrompt" [ngModel]="reprompt" (change)="repromptChanged()">
</div>
<button type="button" class="box-content-row box-content-row-flex text-default" appStopClick appBlurClick
(click)="attachments()" *ngIf="editMode && showAttachments && !cloneMode">
@@ -324,7 +323,8 @@
</div>
</div>
</div>
<app-vault-add-edit-custom-fields [cipher]="cipher" [editMode]="editMode"></app-vault-add-edit-custom-fields>
<app-vault-add-edit-custom-fields [cipher]="cipher" [thisCipherType]="cipher.type" [editMode]="editMode">
</app-vault-add-edit-custom-fields>
<div class="box" *ngIf="allowOwnershipOptions()">
<h2 class="box-header">
{{'ownership' | i18n}}

View File

@@ -17,6 +17,7 @@ import { FolderService } from 'jslib-common/abstractions/folder.service';
import { I18nService } from 'jslib-common/abstractions/i18n.service';
import { LogService } from 'jslib-common/abstractions/log.service';
import { MessagingService } from 'jslib-common/abstractions/messaging.service';
import { PasswordRepromptService } from 'jslib-common/abstractions/passwordReprompt.service';
import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
import { PolicyService } from 'jslib-common/abstractions/policy.service';
import { StateService } from 'jslib-common/abstractions/state.service';
@@ -51,9 +52,10 @@ export class AddEditComponent extends BaseAddEditComponent {
private router: Router, private location: Location,
eventService: EventService, policyService: PolicyService,
private popupUtilsService: PopupUtilsService, private storageService: StorageService,
logService: LogService) {
logService: LogService, passwordRepromptService: PasswordRepromptService) {
super(cipherService, folderService, i18nService, platformUtilsService, auditService, stateService,
userService, collectionService, messagingService, eventService, policyService, logService);
userService, collectionService, messagingService, eventService, policyService, passwordRepromptService,
logService);
}
async ngOnInit() {

View File

@@ -15,6 +15,7 @@ import { first } from 'rxjs/operators';
import { BrowserApi } from '../../browser/browserApi';
import { BroadcasterService } from 'jslib-common/abstractions/broadcaster.service';
import { CipherService } from 'jslib-common/abstractions/cipher.service';
import { CollectionService } from 'jslib-common/abstractions/collection.service';
import { FolderService } from 'jslib-common/abstractions/folder.service';
@@ -31,8 +32,6 @@ import { FolderView } from 'jslib-common/models/view/folderView';
import { TreeNode } from 'jslib-common/models/domain/treeNode';
import { BroadcasterService } from 'jslib-angular/services/broadcaster.service';
import { CiphersComponent as BaseCiphersComponent } from 'jslib-angular/components/ciphers.component';
import { PopupUtilsService } from '../services/popup-utils.service';

View File

@@ -5,20 +5,16 @@ import {
OnDestroy,
OnInit,
} from '@angular/core';
import { Router } from '@angular/router';
import { ToasterService } from 'angular2-toaster';
import { BrowserApi } from '../../browser/browserApi';
import { BroadcasterService } from 'jslib-angular/services/broadcaster.service';
import { CipherRepromptType } from 'jslib-common/enums/cipherRepromptType';
import { CipherType } from 'jslib-common/enums/cipherType';
import { CipherView } from 'jslib-common/models/view/cipherView';
import { BroadcasterService } from 'jslib-common/abstractions/broadcaster.service';
import { CipherService } from 'jslib-common/abstractions/cipher.service';
import { I18nService } from 'jslib-common/abstractions/i18n.service';
import { PasswordRepromptService } from 'jslib-common/abstractions/passwordReprompt.service';
@@ -60,7 +56,7 @@ export class CurrentTabComponent implements OnInit, OnDestroy {
constructor(private platformUtilsService: PlatformUtilsService, private cipherService: CipherService,
private popupUtilsService: PopupUtilsService, private autofillService: AutofillService,
private toasterService: ToasterService, private i18nService: I18nService, private router: Router,
private i18nService: I18nService, private router: Router,
private ngZone: NgZone, private broadcasterService: BroadcasterService,
private changeDetectorRef: ChangeDetectorRef, private syncService: SyncService,
private searchService: SearchService, private storageService: StorageService,
@@ -141,7 +137,7 @@ export class CurrentTabComponent implements OnInit, OnDestroy {
}
if (this.pageDetails == null || this.pageDetails.length === 0) {
this.toasterService.popAsync('error', null, this.i18nService.t('autofillError'));
this.platformUtilsService.showToast('error', null, this.i18nService.t('autofillError'));
return;
}
@@ -165,7 +161,7 @@ export class CurrentTabComponent implements OnInit, OnDestroy {
}
} catch {
this.ngZone.run(() => {
this.toasterService.popAsync('error', null, this.i18nService.t('autofillError'));
this.platformUtilsService.showToast('error', null, this.i18nService.t('autofillError'));
this.changeDetectorRef.detectChanges();
});
}

View File

@@ -21,6 +21,7 @@ import { CipherView } from 'jslib-common/models/view/cipherView';
import { CollectionView } from 'jslib-common/models/view/collectionView';
import { FolderView } from 'jslib-common/models/view/folderView';
import { BroadcasterService } from 'jslib-common/abstractions/broadcaster.service';
import { CipherService } from 'jslib-common/abstractions/cipher.service';
import { CollectionService } from 'jslib-common/abstractions/collection.service';
import { FolderService } from 'jslib-common/abstractions/folder.service';
@@ -31,8 +32,6 @@ import { StorageService } from 'jslib-common/abstractions/storage.service';
import { SyncService } from 'jslib-common/abstractions/sync.service';
import { UserService } from 'jslib-common/abstractions/user.service';
import { BroadcasterService } from 'jslib-angular/services/broadcaster.service';
import { GroupingsComponent as BaseGroupingsComponent } from 'jslib-angular/components/groupings.component';
import { PopupUtilsService } from '../services/popup-utils.service';

View File

@@ -18,6 +18,13 @@
<i class="fa fa-square-o" *ngIf="field.value !== 'true'" aria-hidden="true"></i>
<span class="sr-only">{{field.value}}</span>
</div>
<div *ngIf="field.type === fieldType.Linked" class="box-content-row-flex">
<div class="icon icon-small">
<i class="fa fa-link" aria-hidden="true" appA11yTitle="{{'linkedValue' | i18n}}"></i>
<span class="sr-only">{{'linkedValue' | i18n}}</span>
</div>
<span>{{cipher.linkedFieldI18nKey(field.linkedId) | i18n}}</span>
</div>
</div>
<div class="action-buttons">
<button type="button" class="row-btn" appStopClick appA11yTitle="{{'toggleVisibility' | i18n}}"
@@ -27,7 +34,8 @@
[ngClass]="{'fa-eye': !field.showValue, 'fa-eye-slash': field.showValue}"></i>
</button>
<button type="button" class="row-btn" appStopClick appA11yTitle="{{'copyValue' | i18n}}"
*ngIf="field.value && field.type !== fieldType.Boolean && !(field.type === fieldType.Hidden && !cipher.viewPassword)"
*ngIf="field.value && field.type !== fieldType.Boolean && field.type !== fieldType.Linked &&
!(field.type === fieldType.Hidden && !cipher.viewPassword)"
(click)="copy(field.value, 'value', field.type === fieldType.Hidden ? 'H_Field' : 'Field')">
<i class="fa fa-lg fa-clone" aria-hidden="true"></i>
</button>

View File

@@ -13,6 +13,7 @@ import { first } from 'rxjs/operators';
import { ApiService } from 'jslib-common/abstractions/api.service';
import { AuditService } from 'jslib-common/abstractions/audit.service';
import { BroadcasterService } from 'jslib-common/abstractions/broadcaster.service';
import { CipherService } from 'jslib-common/abstractions/cipher.service';
import { CryptoService } from 'jslib-common/abstractions/crypto.service';
import { EventService } from 'jslib-common/abstractions/event.service';
@@ -25,8 +26,6 @@ import { TokenService } from 'jslib-common/abstractions/token.service';
import { TotpService } from 'jslib-common/abstractions/totp.service';
import { UserService } from 'jslib-common/abstractions/user.service';
import { BroadcasterService } from 'jslib-angular/services/broadcaster.service';
import { Cipher } from 'jslib-common/models/domain/cipher';
import { LoginUriView } from 'jslib-common/models/view/loginUriView';