diff --git a/src/router.ts b/src/router.ts index e451b5f..f600f40 100755 --- a/src/router.ts +++ b/src/router.ts @@ -104,6 +104,7 @@ async function init(): Promise { await services.restoreDevice(device); } await services.restoreProcesses(); + await services.restoreSecrets(); if (services.isPaired()) { await navigate('process'); diff --git a/src/services/modal.service.ts b/src/services/modal.service.ts index ee171ec..98ae36d 100755 --- a/src/services/modal.service.ts +++ b/src/services/modal.service.ts @@ -53,23 +53,11 @@ export default class ModalService { } // this is kind of too specific for pairing though - public async openConfirmationModal(pcd: any, commitmentTx: string, merkleRoot: string) { - let map: Record; - if (pcd['roles']) { - const roles = pcd['roles']; - try { - map = JSON.parse(roles); - } catch (e) { - throw new Error(`Failed to parse roles: ${e}`); - } - } else { - throw new Error('Pcd doesn\'t have a \"roles\" field'); - } - + public async openPairingConfirmationModal(roleDefinition: Record, commitmentTx: string, merkleRoot: string) { // pairing specifics let members; - if (map['owner']) { - const owner = map['owner']; + if (roleDefinition['owner']) { + const owner = roleDefinition['owner']; members = owner.members; } else { throw new Error('No \"owner\" role'); @@ -83,7 +71,6 @@ export default class ModalService { // We take all the addresses except our own const service = await Services.getInstance(); const localAddress = await service.getDeviceAddress(); - console.log('🚀 ~ Routing ~ openConfirmationModal ~ pcd:', pcd); for (const member of members) { for (const address of member['sp_addresses']) { if (address !== localAddress) { @@ -127,7 +114,7 @@ export default class ModalService { // We send the prd update if (this.currentPcdCommitment) { try { - const createPrdUpdateReturn = await service.createPrdUpdate(this.currentPcdCommitment); + const createPrdUpdateReturn = service.createPrdUpdate(this.currentPcdCommitment); await service.handleApiReturn(createPrdUpdateReturn); } catch (e) { throw e @@ -138,13 +125,18 @@ export default class ModalService { // We send confirmation that we validate the change try { - const approveChangeReturn = await service.approveChange(this.currentPcdCommitment!); + const approveChangeReturn = service.approveChange(this.currentPcdCommitment!); await service.handleApiReturn(approveChangeReturn); } catch (e) { throw e } - service.pairDevice(this.paired_addresses); + try { + service.pairDevice(this.paired_addresses); + } catch (e) { + throw e; + } + this.paired_addresses = []; this.currentOutpoint = null; this.currentPcdCommitment = null; diff --git a/src/services/service.ts b/src/services/service.ts index 2ce61a3..7d2d1b2 100755 --- a/src/services/service.ts +++ b/src/services/service.ts @@ -3,7 +3,7 @@ import { INotification } from '~/models/notification.model'; import { IProcess } from '~/models/process.model'; // import Database from './database'; import { initWebsocket, sendMessage } from '../websockets'; -import { ApiReturn, Member, Process } from '../../dist/pkg/sdk_client'; +import { ApiReturn, Member, PcdUpdates, Process, RoleDefinition } from '../../dist/pkg/sdk_client'; import ModalService from './modal.service'; import { navigate } from '../router'; import Database from './database.service'; @@ -16,7 +16,7 @@ export default class Services { private static initializing: Promise | null = null; private static instance: Services; private currentProcess: string | null = null; - private pendingUpdates: Record = {}; + private pendingUpdates: PcdUpdates | null = null; private currentUpdateMerkleRoot: string | null = null; private localAddress: string | null = null; private pairedAddresses: string[] = []; @@ -69,7 +69,7 @@ export default class Services { public isPaired(): boolean { try { - return this.sdkClient.is_linking(); + return this.sdkClient.is_paired(); } catch (e) { throw new Error(`isPaired ~ Error: ${e}`); } @@ -215,17 +215,17 @@ export default class Services { } async sendNewTxMessage(message: string) { - await sendMessage('NewTx', message); + sendMessage('NewTx', message); } async sendCommitMessage(message: string) { - await sendMessage('Commit', message); + sendMessage('Commit', message); } async sendCipherMessages(ciphers: string[]) { for (let i = 0; i < ciphers.length; i++) { const cipher = ciphers[i]; - await sendMessage('Cipher', cipher); + sendMessage('Cipher', cipher); } } @@ -235,8 +235,8 @@ export default class Services { async parseCipher(message: string) { try { - console.log('parsing new cipher'); - const apiReturn = await this.sdkClient.parse_cipher(message); + // console.log('parsing new cipher'); + const apiReturn = this.sdkClient.parse_cipher(message); console.log('🚀 ~ Services ~ parseCipher ~ apiReturn:', apiReturn); await this.handleApiReturn(apiReturn); } catch (e) { @@ -247,12 +247,11 @@ export default class Services { async parseNewTx(tx: string) { try { - const parsedTx = await this.sdkClient.parse_new_tx(tx, 0); + const parsedTx = this.sdkClient.parse_new_tx(tx, 0); if (parsedTx) { - console.log('🚀 ~ Services ~ parseNewTx ~ parsedTx:', parsedTx); try { await this.handleApiReturn(parsedTx); - const newDevice = await this.dumpDevice(); + const newDevice = this.dumpDevice(); await this.saveDevice(newDevice); } catch (e) { console.error('Failed to update device with new tx'); @@ -265,10 +264,10 @@ export default class Services { public getUpdateProposals(commitmentOutpoint: string) { try { - const proposals: ApiReturn = this.sdkClient.get_update_proposals(commitmentOutpoint); + const proposals: PcdUpdates = this.sdkClient.get_update_proposals(commitmentOutpoint); if (proposals.decrypted_pcds && proposals.decrypted_pcds.length != 0) { this.currentProcess = commitmentOutpoint; - this.pendingUpdates = proposals.decrypted_pcds; + this.pendingUpdates = proposals; } else { throw new Error('No pending proposals'); } @@ -296,11 +295,18 @@ export default class Services { } const entries = Object.entries(confirmedSecrets).map(([key, value]) => ({ key, value })); for (const entry of entries) { - db.addObject({ - storeName: 'shared_secrets', - object: entry.value, - key: entry.key, - }); + try { + db.addObject({ + storeName: 'shared_secrets', + object: entry.value, + key: entry.key, + }); + } catch (e) { + throw e; + } + + // We don't want to throw an error, it could simply be that we registered directly the shared secret + // this.removeUnconfirmedSecret(entry.value); } } @@ -315,8 +321,25 @@ export default class Services { throw e; } - // do we need to act? - updatedProcess.user_validation_required + if (updatedProcess.new_state) { + this.currentProcess = updatedProcess.commitment_tx; + + this.getUpdateProposals(this.currentProcess!); + + await this.evaluatePendingUpdates(); + } else if (updatedProcess.modified_state) { + // We added validation tokens + // We check if the state is now valid + // If enough validation tokens we shoot a commit msg to the relay + const [previous_state, new_state] = updatedProcess.modified_state; + const init_commitment = updatedProcess.commitment_tx; + try { + const apiReturn = this.sdkClient.evaluate_state(init_commitment, null, JSON.stringify(new_state)); + await this.handleApiReturn(apiReturn); + } catch (e) { + throw e + } + } } if (apiReturn.commit_to_send) { @@ -343,16 +366,28 @@ export default class Services { } private async openConfirmationModal() { - if (this.pendingUpdates.length === 0) { - console.log('No pending updates'); + if (!this.pendingUpdates || this.pendingUpdates.modified_values.length === 0) { + console.log('No pending updates to validate'); } - try { - for (const [merkleRoot, actual_proposal] of Object.entries(this.pendingUpdates)) { - await this.routingInstance.openConfirmationModal(actual_proposal, this.currentProcess!, merkleRoot); + for (const value of this.pendingUpdates!.modified_values) { + if (value.notify_user) { + // TODO notification pop up + } + if (!value.need_validation) { + continue; + } + if (value.proof) { + // It seems we already validated that, check the proof and if valid just notify user + continue; + } + const actualProposal: Record = JSON.parse(value.new_value); + const merkleRoot: string = value.new_state_merkle_root; + try { + await this.routingInstance.openPairingConfirmationModal(actualProposal, this.currentProcess!, merkleRoot); + } catch (e) { + throw new Error(`${e}`); } - } catch (e) { - throw new Error(`${e}`); } } @@ -488,6 +523,22 @@ export default class Services { } + public async restoreSecrets() { + const db = await Database.getInstance(); + try { + const sharedSecrets: Record = await db.dumpStore('shared_secrets'); + const unconfirmedSecrets = await db.dumpStore('unconfirmed_secrets'); + const secretsStore = { + 'shared_secrets': sharedSecrets, + 'unconfirmed_secrets': Object.values(unconfirmedSecrets), + }; + this.sdkClient.set_shared_secrets(JSON.stringify(secretsStore)); + } catch (e) { + throw e; + } + + } + getNotifications(): INotification[] { return [ { diff --git a/src/utils/sp-address.utils.ts b/src/utils/sp-address.utils.ts index 1c8b535..3f14b15 100755 --- a/src/utils/sp-address.utils.ts +++ b/src/utils/sp-address.utils.ts @@ -159,20 +159,16 @@ async function onOkButtonClick() { await service.handleApiReturn(connectMemberResult); } // Create the process - const relayAddress = await service.getRelayAddresses(); // Get one (or more?) relay addresses - const createPairingProcessReturn = await service.createPairingProcess([addressInput], relayAddress[0], 1); - await service.handleApiReturn(createPairingProcessReturn); - - if (!createPairingProcessReturn.updated_process) { - throw new Error('createPairingProcess returned an empty new process'); // This should never happen - } + setTimeout(async () => { + const relayAddress = await service.getRelayAddresses(); // Get one (or more?) relay addresses + const createPairingProcessReturn = await service.createPairingProcess([addressInput], relayAddress[0], 1); - const commitmentOutpoint = createPairingProcessReturn.updated_process.commitment_tx; + if (!createPairingProcessReturn.updated_process) { + throw new Error('createPairingProcess returned an empty new process'); // This should never happen + } - // We set the service to the process - service.getUpdateProposals(commitmentOutpoint); - - await service.evaluatePendingUpdates(); + await service.handleApiReturn(createPairingProcessReturn); + }, 1000); } catch (e) { console.error(`onOkButtonClick error: ${e}`); }