private key loading error handling
This commit is contained in:
parent
c2d8290c42
commit
8e26628092
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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> {
|
||||||
|
@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
@ -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]
|
||||||
})
|
})
|
||||||
|
Loading…
Reference in New Issue
Block a user