diff --git a/src/app/_services/user.service.ts b/src/app/_services/user.service.ts index 666ad9a..560c3bf 100644 --- a/src/app/_services/user.service.ts +++ b/src/app/_services/user.service.ts @@ -1,9 +1,9 @@ import { Injectable } from '@angular/core'; -import {BehaviorSubject, Observable} from 'rxjs'; -import {HttpClient, HttpParams} from '@angular/common/http'; +import {BehaviorSubject, Observable, of} from 'rxjs'; +import {HttpClient, HttpHeaders, HttpParams} from '@angular/common/http'; import {environment} from '../../environments/environment'; import {first, map} from 'rxjs/operators'; -import {} from '../../assets/js/cic-meta/sync'; +import { Envelope, Syncable } from '../../assets/js/cic-meta/sync.js'; @Injectable({ providedIn: 'root' @@ -48,10 +48,37 @@ export class UserService { ); } - changeAccountInfo(status: string, name: string, phoneNumber: string, type: string, token: string, failedPinAttempts: string, bio: string, - gender: string, businessCategory: string, userLocation: string, location: string, referrer: string): Observable { - console.log(status); - return ; + changeAccountInfo(address: string, status: string, name: string, phoneNumber: string, type: string, token: string, + failedPinAttempts: string, bio: string, gender: string, businessCategory: string, userLocation: string, + location: string, referrer: string): Observable { + const accountDetails = { + status, + name, + phoneNumber, + type, + token, + failedPinAttempts, + bio, + gender, + businessCategory, + userLocation, + location, + referrer + }; + const addressStub = address.slice(2); + const headers = new HttpHeaders().append('x-cic-automerge', 'client'); + this.http.get(`${environment.cicMetaUrl}/${addressStub}`, { headers }).pipe(first()).subscribe(res => { + console.log(res); + const response = Envelope.fromJSON(res); + response.unwrap(); + console.log(response); + }, error => { + console.error('There is an error!', error); + }); + this.http.put(`${environment.cicMetaUrl}/${addressStub}`, { data: accountDetails }, { headers }).pipe(first()).subscribe(res => { + console.log(res); + }); + return of(addressStub); } getAccounts(): void { @@ -109,8 +136,4 @@ export class UserService { return response; })); } - - changeUserCredentials(): void { - - } } diff --git a/src/app/pages/accounts/account-details/account-details.component.ts b/src/app/pages/accounts/account-details/account-details.component.ts index c9dcf70..54fa11c 100644 --- a/src/app/pages/accounts/account-details/account-details.component.ts +++ b/src/app/pages/accounts/account-details/account-details.component.ts @@ -1,6 +1,5 @@ import {Component, OnInit, ViewChild} from '@angular/core'; import {MatTableDataSource} from '@angular/material/table'; -import {Transaction, User} from '../../../_models'; import {SelectionModel} from '@angular/cdk/collections'; import {MatPaginator} from '@angular/material/paginator'; import {MatSort} from '@angular/material/sort'; @@ -158,9 +157,9 @@ export class AccountDetailsComponent implements OnInit { saveInfo(): void { this.submitted = true; - console.log(this.accountInfoFormStub.userLocation.value); if (this.accountInfoForm.invalid) { return; } this.userService.changeAccountInfo( + this.account.address, this.accountInfoFormStub.status.value, this.accountInfoFormStub.name.value, this.accountInfoFormStub.phoneNumber.value, diff --git a/src/assets/js/cic-meta/constants.js b/src/assets/js/cic-meta/constants.js new file mode 100644 index 0000000..6588949 --- /dev/null +++ b/src/assets/js/cic-meta/constants.js @@ -0,0 +1,24 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.networkSpec = exports.cryptoSpec = exports.engineSpec = void 0; +var ENGINE_NAME = 'automerge'; +var ENGINE_VERSION = '0.14.1'; +var NETWORK_NAME = 'cic'; +var NETWORK_VERSION = '1'; +var CRYPTO_NAME = 'pgp'; +var CRYPTO_VERSION = '2'; +var engineSpec = { + name: ENGINE_NAME, + version: ENGINE_VERSION, +}; +exports.engineSpec = engineSpec; +var cryptoSpec = { + name: CRYPTO_NAME, + version: CRYPTO_VERSION, +}; +exports.cryptoSpec = cryptoSpec; +var networkSpec = { + name: NETWORK_NAME, + version: NETWORK_VERSION, +}; +exports.networkSpec = networkSpec; diff --git a/src/assets/js/cic-meta/sync.d.ts b/src/assets/js/cic-meta/sync.d.ts deleted file mode 100644 index cf48f69..0000000 --- a/src/assets/js/cic-meta/sync.d.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { JSONSerializable } from './format'; -import { Authoritative, Signer } from './auth'; -import { VersionedSpec } from './constants'; -declare class Envelope { - o: VersionedSpec; - constructor(payload: Object); - set(payload: Object): void; - get(): string; - toJSON(): string; - static fromJSON(s: string): Envelope; - unwrap(): Syncable; -} -declare class ArgPair { - k: string; - v: any; - constructor(k: string, v: any); -} -declare class Syncable implements JSONSerializable, Authoritative { - id: string; - timestamp: number; - m: any; - e: Envelope; - signer: Signer; - onwrap: (string: any) => void; - onauthenticate: (boolean: any) => void; - constructor(id: string, v: Object); - setSigner(signer: Signer): void; - digest(): string; - private wrap; - authenticate(full?: boolean): void; - sign(): void; - update(changes: Array, changesDescription: string): void; - replace(o: Object, changesDescription: string): void; - merge(s: Syncable): void; - toJSON(): string; - static fromJSON(s: string): Syncable; -} -export { JSONSerializable, Syncable, ArgPair, Envelope }; diff --git a/src/assets/js/cic-meta/sync.ts b/src/assets/js/cic-meta/sync.ts deleted file mode 100644 index 94217b1..0000000 --- a/src/assets/js/cic-meta/sync.ts +++ /dev/null @@ -1,264 +0,0 @@ -import * as Automerge from 'automerge'; - -import { JSONSerializable } from './format'; - -import { Authoritative, Signer, PGPSigner, Signable, Signature } from './auth'; - -import { engineSpec, cryptoSpec, networkSpec, VersionedSpec } from './constants'; - -const fullSpec: VersionedSpec = { - name: 'cic', - version: '1', - ext: { - network: cryptoSpec, - engine: engineSpec, - }, -}; - -class Envelope { - - o = fullSpec; - - constructor(payload: Object) { - this.set(payload); - } - - public set(payload: Object) { - this.o['payload'] = payload; - } - - public get(): string { - return this.o['payload']; - } - - public toJSON() { - return JSON.stringify(this.o); - } - - public static fromJSON(s: string): Envelope { - const e = new Envelope(undefined); - e.o = JSON.parse(s); - return e; - } - - public unwrap(): Syncable { - return Syncable.fromJSON(this.o['payload']); - } -} - -class ArgPair { - - k: string; - v: any; - - constructor(k: string, v: any) { - this.k = k; - this.v = v; - } -} - -class SignablePart implements Signable { - - s: string; - - constructor(s: string) { - this.s = s; - } - - public digest(): string { - return this.s; - } -} - -function orderDict(src) { - let dst; - if (Array.isArray(src)) { - dst = []; - src.forEach((v) => { - if (typeof (v) == 'object') { - v = orderDict(v); - } - dst.push(v); - }); - } else { - dst = {}; - Object.keys(src).sort().forEach((k) => { - let v = src[k]; - if (typeof (v) == 'object') { - v = orderDict(v); - } - dst[k] = v; - }); - } - return dst; -} - -class Syncable implements JSONSerializable, Authoritative { - - // TODO: Move data to sub-object so timestamp, id, signature don't collide - constructor(id: string, v: Object) { - this.id = id; - const o = { - id: id, - timestamp: Math.floor(Date.now() / 1000), - data: v, - }; - // this.m = Automerge.from(v) - this.m = Automerge.from(o); - } - - id: string; - timestamp: number; - m: any; // automerge object - e: Envelope; - signer: Signer; - onwrap: (string) => void; - onauthenticate: (boolean) => void; - - public static fromJSON(s: string): Syncable { - const doc = Automerge.load(s); - let y = new Syncable(doc['id'], {}); - y.m = doc; - return y; - } - - public setSigner(signer: Signer) { - this.signer = signer; - this.signer.onsign = (s) => { - this.wrap(s); - }; - } - - // TODO: To keep integrity, the non-link key/value pairs for each step also need to be hashed - public digest(): string { - const links = []; - Automerge.getAllChanges(this.m).forEach((ch: Object) => { - const op: Array = ch['ops']; - ch['ops'].forEach((op: Array) => { - if (op['action'] == 'link') { - // console.log('op link', op); - links.push([op['obj'], op['value']]); - } - }); - }); - // return JSON.stringify(links); - const j = JSON.stringify(links); - return Buffer.from(j).toString('base64'); - } - - private wrap(s: string) { - this.m = Automerge.change(this.m, 'sign', (doc) => { - doc['signature'] = s; - }); - this.e = new Envelope(this.toJSON()); - if (this.onwrap !== undefined) { - this.onwrap(this.e); - } - - } - -// private _verifyLoop(i:number, history:Array, signable:Signable, result:boolean) { -// if (!result) { -// this.onauthenticate(false); -// return; -// } else if (history.length == 0) { -// this.onauthenticate(true); -// return; -// } -// const h = history.shift() -// if (i % 2 == 0) { -// i++; -// signable = { -// digest: () => { -// return Automerge.save(h.snapshot) -// }, -// }; -// this._verifyLoop(i, history, signable, true); -// } else { -// i++; -// const signature = h.snapshot['signature']; -// console.debug('signature', signature, signable.digest()); -// this.signer.onverify = (v) => { -// this._verifyLoop(i, history, signable, v) -// } -// this.signer.verify(signable, signature); -// } -// } -// -// // TODO: This should replay the graph and check signatures on each step -// public _authenticate(full:boolean=false) { -// let h = Automerge.getHistory(this.m); -// h.forEach((m) => { -// //console.debug(m.snapshot); -// }); -// const signable = { -// digest: () => { return '' }, -// } -// if (!full) { -// h = h.slice(h.length-2); -// } -// this._verifyLoop(0, h, signable, true); -// } - - public authenticate(full: boolean = false) { - if (full) { - console.warn('only doing shallow authentication for now, sorry'); - } - // console.log('authenticating', signable.digest()); - // console.log('signature', this.m.signature); - this.signer.onverify = (v) => { - // this._verifyLoop(i, history, signable, v) - this.onauthenticate(v); - }; - this.signer.verify(this.m.signature.digest, this.m.signature); - } - - - public sign() { - // this.signer.prepare(this); - this.signer.sign(this.digest()); - } - - public update(changes: Array, changesDescription: string) { - this.m = Automerge.change(this.m, changesDescription, (m) => { - changes.forEach((c) => { - let path = c.k.split('.'); - let target = m['data']; - while (path.length > 1) { - const part = path.shift(); - target = target[part]; - } - target[path[0]] = c.v; - }); - m['timestamp'] = Math.floor(Date.now() / 1000); - }); - } - - public replace(o: Object, changesDescription: string) { - this.m = Automerge.change(this.m, changesDescription, (m) => { - Object.keys(o).forEach((k) => { - m['data'][k] = o[k]; - }); - Object.keys(m).forEach((k) => { - if (o[k] == undefined) { - delete m['data'][k]; - } - }); - m['timestamp'] = Math.floor(Date.now() / 1000); - }); - } - - public merge(s: Syncable) { - this.m = Automerge.merge(s.m, this.m); - } - - public toJSON(): string { - const s = Automerge.save(this.m); - const o = JSON.parse(s); - const oo = orderDict(o); - return JSON.stringify(oo); - - } -} - -export { JSONSerializable, Syncable, ArgPair, Envelope }; diff --git a/src/environments/environment.prod.ts b/src/environments/environment.prod.ts index 12e5efc..3ae5e32 100644 --- a/src/environments/environment.prod.ts +++ b/src/environments/environment.prod.ts @@ -2,6 +2,7 @@ export const environment = { production: true, cicCacheUrl: 'http://localhost:63313', cicScriptsUrl: 'http://localhost:9999', + cicMetaUrl: 'http://localhost:63380', web3Provider: 'ws://localhost:8546', cicUssdUrl: 'http://localhost:63315', cicEthUrl: 'http://localhost:63314', diff --git a/src/environments/environment.ts b/src/environments/environment.ts index 2eee8db..458c654 100644 --- a/src/environments/environment.ts +++ b/src/environments/environment.ts @@ -6,6 +6,7 @@ export const environment = { production: false, cicCacheUrl: 'http://localhost:63313', cicScriptsUrl: 'http://localhost:9999', + cicMetaUrl: 'http://localhost:63380', web3Provider: 'ws://localhost:8546', cicUssdUrl: 'http://localhost:63315', cicEthUrl: 'http://localhost:63314',