From 033b92eed8c0ddaa4e35556b8434f32f4eee6555 Mon Sep 17 00:00:00 2001 From: AnisHADJARAB Date: Tue, 3 Sep 2024 13:39:07 +0000 Subject: [PATCH] poc pairing with device1 side missing popup --- src/html/home.html | 2 +- src/html/home.js | 4 +- src/html/login-modal.js | 1 - src/index.ts | 26 ++-- src/services/database.ts | 7 +- src/services/routing.service.ts | 10 +- src/services/service.ts | 229 +++++++++++++++++++++++++++++--- src/websockets.ts | 38 +++--- 8 files changed, 257 insertions(+), 60 deletions(-) diff --git a/src/html/home.html b/src/html/home.html index 3cc3c57..86ef726 100644 --- a/src/html/home.html +++ b/src/html/home.html @@ -21,7 +21,7 @@ diff --git a/src/html/home.js b/src/html/home.js index caf702d..85464cf 100644 --- a/src/html/home.js +++ b/src/html/home.js @@ -25,9 +25,9 @@ document.querySelectorAll('.tab').forEach(tab => { //// Modal - export async function openModal() { + export async function openModal(prd) { const router = await Routing.getInstance(); - router.openLoginModal() + router.openLoginModal(prd) } diff --git a/src/html/login-modal.js b/src/html/login-modal.js index f5fe78a..c47c7c2 100644 --- a/src/html/login-modal.js +++ b/src/html/login-modal.js @@ -9,6 +9,5 @@ export async function closeLoginModal() { router.closeLoginModal() } - window.confirmLogin = confirmLogin; window.closeLoginModal = closeLoginModal; \ No newline at end of file diff --git a/src/index.ts b/src/index.ts index 5db8ed8..f140d45 100644 --- a/src/index.ts +++ b/src/index.ts @@ -7,22 +7,20 @@ document.addEventListener('DOMContentLoaded', async () => { const services = await Services.getInstance(); let user = await services.getWallet() - console.log("🚀 ~ document.addEventListener ~ user:", user); - const device = await services.dumpDevice() - console.log("🚀 ~ Services ~ sendPairingTx ~ device:", device) - const wallet = await services.dumpWallet() - console.log("🚀 ~ Services ~ sendPairingTx ~ wallet:", wallet) - const amount = await services.getAmount() - console.log("🚀 ~ Services ~ sendPairingTx ~ amount:", amount) - // services.sendPairingTx('sprt1qqfgf9xm5cxsyj49h3d9kqd0f0f0q0zj6pu5we9k4g7l7axkwsqavqqjsj2dhfsdqf92t0z6tvq67j7j7q7995regajtd23ala6dvaqp6cqravfjh') - if(!user) { - const sp_adress = await services.createNewDevice(); - user = await services.getWallet() - console.log("🚀 ~ document.addEventListener ~ sp_adress:", sp_adress) - } - await services.getAdresses() + + setTimeout(async () => { + if(!user) { + const sp_adress = await services.createNewDevice(); + user = await services.getWallet() + + } else { + const address = await services.getAdresses() + const device = await services.getDevice() + if(device) await services.restoreDevice(device) + } await services.addWebsocketConnection(wsurl); await services.recoverInjectHtml() + }) } catch (error) { console.error(error); } diff --git a/src/services/database.ts b/src/services/database.ts index f14ba88..b3042aa 100644 --- a/src/services/database.ts +++ b/src/services/database.ts @@ -14,6 +14,11 @@ class Database { options: {'keyPath': 'sp_address'}, indices: [] }, + AnkCipherMessages: { + name: "ciphers", + options: {}, + indices: [ {'keyPath': 'id'}] + }, AnkSession: { name: "session", options: {}, @@ -32,7 +37,7 @@ class Database { }, AnkMessages: { name: "messages", - options: {'keyPath': 'id'}, + options: {'keyPath': 'transaction'}, indices: [] } } diff --git a/src/services/routing.service.ts b/src/services/routing.service.ts index 32b4763..cc0386b 100644 --- a/src/services/routing.service.ts +++ b/src/services/routing.service.ts @@ -1,12 +1,14 @@ import Database from './database'; import modalHtml from '../html/login-modal.html?raw'; import modalScript from '../html/login-modal.js?raw'; +import Services from './service'; export default class Routing { private static instance: Routing; private database: any; private sdkClient: any; + private prd: any; private constructor() {} // Method to access the singleton instance of Services @@ -23,7 +25,7 @@ export default class Routing { this.database = Database.getInstance() } - public openLoginModal() { + public openLoginModal(prd?: any) { const container = document.querySelector('.page-container'); if (container) container.innerHTML += modalHtml; const modal = document.getElementById('modal') @@ -36,7 +38,7 @@ export default class Routing { window.onclick = (event) => { const modal = document.getElementById('modal'); if (event.target === modal) { - this.closeLoginModal(); + this.closeLoginModal(prd); } } } @@ -46,8 +48,10 @@ export default class Routing { console.log("🚀 ~ Routing ~ confirmLogin ~ loginTx:", loginTx) this.sdkClient.login('LOGIN', loginTx) } - closeLoginModal() { + async closeLoginModal(prd?: any) { + const service = await Services.getInstance() const modal = document.getElementById('modal') if (modal) modal.style.display = 'none'; + if(prd) service.pairDevice(prd) } } \ No newline at end of file diff --git a/src/services/service.ts b/src/services/service.ts index d6549d2..7b107c0 100644 --- a/src/services/service.ts +++ b/src/services/service.ts @@ -8,6 +8,9 @@ import { IProcess } from '~/models/process.model'; import Database from './database'; import { WebSocketClient } from '../websockets'; import QRCode from 'qrcode' +import { servicesVersion } from 'typescript'; +import { CachedMessage } from '../../dist/pkg/sdk_client'; +import Routing from './routing.service'; export default class Services { private static instance: Services; @@ -25,6 +28,7 @@ export default class Services { // Method to access the singleton instance of Services public static async getInstance(): Promise { if (!Services.instance) { + console.log("🚀 ~ Services ~ getInstance ~ Services.instance:", Services.instance) Services.instance = new Services(); await Services.instance.init(); } @@ -80,43 +84,213 @@ export default class Services { } } + async prepareProcessTx(myAddress: string, recipientAddress: string) { + + const txid = '0'.repeat(64) + var vout = Number.MAX_SAFE_INTEGER; + const paringTemplate = { + "uuid": "", + "html": "", + "script": "", + "style": "", + "init_state": { + "roles": { + "owner": { + "members": [{sp_addresses: [myAddress]}, {sp_addresses:[recipientAddress]}], + "validation_rules": + [ + { + "quorum": 0.0, + "fields": [ + "roles", + "pairing_tx" + ], + "min_sig_member": 0.0 + } + ] + } + }, + "pairing_tx": "", + }, + "commited_in": `${txid}:4294967295` + } + + const service = await Services.getInstance(); + const process = await service.sdkClient.create_process_from_template(JSON.stringify(paringTemplate)) + console.log("🚀 ~ Services ~ prepareProcessTx ~ process:", process) + return process + } + async sendPairingTx(sp_address: string): Promise { const services = await Services.getInstance(); - const faucetMessage = await services.createFaucetMessage() - console.log("🚀 ~ WebSocketClient ~ this.ws.onopen= ~ faucetMessage:", faucetMessage, services.websocketConnection) - services.websocketConnection?.sendNormalMessage(faucetMessage) - const amount = await services.sdkClient.get_available_amount() + const amount = await this.getAmount() as any + console.log("🚀 ~ Services ~ sendPairingTx ~ amount:", typeof amount) console.log("🚀 ~ Services ~ sendPairingTx ~ amount:", amount) - // setTimeout(() => services.sdkClient.create_pairing_transaction('sprt1qqfgf9xm5cxsyj49h3d9kqd0f0f0q0zj6pu5we9k4g7l7axkwsqavqqjsj2dhfsdqf92t0z6tvq67j7j7q7995regajtd23ala6dvaqp6cqravfjh', 0.00000001), 5000) - setTimeout(() => services.sdkClient.create_pairing_transaction('sprt1qqv35lxum62lpm4zmfekjqsskx62clzx5qgsfyrgdu78vj52fync52q7fp2h6lugyfnuk8z32lycandds97nc74sz7nc7e90f9tl2dtzpeshg8nss', 0.00001), 5000) + if(amount === 0n) { + const faucetMessage = await services.createFaucetMessage() + console.log("🚀 ~ WebSocketClient ~ this.ws.onopen= ~ faucetMessage:", faucetMessage) + services.websocketConnection?.sendNormalMessage(faucetMessage) + } + + const spAddress = await this.getDeviceAddress() as any + const process = await this.prepareProcessTx(spAddress, 'sprt1qqdxya9n4pzc9vetzug7fch2xag4x5vxxrjc6rnh2rh3xhlvalmlrsqmy5t6vfa0nuf92dudf9uvaye3afw6uu86kw34q2x3k9qmmf8qp0vtfm9xa') + if(process) await services.sdkClient.pair_device(process.uuid, ['sprt1qqdxya9n4pzc9vetzug7fch2xag4x5vxxrjc6rnh2rh3xhlvalmlrsqmy5t6vfa0nuf92dudf9uvaye3afw6uu86kw34q2x3k9qmmf8qp0vtfm9xa']) + setTimeout(async () => { + const tx = await services.sdkClient.create_process_init_transaction(process, 1) + console.log("🚀 ~ Services ~ sendPairingTx ~ tx:", tx) + services.websocketConnection?.sendMessage('NewTx', JSON.stringify(tx)) + if(tx?.new_messages && tx.new_messages.length) { + await this.sendCipherMessages(tx.new_messages) + } + },2000) + // setTimeout(() => { + // const paringin = services.sdkClient.create_pairing_transaction('sprt1qqf7jes989hkmfh0w9526pqy0rd5hlflclzez5dzateeza7hhl0vqzqhnmhe0kkez9m5vx2rastph5patqr5h3tr9pcsukzea0lz0dp6tcqaz2u8j', 1) + // console.log("🚀 ~ Services ~ setTimeout ~ paringin:", paringin) + // services.websocketConnection?.sendMessage('NewTx', JSON.stringify(paringin)) + // if(paringin?.new_network_msg?.ciphertext) { + // services.websocketConnection?.sendMessage('Cipher', paringin?.new_network_msg?.ciphertext) + // let get_outputs_result = services.sdkClient.get_outputs() + // console.log("🚀 ~ Services ~ setTimeout ~ get_outputs_result:", get_outputs_result) + // } + // }, 5000) + } + + async sendCipherMessages(messages: CachedMessage[]) { + const service = await Services.getInstance(); + messages.forEach((message) => { + message.cipher?.forEach((cipher => { + service.websocketConnection?.sendMessage('Cipher', cipher) + })) + }) + } + + async sendFaucetMessage(): Promise { + const services = await Services.getInstance(); + const faucetMessage = await services.createFaucetMessage() + console.log("🚀 ~ WebSocketClient ~ this.ws.onopen= ~ faucetMessage:", faucetMessage) + services.websocketConnection?.sendNormalMessage(faucetMessage) + } + + async parseCipher(message: string) { + try { + const services = await Services.getInstance(); + const parsedTx = await services.sdkClient.parse_cipher(message, 0.00001) + console.log("🚀 ~ Services ~ parseCipher ~ parsedTx:", parsedTx) + await this.processTx(parsedTx) + await this.saveCipherTxToDb(parsedTx) + } catch(e) { + console.log(e) + } } async parseNewTx(tx: string) { try { - console.log('==============> sendind txxxxxxx parser', tx) + console.log('==============> sending txxxxxxx parser', tx) const services = await Services.getInstance(); - const parsedTx = await services.sdkClient.parse_new_tx(tx, 0, 0.00001) + const parsedTx = await services.sdkClient.parse_new_tx(tx, 0, 0.01) console.log("🚀 ~ Services ~ parseNewTx ~ parsedTx:", parsedTx) + if(parsedTx) { + await this.processTx(parsedTx) + await this.saveTxToDb(parsedTx) + } } catch(e) { console.log(e) } } + async processTx(tx: CachedMessage) { + if(tx.status) { + switch(tx.status) { + case 'Opened': + if(tx.prd) { + const parsedPrd = JSON.parse(tx.prd) + console.log("🚀 ~ Services ~ processTx ~ Opened:", parsedPrd) + const router = await Routing.getInstance(); + + // Mocker le fait que c'est une transaction de connection + if(parsedPrd && parsedPrd.prd_type === 'Init') { + router.openLoginModal(parsedPrd) + } else if(parsedPrd && parsedPrd.prd_type === 'Signed') { + router.closeLoginModal() + } + } + break; + case 'TxWaitingPrd': + console.log("🚀 ~ Services ~ processTx ~ TxWaitingPrd:", tx) + break; + case 'CipherWaitingTx': + console.log("🚀 ~ Services ~ processTx ~ CipherWaitingTx:", tx) + break; + } + } + } + + async pairDevice(prd: any) { + const service = await Services.getInstance(); + await service.sdkClient.pair_device(prd.process_uuid, ['sprt1qqwp87lrahm2ye9kje45dqgsncvkg94fr7amrnaaflxkx6kn62za7uq4kpegfp3ks475e9jp7y0h0xzsqydkf35lg7g0kukr6zkynde552gk6z92n']) + const spAddress = await this.getDeviceAddress() as any + const process = await this.prepareProcessTx(spAddress, 'sprt1qqwp87lrahm2ye9kje45dqgsncvkg94fr7amrnaaflxkx6kn62za7uq4kpegfp3ks475e9jp7y0h0xzsqydkf35lg7g0kukr6zkynde552gk6z92n') + const tx = await service.sdkClient.create_process_init_transaction(process, 1) + for(const msg of tx.new_messages) { + msg.prd?.replace('Init', 'Signed') + } + console.log("🚀 ~ Services ~ pairDevice ~ tx:", tx) + service.websocketConnection?.sendMessage('NewTx', JSON.stringify(tx)) + } + + async saveTxToDb(tx: string) { + const database = await Database.getInstance(); + const indexedDb = await database.getDb(); + + if(tx) { + await database.writeObject(indexedDb, database.getStoreList().AnkMessages, tx, null); + } + } + + async saveCipherTxToDb(tx: string) { + const database = await Database.getInstance(); + const indexedDb = await database.getDb(); + + if(tx) { + await database.writeObject(indexedDb, database.getStoreList().AnkCipherMessages, tx, null); + } + } + async getAmount() { const services = await Services.getInstance(); const amount = await services.sdkClient.get_available_amount() console.log("🚀 ~ Services ~ sendPairingTx ~ amount:", amount) + return amount + } + + async getDeviceAddress() { + const services = await Services.getInstance(); + const address = await services.sdkClient.get_address() + console.log("🚀 ~ Services ~ sendPairingTx ~ address:", address) + return address } async dumpDevice() { const services = await Services.getInstance(); const device = await services.sdkClient.dump_device() console.log("🚀 ~ Services ~ sendPairingTx ~ device:", device) + return device } + + async saveDevice(device: any): Promise { + console.log("🚀 ~ Services ~ saveDevice ~ device:", device) + localStorage.setItem('wallet', device); + } + + async getDevice(): Promise { + return localStorage.getItem('wallet') + } + async dumpWallet() { const services = await Services.getInstance(); const wallet = await services.sdkClient.dump_wallet() console.log("🚀 ~ Services ~ sendPairingTx ~ wallet:", wallet) + return wallet } async createFaucetMessage() { @@ -141,25 +315,38 @@ export default class Services { async createNewDevice() { const service = await Services.getInstance(); - const device = await service.sdkClient.create_new_device(1994, 'regtest') - const adresses = await service.sdkClient.get_address() - console.log("🚀 ~ Services ~ createNewDevice ~ adresses:", adresses) - if(device) { - console.log("🚀 ~ Services ~ createNewDevice ~ device:", {sp_adress: device}) + const sp_address = await service.sdkClient.create_new_device(1994, 'regtest') + if(sp_address) { + console.log("🚀 ~ Services ~ createNewDevice ~ device:", {sp_adress: sp_address}) const database = await Database.getInstance(); const indexedDb = await database.getDb(); - await database.writeObject(indexedDb, database.getStoreList().AnkSpAddress, {sp_address: device}, null); + await database.writeObject(indexedDb, database.getStoreList().AnkSpAddress, {sp_address: sp_address}, null); + const device = await service.dumpDevice() + console.log("🚀 ~ WebSocketClient ~ device:", device) + await service.saveDevice(device) } - this.sp_address = device; - console.log("🚀 ~ Services ~ createNewDevice ~ device:", device) - return device; + this.sp_address = sp_address; + console.log("🚀 ~ Services ~ createNewDevice ~ device:", sp_address) + return sp_address; } async getAdresses() { - const service = await Services.getInstance(); - const adresses:string = await service.sdkClient.get_address() - console.log("🚀 ~ Services ~ createNewDevice ~ adresses:", adresses) - this.sp_address = adresses + const database = await Database.getInstance(); + const indexedDb = await database.getDb(); + const wallet = await database.getAll(indexedDb, database.getStoreList().AnkSpAddress) as {sp_address: string}[] + console.log("🚀 ~ Services ~ getWallet ~ wallet:", wallet) + if(wallet.length) { + this.sp_address = wallet[0].sp_address + } + return this.sp_address + } + + async restoreDevice(address: string) { + const services = await Services.getInstance(); + // const sp_wallet = JSON.parse(address)?.sp_wallet + console.log("🚀 ~ Services ~ restoreDevice ~ services?.sdkClient:", address) + const res = await services?.sdkClient?.restore_device(address) + console.log("🚀 ~ Services ~ restoreDevice ~ res:", res) } private cleanSubsciptions(): void { diff --git a/src/websockets.ts b/src/websockets.ts index 12b2099..a839ec9 100644 --- a/src/websockets.ts +++ b/src/websockets.ts @@ -1,5 +1,6 @@ -import { AnkFlag, AnkNetworkMsg, CachedMessage } from "dist/pkg/sdk_client"; +import { AnkFlag, CachedMessage } from "dist/pkg/sdk_client"; import Services from "./services/service"; +import Database from "./services/database"; // import { AnkFlag, AnkNetworkMsg, CachedMessage } from "../dist/pkg/sdk_client"; class WebSocketClient { @@ -13,9 +14,6 @@ class WebSocketClient { this.ws.onopen = async (event) => { console.log('WebSocket connection established'); // Once the connection is open, send all messages in the queue - const services = await Services.getInstance() - // const faucetMessage = await services.createFaucetMessage() - // console.log("🚀 ~ WebSocketClient ~ this.ws.onopen= ~ faucetMessage:", faucetMessage) // this.sendNormalMessage(faucetMessage) while (this.messageQueue.length > 0) { @@ -39,17 +37,19 @@ class WebSocketClient { const feeRate = 0.0001; const parsedMessage = JSON.parse(msgData) console.log("🚀 ~ WebSocketClient ~ parsedMessage:", parsedMessage) - if(parsedMessage?.flag === 'NewTx') { - // const content = parsedMessage?.content; - // if(content) { - // const parsedContent = JSON.parse(content) - // if(parsedContent?.transaction) - console.log("🚀 ~ WebSocketClient ~ msgData:", msgData) - const services = await Services.getInstance() - - await services.parseNewTx(parsedMessage.content) - // } - + const services = await Services.getInstance() + switch(parsedMessage.flag) { + case 'NewTx': + await services.parseNewTx(parsedMessage.content) + let device = await services.dumpDevice() + await services.saveDevice(device) + break; + case 'Cipher': + await services.parseCipher(parsedMessage.content) + // device = await services.dumpWallet() + // console.log("🚀 ~ WebSocketClient ~ device:", device) + // await services.saveDevice(device) + break; } // By parsing the message, we can link it with existing cached message and return the updated version of the message // if (res.status === 'FaucetComplete') { @@ -100,12 +100,16 @@ class WebSocketClient { } // Method to send messages - public sendMessage(flag: AnkFlag, message: string): void { + public async sendMessage(flag: AnkFlag, message: string): Promise { if (this.ws.readyState === WebSocket.OPEN) { - const networkMessage: AnkNetworkMsg = { + const networkMessage = { 'flag': flag, 'content': message } + // if(flag === 'Cipher') { + // const services = await Services.getInstance(); + // services.parseCipher(JSON.stringify(networkMessage)) + // } console.log("Sending message:", JSON.stringify(networkMessage)); this.ws.send(JSON.stringify(networkMessage)); } else {