private key loading error handling

This commit is contained in:
Blair Vanderlugt 2021-03-20 19:23:50 -07:00
parent c2d8290c42
commit 8e26628092
5 changed files with 63 additions and 29 deletions

View File

@ -19,11 +19,12 @@ export class HttpConfigInterceptor implements HttpInterceptor {
request = request.clone({headers: request.headers.set('Authorization', 'Bearer ' + token)}); request = request.clone({headers: request.headers.set('Authorization', 'Bearer ' + token)});
} }
if (!request.headers.has('Content-Type')) { // I think this is the default behavior
request = request.clone({headers: request.headers.set('Content-Type', 'text/plain')}); // if (!request.headers.has('Content-Type')) {
} // request = request.clone({headers: request.headers.set('Content-Type', 'application/json')});
// }
request = request.clone({headers: request.headers.set('Accept', 'application/json')});
// request = request.clone({headers: request.headers.set('Accept', 'application/json')});
return next.handle(request); return next.handle(request);
} }
} }

View File

@ -1,11 +1,12 @@
import { KeyStore } from 'cic-client-meta'; import { KeyStore } from 'cic-client-meta';
const openpgp = require('openpgp'); // const openpgp = require('openpgp'); //TODO should we put this on the mutalble key store object
import * as openpgp from 'openpgp';
const keyring = new openpgp.Keyring(); const keyring = new openpgp.Keyring();
interface MutableKeyStore extends KeyStore { interface MutableKeyStore extends KeyStore {
loadKeyring(): Promise<void>; loadKeyring(): void;
importKeyPair(publicKey: any, privateKey: any): Promise<void>; importKeyPair(publicKey: any, privateKey: any): Promise<void>;
importPublicKey(publicKey: any): Promise<void>; importPublicKey(publicKey: any): void;
importPrivateKey(privateKey: any): Promise<void>; importPrivateKey(privateKey: any): Promise<void>;
getPublicKeys(): Array<any>; getPublicKeys(): Array<any>;
getTrustedKeys(): Array<any>; getTrustedKeys(): Array<any>;
@ -13,7 +14,7 @@ interface MutableKeyStore extends KeyStore {
getEncryptKeys(): Array<any>; getEncryptKeys(): Array<any>;
getPrivateKeys(): Array<any>; getPrivateKeys(): Array<any>;
getPrivateKey(): any; getPrivateKey(): any;
isValidKey(key: any): boolean; isValidKey(key: any): Promise<boolean>;
getFingerprint(): string; getFingerprint(): string;
getKeyId(key: any): string; getKeyId(key: any): string;
getPrivateKeyId(): string; getPrivateKeyId(): string;
@ -43,8 +44,8 @@ class MutablePgpKeyStore implements MutableKeyStore{
await keyring.privateKeys.importKey(privateKey); await keyring.privateKeys.importKey(privateKey);
} }
async importPublicKey(publicKey: any): Promise<void> { importPublicKey(publicKey: any): void {
await keyring.publicKeys.importKey(publicKey); keyring.publicKeys.importKey(publicKey)
} }
async importPrivateKey(privateKey: any): Promise<void> { async importPrivateKey(privateKey: any): Promise<void> {
@ -75,8 +76,14 @@ class MutablePgpKeyStore implements MutableKeyStore{
return keyring.privateKeys.keys[0]; return keyring.privateKeys.keys[0];
} }
isValidKey(key): boolean { async isValidKey(key): Promise<boolean> {
return typeof key === openpgp.Key; // There is supposed to be an opengpg.readKey() method but I can't find it?
const _key = await openpgp.key.readArmored(key)
if (_key.err) {
return false
} else {
return true
}
} }
getFingerprint(): string { getFingerprint(): string {
@ -88,7 +95,8 @@ class MutablePgpKeyStore implements MutableKeyStore{
} }
getPrivateKeyId(): string { getPrivateKeyId(): string {
return keyring.privateKeys.keys[0].getKeyId().toHex(); // TODO is there a library that comes with angular for doing this?
return keyring.privateKeys && keyring.privateKeys.keys[0] && keyring.privateKeys.keys[0].getKeyId().toHex();
} }
getKeysForId(keyId: string): Array<any> { getKeysForId(keyId: string): Array<any> {

View File

@ -6,8 +6,9 @@ import {LoggingService} from '@app/_services/logging.service';
import {HttpWrapperService} from '@app/_services/http-wrapper.service'; import {HttpWrapperService} from '@app/_services/http-wrapper.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 {first} from 'rxjs/operators'; import {catchError, first, tap} from 'rxjs/operators';
import { HttpClient } from '@angular/common/http'; import { HttpClient, HttpErrorResponse } from '@angular/common/http';
import { throwError } from 'rxjs';
@Injectable({ @Injectable({
providedIn: 'root' providedIn: 'root'
@ -24,6 +25,7 @@ export class AuthService {
private loggingService: LoggingService, private loggingService: LoggingService,
private errorDialogService: ErrorDialogService private errorDialogService: ErrorDialogService
) { ) {
// TODO setting these together shoulds be atomic
if (sessionStorage.getItem(btoa('CICADA_SESSION_TOKEN'))) { if (sessionStorage.getItem(btoa('CICADA_SESSION_TOKEN'))) {
this.sessionToken = sessionStorage.getItem(btoa('CICADA_SESSION_TOKEN')); this.sessionToken = sessionStorage.getItem(btoa('CICADA_SESSION_TOKEN'));
} }
@ -121,13 +123,17 @@ export class AuthService {
async setKey(privateKeyArmored): Promise<boolean> { async setKey(privateKeyArmored): Promise<boolean> {
try { try {
await this.mutableKeyStore.importPrivateKey(privateKeyArmored); const isValidKeyCheck = await this.mutableKeyStore.isValidKey(privateKeyArmored)
if (!isValidKeyCheck) {
throw Error("The private key is invalid")
}
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 setting key', this, {error: err});
// TODO use a global error handler here
this.errorDialogService.openDialog({ this.errorDialogService.openDialog({
message: `Failed to set key, Enter your private key again. Reason: ${err.error.message || err.statusText}`, message: `Failed to set key: ${err.message || err.statusText}`,
status: err.status
}); });
return false; return false;
} }
@ -146,14 +152,33 @@ export class AuthService {
return trustedUsers; return trustedUsers;
} }
async getPublicKeys(): Promise<void> { getPublicKeys() {
this.httpClient.get(`${environment.publicKeysUrl}`).pipe(first()).subscribe(async res => { return this.httpClient.get(`${environment.publicKeysUrl}`, {responseType: 'text'})
await this.mutableKeyStore.importPublicKey(res); .pipe(tap(
}, error => { data => { },
this.loggingService.sendErrorLevelMessage('There was an error fetching public keys!', this, {error}); error => { this.handleError(error, 'Unable to load trusted public keys.') }
}); ))
}
async getPrivateKeys(): Promise<void> {
if (this.privateKey !== undefined) { if (this.privateKey !== undefined) {
await this.mutableKeyStore.importPrivateKey(this.privateKey); await this.mutableKeyStore.importPrivateKey(this.privateKey);
} }
} }
// TODO this is from the docs and for reference. Move it somewhere better.
private handleError(error: HttpErrorResponse, customMessage: string) {
if (error.error instanceof ErrorEvent) {
// A client-side or network error occurred. Handle it accordingly.
console.error('An error occurred:', error.error.message);
} else {
// The backend returned an unsuccessful response code.
// The response body may contain clues as to what went wrong.
console.error(
`Backend returned code ${error.status}, ` +
`body was: ${JSON.stringify(error.error)}`);
}
// Return an observable with a user-facing error message.
return throwError(customMessage);
}
} }

View File

@ -21,8 +21,8 @@ export class AppComponent {
) { ) {
(async () => { (async () => {
await this.authService.mutableKeyStore.loadKeyring(); await this.authService.mutableKeyStore.loadKeyring();
await this.authService.getPublicKeys(); this.authService.getPublicKeys().subscribe(this.authService.mutableKeyStore.importPublicKey)
this.loggingService.sendInfoLevelMessage(await this.tokenService.getTokens()); // this.loggingService.sendInfoLevelMessage(await this.tokenService.getTokens());
})(); })();
this.mediaQuery.addListener(this.onResize); this.mediaQuery.addListener(this.onResize);
this.onResize(this.mediaQuery); this.onResize(this.mediaQuery);

View File

@ -44,8 +44,8 @@ import {MutablePgpKeyStore} from '@app/_pgp';
GlobalErrorHandler, GlobalErrorHandler,
{ provide: ErrorHandler, useClass: GlobalErrorHandler }, { provide: ErrorHandler, useClass: GlobalErrorHandler },
{ provide: HTTP_INTERCEPTORS, useClass: HttpConfigInterceptor, multi: true }, { provide: HTTP_INTERCEPTORS, useClass: HttpConfigInterceptor, multi: true },
{ provide: HTTP_INTERCEPTORS, useClass: ErrorInterceptor, multi: true }, // { provide: HTTP_INTERCEPTORS, useClass: ErrorInterceptor, multi: true },
{ provide: HTTP_INTERCEPTORS, useClass: LoggingInterceptor, multi: true }, // { provide: HTTP_INTERCEPTORS, useClass: LoggingInterceptor, multi: true },
], ],
bootstrap: [AppComponent] bootstrap: [AppComponent]
}) })