Skip to content

Commit

Permalink
enable "2FA code" keepass record referencing
Browse files Browse the repository at this point in the history
  • Loading branch information
vladimiry committed Jun 30, 2018
1 parent 26fab7b commit c99e517
Show file tree
Hide file tree
Showing 12 changed files with 166 additions and 115 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@
"@types/sinon": "5.0.1",
"@types/source-map": "0.5.7",
"@types/stacktrace-js": "0.0.32",
"@types/tapable": "1.0.2",
"@types/tapable": "1.0.3",
"@types/uglifyjs-webpack-plugin": "1.1.0",
"@types/valid-url": "1.0.2",
"@types/webdriverio": "4.10.3",
Expand Down
1 change: 0 additions & 1 deletion src/electron-main/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import logger from "electron-log";
import {app} from "electron";

import {activateBrowserWindow, initContext} from "./util";
import {BuildEnvironment} from "_@shared/model/common";
import {Context} from "./model";
import {initAutoUpdate} from "./app-update";
import {initBrowserWindow} from "./window";
Expand Down
37 changes: 23 additions & 14 deletions src/electron-main/ipc-main-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -213,29 +213,38 @@ export const initEndpoints = async (ctx: Context): Promise<Endpoints> => {
);
}

const {credentials} = matchedAccount;

if ("passwordValue" in payload) {
matchedAccount.credentials.password.value = payload.passwordValue || undefined;
credentials.password.value = payload.passwordValue || undefined;
}
if ("passwordKeePassRef" in payload) {
if (payload.passwordKeePassRef) {
credentials.password.keePassRef = payload.passwordKeePassRef;
} else {
delete credentials.password.keePassRef;
}
}

if ("twoFactorCodeValue" in payload) {
matchedAccount.credentials.twoFactorCode = {
value: payload.twoFactorCodeValue || undefined,
};
(credentials.twoFactorCode = credentials.twoFactorCode || {}).value = payload.twoFactorCodeValue || undefined;
}
if ("twoFactorCodeKeePassRef" in payload) {
if (payload.twoFactorCodeKeePassRef) {
(credentials.twoFactorCode = credentials.twoFactorCode || {}).keePassRef = payload.twoFactorCodeKeePassRef;
} else {
delete (credentials.twoFactorCode = credentials.twoFactorCode || {}).keePassRef;
}
}

if ("mailPasswordValue" in payload) {
matchedAccount.credentials.mailPassword.value = payload.mailPasswordValue || undefined;
credentials.mailPassword.value = payload.mailPasswordValue || undefined;
}
if ("mailPasswordKeePassRef" in payload) {
if (payload.mailPasswordKeePassRef) {
matchedAccount.credentials.mailPassword.keePassRef = payload.mailPasswordKeePassRef;
} else {
delete matchedAccount.credentials.mailPassword.keePassRef;
}
}
if ("passwordKeePassRef" in payload) {
if (payload.passwordKeePassRef) {
matchedAccount.credentials.password.keePassRef = payload.passwordKeePassRef;
credentials.mailPassword.keePassRef = payload.mailPasswordKeePassRef;
} else {
delete matchedAccount.credentials.password.keePassRef;
delete credentials.mailPassword.keePassRef;
}
}

Expand Down
3 changes: 1 addition & 2 deletions src/shared/model/account.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@ export interface AccountCredentials {
};
twoFactorCode?: {
value?: string;
// TODO enable keepass interaction for "twoFactorCode"
// keePassRef?: KeePassRef;
keePassRef?: KeePassRef;
};
}

