- Add handling of errors from getPublicKeys function.
- Check if added private keys are encrypted.
This commit is contained in:
Spencer Ofwiti 2021-03-21 22:05:00 +03:00
parent 8c2b659360
commit aceccedf5e
3 changed files with 27 additions and 23 deletions

View File

@ -1,7 +1,6 @@
import { KeyStore } from 'cic-client-meta'; import { KeyStore } from 'cic-client-meta';
// const openpgp = require('openpgp'); //TODO should we put this on the mutalble key store object // TODO should we put this on the mutalble key store object
import * as openpgp from 'openpgp'; import * as openpgp from 'openpgp';
import {throwError} from 'rxjs';
const keyring = new openpgp.Keyring(); const keyring = new openpgp.Keyring();
interface MutableKeyStore extends KeyStore { interface MutableKeyStore extends KeyStore {
@ -16,6 +15,7 @@ interface MutableKeyStore extends KeyStore {
getPrivateKeys(): Array<any>; getPrivateKeys(): Array<any>;
getPrivateKey(): any; getPrivateKey(): any;
isValidKey(key: any): Promise<boolean>; isValidKey(key: any): Promise<boolean>;
isEncryptedPrivateKey(privateKey: any): Promise<boolean>;
getFingerprint(): string; getFingerprint(): string;
getKeyId(key: any): string; getKeyId(key: any): string;
getPrivateKeyId(): string; getPrivateKeyId(): string;
@ -35,8 +35,6 @@ class MutablePgpKeyStore implements MutableKeyStore{
async loadKeyring(): Promise<void> { async loadKeyring(): Promise<void> {
await keyring.load(); await keyring.load();
// clear any keys already in the keychain
// keyring.clear();
await keyring.store(); await keyring.store();
} }
@ -83,6 +81,17 @@ class MutablePgpKeyStore implements MutableKeyStore{
return !_key.err; return !_key.err;
} }
async isEncryptedPrivateKey(privateKey: any): Promise<boolean> {
const imported = await openpgp.key.readArmored(privateKey);
for (let i = 0; i < imported.keys.length; i++) {
const key = imported.keys[i];
if (key.isDecrypted()) {
return false;
}
}
return true;
}
getFingerprint(): string { getFingerprint(): string {
// TODO Handle multiple keys // TODO Handle multiple keys
return keyring.privateKeys.keys[0].keyPacket.fingerprint; return keyring.privateKeys.keys[0].keyPacket.fingerprint;

View File

@ -5,10 +5,8 @@ import {environment} from '@src/environments/environment';
import {LoggingService} from '@app/_services/logging.service'; import {LoggingService} from '@app/_services/logging.service';
import {MutableKeyStore, MutablePgpKeyStore} from '@app/_pgp'; import {MutableKeyStore, MutablePgpKeyStore} from '@app/_pgp';
import {ErrorDialogService} from '@app/_services/error-dialog.service'; import {ErrorDialogService} from '@app/_services/error-dialog.service';
import {tap} from 'rxjs/operators';
import { HttpClient } from '@angular/common/http'; import { HttpClient } from '@angular/common/http';
import {Observable } from 'rxjs'; import {Observable } from 'rxjs';
import * as openpgp from 'openpgp';
@Injectable({ @Injectable({
providedIn: 'root' providedIn: 'root'
@ -125,18 +123,19 @@ export class AuthService {
} }
async setKey(privateKeyArmored): Promise<boolean> { async setKey(privateKeyArmored): Promise<boolean> {
// TODO Check if key is encrypted else warn user.
try { try {
const isValidKeyCheck = await this.mutableKeyStore.isValidKey(privateKeyArmored); const isValidKeyCheck = await this.mutableKeyStore.isValidKey(privateKeyArmored);
if (!isValidKeyCheck) { if (!isValidKeyCheck) {
throw Error('The private key is invalid'); throw Error('The private key is invalid');
} }
const isEncryptedKeyCheck = await this.mutableKeyStore.isEncryptedPrivateKey(privateKeyArmored);
if (!isEncryptedKeyCheck) {
throw Error('The private key doesn\'t have a password!');
}
const key = await this.mutableKeyStore.importPrivateKey(privateKeyArmored); const key = await this.mutableKeyStore.importPrivateKey(privateKeyArmored);
localStorage.setItem(btoa('CICADA_PRIVATE_KEY'), privateKeyArmored); localStorage.setItem(btoa('CICADA_PRIVATE_KEY'), privateKeyArmored);
} catch (err) { } catch (err) {
this.loggingService.sendErrorLevelMessage('Failed setting key', this, {error: err}); this.loggingService.sendErrorLevelMessage(`Failed to set key: ${err.message || err.statusText}`, this, {error: err});
// TODO use a global error handler here
this.errorDialogService.openDialog({ this.errorDialogService.openDialog({
message: `Failed to set key: ${err.message || err.statusText}`, message: `Failed to set key: ${err.message || err.statusText}`,
}); });
@ -158,14 +157,7 @@ export class AuthService {
} }
getPublicKeys(): Observable<any> { getPublicKeys(): Observable<any> {
return this.httpClient.get(`${environment.publicKeysUrl}`, {responseType: 'text'}) return this.httpClient.get(`${environment.publicKeysUrl}`, {responseType: 'text'});
.pipe(tap(
data => { },
error => {
this.loggingService.sendErrorLevelMessage('Unable to load trusted public keys.', this, {error});
this.errorDialogService.openDialog({message: 'Trusted keys endpoint can\'t be reached. Please try again later.'});
}
));
} }
async getPrivateKeys(): Promise<void> { async getPrivateKeys(): Promise<void> {

View File

@ -1,5 +1,6 @@
import {ChangeDetectionStrategy, Component, HostListener} from '@angular/core'; import {ChangeDetectionStrategy, Component, HostListener} from '@angular/core';
import {AuthService, LoggingService, TokenService, TransactionService} from '@app/_services'; import {AuthService, ErrorDialogService, LoggingService, TransactionService} from '@app/_services';
import {catchError} from 'rxjs/operators';
@Component({ @Component({
selector: 'app-root', selector: 'app-root',
@ -15,15 +16,17 @@ export class AppComponent {
constructor( constructor(
private authService: AuthService, private authService: AuthService,
private tokenService: TokenService,
private transactionService: TransactionService, private transactionService: TransactionService,
private loggingService: LoggingService, private loggingService: LoggingService,
private errorDialogService: ErrorDialogService
) { ) {
(async () => { (async () => {
await this.authService.mutableKeyStore.loadKeyring(); await this.authService.mutableKeyStore.loadKeyring();
// TODO Handle error from get public keys function. this.authService.getPublicKeys()
this.authService.getPublicKeys().subscribe(this.authService.mutableKeyStore.importPublicKey); .pipe(catchError(async (error) => {
// this.loggingService.sendInfoLevelMessage(await this.tokenService.getTokens()); this.loggingService.sendErrorLevelMessage('Unable to load trusted public keys.', this, {error});
this.errorDialogService.openDialog({message: 'Trusted keys endpoint can\'t be reached. Please try again later.'});
})).subscribe(this.authService.mutableKeyStore.importPublicKey);
})(); })();
this.mediaQuery.addListener(this.onResize); this.mediaQuery.addListener(this.onResize);
this.onResize(this.mediaQuery); this.onResize(this.mediaQuery);