This commit is contained in:
NicolasCantu 2024-10-17 10:56:22 +02:00
parent 76affefad9
commit cfed50a226
8 changed files with 104 additions and 276 deletions

View File

@ -2,7 +2,7 @@ import Routing from "/src/services/routing.service.ts";
const router = await Routing.getInstance();
export async function confirm() {
router.confirm()
router.confirmPairing()
}
export async function closeConfirmationModal() {

View File

@ -58,30 +58,32 @@ docReady(function () {
scanDevice();
var resultContainer = document.getElementById('qr-reader-results');
var lastResult, countResults = 0;
function onScanSuccess(decodedText, decodedResult) {
++countResults;
lastResult = decodedText;
// Handle on success condition with the decoded message.
console.log(`Scan result ${decodedText}`, decodedResult);
try {
// Attempt to parse the decoded text as a URL
const scannedUrl = new URL(decodedText);
async function onScanSuccess(decodedText, decodedResult) {
if (lastResult === decodedText) { return; }
lastResult = decodedText;
++countResults;
// Handle on success condition with the decoded message.
console.log(`Scan result ${decodedText}`, decodedResult);
try {
// Attempt to parse the decoded text as a URL
const scannedUrl = new URL(decodedText);
// Extract the 'sp_address' parameter
const spAddress = scannedUrl.searchParams.get('sp_address');
// Extract the 'sp_address' parameter
const spAddress = scannedUrl.searchParams.get('sp_address');
if (spAddress) {
// Call the sendPairingTx function with the extracted sp_address
service.sendPairingTx(spAddress);
} else {
console.error('The scanned URL does not contain the sp_address parameter.');
alert('Invalid QR code: sp_address parameter missing.');
}
} catch (error) {
// Handle cases where decodedText is not a valid URL
console.error('Scanned text is not a valid URL:', error);
alert('Invalid QR code: Unable to parse URL.');
}
if (spAddress) {
html5QrcodeScanner.clear();
// Call the sendPairingTx function with the extracted sp_address
await service.sendPairingTx(spAddress);
} else {
console.error('The scanned URL does not contain the sp_address parameter.');
alert('Invalid QR code: sp_address parameter missing.');
}
} catch (error) {
// Handle cases where decodedText is not a valid URL
console.error('Scanned text is not a valid URL:', error);
alert('Invalid QR code: Unable to parse URL.');
}
}
var html5QrcodeScanner = new Html5QrcodeScanner(

View File

@ -15,14 +15,16 @@ document.addEventListener('DOMContentLoaded', async () => {
await services.restoreProcesses();
await services.restoreMessages();
const queryString = window.location.search;
const urlParams = new URLSearchParams(queryString)
const pairingAddress = urlParams.get('sp_address')
if (services.isPaired()) { await services.injectProcessListPage() }
else {
const queryString = window.location.search;
const urlParams = new URLSearchParams(queryString)
const pairingAddress = urlParams.get('sp_address')
if(pairingAddress) {
await services.sendPairingTx(pairingAddress)
if(pairingAddress) {
await services.sendPairingTx(pairingAddress)
}
}
}, 500);
} catch (error) {
console.error(error);

View File

@ -1,188 +0,0 @@
class Database {
private static instance: Database;
private db: IDBDatabase | null = null;
private dbName: string = '4nk';
private dbVersion: number = 1;
private storeDefinitions = {
AnkUser: {
name: "user",
options: {'keyPath': 'pre_id'},
indices: []
},
AnkSpAddress: {
name: "address",
options: {'keyPath': 'sp_address'},
indices: []
},
AnkCipherMessages: {
name: "ciphers",
options: {},
indices: [ {'keyPath': 'id'}]
},
AnkSession: {
name: "session",
options: {},
indices: []
},
AnkProcess: {
name: "process",
options: {'keyPath': 'id'},
indices: [{
name: 'by_name',
keyPath: 'name',
options: {
'unique': true
}
}]
},
AnkMessages: {
name: "messages",
options: {'keyPath': 'id'},
indices: []
}
}
// Private constructor to prevent direct instantiation from outside
private constructor() {}
// Method to access the singleton instance of Database
public static async getInstance(): Promise<Database> {
if (!Database.instance) {
Database.instance = new Database();
await Database.instance.init();
}
return Database.instance;
}
// Initialize the database
private async init(): Promise<void> {
return new Promise((resolve, reject) => {
const request = indexedDB.open(this.dbName, this.dbVersion);
request.onupgradeneeded = () => {
const db = request.result;
Object.values(this.storeDefinitions).forEach(({name, options, indices}) => {
if (!db.objectStoreNames.contains(name)) {
let store = db.createObjectStore(name, options);
indices.forEach(({name, keyPath, options}) => {
store.createIndex(name, keyPath, options);
})
}
});
};
request.onsuccess = () => {
this.db = request.result;
resolve();
};
request.onerror = () => {
console.error("Database error:", request.error);
reject(request.error);
};
});
}
public async getDb(): Promise<IDBDatabase> {
if (!this.db) {
await this.init();
}
return this.db!;
}
public getStoreList(): {[key: string]: string} {
const objectList: {[key: string]: string} = {};
Object.keys(this.storeDefinitions).forEach(key => {
objectList[key] = this.storeDefinitions[key as keyof typeof this.storeDefinitions].name;
});
return objectList;
}
public writeObject(db: IDBDatabase, storeName: string, obj: any, key: IDBValidKey | null): Promise<IDBRequest> {
return new Promise((resolve, reject) => {
const transaction = db.transaction(storeName, 'readwrite');
const store = transaction.objectStore(storeName);
let request: IDBRequest<any>;
if (key) {
request = store.add(obj, key);
} else {
request = store.add(obj);
}
request.onerror = () => reject(request.error);
request.onsuccess = () => resolve(request.result);
});
}
public getObject<T>(db: IDBDatabase, storeName: string, key: IDBValidKey): Promise<T> {
return new Promise((resolve, reject) => {
const transaction = db.transaction(storeName, 'readonly');
const store = transaction.objectStore(storeName);
const request = store.get(key);
request.onerror = () => reject(request.error);
request.onsuccess = () => resolve(request.result);
});
}
public rmObject(db: IDBDatabase, storeName: string, key: IDBValidKey): Promise<void> {
return new Promise((resolve, reject) => {
const transaction = db.transaction(storeName, 'readwrite');
const store = transaction.objectStore(storeName);
const request = store.delete(key);
request.onerror = () => reject(request.error);
request.onsuccess = () => resolve(request.result);
});
}
public getFirstMatchWithIndex<T>(db: IDBDatabase, storeName: string, indexName: string, lookup: string): Promise<T | null> {
return new Promise((resolve, reject) => {
const transaction = db.transaction(storeName, 'readonly');
const store = transaction.objectStore(storeName);
const index = store.index(indexName);
const request = index.openCursor(IDBKeyRange.only(lookup));
request.onerror = () => reject(request.error);
request.onsuccess = () => {
const cursor = request.result;
if (cursor) {
resolve(cursor.value);
} else {
resolve(null)
}
}
});
}
public setObject(db: IDBDatabase, storeName: string, obj: any, key: string | null): Promise<IDBRequest> {
return new Promise((resolve, reject) => {
const transaction = db.transaction(storeName, 'readwrite');
const store = transaction.objectStore(storeName);
let request: IDBRequest<any>;
if (key) {
request = store.put(obj, key);
} else {
request = store.put(obj);
}
request.onerror = () => reject(request.error);
request.onsuccess = () => resolve(request.result);
});
}
public getAll<T>(db: IDBDatabase, storeName: string): Promise<T[]> {
return new Promise((resolve, reject) => {
const transaction = db.transaction(storeName, 'readonly');
const store = transaction.objectStore(storeName);
const request = store.getAll();
request.onerror = () => reject(request.error);
request.onsuccess = () => resolve(request.result);
});
}
}
export default Database;

View File

@ -1,14 +1,13 @@
import Database from './database';
import modalHtml from '../html/login-modal.html?raw';
import confirmationModalHtml from '../html/confirmation-modal.html?raw';
import modalScript from '../html/login-modal.js?raw';
import confirmationModalScript from '../html/confirmation-modal.js?raw';
import Services from './service';
import { U32_MAX } from './service';
export default class Routing {
private static instance: Routing;
private database: any;
private sdkClient: any;
private currentPrd: any;
private currentOutpoint?: string;
@ -25,7 +24,6 @@ export default class Routing {
public async init(): Promise<void> {
this.sdkClient = await import("../../dist/pkg/sdk_client");
this.database = Database.getInstance()
}
public openLoginModal(myAddress: string, receiverAddress: string) {
@ -45,10 +43,18 @@ export default class Routing {
}
public openConfirmationModal(pcd: any, outpointCommitment: string) {
console.log("")
let roles = JSON.parse(pcd['roles']);// ['members'][0];
console.log(roles);
let members = roles['owner']['members'];
console.log(members);
// We take all the addresses except our own
const local_address = this.sdkClient.get_address();
console.log("🚀 ~ Routing ~ openConfirmationModal ~ pcd:", pcd)
let paired_addresses: string[] = [];
for (const address of members[0]['sp_addresses']) {
if (address !== local_address) { paired_addresses.push(address) }
}
let html = confirmationModalHtml;
// html = html.replace('{{device1}}', members[0]['sp_addresses'][0]);
// html = html.replace('{{device2}}', members[0]['sp_addresses'][1]);
@ -65,11 +71,11 @@ export default class Routing {
// Add correct text
// Close modal when clicking outside of it
// Close modal when clicking outside of it
window.onclick = (event) => {
const modal = document.getElementById('modal');
if (event.target === modal) {
this.confirm(pcd, outpointCommitment);
this.confirmPairing(paired_addresses);
}
}
}
@ -84,13 +90,21 @@ export default class Routing {
if (modal) modal.style.display = 'none';
}
async confirm(prd: any, outpointCommitment: string) {
async confirmPairing(paired_addresses: string[]) {
const service = await Services.getInstance()
const modal = document.getElementById('modal')
console.log("🚀 ~ Routing ~ confirm ~ prd:", prd, outpointCommitment)
// console.log("🚀 ~ Routing ~ confirm ~ prd:", prd)
if (modal) modal.style.display = 'none';
await service.pairDevice(prd, outpointCommitment);
}
// Just make an empty commitment for now
const emptyTxid = '0'.repeat(64)
const commitmentOutpoint = `${emptyTxid}:${U32_MAX}`;
// We take the paired device(s) from the contract
this.sdkClient.pair_device(commitmentOutpoint, paired_addresses)
service.injectProcessListPage();
}
async closeConfirmationModal() {
const modal = document.getElementById('modal')
if (modal) modal.style.display = 'none';

View File

@ -16,7 +16,7 @@ type ProcessesCache = {
[key: string]: any;
};
const U32_MAX = 4294967295;
export const U32_MAX = 4294967295;
const wsurl = `https://demo.4nkweb.com/ws/`;
export default class Services {
@ -83,11 +83,6 @@ export default class Services {
newScript.setAttribute('type', 'module')
newScript.textContent = homeScript;
document.head.appendChild(newScript).parentNode?.removeChild(newScript);
const btn = container.querySelector('#scan-this-device')
if(btn) {
this.addSubscription(btn, 'click', 'injectProcessListPage')
}
}
private generateQRCode = async (text: string) => {
@ -103,6 +98,14 @@ export default class Services {
}
}
public isPaired(): boolean | undefined {
try {
return this.sdkClient.is_linking();
} catch (e) {
console.error("isPaired ~ Error:", e);
}
}
private prepareProcessTx(myAddress: string, recipientAddress: string) {
const initial_session_privkey = new Uint8Array(32);
const initial_session_pubkey = new Uint8Array(32);
@ -281,48 +284,48 @@ export default class Services {
async pairDevice(prd: any, outpointCommitment: string) {
console.log("🚀 ~ Services ~ pairDevice ~ prd:", prd)
const service = await Services.getInstance();
const spAddress = await this.getDeviceAddress() as any;
const sender = JSON.parse(prd?.sender)
const senderAddress = sender?.sp_addresses?.find((address: string) => address !== spAddress)
console.log("🚀 ~ Services ~ pairDevice ~ senderAddress:", senderAddress)
if(senderAddress) {
const proposal = service.sdkClient.get_update_proposals(outpointCommitment);
console.log("🚀 ~ Services ~ pairDevice ~ proposal:", proposal)
// const pairingTx = proposal.pairing_tx.replace(/^\"+|\"+$/g, '')
const parsedProposal = JSON.parse(proposal[0])
// const service = await Services.getInstance();
// const spAddress = await this.getDeviceAddress() as any;
// const sender = JSON.parse(prd?.sender)
// const senderAddress = sender?.sp_addresses?.find((address: string) => address !== spAddress)
// console.log("🚀 ~ Services ~ pairDevice ~ senderAddress:", senderAddress)
// if(senderAddress) {
// const proposal = service.sdkClient.get_update_proposals(outpointCommitment);
// console.log("🚀 ~ Services ~ pairDevice ~ proposal:", proposal)
// // const pairingTx = proposal.pairing_tx.replace(/^\"+|\"+$/g, '')
// const parsedProposal = JSON.parse(proposal[0])
console.log("🚀 ~ Services ~ pairDevice ~ parsedProposal:", parsedProposal)
const roles = JSON.parse(parsedProposal.roles)
console.log("🚀 ~ Services ~ pairDevice ~ roles:", roles, Array.isArray(roles), !roles.owner)
if(Array.isArray(roles) || !roles.owner) return
const proposalMembers = roles?.owner?.members
const isFirstDevice = proposalMembers.some((member: Member) => member.sp_addresses.some(address => address === spAddress))
const isSecondDevice = proposalMembers.some((member: Member) => member.sp_addresses.some(address => address === senderAddress))
console.log("🚀 ~ Services ~ pairDevice ~ proposalMembers:", proposalMembers)
if(proposalMembers?.length !== 2 || !isFirstDevice || !isSecondDevice) return
const pairingTx = parsedProposal?.pairing_tx?.replace(/^\"+|\"+$/g, '')
// console.log("🚀 ~ Services ~ pairDevice ~ parsedProposal:", parsedProposal)
// const roles = JSON.parse(parsedProposal.roles)
// console.log("🚀 ~ Services ~ pairDevice ~ roles:", roles, Array.isArray(roles), !roles.owner)
// if(Array.isArray(roles) || !roles.owner) return
// const proposalMembers = roles?.owner?.members
// const isFirstDevice = proposalMembers.some((member: Member) => member.sp_addresses.some(address => address === spAddress))
// const isSecondDevice = proposalMembers.some((member: Member) => member.sp_addresses.some(address => address === senderAddress))
// console.log("🚀 ~ Services ~ pairDevice ~ proposalMembers:", proposalMembers)
// if(proposalMembers?.length !== 2 || !isFirstDevice || !isSecondDevice) return
// const pairingTx = parsedProposal?.pairing_tx?.replace(/^\"+|\"+$/g, '')
let txid = '0'.repeat(64)
console.log("🚀 ~ Services ~ pairDevice ~ pairingTx:", pairingTx, `${txid}:4294967295`)
// let txid = '0'.repeat(64)
// console.log("🚀 ~ Services ~ pairDevice ~ pairingTx:", pairingTx, `${txid}:4294967295`)
const pairing = await service.sdkClient.pair_device(`${txid}:4294967295`, [senderAddress])
const device = this.dumpDevice()
console.log("🚀 ~ Services ~ pairDevice ~ device:", device)
this.saveDevice(device)
// await service.sdkClient.pair_device(pairingTx, [senderAddress])
console.log("🚀 ~ Services ~ pairDevice ~ pairing:", pairing)
// const process = await this.prepareProcessTx(spAddress, senderAddress)
console.log("🚀 ~ Services ~ pairDevice ~ process:", outpointCommitment, prd, prd.payload)
const prdString = JSON.stringify(prd).trim()
console.log("🚀 ~ Services ~ pairDevice ~ prdString:", prdString)
let tx = await service.sdkClient.response_prd(outpointCommitment, prdString, true)
console.log("🚀 ~ Services ~ pairDevice ~ tx:", tx)
if(tx.ciphers_to_send) {
tx.ciphers_to_send.forEach((cipher: string) => service.websocketConnection?.sendMessage('Cipher', cipher))
}
this.injectProcessListPage()
}
// const pairing = await service.sdkClient.pair_device(`${txid}:4294967295`, [senderAddress])
// const device = this.dumpDevice()
// console.log("🚀 ~ Services ~ pairDevice ~ device:", device)
// this.saveDevice(device)
// // await service.sdkClient.pair_device(pairingTx, [senderAddress])
// console.log("🚀 ~ Services ~ pairDevice ~ pairing:", pairing)
// // const process = await this.prepareProcessTx(spAddress, senderAddress)
// console.log("🚀 ~ Services ~ pairDevice ~ process:", outpointCommitment, prd, prd.payload)
// const prdString = JSON.stringify(prd).trim()
// console.log("🚀 ~ Services ~ pairDevice ~ prdString:", prdString)
// let tx = await service.sdkClient.response_prd(outpointCommitment, prdString, true)
// console.log("🚀 ~ Services ~ pairDevice ~ tx:", tx)
// if(tx.ciphers_to_send) {
// tx.ciphers_to_send.forEach((cipher: string) => service.websocketConnection?.sendMessage('Cipher', cipher))
// }
// this.injectProcessListPage()
// }
}
// async saveTxToDb(tx: CachedMessage) {

View File

@ -1,6 +1,5 @@
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 {

View File

@ -38,9 +38,5 @@ export default defineConfig({
open: false,
port: 3001,
strictPort: true, // Empêche de changer de port si le 3001 est occupé
hmr: {
port: 9050, // Assure que le WebSocket HMR utilise bien le même port
protocol: 'wss',
}
},
});