Expand Down
3 changes: 2 additions & 1 deletion src/shared/model/container.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,10 @@ export interface AccountFieldContainer {
export interface PasswordChangeContainer extends PasswordFieldContainer, NewPasswordFieldContainer {}

export interface AccountConfigPatch extends LoginFieldContainer {
twoFactorCodeValue?: string;
passwordValue?: string;
passwordKeePassRef?: KeePassRef | null;
twoFactorCodeValue?: string;
twoFactorCodeKeePassRef?: KeePassRef | null;
mailPasswordValue?: string;
mailPasswordKeePassRef?: KeePassRef | null;
}
13 changes: 7 additions & 6 deletions src/web/src/app/+accounts/account.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,22 @@
[keePassRef$]="passwordKeePassRef$"
[keePassClientConf$]="keePassClientConf$"
(passwordHandler)="onPassword($event)"
[lock$]="passwordProgress$"
></protonmail-desktop-app-keepass-request>

<protonmail-desktop-app-keepass-request
*ngIf="(account$ | async).sync.pageType.type == 'login2fa'"
[keePassRef$]="twoFactorCodeKeePassRef$"
[keePassClientConf$]="keePassClientConf$"
(passwordHandler)="onTwoFactorCode($event)"
></protonmail-desktop-app-keepass-request>

<protonmail-desktop-app-keepass-request
*ngIf="(account$ | async).sync.pageType.type == 'unlock'"
[keePassRef$]="mailPasswordKeePassRef$"
[keePassClientConf$]="keePassClientConf$"
(passwordHandler)="onMailPassword($event)"
[lock$]="mailPasswordProgress$"
></protonmail-desktop-app-keepass-request>

<!--
TODO enable keepass interaction for "twoFactorCode"
-->

<webview
*ngIf="webViewPreload$ | async"
#webViewRef
Expand Down
31 changes: 16 additions & 15 deletions src/web/src/app/+accounts/account.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import {
} from "_@web/src/app/store/reducers/options";
import {State} from "_@web/src/app/store/reducers/accounts";
import {ACCOUNTS_ACTIONS, NAVIGATION_ACTIONS} from "_@web/src/app/store/actions";
import {BuildEnvironment} from "_@shared/model/common";

@Component({
selector: `protonmail-desktop-app-account`,
Expand All @@ -29,12 +28,10 @@ export class AccountComponent implements AfterViewInit, OnDestroy {
// account
// TODO simplify account$ initialization and usage
account$: BehaviorSubject<WebAccount>;
// progress
passwordProgress$: Observable<boolean>;
mailPasswordProgress$: Observable<boolean>;
// keepass
keePassClientConf$ = this.optionsStore.select(settingsKeePassClientConfSelector);
passwordKeePassRef$: Observable<KeePassRef | undefined>;
twoFactorCodeKeePassRef$: Observable<KeePassRef | undefined>;
mailPasswordKeePassRef$: Observable<KeePassRef | undefined>;
// offline interval
offlineIntervalStepSec = 10;
Expand Down Expand Up @@ -82,17 +79,15 @@ export class AccountComponent implements AfterViewInit, OnDestroy {
)
.subscribe(() => this.pageLoadedReaction(this.account$.getValue()));

// keepass - password
this.passwordKeePassRef$ = this.account$.pipe(map(({accountConfig}) =>
accountConfig.credentials.password.keePassRef,
));
this.passwordProgress$ = this.account$.pipe(map(({progress}) => !!progress.password));

// keepass - mail password
this.mailPasswordKeePassRef$ = this.account$.pipe(map(({accountConfig}) =>
accountConfig.credentials.mailPassword.keePassRef,
));
this.mailPasswordProgress$ = this.account$.pipe(map(({progress}) => !!progress.mailPassword));
this.passwordKeePassRef$ = this.account$.pipe(map(({accountConfig}) => {
return accountConfig.credentials.password.keePassRef;
}));
this.mailPasswordKeePassRef$ = this.account$.pipe(map(({accountConfig}) => {
return accountConfig.credentials.mailPassword.keePassRef;
}));
this.twoFactorCodeKeePassRef$ = this.account$.pipe(map(({accountConfig}) => {
return accountConfig.credentials.twoFactorCode && accountConfig.credentials.twoFactorCode.keePassRef;
}));

// unread notifications
this.account$
Expand Down Expand Up @@ -126,6 +121,12 @@ export class AccountComponent implements AfterViewInit, OnDestroy {
);
}

onTwoFactorCode(password: string) {
this.optionsStore.dispatch(
ACCOUNTS_ACTIONS.Login({pageType: "login2fa", webView: this.webView, account: this.account$.getValue(), password}),
);
}

onMailPassword(mailPassword: string) {
this.optionsStore.dispatch(
ACCOUNTS_ACTIONS.Login({pageType: "unlock", webView: this.webView, account: this.account$.getValue(), password: mailPassword}),
Expand Down
2 changes: 1 addition & 1 deletion src/web/src/app/+accounts/keepass-request.component.scss
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ $bg-color: #ffffff;
$border-width: 1px;

:host {
display: block;
display: none;
position: relative;
border: $border-width solid $fill-color;
border-radius: $border-radius;
Expand Down
24 changes: 11 additions & 13 deletions src/web/src/app/+accounts/keepass-request.component.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {BehaviorSubject, EMPTY, interval, Observable, Subject} from "rxjs";
import {Component, EventEmitter, Input, OnDestroy, OnInit, Output} from "@angular/core";
import {distinctUntilChanged, scan, switchMap, takeUntil, tap, withLatestFrom} from "rxjs/operators";
import {EMPTY, interval, Observable, Subject} from "rxjs";
import {Component, EventEmitter, HostBinding, Input, OnDestroy, OnInit, Output} from "@angular/core";
import {distinctUntilChanged, scan, switchMap, takeUntil, withLatestFrom} from "rxjs/operators";
import {Store} from "@ngrx/store";

import {CORE_ACTIONS} from "_@web/src/app/store/actions";
Expand All @@ -14,7 +14,9 @@ import {State} from "_@web/src/app/store/reducers/root";
styleUrls: ["./keepass-request.component.scss"],
})
export class KeePassRequestComponent implements OnInit, OnDestroy {
paused = false;
@HostBinding("class.d-block")
visible = false;
paused = true;
locked = false;
message?: string;
wait = 10;
Expand All @@ -25,8 +27,6 @@ export class KeePassRequestComponent implements OnInit, OnDestroy {
keePassRef$: Observable<KeePassRef | undefined>;
@Input()
keePassClientConf$: Observable<KeePassClientConf>;
@Input()
locked$: Observable<boolean> = new BehaviorSubject(false);
@Output()
passwordHandler = new EventEmitter<string>();

Expand All @@ -41,7 +41,12 @@ export class KeePassRequestComponent implements OnInit, OnDestroy {
distinctUntilChanged(),
withLatestFrom(this.keePassClientConf$),
switchMap(([keePassRef, keePassClientConf]) => {
this.paused = false;
this.visible = true;

if (!keePassRef) {
this.paused = true;
this.visible = false;
return EMPTY;
}

Expand Down Expand Up @@ -77,13 +82,6 @@ export class KeePassRequestComponent implements OnInit, OnDestroy {
this.store.dispatch(CORE_ACTIONS.Fail(err));
},
);

this.locked$
.pipe(takeUntil(this.unSubscribe$))
.subscribe((locked) => {
this.locked = locked;
this.togglePause(locked);
});
}

ngOnDestroy() {
Expand Down
24 changes: 16 additions & 8 deletions src/web/src/app/+options/account-edit.component.html
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
<nav aria-label="breadcrumb" role="navigation">
<ol class="breadcrumb">
<li class="breadcrumb-item active">
{{ (account$ | async) ? "Edit Account: " + ((account$ | async).login) : "Add Account" }}
{{ (possiblyExistingAccount$ | async) ? "Edit Account: " + ((possiblyExistingAccount$ | async).login) : "Add
Account" }}
</li>
</ol>
</nav>
<fieldset [disabled]="(processing$ | async) || (removing$ | async)">
<form [formGroup]="form" (ngSubmit)="submit()" novalidate class="form-group">
<div class="form-group required" *ngIf="!(account$ | async)">
<div class="form-group required" *ngIf="!(possiblyExistingAccount$ | async)">
<label>Login</label>
<input type="text" class="form-control" formControlName="login" #loginRef
[ngClass]="login.dirty ? {'is-invalid': login.invalid, 'is-valid': login.valid} : {}">
Expand All @@ -28,7 +29,7 @@
[ngClass]="mailPassword.dirty ? {'is-invalid': mailPassword.invalid, 'is-valid': mailPassword.valid} : {}">
</div>
<div class="clearfix">
<button class="btn btn-outline-danger pull-left" type="button" *ngIf="(account$ | async)" (click)="remove()">
<button class="btn btn-outline-danger pull-left" type="button" *ngIf="(possiblyExistingAccount$ | async)" (click)="remove()">
<i class="fa" [ngClass]="{
'fa-spinner fa-pulse fa-fw': (removing$ | async),
'fa-times': !(removing$ | async)
Expand All @@ -40,11 +41,11 @@
'fa-spinner fa-pulse fa-fw': (processing$ | async),
'fa-check': !(processing$ | async)
}"></i>
{{ (account$ | async) ? "Update" : "Add" }}
{{ (possiblyExistingAccount$ | async) ? "Update" : "Add" }}
</button>
</div>
</form>
<div *ngIf="(account$ | async)">
<div *ngIf="(possiblyExistingAccount$ | async)">
<div>
<a href="javascript:void(0)" (click)="keePassRefCollapsed = !keePassRefCollapsed">KeePass References</a>
<i class="fa" [ngClass]="{
Expand All @@ -63,9 +64,16 @@
(unlinkHandler)="onPasswordKeePassUnlink($event)"
></protonmail-desktop-app-keepass-reference>
</div>
<!--
TODO enable keepass interaction for "twoFactorCode"
-->
<hr>
<div class="form-group">
<label>Two Factor Secret Key</label>
<protonmail-desktop-app-keepass-reference
[keePassClientConf$]="keePassClientConf$"
[reference$]="twoFactorCodeKeePassRef$"
(linkHandler)="onTwoFactorCodeKeePassLink($event)"
(unlinkHandler)="onTwoFactorCodeKeePassUnlink($event)"
></protonmail-desktop-app-keepass-reference>
</div>
<hr>
<div class="form-group">
<label>Mail Password</label>
Expand Down
Loading

0 comments on commit c99e517

Please sign in to comment.