From 88100903703a3e68cb1da0e5ec95b0983ad17286 Mon Sep 17 00:00:00 2001 From: Sosthene Date: Tue, 26 Nov 2024 21:19:46 +0100 Subject: [PATCH 01/14] Complete pairing --- src/services/modal.service.ts | 45 ++++-- src/services/service.ts | 285 ++++++++++++++++------------------ src/utils/sp-address.utils.ts | 19 ++- 3 files changed, 181 insertions(+), 168 deletions(-) diff --git a/src/services/modal.service.ts b/src/services/modal.service.ts index fc6c155..ee171ec 100755 --- a/src/services/modal.service.ts +++ b/src/services/modal.service.ts @@ -8,7 +8,7 @@ import { RoleDefinition } from 'dist/pkg/sdk_client'; export default class ModalService { private static instance: ModalService; - private currentPrd: any; + private currentPcdCommitment: string | null = null; private currentOutpoint: string | null = null; private constructor() {} private paired_addresses: string[] = []; @@ -52,7 +52,8 @@ export default class ModalService { } } - public async openConfirmationModal(pcd: any, commitmentTx: string) { + // 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']; @@ -65,6 +66,7 @@ export default class ModalService { throw new Error('Pcd doesn\'t have a \"roles\" field'); } + // pairing specifics let members; if (map['owner']) { const owner = map['owner']; @@ -73,6 +75,7 @@ export default class ModalService { throw new Error('No \"owner\" role'); } + // pairing specifics if (members.length != 1) { throw new Error('Must have exactly 1 member'); } @@ -81,12 +84,15 @@ export default class ModalService { const service = await Services.getInstance(); const localAddress = await service.getDeviceAddress(); console.log('πŸš€ ~ Routing ~ openConfirmationModal ~ pcd:', pcd); - for (const address of members[0]['sp_addresses']) { - if (address !== localAddress) { - this.paired_addresses.push(address); + for (const member of members) { + for (const address of member['sp_addresses']) { + if (address !== localAddress) { + this.paired_addresses.push(address); + } } } this.currentOutpoint = commitmentTx; + this.currentPcdCommitment = merkleRoot; await this.injectModal(members); const modal = document.getElementById('modal'); if (modal) modal.style.display = 'flex'; @@ -116,18 +122,33 @@ export default class ModalService { async confirmPairing() { const service = await Services.getInstance(); const modal = document.getElementById('modal'); - // console.log("πŸš€ ~ Routing ~ confirm ~ prd:", prd) if (modal) modal.style.display = 'none'; - if (this.currentOutpoint === null || this.paired_addresses.length === 0) { - throw new Error('Missing outpoint and/or paired addresses'); - } + // We send the prd update + if (this.currentPcdCommitment) { + try { + const createPrdUpdateReturn = await service.createPrdUpdate(this.currentPcdCommitment); + await service.handleApiReturn(createPrdUpdateReturn); + } catch (e) { + throw e + } + } else { + throw new Error('No currentPcdCommitment'); + } - // We take the paired device(s) from the contract - await service.pairDevice(this.currentOutpoint, this.paired_addresses); + // We send confirmation that we validate the change + try { + const approveChangeReturn = await service.approveChange(this.currentPcdCommitment!); + await service.handleApiReturn(approveChangeReturn); + } catch (e) { + throw e + } + + service.pairDevice(this.paired_addresses); this.paired_addresses = []; this.currentOutpoint = null; - const newDevice = await service.dumpDevice(); + this.currentPcdCommitment = null; + const newDevice = service.dumpDevice(); await service.saveDevice(newDevice); navigate('process'); } diff --git a/src/services/service.ts b/src/services/service.ts index 8596d76..d09efc5 100755 --- a/src/services/service.ts +++ b/src/services/service.ts @@ -8,17 +8,18 @@ import ModalService from './modal.service'; import { navigate } from '../router'; import Database from './database.service'; -type ProcessesCache = { - [key: string]: any; -}; - export const U32_MAX = 4294967295; +const RELAY_ADDRESS = "sprt1qqdg4x69xdyhxpz4weuel0985qyswa0x9ycl4q6xc0fngf78jtj27gqj5vff4fvlt3fydx4g7vv0mh7vqv8jncgusp6n2zv860nufdzkyy59pqrdr"; const wsurl = `https://demo.4nkweb.com/ws/`; export default class Services { private static initializing: Promise | null = null; private static instance: Services; - private current_process: string | null = null; + private currentProcess: string | null = null; + private pendingUpdates: Record = {}; + private currentUpdateMerkleRoot: string | null = null; + private localAddress: string | null = null; + private pairedAddresses: string[] = []; private sdkClient: any; private processes: IProcess[] | null = null; private notifications: INotification[] | null = null; @@ -57,50 +58,31 @@ export default class Services { } public async addWebsocketConnection(url: string): Promise { - // const services = await Services.getInstance(); console.log('Opening new websocket connection'); - const newClient = initWebsocket(url); + await initWebsocket(url); } - public isPaired(): boolean | undefined { + public async getRelayAddresses(): Promise { + // We just return one hardcoded address for now + return [RELAY_ADDRESS]; + } + + public isPaired(): boolean { try { return this.sdkClient.is_linking(); } catch (e) { - console.error('isPaired ~ Error:', e); + throw new Error(`isPaired ~ Error: ${e}`); } } public async unpairDevice(): Promise { - const service = await Services.getInstance(); - await service.sdkClient.unpair_device(); - const newDevice = await this.dumpDevice(); - await this.saveDevice(newDevice); - } - - private prepareProcessTx(myAddress: string, recipientAddress: string) { - const initial_session_privkey = new Uint8Array(32); - const initial_session_pubkey = new Uint8Array(32); - const pairingTemplate = { - description: 'AliceBob', - roles: { - owner: { - members: [{ sp_addresses: [myAddress, recipientAddress] }], - validation_rules: [ - { - quorum: 1.0, - fields: ['description', 'roles', 'session_privkey', 'session_pubkey', 'key_parity'], - min_sig_member: 1.0, - }, - ], - }, - }, - session_privkey: initial_session_privkey, - session_pubkey: initial_session_pubkey, - key_parity: true, - }; - - const apiReturn = this.sdkClient.create_update_transaction(undefined, JSON.stringify(pairingTemplate), 1); - return apiReturn; + try { + this.sdkClient.unpair_device(); + const newDevice = this.dumpDevice(); + await this.saveDevice(newDevice); + } catch (e) { + throw new Error(`Failed to unpair device: ${e}`); + } } public async getSecretForAddress(address: string): Promise { @@ -108,7 +90,7 @@ export default class Services { return await db.getObject('shared_secrets', address); } - public async connectMember(members: Member[]): Promise { + public async connectMember(members: Member[]): Promise { if (members.length === 0) { throw new Error('Trying to connect to empty members list'); } @@ -144,15 +126,13 @@ export default class Services { } try { - const apiReturn = this.sdkClient.create_connect_transaction(members_str, 1); - - await this.handleApiReturn(apiReturn); + return this.sdkClient.create_connect_transaction(members_str, 1); } catch (e) { - console.error('Failed to connect:', e); + throw e; } } - public async createPairingProcess(pairWith: string[], relayAddress: string, feeRate: number): Promise { + public async createPairingProcess(pairWith: string[], relayAddress: string, feeRate: number): Promise { const myAddress: string = this.sdkClient.get_address(); pairWith.push(myAddress); const newKey = this.sdkClient.get_new_keypair(); @@ -175,14 +155,61 @@ export default class Services { key_parity: newKey['key_parity'], }; try { - const newProcessReturn = this.sdkClient.create_new_process(JSON.stringify(pairingTemplate), relayAddress, feeRate); - console.log('newProcessReturn:', newProcessReturn); - await this.handleApiReturn(newProcessReturn); + return this.sdkClient.create_new_process(JSON.stringify(pairingTemplate), relayAddress, feeRate); } catch (e) { throw new Error(`Creating process failed:, ${e}`); } } + // Create prd update for current process and update + public createPrdUpdate(pcdMerkleRoot: string): ApiReturn { + if (!this.currentProcess) { + throw new Error('No current process defined'); + } + + try { + return this.sdkClient.create_update_message(this.currentProcess, pcdMerkleRoot); + } catch (e) { + throw new Error(`Failed to create prd update: ${e}`); + } + } + + public createPrdResponse(pcdMerkleRoot: string): ApiReturn { + if (!this.currentProcess) { + throw new Error('No current process defined'); + } + + try { + return this.sdkClient.create_response_prd(this.currentProcess, pcdMerkleRoot); + } catch (e) { + throw e + } + } + + public approveChange(currentPcdMerkleRoot: string): ApiReturn { + if (!this.currentProcess) { + throw new Error('No current process defined'); + } + + try { + return this.sdkClient.validate_state(this.currentProcess, currentPcdMerkleRoot); + } catch (e) { + throw new Error(`Failed to create prd response: ${e}`); + } + } + + public rejectChange(): ApiReturn { + if (!this.currentProcess || !this.currentUpdateMerkleRoot) { + throw new Error('No current process and/or current update defined'); + } + + try { + return this.sdkClient.refuse_state(this.currentProcess, this.currentUpdateMerkleRoot); + } catch (e) { + throw new Error(`Failed to create prd response: ${e}`); + } + } + async resetDevice() { await this.sdkClient.reset_device(); } @@ -209,11 +236,11 @@ export default class Services { async parseCipher(message: string) { try { console.log('parsing new cipher'); - const apiReturn = await this.sdkClient.parse_cipher(message, 0.00001); + const apiReturn = await this.sdkClient.parse_cipher(message); console.log('πŸš€ ~ Services ~ parseCipher ~ apiReturn:', apiReturn); await this.handleApiReturn(apiReturn); } catch (e) { - console.log("Cipher isn't for us"); + console.error(`Parsed cipher with error: ${e}`); } // await this.saveCipherTxToDb(parsedTx) } @@ -236,7 +263,21 @@ export default class Services { } } - private async handleApiReturn(apiReturn: ApiReturn) { + public getUpdateProposals(commitmentOutpoint: string) { + try { + const proposals: ApiReturn = this.sdkClient.get_update_proposals(commitmentOutpoint); + if (proposals.decrypted_pcds && proposals.decrypted_pcds.length != 0) { + this.currentProcess = commitmentOutpoint; + this.pendingUpdates = proposals.decrypted_pcds; + } else { + throw new Error('No pending proposals'); + } + } catch (e) { + throw new Error(`Failed to get proposal updates for process ${commitmentOutpoint}: ${e}`); + } + } + + public async handleApiReturn(apiReturn: ApiReturn) { if (apiReturn.new_tx_to_send && apiReturn.new_tx_to_send.transaction.length != 0) { await this.sendNewTxMessage(JSON.stringify(apiReturn.new_tx_to_send)); } @@ -245,7 +286,6 @@ export default class Services { const unconfirmedSecrets = apiReturn.secrets.unconfirmed_secrets; const confirmedSecrets = apiReturn.secrets.shared_secrets; - console.log('confirmedSecrets:', confirmedSecrets); const db = await Database.getInstance(); for (const secret of unconfirmedSecrets) { db.addObject({ @@ -256,8 +296,6 @@ export default class Services { } const entries = Object.entries(confirmedSecrets).map(([key, value]) => ({ key, value })); for (const entry of entries) { - console.log('entry:', entry); - db.addObject({ storeName: 'shared_secrets', object: entry, @@ -277,18 +315,6 @@ export default class Services { object: { id: commitmentTx, process }, key: null, }); - // Check if the newly updated process reveals some new information - try { - const proposals: ApiReturn = this.sdkClient.get_update_proposals(commitmentTx); - const decrypted_pcds = proposals.decrypted_pcds; - if (decrypted_pcds && decrypted_pcds.length != 0) { - for (const actual_proposal of Object.values(decrypted_pcds)) { - await this.routingInstance.openConfirmationModal(actual_proposal, commitmentTx); - } - } - } catch (e) { - console.error(e); - } } if (apiReturn.commit_to_send) { @@ -296,62 +322,45 @@ export default class Services { await this.sendCommitMessage(JSON.stringify(commit)); } - if (apiReturn.decrypted_pcds && apiReturn.decrypted_pcds.length != 0) { - // TODO - } - if (apiReturn.ciphers_to_send && apiReturn.ciphers_to_send.length != 0) { await this.sendCipherMessages(apiReturn.ciphers_to_send); } }, 0); } - async pairDevice(commitmentTx: string, spAddressList: string[]) { - await this.sdkClient.pair_device(commitmentTx, spAddressList); + public async evaluatePendingUpdates() { + if (!this.currentProcess) { + throw new Error('No current process'); + } + + try { + await this.openConfirmationModal(); + } catch (e) { + throw new Error(`Error while evaluating pending updates for process ${this.currentProcess}: ${e}`) + } } - async validatePairingDevice(prd: any, outpointCommitment: string) { - console.log('πŸš€ ~ Services ~ pairDevice ~ prd:', prd); - 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 = this.sdkClient.get_update_proposals(outpointCommitment); - console.log('πŸš€ ~ Services ~ pairDevice ~ proposal:', proposal); - // const pairingTx = proposal.pairing_tx.replace(/^\"+|\"+$/g, '') - const parsedProposal = JSON.parse(proposal[0]); + private async openConfirmationModal() { + if (this.pendingUpdates.length === 0) { + console.log('No pending updates'); + } - 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`); - - const pairing = await this.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 this.sdkClient.response_prd(outpointCommitment, prdString, true); - console.log('πŸš€ ~ Services ~ pairDevice ~ tx:', tx); - if (tx.ciphers_to_send) { - tx.ciphers_to_send.forEach((cipher: string) => sendMessage('Cipher', cipher)); + try { + for (const [merkleRoot, actual_proposal] of Object.entries(this.pendingUpdates)) { + await this.routingInstance.openConfirmationModal(actual_proposal, this.currentProcess!, merkleRoot); + } + } catch (e) { + throw new Error(`${e}`); + } + } + + pairDevice(spAddressList: string[]) { + if (this.currentProcess) { + try { + this.sdkClient.pair_device(this.currentProcess, spAddressList); + } catch (e) { + throw new Error(`Failed to pair device: ${e}`); } - navigate('process'); } } @@ -364,12 +373,15 @@ export default class Services { return await this.sdkClient.get_address(); } - async dumpDevice() { - const device = await this.sdkClient.dump_device(); - return device; + public dumpDevice(): string { + try { + return this.sdkClient.dump_device(); + } catch (e) { + throw new Error(`Failed to dump device: ${e}`); + } } - async saveDevice(device: any): Promise { + async saveDevice(device: any): Promise { const db = await Database.getInstance(); try { await db.addObject({ @@ -506,47 +518,12 @@ export default class Services { return process; } - private getProcessesCache(): ProcessesCache { - // Regular expression to match 64-character hexadecimal strings - const hexU32KeyRegex: RegExp = /^[0-9a-fA-F]{64}:\d+$/; - const hexObjects: ProcessesCache = {}; - - // Iterate over all keys in localStorage - for (let i = 0; i < localStorage.length; i++) { - const key = localStorage.key(i); - - if (!key) { - return hexObjects; - } - - // Check if the key matches the 32-byte hex pattern - if (hexU32KeyRegex.test(key)) { - const value = localStorage.getItem(key); - if (!value) { - continue; - } - - hexObjects[key] = JSON.parse(value); - } - } - - return hexObjects; + private getProcessesCache() { + console.log('TODO get processes from indexedDB') } public async restoreProcesses() { - const processesCache = this.getProcessesCache(); - console.log('πŸš€ ~ Services ~ restoreProcesses ~ processesCache:', processesCache); - - if (processesCache.length == 0) { - console.debug('πŸš€ ~ Services ~ restoreProcesses ~ no processes in local storage'); - return; - } - - try { - await this.sdkClient.set_process_cache(JSON.stringify(processesCache)); - } catch (e) { - console.error('Services ~ restoreProcesses ~ Error:', e); - } + console.log('TODO: restore processes from indexedDB'); } getNotifications(): INotification[] { diff --git a/src/utils/sp-address.utils.ts b/src/utils/sp-address.utils.ts index b0e2cc4..725e67f 100755 --- a/src/utils/sp-address.utils.ts +++ b/src/utils/sp-address.utils.ts @@ -149,14 +149,29 @@ async function onOkButtonClick() { const service = await Services.getInstance(); const addressInput = (document.getElementById('addressInput') as HTMLInputElement).value; try { + // Connect to target, if necessary const sharedSecret = await service.getSecretForAddress(addressInput); if (!sharedSecret) { const member = { sp_addresses: [addressInput], } - await service.connectMember([member]); + const connectMemberResult = await service.connectMember([member]); + await service.handleApiReturn(connectMemberResult); } - await service.createPairingProcess([addressInput], "sprt1qqdg4x69xdyhxpz4weuel0985qyswa0x9ycl4q6xc0fngf78jtj27gqj5vff4fvlt3fydx4g7vv0mh7vqv8jncgusp6n2zv860nufdzkyy59pqrdr", 1); + // 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 + } + const [commitmentOutpoint, process] = createPairingProcessReturn.updated_process; + + // We set the service to the process + service.getUpdateProposals(commitmentOutpoint); + + await service.evaluatePendingUpdates(); } catch (e) { console.error('onOkButtonClick error:', e); } From 78e868d1f65c93bce155685a237dd78de5e7ac02 Mon Sep 17 00:00:00 2001 From: Sosthene Date: Thu, 28 Nov 2024 12:39:21 +0100 Subject: [PATCH 02/14] Fix Process storage --- src/pages/process/process.ts | 11 ++- src/services/database.service.ts | 39 ++++++++-- src/services/service.ts | 130 +++++++++++-------------------- src/utils/sp-address.utils.ts | 5 +- 4 files changed, 89 insertions(+), 96 deletions(-) diff --git a/src/pages/process/process.ts b/src/pages/process/process.ts index b587592..ad516d1 100755 --- a/src/pages/process/process.ts +++ b/src/pages/process/process.ts @@ -36,7 +36,7 @@ export async function init() { const processes = await getProcesses(); for (let process of processes) { - const processName = process[1].title; + const processName = process['description']; const opt = new Option(processName); opt.value = processName; element.add(opt); @@ -364,7 +364,7 @@ async function showSelectedProcess(elem: MouseEvent) { titleDiv.className = 'process-title'; titleDiv.innerHTML = `${process[1].title} : ${process[1].description}`; processDiv.appendChild(titleDiv); - for (const zone of process[1].zones) { + for (const zone of process.zones) { const zoneElement = document.createElement('div'); zoneElement.className = 'process-element'; const zoneId = process[1].title + '-' + zone.id; @@ -408,5 +408,10 @@ async function getProcesses(): Promise { const service = await Services.getInstance(); const processes = await service.getProcesses(); - return processes; + const res = Object.entries(processes).map(([key, value]) => ({ + key, + value + })) + + return res; } diff --git a/src/services/database.service.ts b/src/services/database.service.ts index 53225b7..9c60fc9 100755 --- a/src/services/database.service.ts +++ b/src/services/database.service.ts @@ -13,8 +13,8 @@ class Database { indices: [], }, AnkProcess: { - name: 'process', - options: { keyPath: 'id' }, + name: 'processes', + options: {}, indices: [], }, AnkSharedSecrets: { @@ -27,11 +27,6 @@ class Database { options: { autoIncrement: true }, indices: [], }, - AnkProcessData: { - name: 'process-data', - options: { keyPath: 'id' }, - indices: [], - }, }; // Private constructor to prevent direct instantiation from outside @@ -191,6 +186,36 @@ class Database { }); return result } + + public async dumpStore(storeName: string): Promise> { + const db = await this.getDb(); + const tx = db.transaction(storeName, 'readonly'); + const store = tx.objectStore(storeName); + + try { + // Wait for both getAllKeys() and getAll() to resolve + const [keys, values] = await Promise.all([ + new Promise((resolve, reject) => { + const request = store.getAllKeys(); + request.onsuccess = () => resolve(request.result); + request.onerror = () => reject(request.error); + }), + new Promise((resolve, reject) => { + const request = store.getAll(); + request.onsuccess = () => resolve(request.result); + request.onerror = () => reject(request.error); + }), + ]); + + // Combine keys and values into an object + const result: Record = Object.fromEntries(keys.map((key, index) => [key, values[index]])); + return result; + + } catch (error) { + console.error("Error fetching data from IndexedDB:", error); + throw error; + } + } } export default Database; diff --git a/src/services/service.ts b/src/services/service.ts index d09efc5..76ff81c 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 } from '../../dist/pkg/sdk_client'; +import { ApiReturn, Member, Process } from '../../dist/pkg/sdk_client'; import ModalService from './modal.service'; import { navigate } from '../router'; import Database from './database.service'; @@ -305,16 +305,18 @@ export default class Services { } setTimeout(async () => { - if (apiReturn.updated_process && apiReturn.updated_process.length) { - const [commitmentTx, process] = apiReturn.updated_process; + if (apiReturn.updated_process) { + const updatedProcess = apiReturn.updated_process; // Save process to storage - const db = await Database.getInstance(); - db.addObject({ - storeName: 'process', - object: { id: commitmentTx, process }, - key: null, - }); + try { + await this.saveProcess(updatedProcess.commitment_tx, updatedProcess.current_process); + } catch (e) { + throw e; + } + + // do we need to act? + updatedProcess.user_validation_required } if (apiReturn.commit_to_send) { @@ -444,86 +446,46 @@ export default class Services { } } - async getProcesses(): Promise { - const process = [ - [ - '1', - { - title: 'Messaging', - description: 'Messagerie chiffrΓ©e', - html: '
', - css: '', - script: '', - zones: [ - { - id: '1', - title: 'zone 1', - description: 'zone 1', - }, - { - id: '2', - title: 'zone 2', - description: 'zone 2', - }, - ], - roles: { - owner: { - members: ['dfdsfdfdsf', 'dfdfdfdsfsfdfdsf'], - validation_rules: [ - { - quorum: 1.0, - fields: ['description', 'roles', 'session_privkey', 'session_pubkey', 'key_parity'], - min_sig_member: 1.0, - }, - ], - }, - }, - }, - ], - [ - '2', - { - title: 'Database', - description: 'Database chiffrΓ©e', - html: '
', - css: '', - script: '', - zones: [ - { - id: '1', - title: 'zone 1', - description: 'zone 1', - }, - { - id: '2', - title: 'zone 2', - description: 'zone 2', - }, - ], - roles: { - owner: { - members: ['dfdsfdfdsf', 'dfdfdfdsfsfdfdsf'], - validation_rules: [ - { - quorum: 1.0, - fields: ['description', 'roles', 'session_privkey', 'session_pubkey', 'key_parity'], - min_sig_member: 1.0, - }, - ], - }, - }, - }, - ], - ]; - return process; + public async saveProcess(commitedIn: string, process: any) { + const db = await Database.getInstance(); + try { + await db.addObject({ + storeName: 'processes', + object: process, + key: commitedIn, + }); + } catch (e) { + throw new Error(`Failed to save process: ${e}`) + } } - private getProcessesCache() { - console.log('TODO get processes from indexedDB') + public async getProcess(commitedIn: string): Promise { + const db = await Database.getInstance(); + return await db.getObject('processes', commitedIn); } + public async getProcesses(): Promise> { + const db = await Database.getInstance(); + + const processes: Record = await db.dumpStore('processes'); + return processes; + } + + // Restore process in wasm with persistent storage public async restoreProcesses() { - console.log('TODO: restore processes from indexedDB'); + const db = await Database.getInstance(); + try { + const processes: Record = await db.dumpStore('processes'); + if (processes && Object.keys(processes).length != 0) { + console.log(`Restoring ${Object.keys(processes).length} processes`); + this.sdkClient.set_process_cache(JSON.stringify(processes)); + } else { + console.log('No processes to restore!'); + } + } catch (e) { + throw e; + } + } getNotifications(): INotification[] { diff --git a/src/utils/sp-address.utils.ts b/src/utils/sp-address.utils.ts index 725e67f..1c8b535 100755 --- a/src/utils/sp-address.utils.ts +++ b/src/utils/sp-address.utils.ts @@ -166,14 +166,15 @@ async function onOkButtonClick() { if (!createPairingProcessReturn.updated_process) { throw new Error('createPairingProcess returned an empty new process'); // This should never happen } - const [commitmentOutpoint, process] = createPairingProcessReturn.updated_process; + + const commitmentOutpoint = createPairingProcessReturn.updated_process.commitment_tx; // We set the service to the process service.getUpdateProposals(commitmentOutpoint); await service.evaluatePendingUpdates(); } catch (e) { - console.error('onOkButtonClick error:', e); + console.error(`onOkButtonClick error: ${e}`); } } From 0b45ff39628f2425943fa055593ff12ed47d3e6e Mon Sep 17 00:00:00 2001 From: Sosthene Date: Thu, 28 Nov 2024 12:39:46 +0100 Subject: [PATCH 03/14] Fix secrets storage --- src/services/database.service.ts | 2 +- src/services/service.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/services/database.service.ts b/src/services/database.service.ts index 9c60fc9..9f21704 100755 --- a/src/services/database.service.ts +++ b/src/services/database.service.ts @@ -19,7 +19,7 @@ class Database { }, AnkSharedSecrets: { name: 'shared_secrets', - options: { keyPath: 'key' }, + options: {}, indices: [], }, AnkUnconfirmedSecrets: { diff --git a/src/services/service.ts b/src/services/service.ts index 76ff81c..ac4a137 100755 --- a/src/services/service.ts +++ b/src/services/service.ts @@ -298,8 +298,8 @@ export default class Services { for (const entry of entries) { db.addObject({ storeName: 'shared_secrets', - object: entry, - key: null, + object: entry.value, + key: entry.key, }); } } From 113f036838cbc1a09dc1fb747e7ba20187d5515e Mon Sep 17 00:00:00 2001 From: Sosthene Date: Sat, 30 Nov 2024 18:56:59 +0100 Subject: [PATCH 04/14] Add restoreSecrets --- src/router.ts | 1 + src/services/service.ts | 16 ++++++++++++++++ 2 files changed, 17 insertions(+) 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/service.ts b/src/services/service.ts index ac4a137..41d355a 100755 --- a/src/services/service.ts +++ b/src/services/service.ts @@ -488,6 +488,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 [ { From b822f351fde7980547653b42f6784c24190f7e31 Mon Sep 17 00:00:00 2001 From: Sosthene Date: Sat, 30 Nov 2024 20:07:27 +0100 Subject: [PATCH 05/14] Pairing works --- src/services/modal.service.ts | 30 +++++++++--------------- src/services/service.ts | 43 ++++++++++++++++++++++++----------- src/utils/sp-address.utils.ts | 10 ++------ 3 files changed, 43 insertions(+), 40 deletions(-) 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 41d355a..ae6eacc 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[] = []; @@ -265,10 +265,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'); } @@ -315,8 +315,13 @@ export default class Services { throw e; } - // do we need to act? - updatedProcess.user_validation_required + if (updatedProcess.modified_state || updatedProcess.new_state) { + this.currentProcess = updatedProcess.commitment_tx; + + this.getUpdateProposals(this.currentProcess!); + + await this.evaluatePendingUpdates(); + } } if (apiReturn.commit_to_send) { @@ -343,16 +348,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}`); } } diff --git a/src/utils/sp-address.utils.ts b/src/utils/sp-address.utils.ts index 1c8b535..1b54708 100755 --- a/src/utils/sp-address.utils.ts +++ b/src/utils/sp-address.utils.ts @@ -161,18 +161,12 @@ async function onOkButtonClick() { // 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 } - const commitmentOutpoint = createPairingProcessReturn.updated_process.commitment_tx; - - // We set the service to the process - service.getUpdateProposals(commitmentOutpoint); - - await service.evaluatePendingUpdates(); + await service.handleApiReturn(createPairingProcessReturn); } catch (e) { console.error(`onOkButtonClick error: ${e}`); } From 9efc5b089acd81feae84c5c5771923530f74165b Mon Sep 17 00:00:00 2001 From: Sosthene Date: Sat, 30 Nov 2024 20:07:56 +0100 Subject: [PATCH 06/14] Replace is_linked() by is_paired() --- src/services/service.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/services/service.ts b/src/services/service.ts index ae6eacc..27ef0c1 100755 --- a/src/services/service.ts +++ b/src/services/service.ts @@ -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}`); } From bd72302c25be4e31f4a9f51554b1c572ad77cdd0 Mon Sep 17 00:00:00 2001 From: Sosthene Date: Sat, 30 Nov 2024 20:08:32 +0100 Subject: [PATCH 07/14] Minor fixes --- src/services/service.ts | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/src/services/service.ts b/src/services/service.ts index 27ef0c1..097d6ad 100755 --- a/src/services/service.ts +++ b/src/services/service.ts @@ -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'); @@ -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); } } From d5aa9aff431e1d7d1a22f5a84a7f362b9064c78f Mon Sep 17 00:00:00 2001 From: Sosthene Date: Sat, 30 Nov 2024 23:28:16 +0100 Subject: [PATCH 08/14] Add timeout on createPairingProcess to prevent double spends --- src/utils/sp-address.utils.ts | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/utils/sp-address.utils.ts b/src/utils/sp-address.utils.ts index 1b54708..3f14b15 100755 --- a/src/utils/sp-address.utils.ts +++ b/src/utils/sp-address.utils.ts @@ -159,14 +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); + setTimeout(async () => { + const relayAddress = await service.getRelayAddresses(); // Get one (or more?) relay addresses + 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 - } + if (!createPairingProcessReturn.updated_process) { + throw new Error('createPairingProcess returned an empty new process'); // This should never happen + } - await service.handleApiReturn(createPairingProcessReturn); + await service.handleApiReturn(createPairingProcessReturn); + }, 1000); } catch (e) { console.error(`onOkButtonClick error: ${e}`); } From 5bbf0d33f51bc9ccdc1b2817d95bb751c51de26a Mon Sep 17 00:00:00 2001 From: Sosthene Date: Sat, 30 Nov 2024 23:28:51 +0100 Subject: [PATCH 09/14] Handle modified states --- src/services/service.ts | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/services/service.ts b/src/services/service.ts index 097d6ad..baf3413 100755 --- a/src/services/service.ts +++ b/src/services/service.ts @@ -321,12 +321,24 @@ export default class Services { throw e; } - if (updatedProcess.modified_state || updatedProcess.new_state) { + 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 + } } } From 2a1fd9f80cd96345ca48828649f5a5bc45fcaedb Mon Sep 17 00:00:00 2001 From: AnisHADJARAB Date: Wed, 27 Nov 2024 09:08:14 +0000 Subject: [PATCH 10/14] transform home page into a web component --- .env | 3 + index.html | 7 +- package-lock.json | 368 ++++++++++----- package.json | 4 +- src/4nk.css | 785 +++++++++++++++++++++++++++++++ src/decs.d.ts | 10 + src/pages/home/home-component.ts | 48 ++ src/pages/home/home.html | 1 + src/pages/home/home.ts | 169 ++++--- src/router.ts | 27 +- src/services/modal.service.ts | 4 +- src/services/service.ts | 2 +- src/utils/html.utils.ts | 5 + src/utils/sp-address.utils.ts | 19 +- src/websockets.ts | 2 +- vite.config.ts | 37 +- 16 files changed, 1283 insertions(+), 208 deletions(-) create mode 100644 .env create mode 100644 src/4nk.css create mode 100644 src/decs.d.ts create mode 100644 src/pages/home/home-component.ts diff --git a/.env b/.env new file mode 100644 index 0000000..e3cc154 --- /dev/null +++ b/.env @@ -0,0 +1,3 @@ +# .env +VITE_API_URL=https://api.example.com +VITE_API_KEY=your_api_key \ No newline at end of file diff --git a/index.html b/index.html index 648bee8..58c8aed 100755 --- a/index.html +++ b/index.html @@ -17,6 +17,11 @@ - + \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index d0b085d..0b6f39d 100755 --- a/package-lock.json +++ b/package-lock.json @@ -13,6 +13,7 @@ "@vitejs/plugin-react": "^4.3.1", "@vitejs/plugin-vue": "^5.0.5", "html5-qrcode": "^2.3.8", + "qr-scanner": "^1.4.2", "qrcode": "^1.5.3", "sweetalert2": "^11.14.5", "vite-plugin-copy": "^0.1.6", @@ -20,6 +21,7 @@ "vite-plugin-wasm": "^3.3.0" }, "devDependencies": { + "@rollup/plugin-typescript": "^12.1.1", "copy-webpack-plugin": "^12.0.2", "html-webpack-plugin": "^5.6.0", "prettier": "^3.3.3", @@ -909,6 +911,69 @@ "node": ">=14" } }, + "node_modules/@rollup/plugin-typescript": { + "version": "12.1.1", + "resolved": "https://registry.npmjs.org/@rollup/plugin-typescript/-/plugin-typescript-12.1.1.tgz", + "integrity": "sha512-t7O653DpfB5MbFrqPe/VcKFFkvRuFNp9qId3xq4Eth5xlyymzxNpye2z8Hrl0RIMuXTSr5GGcFpkdlMeacUiFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rollup/pluginutils": "^5.1.0", + "resolve": "^1.22.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^2.14.0||^3.0.0||^4.0.0", + "tslib": "*", + "typescript": ">=3.7.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + }, + "tslib": { + "optional": true + } + } + }, + "node_modules/@rollup/plugin-typescript/node_modules/@rollup/pluginutils": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.1.3.tgz", + "integrity": "sha512-Pnsb6f32CD2W3uCaLZIzDmeFyQ2b8UWMFI7xtwUezpcGBDVDW6y9XgAWIlARiGAo6eNF5FK5aQTr0LFyNyqq5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "estree-walker": "^2.0.2", + "picomatch": "^4.0.2" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/plugin-typescript/node_modules/picomatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", + "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/@rollup/pluginutils": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-4.2.1.tgz", @@ -1316,6 +1381,12 @@ "@types/node": "*" } }, + "node_modules/@types/offscreencanvas": { + "version": "2019.7.3", + "resolved": "https://registry.npmjs.org/@types/offscreencanvas/-/offscreencanvas-2019.7.3.tgz", + "integrity": "sha512-ieXiYmgSRXUDeOntE1InxjWyvEelZGP63M+cGuquuRLuIKKT1osnkXjxev9B7d1nXSug5vpunx+gNlbVxMlC9A==", + "license": "MIT" + }, "node_modules/@types/qrcode": { "version": "1.5.5", "resolved": "https://registry.npmjs.org/@types/qrcode/-/qrcode-1.5.5.tgz", @@ -1748,9 +1819,10 @@ } }, "node_modules/acorn": { - "version": "8.12.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", - "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", + "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", + "license": "MIT", "bin": { "acorn": "bin/acorn" }, @@ -1758,15 +1830,6 @@ "node": ">=0.4.0" } }, - "node_modules/acorn-import-attributes": { - "version": "1.9.5", - "resolved": "https://registry.npmjs.org/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz", - "integrity": "sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==", - "dev": true, - "peerDependencies": { - "acorn": "^8" - } - }, "node_modules/ajv": { "version": "8.16.0", "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.16.0.tgz", @@ -1891,10 +1954,11 @@ } }, "node_modules/body-parser": { - "version": "1.20.2", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", - "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", + "version": "1.20.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", + "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", "dev": true, + "license": "MIT", "dependencies": { "bytes": "3.1.2", "content-type": "~1.0.5", @@ -1904,7 +1968,7 @@ "http-errors": "2.0.0", "iconv-lite": "0.4.24", "on-finished": "2.4.1", - "qs": "6.11.0", + "qs": "6.13.0", "raw-body": "2.5.2", "type-is": "~1.6.18", "unpipe": "1.0.0" @@ -1919,6 +1983,7 @@ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.8" } @@ -1928,6 +1993,7 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, + "license": "MIT", "dependencies": { "ms": "2.0.0" } @@ -1936,7 +2002,8 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/bonjour-service": { "version": "1.2.1", @@ -1974,9 +2041,9 @@ } }, "node_modules/browserslist": { - "version": "4.23.1", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.1.tgz", - "integrity": "sha512-TUfofFo/KsK/bWZ9TWQ5O26tsWW4Uhmt8IYklbnUa70udB6P2wA7w7o4PY4muaEPBQaAX+CEnmmIA41NVHtPVw==", + "version": "4.24.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.2.tgz", + "integrity": "sha512-ZIc+Q62revdMcqC6aChtW4jz3My3klmCO1fEmINZY/8J3EpBg5/A/D0AKmBveUh6pgoeycoMkVMko84tuYS+Gg==", "funding": [ { "type": "opencollective", @@ -1991,11 +2058,12 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { - "caniuse-lite": "^1.0.30001629", - "electron-to-chromium": "^1.4.796", - "node-releases": "^2.0.14", - "update-browserslist-db": "^1.0.16" + "caniuse-lite": "^1.0.30001669", + "electron-to-chromium": "^1.5.41", + "node-releases": "^2.0.18", + "update-browserslist-db": "^1.1.1" }, "bin": { "browserslist": "cli.js" @@ -2038,6 +2106,7 @@ "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", "dev": true, + "license": "MIT", "dependencies": { "es-define-property": "^1.0.0", "es-errors": "^1.3.0", @@ -2070,9 +2139,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001640", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001640.tgz", - "integrity": "sha512-lA4VMpW0PSUrFnkmVuEKBUovSWKhj7puyCg8StBChgu298N1AtuF1sKWEvfDuimSEDbhlb/KqPKC3fs1HbuQUA==", + "version": "1.0.30001684", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001684.tgz", + "integrity": "sha512-G1LRwLIQjBQoyq0ZJGqGIJUXzJ8irpbjHLpVRXDvBEScFJ9b17sgK6vlx0GAJFE21okD7zXl08rRRUfq6HdoEQ==", "funding": [ { "type": "opencollective", @@ -2086,7 +2155,8 @@ "type": "github", "url": "https://github.com/sponsors/ai" } - ] + ], + "license": "CC-BY-4.0" }, "node_modules/chalk": { "version": "2.4.2", @@ -2354,6 +2424,7 @@ "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -2364,10 +2435,11 @@ "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==" }, "node_modules/cookie": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", - "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", + "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -2409,10 +2481,11 @@ "dev": true }, "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "dev": true, + "license": "MIT", "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", @@ -2523,6 +2596,7 @@ "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", "dev": true, + "license": "MIT", "dependencies": { "es-define-property": "^1.0.0", "es-errors": "^1.3.0", @@ -2552,6 +2626,7 @@ "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.8" } @@ -2561,6 +2636,7 @@ "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.8", "npm": "1.2.8000 || >= 1.4.16" @@ -2705,9 +2781,10 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.4.816", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.816.tgz", - "integrity": "sha512-EKH5X5oqC6hLmiS7/vYtZHZFTNdhsYG5NVPRN6Yn0kQHNBlT59+xSM8HBy66P5fxWpKgZbPqb+diC64ng295Jw==" + "version": "1.5.65", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.65.tgz", + "integrity": "sha512-PWVzBjghx7/wop6n22vS2MLU8tKGd4Q91aCEGhG/TYmW6PP5OcSXcdnxTe1NNt0T66N8D6jxh4kC8UsdzOGaIw==", + "license": "ISC" }, "node_modules/emoji-regex": { "version": "9.2.2", @@ -2722,19 +2799,21 @@ "integrity": "sha512-ucAnuBEhUK4boH2HjVYG5Q2mQyPorvv0u/ocS+zhdw0S8AlHYY+GOFhP1Gio5z4icpP2ivFSvhtFjQi8+T9ppw==" }, "node_modules/encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.8" } }, "node_modules/enhanced-resolve": { - "version": "5.17.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.0.tgz", - "integrity": "sha512-dwDPwZL0dmye8Txp2gzFmA6sxALaSvdRDjPH0viLcKrtlOL3tw62nWWweVD1SdILDTJrbrL6tdWVN58Wo6U3eA==", + "version": "5.17.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz", + "integrity": "sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==", "dev": true, + "license": "MIT", "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.2.0" @@ -2768,6 +2847,7 @@ "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", "dev": true, + "license": "MIT", "dependencies": { "get-intrinsic": "^1.2.4" }, @@ -2780,6 +2860,7 @@ "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" } @@ -2828,9 +2909,10 @@ } }, "node_modules/escalade": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", - "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "license": "MIT", "engines": { "node": ">=6" } @@ -2902,6 +2984,7 @@ "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -2945,37 +3028,38 @@ } }, "node_modules/express": { - "version": "4.19.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", - "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", + "version": "4.21.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.1.tgz", + "integrity": "sha512-YSFlK1Ee0/GC8QaO91tHcDxJiE/X4FbpAyQWkxAvG6AXCuR65YzK8ua6D9hvi/TzUfZMpc+BwuM1IPw8fmQBiQ==", "dev": true, + "license": "MIT", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.20.2", + "body-parser": "1.20.3", "content-disposition": "0.5.4", "content-type": "~1.0.4", - "cookie": "0.6.0", + "cookie": "0.7.1", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "2.0.0", - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "etag": "~1.8.1", - "finalhandler": "1.2.0", + "finalhandler": "1.3.1", "fresh": "0.5.2", "http-errors": "2.0.0", - "merge-descriptors": "1.0.1", + "merge-descriptors": "1.0.3", "methods": "~1.1.2", "on-finished": "2.4.1", "parseurl": "~1.3.3", - "path-to-regexp": "0.1.7", + "path-to-regexp": "0.1.10", "proxy-addr": "~2.0.7", - "qs": "6.11.0", + "qs": "6.13.0", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", - "send": "0.18.0", - "serve-static": "1.15.0", + "send": "0.19.0", + "serve-static": "1.16.2", "setprototypeof": "1.2.0", "statuses": "2.0.1", "type-is": "~1.6.18", @@ -3107,13 +3191,14 @@ } }, "node_modules/finalhandler": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", - "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", + "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", "dev": true, + "license": "MIT", "dependencies": { "debug": "2.6.9", - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "on-finished": "2.4.1", "parseurl": "~1.3.3", @@ -3129,6 +3214,7 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, + "license": "MIT", "dependencies": { "ms": "2.0.0" } @@ -3137,7 +3223,8 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/find-up": { "version": "4.1.0", @@ -3224,6 +3311,7 @@ "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -3284,6 +3372,7 @@ "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", "dev": true, + "license": "MIT", "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2", @@ -3411,6 +3500,7 @@ "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", "dev": true, + "license": "MIT", "dependencies": { "get-intrinsic": "^1.1.3" }, @@ -3442,6 +3532,7 @@ "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", "dev": true, + "license": "MIT", "dependencies": { "es-define-property": "^1.0.0" }, @@ -3454,6 +3545,7 @@ "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -3466,6 +3558,7 @@ "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -3638,6 +3731,7 @@ "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", "dev": true, + "license": "MIT", "dependencies": { "depd": "2.0.0", "inherits": "2.0.4", @@ -3670,10 +3764,11 @@ } }, "node_modules/http-proxy-middleware": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz", - "integrity": "sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw==", + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.7.tgz", + "integrity": "sha512-fgVY8AV7qU7z/MmXJ/rxwbrtQH4jBQ9m7kp3llF0liB7glmFeVZFBepQb32T3y8n8k2+AEYuMPCpinYW+/CuRA==", "dev": true, + "license": "MIT", "dependencies": { "@types/http-proxy": "^1.17.8", "http-proxy": "^1.18.1", @@ -3716,6 +3811,7 @@ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", "dev": true, + "license": "MIT", "dependencies": { "safer-buffer": ">= 2.1.2 < 3" }, @@ -4214,6 +4310,7 @@ "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -4238,10 +4335,14 @@ } }, "node_modules/merge-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==", - "dev": true + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, "node_modules/merge-stream": { "version": "2.0.0", @@ -4267,9 +4368,10 @@ } }, "node_modules/micromatch": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz", - "integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==", + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "license": "MIT", "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" @@ -4283,6 +4385,7 @@ "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", "dev": true, + "license": "MIT", "bin": { "mime": "cli.js" }, @@ -4425,9 +4528,10 @@ } }, "node_modules/node-releases": { - "version": "2.0.14", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", - "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==" + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", + "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==", + "license": "MIT" }, "node_modules/normalize-path": { "version": "3.0.0", @@ -4462,10 +4566,11 @@ } }, "node_modules/object-inspect": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", - "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==", + "version": "1.13.3", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.3.tgz", + "integrity": "sha512-kDCGIbxkDSXE3euJZZXzc6to7fCrKHNI/hSRQnRuQ+BWjFNzZwiFF8fj/6o2t2G9/jTj8PSIYTfCLelLZEeRpA==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -4668,10 +4773,11 @@ } }, "node_modules/path-to-regexp": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==", - "dev": true + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz", + "integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==", + "dev": true, + "license": "MIT" }, "node_modules/path-type": { "version": "5.0.0", @@ -4818,6 +4924,15 @@ "node": ">=6" } }, + "node_modules/qr-scanner": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/qr-scanner/-/qr-scanner-1.4.2.tgz", + "integrity": "sha512-kV1yQUe2FENvn59tMZW6mOVfpq9mGxGf8l6+EGaXUOd4RBOLg7tRC83OrirM5AtDvZRpdjdlXURsHreAOSPOUw==", + "license": "MIT", + "dependencies": { + "@types/offscreencanvas": "^2019.6.4" + } + }, "node_modules/qrcode": { "version": "1.5.3", "resolved": "https://registry.npmjs.org/qrcode/-/qrcode-1.5.3.tgz", @@ -4836,12 +4951,13 @@ } }, "node_modules/qs": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", - "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { - "side-channel": "^1.0.4" + "side-channel": "^1.0.6" }, "engines": { "node": ">=0.6" @@ -4892,6 +5008,7 @@ "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", "dev": true, + "license": "MIT", "dependencies": { "bytes": "3.1.2", "http-errors": "2.0.0", @@ -4907,6 +5024,7 @@ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.8" } @@ -5175,7 +5293,8 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/schema-utils": { "version": "4.2.0", @@ -5224,10 +5343,11 @@ } }, "node_modules/send": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", - "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", + "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", "dev": true, + "license": "MIT", "dependencies": { "debug": "2.6.9", "depd": "2.0.0", @@ -5252,6 +5372,7 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, + "license": "MIT", "dependencies": { "ms": "2.0.0" } @@ -5260,13 +5381,25 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true + "dev": true, + "license": "MIT" + }, + "node_modules/send/node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } }, "node_modules/send/node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/serialize-javascript": { "version": "6.0.2", @@ -5356,15 +5489,16 @@ } }, "node_modules/serve-static": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", - "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", + "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", "dev": true, + "license": "MIT", "dependencies": { - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "parseurl": "~1.3.3", - "send": "0.18.0" + "send": "0.19.0" }, "engines": { "node": ">= 0.8.0" @@ -5380,6 +5514,7 @@ "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", "dev": true, + "license": "MIT", "dependencies": { "define-data-property": "^1.1.4", "es-errors": "^1.3.0", @@ -5396,7 +5531,8 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/shallow-clone": { "version": "3.0.1", @@ -5445,6 +5581,7 @@ "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.7", "es-errors": "^1.3.0", @@ -5548,6 +5685,7 @@ "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.8" } @@ -5853,6 +5991,7 @@ "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.6" } @@ -5994,6 +6133,7 @@ "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", "dev": true, + "license": "MIT", "dependencies": { "media-typer": "0.3.0", "mime-types": "~2.1.24" @@ -6045,14 +6185,15 @@ "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.8" } }, "node_modules/update-browserslist-db": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz", - "integrity": "sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz", + "integrity": "sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==", "funding": [ { "type": "opencollective", @@ -6067,9 +6208,10 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { - "escalade": "^3.1.2", - "picocolors": "^1.0.1" + "escalade": "^3.2.0", + "picocolors": "^1.1.0" }, "bin": { "update-browserslist-db": "cli.js" @@ -6302,21 +6444,21 @@ } }, "node_modules/webpack": { - "version": "5.92.1", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.92.1.tgz", - "integrity": "sha512-JECQ7IwJb+7fgUFBlrJzbyu3GEuNBcdqr1LD7IbSzwkSmIevTm8PF+wej3Oxuz/JFBUZ6O1o43zsPkwm1C4TmA==", + "version": "5.96.1", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.96.1.tgz", + "integrity": "sha512-l2LlBSvVZGhL4ZrPwyr8+37AunkcYj5qh8o6u2/2rzoPc8gxFJkLj1WxNgooi9pnoc06jh0BjuXnamM4qlujZA==", "dev": true, + "license": "MIT", "dependencies": { - "@types/eslint-scope": "^3.7.3", - "@types/estree": "^1.0.5", + "@types/eslint-scope": "^3.7.7", + "@types/estree": "^1.0.6", "@webassemblyjs/ast": "^1.12.1", "@webassemblyjs/wasm-edit": "^1.12.1", "@webassemblyjs/wasm-parser": "^1.12.1", - "acorn": "^8.7.1", - "acorn-import-attributes": "^1.9.5", - "browserslist": "^4.21.10", + "acorn": "^8.14.0", + "browserslist": "^4.24.0", "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.17.0", + "enhanced-resolve": "^5.17.1", "es-module-lexer": "^1.2.1", "eslint-scope": "5.1.1", "events": "^3.2.0", diff --git a/package.json b/package.json index 898b808..2ecae79 100755 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "main": "dist/index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", - "build_wasm": "wasm-pack build --out-dir ../ihm_client/dist/pkg ../sdk_client --target bundler --dev", + "build_wasm": "wasm-pack build --out-dir ../ihm_client/pkg ../sdk_client --target bundler --dev", "start": "vite --host 0.0.0.0", "build": "tsc && vite build", "deploy": "sudo cp -r dist/* /var/www/html/", @@ -15,6 +15,7 @@ "author": "", "license": "ISC", "devDependencies": { + "@rollup/plugin-typescript": "^12.1.1", "copy-webpack-plugin": "^12.0.2", "html-webpack-plugin": "^5.6.0", "prettier": "^3.3.3", @@ -32,6 +33,7 @@ "@vitejs/plugin-react": "^4.3.1", "@vitejs/plugin-vue": "^5.0.5", "html5-qrcode": "^2.3.8", + "qr-scanner": "^1.4.2", "qrcode": "^1.5.3", "sweetalert2": "^11.14.5", "vite-plugin-copy": "^0.1.6", diff --git a/src/4nk.css b/src/4nk.css new file mode 100644 index 0000000..5149c3b --- /dev/null +++ b/src/4nk.css @@ -0,0 +1,785 @@ +:root { + --primary-color + : #3A506B; + /* Bleu mΓ©tallique */ + --secondary-color + : #B0BEC5; + /* Gris acier */ + --accent-color + : #D68C45; + /* Cuivre */ +} +body { + font-family: Arial, sans-serif; + margin: 0; + padding: 0; + background-color: #f4f4f4; + background-image: url(../assets/bgd.webp); + background-repeat:no-repeat; + background-size: cover; + background-blend-mode :soft-light; + height: 100vh; + } + .message { + margin: 30px 0; + font-size: 14px; + overflow-wrap: anywhere; + } + + .message strong{ + font-family: "Segoe UI Emoji", "Noto Color Emoji", "Apple Color Emoji", sans-serif; + font-size: 20px; + } + + /** Modal Css */ + .modal { + display: none; + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-color: rgba(0, 0, 0, 0.5); + justify-content: center; + align-items: center; + z-index: 3; + } + + .modal-content { + width: 55%; + height: 30%; + background-color: white; + border-radius: 4px; + padding: 20px; + text-align: center; + display: flex; + flex-direction: column; + align-items: center; + } + + .modal-title { + margin: 0; + padding-bottom: 8px; + width: 100%; + font-size: 0.9em; + border-bottom: 1px solid #ccc; + } + + .confirmation-box { + /* margin-top: 20px; */ + align-content: center; + width: 70%; + height: 20%; + /* padding: 20px; */ + font-size: 1.5em; + color: #333333; + top: 5%; + position: relative; + } + + + .nav-wrapper { + position: fixed; + background: radial-gradient(circle, white, var(--primary-color)); + /* background-color: #CFD8DC; */ + display: flex; + justify-content: flex-end; + align-items: center; + color: #37474F; + height: 9vh; + width: 100vw; + left: 0; + top: 0; + box-shadow: 0px 8px 10px -5px rgba(0, 0, 0, .2), 0px 16px 24px 2px rgba(0, 0, 0, .14), 0px 6px 30px 5px rgba(0, 0, 0, .12); + + .nav-right-icons { + display: flex; + .notification-container { + position: relative; + display: inline-block; + } + .notification-bell, .burger-menu { + z-index: 3; + height: 20px; + width: 20px; + margin-right: 1rem; + } + .notification-badge { + position: absolute; + top: -.7rem; + left: -.8rem; + background-color: red; + color: white; + border-radius: 50%; + padding: 2.5px 6px; + font-size: 0.8em; + font-weight: bold; + } + } + .notification-board { + position: absolute; + width: 20rem; + min-height: 8rem; + background-color: white; + right: 0.5rem; + display: none; + border-radius: 4px; + text-align: center; + display: flex; + flex-direction: column; + align-items: center; + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); + display: none; + + .notification-element { + padding: .8rem 0; + width: 100%; + &:hover { + background-color: rgba(26, 28, 24, .08); + } + } + .notification-element:not(:last-child) { + border-bottom: 1px solid; + } + } + } + + .brand-logo { + height: 100%; + width: 100vw; + align-content: center; + position: relative; + display: flex; + position: absolute; + align-items: center; + justify-content: center; + text-align: center; + font-size: 1.5em; + font-weight: bold; + } + + .container { + text-align: center; + display: grid; + height: 100vh; + grid-template-columns: repeat(7, 1fr); + gap: 10px; + grid-auto-rows: 10vh 15vh 1fr; + } + .title-container { + grid-column: 2 / 7; + grid-row: 2; + } + .page-container { + grid-column: 2 / 7; + grid-row: 3 ; + justify-content: center; + display: flex; + padding: 1rem; + box-sizing: border-box; + max-height: 60vh; + } + + h1 { + font-size: 2em; + margin: 20px 0; + } + @media only screen and (min-width: 600px) { + .tab-container { + display: none; + } + .page-container { + display: flex; + align-items: center; + } + .process-container { + grid-column: 3 / 6; + grid-row: 3 ; + + .card { + min-width: 40vw; + } + } + .separator { + width: 2px; + background-color: #78909C; + height: 80%; + margin: 0 0.5em; + } + .tab-content { + display: flex; + flex-direction: column; + justify-content: space-evenly; + align-items: center; + height: 80%; + } + } + + @media only screen and (max-width: 600px) { + .process-container { + grid-column: 2 / 7; + grid-row: 3 ; + } + .container { + grid-auto-rows: 10vh 15vh 15vh 1fr; + } + .tab-container { + grid-column: 1 / 8; + grid-row: 3; + } + .page-container { + grid-column: 2 / 7; + grid-row: 4 ; + } + .separator { + display: none; + } + .tabs { + display: flex; + flex-grow: 1; + overflow: hidden; + z-index: 1; + border-bottom-style: solid; + border-bottom-width: 1px; + border-bottom-color: #E0E4D6; + } + + .tab { + flex: 1; + text-align: center; + padding: 10px 0; + cursor: pointer; + font-size: 1em; + color: #6200ea; + &:hover { + background-color: rgba(26, 28, 24, .08); + } + } + .tab.active { + border-bottom: 2px solid #6200ea; + font-weight: bold; + } + + .card.tab-content { + display: none; + } + + .tab-content.active { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + height: 80%; + } + .modal-content { + width: 80%; + height: 20%; + } + } + + .qr-code { + display: flex; + justify-content: center; + align-items: center; + height: 200px; + } + + .emoji-display { + font-family: "Segoe UI Emoji", "Noto Color Emoji", "Apple Color Emoji", sans-serif; + font-size: 20px; + + } + + #emoji-display-2{ + margin-top: 30px; + font-family: "Segoe UI Emoji", "Noto Color Emoji", "Apple Color Emoji", sans-serif; + font-size: 20px; + } + + #okButton{ + margin-bottom: 2em; + cursor: pointer; + background-color: #D0D0D7; + color: white; + border-style: none; + border-radius: 5px; + color: #000; + padding: 2px; + margin-top: 10px; + } + + .pairing-request { + font-family: "Segoe UI Emoji", "Noto Color Emoji", "Apple Color Emoji", sans-serif; + font-size: 14px; + margin-top: 0px; + } + + .sp-address-btn { + margin-bottom: 2em; + cursor: pointer; + background-color: #D0D0D7; + color: white; + border-style: none; + border-radius: 5px; + color: #000; + padding: 2px; + + } + + .camera-card { + display: flex; + justify-content: center; + align-items: center; + flex-direction: column; + /* height: 200px; */ + } + + .btn { + display: inline-block; + padding: 10px 20px; + background-color: var(--primary-color); + color: white; + text-align: center; + border-radius: 5px; + cursor: pointer; + text-decoration: none; + } + + .btn:hover { + background-color: #3700b3; + } + + + .card { + min-width: 300px; + border: 1px solid #e0e0e0; + border-radius: 8px; + background-color: white; + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); + box-sizing: border-box; + overflow: hidden; + display: flex; + flex-direction: column; + align-items: center; + text-align: center; + min-height: 40vh; + max-height: 60vh; + justify-content: flex-start; + padding: 1rem; + overflow-y: auto; + + } + + .card-content { + flex-grow: 1; + flex-direction: column; + display: flex; + justify-content: flex-start; + align-items: center; + text-align: left; + font-size: .8em; + position: relative; + left: 2vw; + width: 90%; + .process-title { + font-weight: bold; + padding: 1rem 0; + } + .process-element { + padding: .4rem 0; + &:hover { + background-color: rgba(26, 28, 24, .08); + } + &.selected { + background-color: rgba(26, 28, 24, .08); + } + } + } + + .card-description { + padding: 20px; + font-size: 1em; + color: #333; + width: 90%; + height: 50px; + display: flex; + justify-content: center; + align-items: center; + margin-bottom: 0px; + } + + + .card-action { + width: 100%; + } + + .menu-content { + display: none; + position: absolute; + top: 3.4rem; + right: 1rem; + background-color: white; + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); + border-radius: 5px; + overflow: hidden; + } + + .menu-content a { + display: block; + padding: 10px 20px; + text-decoration: none; + color: #333; + border-bottom: 1px solid #e0e0e0; + &:hover { + background-color: rgba(26, 28, 24, .08); + } + } + + .menu-content a:last-child { + border-bottom: none; + } + + .qr-code-scanner { + display: none; + } + + + /* QR READER */ + #qr-reader div { + position: inherit; + } + + #qr-reader div img{ + top: 15px ; + right: 25px; + margin-top: 5px; + } + + + /* INPUT CSS **/ + .input-container { + position: relative; + width: 100%; + background-color: #ECEFF1; + } + + .input-field { + width: 36vw; + padding: 10px 0; + font-size: 1em; + border: none; + border-bottom: 1px solid #ccc; + outline: none; + background: transparent; + transition: border-color 0.3s; + } + + .input-field:focus { + border-bottom: 2px solid #6200ea; + } + + .input-label { + position: absolute; + margin-top: -0.5em; + top: 0; + left: 0; + padding: 10px 0; + font-size: 1em; + color: #999; + pointer-events: none; + transition: transform 0.3s, color 0.3s, font-size 0.3s; + } + + .input-field:focus + .input-label, + .input-field:not(:placeholder-shown) + .input-label { + transform: translateY(-20px); + font-size: 0.8em; + color: #6200ea; + } + + .input-underline { + position: absolute; + bottom: 0; + left: 50%; + width: 0; + height: 2px; + background-color: #6200ea; + transition: width 0.3s, left 0.3s; + } + + .input-field:focus ~ .input-underline { + width: 100%; + left: 0; + } + + .dropdown-content { + position: absolute; + flex-direction: column; + top: 100%; + left: 0; + width: 100%; + max-height: 150px; + overflow-y: auto; + border: 1px solid #ccc; + border-radius: 4px; + background-color: white; + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); + display: none; + z-index: 1; + } + + .dropdown-content span { + padding: 10px; + cursor: pointer; + list-style: none; + } + + .dropdown-content span:hover { + background-color: #f0f0f0; + } + + + + + /** AUTOCOMPLETE **/ + +select[data-multi-select-plugin] { + display: none !important; +} + +.multi-select-component { + width: 36vw; + padding: 5px 0; + font-size: 1em; + border: none; + border-bottom: 1px solid #ccc; + outline: none; + background: transparent; + display: flex; + flex-direction: row; + height: auto; + width: 100%; + -o-transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s; + transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s; +} + +.autocomplete-list { + border-radius: 4px 0px 0px 4px; +} + +.multi-select-component:focus-within { + box-shadow: inset 0px 0px 0px 2px #78ABFE; +} + +.multi-select-component .btn-group { + display: none !important; +} + +.multiselect-native-select .multiselect-container { + width: 100%; +} + +.selected-processes { + background-color: white; + padding: 0.4em; +} + +.selected-wrapper { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + display: inline-block; + border: 1px solid #d9d9d9; + background-color: #ededed; + white-space: nowrap; + margin: 1px 5px 5px 0; + height: 22px; + vertical-align: top; + cursor: default; +} + +.selected-wrapper .selected-label { + max-width: 514px; + display: inline-block; + overflow: hidden; + text-overflow: ellipsis; + padding-left: 4px; + vertical-align: top; +} + +.selected-wrapper .selected-close { + display: inline-block; + text-decoration: none; + font-size: 14px; + line-height: 1.49em; + margin-left: 5px; + padding-bottom: 10px; + height: 100%; + vertical-align: top; + padding-right: 4px; + opacity: 0.2; + color: #000; + text-shadow: 0 1px 0 #fff; + font-weight: 700; +} + +.search-container { + display: flex; + flex-direction: row; +} + +.search-container .selected-input { + background: none; + border: 0; + height: 20px; + width: 60px; + padding: 0; + margin-bottom: 6px; + -webkit-box-shadow: none; + box-shadow: none; +} + +.search-container .selected-input:focus { + outline: none; +} + +.dropdown-icon.active { + transform: rotateX(180deg) +} + +.search-container .dropdown-icon { + display: inline-block; + padding: 10px 5px; + position: absolute; + top: 5px; + right: 5px; + width: 10px; + height: 10px; + border: 0 !important; + /* needed */ + -webkit-appearance: none; + -moz-appearance: none; + /* SVG background image */ + background-image: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2212%22%20height%3D%2212%22%20viewBox%3D%220%200%2012%2012%22%3E%3Ctitle%3Edown-arrow%3C%2Ftitle%3E%3Cg%20fill%3D%22%23818181%22%3E%3Cpath%20d%3D%22M10.293%2C3.293%2C6%2C7.586%2C1.707%2C3.293A1%2C1%2C0%2C0%2C0%2C.293%2C4.707l5%2C5a1%2C1%2C0%2C0%2C0%2C1.414%2C0l5-5a1%2C1%2C0%2C1%2C0-1.414-1.414Z%22%20fill%3D%22%23818181%22%3E%3C%2Fpath%3E%3C%2Fg%3E%3C%2Fsvg%3E"); + background-position: center; + background-size: 10px; + background-repeat: no-repeat; +} + +.search-container ul { + position: absolute; + list-style: none; + padding: 0; + z-index: 3; + margin-top: 29px; + width: 100%; + right: 0px; + background: #fff; + border: 1px solid #ccc; + border-top: none; + border-bottom: none; + -webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, .175); + box-shadow: 0 6px 12px rgba(0, 0, 0, .175); +} + +.search-container ul :focus { + outline: none; +} + +.search-container ul li { + display: block; + text-align: left; + padding: 8px 29px 2px 12px; + border-bottom: 1px solid #ccc; + font-size: 14px; + min-height: 31px; +} + +.search-container ul li:first-child { + border-top: 1px solid #ccc; + border-radius: 4px 0px 0 0; +} + +.search-container ul li:last-child { + border-radius: 4px 0px 0 0; +} + + +.search-container ul li:hover.not-cursor { + cursor: default; +} + +.search-container ul li:hover { + color: #333; + background-color: #f0f0f0; + ; + border-color: #adadad; + cursor: pointer; +} + +/* Adding scrool to select options */ +.autocomplete-list { + max-height: 130px; + overflow-y: auto; +} + + + +/**************************************** Process page card ******************************************************/ +.process-card { + min-width: 300px; + border: 1px solid #e0e0e0; + border-radius: 8px; + background-color: white; + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); + overflow: hidden; + display: flex; + flex-direction: column; + align-items: center; + text-align: center; + min-height: 40vh; + max-height: 60vh; + justify-content: space-between; + padding: 1rem; + overflow-y: auto; + +} + +.process-card-content { + text-align: left; + font-size: .8em; + position: relative; + left: 2vw; + width: 90%; + .process-title { + font-weight: bold; + padding: 1rem 0; + } + .process-element { + padding: .4rem 0; + &:hover { + background-color: rgba(26, 28, 24, .08); + } + &.selected { + background-color: rgba(26, 28, 24, .08); + } + } + .selected-process-zone { + background-color: rgba(26, 28, 24, .08); + } +} + +.process-card-description { + padding: 20px; + font-size: 1em; + color: #333; + width: 90%; +} + + +.process-card-action { + width: 100%; +} \ No newline at end of file diff --git a/src/decs.d.ts b/src/decs.d.ts new file mode 100644 index 0000000..e482c3e --- /dev/null +++ b/src/decs.d.ts @@ -0,0 +1,10 @@ +declare class AccountComponent extends HTMLElement { + _callback: any; + constructor(); + connectedCallback(): void; + fetchData(): Promise; + set callback(fn: any); + get callback(): any; + render(): void; +} +export { AccountComponent }; diff --git a/src/pages/home/home-component.ts b/src/pages/home/home-component.ts new file mode 100644 index 0000000..94c8605 --- /dev/null +++ b/src/pages/home/home-component.ts @@ -0,0 +1,48 @@ +import loginHtml from './home.html?raw' +import loginScript from './home.ts?raw' +import loginCss from '../../4nk.css?raw' +import { initHomePage } from './home'; + +export class LoginComponent extends HTMLElement { + _callback: any; + constructor() { + super(); + this.attachShadow({ mode: 'open' }); + } + + connectedCallback() { + console.log('CALLBACK LOGIN PAGE') + this.render(); + setTimeout(() => { + initHomePage(); + }, 500); + } + + set callback(fn) { + if (typeof fn === 'function') { + this._callback = fn; + } else { + console.error('Callback is not a function'); + } + } + + get callback() { + return this._callback; + } + + render() { + if(this.shadowRoot) this.shadowRoot.innerHTML = ` + ${loginHtml} +