cic-staff-client/src/app/_pgp/pgp-signer.ts

115 lines
2.9 KiB
TypeScript

import { MutableKeyStore } from '@app/_pgp/pgp-key-store';
import { LoggingService } from '@app/_services/logging.service';
const openpgp = require('openpgp');
interface Signable {
digest(): string;
}
interface Signature {
engine: string;
algo: string;
data: string;
digest: string;
}
interface Signer {
onsign(signature: Signature): void;
onverify(flag: boolean): void;
fingerprint(): string;
prepare(material: Signable): boolean;
verify(digest: string, signature: Signature): void;
sign(digest: string): Promise<void>;
}
class PGPSigner implements Signer {
engine = 'pgp';
algo = 'sha256';
dgst: string;
signature: Signature;
keyStore: MutableKeyStore;
onsign: (signature: Signature) => void;
onverify: (flag: boolean) => void;
loggingService: LoggingService;
constructor(keyStore: MutableKeyStore) {
this.keyStore = keyStore;
this.onsign = (signature: Signature) => {};
this.onverify = (flag: boolean) => {};
}
public fingerprint(): string {
return this.keyStore.getFingerprint();
}
public prepare(material: Signable): boolean {
this.dgst = material.digest();
return true;
}
public verify(digest: string, signature: Signature): void {
openpgp.signature
.readArmored(signature.data)
.then((sig) => {
const opts = {
message: openpgp.cleartext.fromText(digest),
publicKeys: this.keyStore.getTrustedKeys(),
signature: sig,
};
openpgp.verify(opts).then((v) => {
let i = 0;
for (i = 0; i < v.signatures.length; i++) {
const s = v.signatures[i];
if (s.valid) {
this.onverify(s);
return;
}
}
this.loggingService.sendErrorLevelMessage(
`Checked ${i} signature(s) but none valid`,
this,
{ error: '404 Not found!' }
);
this.onverify(false);
});
})
.catch((e) => {
this.loggingService.sendErrorLevelMessage(e.message, this, { error: e });
this.onverify(false);
});
}
public async sign(digest: string): Promise<void> {
const m = openpgp.cleartext.fromText(digest);
const pk = this.keyStore.getPrivateKey();
if (!pk.isDecrypted()) {
const password = window.prompt('password');
await pk.decrypt(password);
}
const opts = {
message: m,
privateKeys: [pk],
detached: true,
};
openpgp
.sign(opts)
.then((s) => {
this.signature = {
engine: this.engine,
algo: this.algo,
data: s.signature,
// TODO: fix for browser later
digest,
};
this.onsign(this.signature);
})
.catch((e) => {
this.loggingService.sendErrorLevelMessage(e.message, this, { error: e });
this.onsign(undefined);
});
}
}
export { Signable, Signature, Signer, PGPSigner };