Add helper classes.

- Add error state matcher for forms.
- Add custom validator for forms.
- Add error interceptor for incoming responses.
- Add unsafe key store for holding private keys.
This commit is contained in:
Spencer Ofwiti 2020-12-28 12:06:30 +03:00
parent 2f8806b8ce
commit 8636cbdf99
9 changed files with 129 additions and 0 deletions

View File

@ -0,0 +1,7 @@
import { CustomErrorStateMatcher } from './custom-error-state-matcher';
describe('CustomErrorStateMatcher', () => {
it('should create an instance', () => {
expect(new CustomErrorStateMatcher()).toBeTruthy();
});
});

View File

@ -0,0 +1,9 @@
import {ErrorStateMatcher} from '@angular/material/core';
import {FormControl, FormGroupDirective, NgForm} from '@angular/forms';
export class CustomErrorStateMatcher implements ErrorStateMatcher{
isErrorState(control: FormControl | null, form: FormGroupDirective | NgForm | null): boolean {
const isSubmitted = form && form.submitted;
return !!(control && control.invalid && (control.dirty || control.touched || isSubmitted));
}
}

View File

@ -0,0 +1,7 @@
import { Custom.Validator } from './custom.validator';
describe('Custom.Validator', () => {
it('should create an instance', () => {
expect(new Custom.Validator()).toBeTruthy();
});
});

View File

@ -0,0 +1,22 @@
import {AbstractControl, ValidationErrors} from '@angular/forms';
export class CustomValidator {
static passwordMatchValidator(control: AbstractControl): void {
const password: string = control.get('password').value;
const confirmPassword: string = control.get('confirmPassword').value;
if (password !== confirmPassword) {
control.get('confirmPassword').setErrors({ NoPasswordMatch: true });
}
}
static patternValidator(regex: RegExp, error: ValidationErrors): ValidationErrors | null {
return (control: AbstractControl): { [key: string]: any } => {
if (!control.value) {
return null;
}
const valid = regex.test(control.value);
return valid ? null : error;
};
}
}

View File

@ -0,0 +1,16 @@
import { TestBed } from '@angular/core/testing';
import { ErrorInterceptor } from './error.interceptor';
describe('ErrorInterceptor', () => {
beforeEach(() => TestBed.configureTestingModule({
providers: [
ErrorInterceptor
]
}));
it('should be created', () => {
const interceptor: ErrorInterceptor = TestBed.inject(ErrorInterceptor);
expect(interceptor).toBeTruthy();
});
});

View File

@ -0,0 +1,25 @@
import { Injectable } from '@angular/core';
import {
HttpRequest,
HttpHandler,
HttpEvent,
HttpInterceptor
} from '@angular/common/http';
import {Observable, throwError} from 'rxjs';
import {catchError} from 'rxjs/operators';
@Injectable()
export class ErrorInterceptor implements HttpInterceptor {
constructor() {}
intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> {
return next.handle(request).pipe(catchError(err => {
if ([401, 403].indexOf(err.status) !== -1) {
location.reload(true);
}
const error = err.error.message || err.statusText;
return throwError(error);
}));
}
}

View File

@ -0,0 +1,4 @@
export * from './custom.validator';
export * from './error.interceptor';
export * from './custom-error-state-matcher';
export * from './unsafe-key-store';

View File

@ -0,0 +1,7 @@
import { UnsafeKeyStore } from './unsafe-key-store';
describe('UnsafeKeyStore', () => {
it('should create an instance', () => {
expect(new UnsafeKeyStore()).toBeTruthy();
});
});

View File

@ -0,0 +1,32 @@
import * as openpgp from '../../assets/js/openpgp.min.js';
export function UnsafeKeyStore(): void {
this.key = undefined;
}
UnsafeKeyStore.prototype.set = async function(privateKeyArmored): Promise<void> {
this.key = (await openpgp.key.readArmored(privateKeyArmored)).keys[0];
console.log('set pgp key', this.key.getKeyId().toHex());
};
UnsafeKeyStore.prototype.fingerprint = function(): any {
return this.key.keyPacket.fingerprint;
};
UnsafeKeyStore.prototype.keyid = function(): any {
return this.key.getKeyId();
};
UnsafeKeyStore.prototype.sign = async function(plainText): Promise<any> {
if (!this.key.isDecrypted()) {
const password = window.prompt('password');
await this.key.decrypt(password);
}
const opts = {
message: openpgp.message.fromText(plainText),
privateKeys: [this.key],
detached: true,
};
const signatureObject = await openpgp.sign(opts);
return signatureObject.signature;
};