Add pgp signer.
This commit is contained in:
parent
9d2fdd687b
commit
7165031fc8
@ -34,6 +34,7 @@
|
|||||||
"mocha": "^8.2.1",
|
"mocha": "^8.2.1",
|
||||||
"moolb": "^0.1.0",
|
"moolb": "^0.1.0",
|
||||||
"ng2-charts": "^2.4.2",
|
"ng2-charts": "^2.4.2",
|
||||||
|
"openpgp": "^4.10.10",
|
||||||
"popper.js": "^1.16.1",
|
"popper.js": "^1.16.1",
|
||||||
"rxjs": "~6.6.0",
|
"rxjs": "~6.6.0",
|
||||||
"tslib": "^2.0.0",
|
"tslib": "^2.0.0",
|
||||||
|
@ -3,3 +3,5 @@ export * from './array-sum';
|
|||||||
export * from './accountIndex';
|
export * from './accountIndex';
|
||||||
export * from './custom-error-state-matcher';
|
export * from './custom-error-state-matcher';
|
||||||
export * from './http-getter';
|
export * from './http-getter';
|
||||||
|
export * from './pgp-signer';
|
||||||
|
|
||||||
|
8
src/app/_helpers/pgp-signer.spec.ts
Normal file
8
src/app/_helpers/pgp-signer.spec.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
import { PGPSigner } from './pgp-signer';
|
||||||
|
let keystore;
|
||||||
|
|
||||||
|
describe('PgpSigner', () => {
|
||||||
|
it('should create an instance', () => {
|
||||||
|
expect(new PGPSigner(keystore)).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
102
src/app/_helpers/pgp-signer.ts
Normal file
102
src/app/_helpers/pgp-signer.ts
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
const openpgp = require('openpgp');
|
||||||
|
|
||||||
|
interface Signable {
|
||||||
|
digest(): string;
|
||||||
|
}
|
||||||
|
|
||||||
|
type 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): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
class PGPSigner implements Signer {
|
||||||
|
|
||||||
|
engine = 'pgp';
|
||||||
|
algo = 'sha256';
|
||||||
|
dgst: string;
|
||||||
|
signature: Signature;
|
||||||
|
keyStore;
|
||||||
|
onsign: (signature: Signature) => void;
|
||||||
|
onverify: (flag: boolean) => void;
|
||||||
|
|
||||||
|
constructor(keyStore) {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.error('checked ' + i + ' signature(s) but none valid');
|
||||||
|
this.onverify(false);
|
||||||
|
});
|
||||||
|
}).catch((e) => {
|
||||||
|
console.error(e);
|
||||||
|
this.onverify(false);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public sign(digest: string): void {
|
||||||
|
const m = openpgp.cleartext.fromText(digest);
|
||||||
|
const pk = this.keyStore.getPrivateKey();
|
||||||
|
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) => {
|
||||||
|
console.error(e);
|
||||||
|
this.onsign(undefined);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export {
|
||||||
|
Signable,
|
||||||
|
Signature,
|
||||||
|
Signer,
|
||||||
|
PGPSigner
|
||||||
|
};
|
@ -3,12 +3,17 @@ import {BehaviorSubject, Observable, of} from 'rxjs';
|
|||||||
import {HttpClient, HttpHeaders, HttpParams} from '@angular/common/http';
|
import {HttpClient, HttpHeaders, HttpParams} from '@angular/common/http';
|
||||||
import {environment} from '../../environments/environment';
|
import {environment} from '../../environments/environment';
|
||||||
import {first, map} from 'rxjs/operators';
|
import {first, map} from 'rxjs/operators';
|
||||||
import { Envelope, Syncable } from '../../assets/js/cic-meta/sync.js';
|
import { ArgPair, Envelope, Syncable } from '../../assets/js/cic-meta/sync.js';
|
||||||
|
import {PGPSigner, Signer} from '../_helpers';
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root'
|
providedIn: 'root'
|
||||||
})
|
})
|
||||||
export class UserService {
|
export class UserService {
|
||||||
|
keystore = '';
|
||||||
|
syncableAccount: Syncable;
|
||||||
|
signer: Signer = new PGPSigner(this.keystore);
|
||||||
|
|
||||||
accounts: any = '';
|
accounts: any = '';
|
||||||
private accountsList = new BehaviorSubject<any>(this.accounts);
|
private accountsList = new BehaviorSubject<any>(this.accounts);
|
||||||
accountsSubject = this.accountsList.asObservable();
|
accountsSubject = this.accountsList.asObservable();
|
||||||
@ -48,9 +53,9 @@ export class UserService {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
changeAccountInfo(address: string, status: string, name: string, phoneNumber: string, type: string, token: string,
|
async changeAccountInfo(address: string, status: string, name: string, phoneNumber: string, type: string, token: string,
|
||||||
failedPinAttempts: string, bio: string, gender: string, businessCategory: string, userLocation: string,
|
failedPinAttempts: string, bio: string, gender: string, businessCategory: string, userLocation: string,
|
||||||
location: string, referrer: string): Observable<any> {
|
location: string, referrer: string): Promise<any> {
|
||||||
const accountDetails = {
|
const accountDetails = {
|
||||||
status,
|
status,
|
||||||
name,
|
name,
|
||||||
@ -65,20 +70,32 @@ export class UserService {
|
|||||||
location,
|
location,
|
||||||
referrer
|
referrer
|
||||||
};
|
};
|
||||||
const addressStub = address.slice(2);
|
let addressStub = address.slice(2);
|
||||||
const headers = new HttpHeaders().append('x-cic-automerge', 'client');
|
addressStub = '0000000000000000000000000000000000000000000000000000000000000000';
|
||||||
this.http.get(`${environment.cicMetaUrl}/${addressStub}`, { headers }).pipe(first()).subscribe(res => {
|
const headers = new HttpHeaders({'x-cic-automerge': 'client'});
|
||||||
console.log(res);
|
this.http.get(`${environment.cicMetaUrl}/${addressStub}`, { headers }).pipe(first()).subscribe(async res => {
|
||||||
const response = Envelope.fromJSON(res);
|
this.syncableAccount = Envelope.fromJSON(res).unwrap();
|
||||||
response.unwrap();
|
let update = [];
|
||||||
console.log(response);
|
for (const prop in accountDetails) {
|
||||||
}, error => {
|
update.push(new ArgPair(prop, accountDetails[prop]));
|
||||||
|
}
|
||||||
|
this.syncableAccount.update(update, 'client-branch');
|
||||||
|
await this.updateMeta(addressStub, headers);
|
||||||
|
}, async error => {
|
||||||
console.error('There is an error!', error);
|
console.error('There is an error!', error);
|
||||||
|
const refName = addressStub + ':cic-person';
|
||||||
|
this.syncableAccount = new Syncable(refName, accountDetails);
|
||||||
|
await this.updateMeta(addressStub, headers);
|
||||||
});
|
});
|
||||||
this.http.put(`${environment.cicMetaUrl}/${addressStub}`, { data: accountDetails }, { headers }).pipe(first()).subscribe(res => {
|
return addressStub;
|
||||||
|
}
|
||||||
|
|
||||||
|
async updateMeta(addressStub: string, headers: HttpHeaders): Promise<any> {
|
||||||
|
const envelope = await this.wrap(this.syncableAccount , this.signer);
|
||||||
|
const reqBody = envelope.toJSON();
|
||||||
|
this.http.put(`${environment.cicMetaUrl}/${addressStub}`, { data: reqBody }, { headers }).pipe(first()).subscribe(res => {
|
||||||
console.log(res);
|
console.log(res);
|
||||||
});
|
});
|
||||||
return of(addressStub);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getAccounts(): void {
|
getAccounts(): void {
|
||||||
@ -136,4 +153,18 @@ export class UserService {
|
|||||||
return response;
|
return response;
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
wrap(syncable: Syncable, signer: Signer): Promise<Envelope> {
|
||||||
|
return new Promise<Envelope>((whohoo, doh) => {
|
||||||
|
syncable.setSigner(signer);
|
||||||
|
syncable.onwrap = async (env) => {
|
||||||
|
if (env === undefined) {
|
||||||
|
doh();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
whohoo(env);
|
||||||
|
};
|
||||||
|
syncable.sign();
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -219,14 +219,14 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-md-6 col-lg-4">
|
<div class="col-md-6 col-lg-4">
|
||||||
<button mat-raised-button color="warn" type="button" class="btn btn-outline-danger">
|
<button mat-raised-button color="warn" type="button" class="btn btn-outline-danger mb-3">
|
||||||
Delete User
|
Delete User
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-md-6 col-lg-4">
|
<div class="col-md-6 col-lg-4">
|
||||||
<button mat-raised-button color="primary" type="submit" class="btn btn-outline-primary ml-2">
|
<button mat-raised-button color="primary" type="submit" class="btn btn-outline-primary">
|
||||||
SAVE
|
SAVE DETAILS
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -172,9 +172,7 @@ export class AccountDetailsComponent implements OnInit {
|
|||||||
this.accountInfoFormStub.userLocation.value,
|
this.accountInfoFormStub.userLocation.value,
|
||||||
this.accountInfoFormStub.location.value,
|
this.accountInfoFormStub.location.value,
|
||||||
this.accountInfoFormStub.referrer.value,
|
this.accountInfoFormStub.referrer.value,
|
||||||
).pipe(first()).subscribe(res => {
|
).then(res => console.log(res));
|
||||||
console.log(res);
|
|
||||||
});
|
|
||||||
this.submitted = false;
|
this.submitted = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user