Merge branch 'ihm_unify_clean_base' of https://git.4nkweb.com/4nk/ihm_client into ihm_unify_clean_base

This commit is contained in:
AnisHADJARAB 2024-12-02 10:57:19 +00:00
commit d61fe9fa47
4 changed files with 98 additions and 58 deletions

View File

@ -104,6 +104,7 @@ async function init(): Promise<void> {
await services.restoreDevice(device); await services.restoreDevice(device);
} }
await services.restoreProcesses(); await services.restoreProcesses();
await services.restoreSecrets();
if (services.isPaired()) { if (services.isPaired()) {
await navigate('process'); await navigate('process');

View File

@ -53,23 +53,11 @@ export default class ModalService {
} }
// this is kind of too specific for pairing though // this is kind of too specific for pairing though
public async openConfirmationModal(pcd: any, commitmentTx: string, merkleRoot: string) { public async openPairingConfirmationModal(roleDefinition: Record<string, RoleDefinition>, commitmentTx: string, merkleRoot: string) {
let map: Record<string, RoleDefinition>;
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');
}
// pairing specifics // pairing specifics
let members; let members;
if (map['owner']) { if (roleDefinition['owner']) {
const owner = map['owner']; const owner = roleDefinition['owner'];
members = owner.members; members = owner.members;
} else { } else {
throw new Error('No \"owner\" role'); throw new Error('No \"owner\" role');
@ -83,7 +71,6 @@ export default class ModalService {
// We take all the addresses except our own // We take all the addresses except our own
const service = await Services.getInstance(); const service = await Services.getInstance();
const localAddress = await service.getDeviceAddress(); const localAddress = await service.getDeviceAddress();
console.log('🚀 ~ Routing ~ openConfirmationModal ~ pcd:', pcd);
for (const member of members) { for (const member of members) {
for (const address of member['sp_addresses']) { for (const address of member['sp_addresses']) {
if (address !== localAddress) { if (address !== localAddress) {
@ -127,7 +114,7 @@ export default class ModalService {
// We send the prd update // We send the prd update
if (this.currentPcdCommitment) { if (this.currentPcdCommitment) {
try { try {
const createPrdUpdateReturn = await service.createPrdUpdate(this.currentPcdCommitment); const createPrdUpdateReturn = service.createPrdUpdate(this.currentPcdCommitment);
await service.handleApiReturn(createPrdUpdateReturn); await service.handleApiReturn(createPrdUpdateReturn);
} catch (e) { } catch (e) {
throw e throw e
@ -138,13 +125,18 @@ export default class ModalService {
// We send confirmation that we validate the change // We send confirmation that we validate the change
try { try {
const approveChangeReturn = await service.approveChange(this.currentPcdCommitment!); const approveChangeReturn = service.approveChange(this.currentPcdCommitment!);
await service.handleApiReturn(approveChangeReturn); await service.handleApiReturn(approveChangeReturn);
} catch (e) { } catch (e) {
throw e throw e
} }
service.pairDevice(this.paired_addresses); try {
service.pairDevice(this.paired_addresses);
} catch (e) {
throw e;
}
this.paired_addresses = []; this.paired_addresses = [];
this.currentOutpoint = null; this.currentOutpoint = null;
this.currentPcdCommitment = null; this.currentPcdCommitment = null;

View File

@ -3,7 +3,7 @@ import { INotification } from '~/models/notification.model';
import { IProcess } from '~/models/process.model'; import { IProcess } from '~/models/process.model';
// import Database from './database'; // import Database from './database';
import { initWebsocket, sendMessage } from '../websockets'; 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 ModalService from './modal.service';
import { navigate } from '../router'; import { navigate } from '../router';
import Database from './database.service'; import Database from './database.service';
@ -16,7 +16,7 @@ export default class Services {
private static initializing: Promise<Services> | null = null; private static initializing: Promise<Services> | null = null;
private static instance: Services; private static instance: Services;
private currentProcess: string | null = null; private currentProcess: string | null = null;
private pendingUpdates: Record<string, any> = {}; private pendingUpdates: PcdUpdates | null = null;
private currentUpdateMerkleRoot: string | null = null; private currentUpdateMerkleRoot: string | null = null;
private localAddress: string | null = null; private localAddress: string | null = null;
private pairedAddresses: string[] = []; private pairedAddresses: string[] = [];
@ -69,7 +69,7 @@ export default class Services {
public isPaired(): boolean { public isPaired(): boolean {
try { try {
return this.sdkClient.is_linking(); return this.sdkClient.is_paired();
} catch (e) { } catch (e) {
throw new Error(`isPaired ~ Error: ${e}`); throw new Error(`isPaired ~ Error: ${e}`);
} }
@ -215,17 +215,17 @@ export default class Services {
} }
async sendNewTxMessage(message: string) { async sendNewTxMessage(message: string) {
await sendMessage('NewTx', message); sendMessage('NewTx', message);
} }
async sendCommitMessage(message: string) { async sendCommitMessage(message: string) {
await sendMessage('Commit', message); sendMessage('Commit', message);
} }
async sendCipherMessages(ciphers: string[]) { async sendCipherMessages(ciphers: string[]) {
for (let i = 0; i < ciphers.length; i++) { for (let i = 0; i < ciphers.length; i++) {
const cipher = ciphers[i]; const cipher = ciphers[i];
await sendMessage('Cipher', cipher); sendMessage('Cipher', cipher);
} }
} }
@ -235,8 +235,8 @@ export default class Services {
async parseCipher(message: string) { async parseCipher(message: string) {
try { try {
console.log('parsing new cipher'); // console.log('parsing new cipher');
const apiReturn = await this.sdkClient.parse_cipher(message); const apiReturn = this.sdkClient.parse_cipher(message);
console.log('🚀 ~ Services ~ parseCipher ~ apiReturn:', apiReturn); console.log('🚀 ~ Services ~ parseCipher ~ apiReturn:', apiReturn);
await this.handleApiReturn(apiReturn); await this.handleApiReturn(apiReturn);
} catch (e) { } catch (e) {
@ -247,12 +247,11 @@ export default class Services {
async parseNewTx(tx: string) { async parseNewTx(tx: string) {
try { try {
const parsedTx = await this.sdkClient.parse_new_tx(tx, 0); const parsedTx = this.sdkClient.parse_new_tx(tx, 0);
if (parsedTx) { if (parsedTx) {
console.log('🚀 ~ Services ~ parseNewTx ~ parsedTx:', parsedTx);
try { try {
await this.handleApiReturn(parsedTx); await this.handleApiReturn(parsedTx);
const newDevice = await this.dumpDevice(); const newDevice = this.dumpDevice();
await this.saveDevice(newDevice); await this.saveDevice(newDevice);
} catch (e) { } catch (e) {
console.error('Failed to update device with new tx'); console.error('Failed to update device with new tx');
@ -265,10 +264,10 @@ export default class Services {
public getUpdateProposals(commitmentOutpoint: string) { public getUpdateProposals(commitmentOutpoint: string) {
try { 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) { if (proposals.decrypted_pcds && proposals.decrypted_pcds.length != 0) {
this.currentProcess = commitmentOutpoint; this.currentProcess = commitmentOutpoint;
this.pendingUpdates = proposals.decrypted_pcds; this.pendingUpdates = proposals;
} else { } else {
throw new Error('No pending proposals'); throw new Error('No pending proposals');
} }
@ -296,11 +295,18 @@ export default class Services {
} }
const entries = Object.entries(confirmedSecrets).map(([key, value]) => ({ key, value })); const entries = Object.entries(confirmedSecrets).map(([key, value]) => ({ key, value }));
for (const entry of entries) { for (const entry of entries) {
db.addObject({ try {
storeName: 'shared_secrets', db.addObject({
object: entry.value, storeName: 'shared_secrets',
key: entry.key, 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; throw e;
} }
// do we need to act? if (updatedProcess.new_state) {
updatedProcess.user_validation_required 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) { if (apiReturn.commit_to_send) {
@ -343,16 +366,28 @@ export default class Services {
} }
private async openConfirmationModal() { private async openConfirmationModal() {
if (this.pendingUpdates.length === 0) { if (!this.pendingUpdates || this.pendingUpdates.modified_values.length === 0) {
console.log('No pending updates'); console.log('No pending updates to validate');
} }
try { for (const value of this.pendingUpdates!.modified_values) {
for (const [merkleRoot, actual_proposal] of Object.entries(this.pendingUpdates)) { if (value.notify_user) {
await this.routingInstance.openConfirmationModal(actual_proposal, this.currentProcess!, merkleRoot); // 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<string, RoleDefinition> = 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<string, string> = 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[] { getNotifications(): INotification[] {
return [ return [
{ {

View File

@ -159,20 +159,16 @@ async function onOkButtonClick() {
await service.handleApiReturn(connectMemberResult); await service.handleApiReturn(connectMemberResult);
} }
// Create the process // Create the process
const relayAddress = await service.getRelayAddresses(); // Get one (or more?) relay addresses setTimeout(async () => {
const createPairingProcessReturn = await service.createPairingProcess([addressInput], relayAddress[0], 1); const relayAddress = await service.getRelayAddresses(); // Get one (or more?) relay addresses
await service.handleApiReturn(createPairingProcessReturn); const createPairingProcessReturn = await service.createPairingProcess([addressInput], relayAddress[0], 1);
if (!createPairingProcessReturn.updated_process) {
throw new Error('createPairingProcess returned an empty new process'); // This should never happen
}
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 await service.handleApiReturn(createPairingProcessReturn);
service.getUpdateProposals(commitmentOutpoint); }, 1000);
await service.evaluatePendingUpdates();
} catch (e) { } catch (e) {
console.error(`onOkButtonClick error: ${e}`); console.error(`onOkButtonClick error: ${e}`);
} }