import { createUserReturn, User } from '../dist/pkg/sdk_client'; import IndexedDB from './database' import Processstore from './store/processstore'; class Services { private static instance: Services; private sdkClient: any; private current_process: string | null = null; // Private constructor to prevent direct instantiation from outside private constructor() {} // Method to access the singleton instance of Services public static async getInstance(): Promise { if (!Services.instance) { Services.instance = new Services(); await Services.instance.init(); } return Services.instance; } // The init method is now part of the instance, and should only be called once private async init(): Promise { this.sdkClient = await import("../dist/pkg/sdk_client"); this.sdkClient.setup(); } // public async getSpAddressDefaultClient(): Promise { // try { // const indexedDB = await IndexedDB.getInstance(); // const db = indexedDB.getDb(); // const spClient = await indexedDB.getObject(db, indexedDB.getStoreList().SpClient, "default"); // if (spClient) { // return this.sdkClient.get_receiving_address(spClient); // } else { // console.error("SP client not found"); // return null; // } // } catch (error) { // console.error("Failed to retrieve object or get sp address:", error); // return null; // } // } public async isNewUser(): Promise { let isNew = false; try { const indexedDB = await IndexedDB.getInstance(); const db = indexedDB.getDb(); let userListObject = await indexedDB.getAll(db, indexedDB.getStoreList().AnkUser); if (userListObject.length == 0) { isNew = true; } } catch (error) { console.error("Failed to retrieve isNewUser :", error); } return isNew; } public async displayCreateId(): Promise { Services.instance.injectHtml(Services.instance.get_html_create_id()); Services.instance.attachSubmitListener("form4nk", (event) => this.createId(event)); Services.instance.attachClickListener("displayrecover", Services.instance.displayRecover); Services.instance.displayProcess(await Services.instance.getAllProcess()); } public get_html_create_id(): string { return this.sdkClient.inject_html_create_id(); } public async createId(event: Event): Promise { event.preventDefault(); const passwordElement = document.getElementById("password") as HTMLInputElement; const processElement = document.getElementById("selectProcess") as HTMLSelectElement; if (!passwordElement || !processElement) { console.error("One or more elements not found"); return; } const password = passwordElement.value; this.current_process = processElement.value; console.log("JS password: " + password + " process: " + this.current_process); // To comment if test // if (!Services.instance.isPasswordValid(password)) return; let label = null; let birthday = 50000; const user: createUserReturn = this.sdkClient.create_user(password, label, birthday, this.current_process); try { const indexedDb = await IndexedDB.getInstance(); const db = indexedDb.getDb(); await indexedDb.writeObject(db, indexedDb.getStoreList().AnkUser, user.user, null); // console.log("JS User added"); await indexedDb.writeObject(db, indexedDb.getStoreList().SpOutputs, user.output_list_vec, null); } catch (error) { console.error("Failed to write user object :", error); } await Services.instance.displayRevokeImage(); } private async getImage(imageUrl:string): Promise { let imageBytes = null; try { const response = await fetch(imageUrl); if (!response.ok) { throw new Error(`Failed to fetch image: ${response.status} ${response.statusText}`); } const arrayBuffer = await response.arrayBuffer(); imageBytes = new Uint8Array(arrayBuffer); console.log(imageBytes); } catch (error) { console.error("Failed to get image : "+imageUrl, error); } return imageBytes; } public async displayRecover(): Promise { Services.instance.injectHtml(Services.instance.get_html_recover()); Services.instance.attachSubmitListener("form4nk", Services.instance.recover); Services.instance.attachClickListener("displaycreateid", Services.instance.displayCreateId); Services.instance.attachClickListener("displayrevoke", Services.instance.displayRevoke); Services.instance.attachClickListener("submitButtonRevoke", Services.instance.revoke); Services.instance.displayProcess(await Services.instance.getAllUserProcess()); } public get_html_recover(): string { return this.sdkClient.inject_html_recover(); } public async recover(event: Event) { event.preventDefault(); console.log("JS recover submit "); const passwordElement = document.getElementById("password") as HTMLInputElement; const processElement = document.getElementById("selectProcess") as HTMLSelectElement; if (!passwordElement || !processElement) { console.error("One or more elements not found"); return; } const password = passwordElement.value; const process = processElement.value; console.log("JS password: " + password + " process: " + process); // To comment if test if (!Services.instance.isPasswordValid(password)) return; // TODO alert("Recover submit to do ..."); } public async displayRevokeImage(): Promise { const html = Services.instance.get_html_revokeimage(); Services.instance.injectHtml(html); Services.instance.attachSubmitListener("form4nk", Services.instance.revokeimage); } public get_html_revokeimage(): string { return this.sdkClient.inject_html_revokeimage(); } public async revokeimage(event: Event): Promise { event.preventDefault(); console.log("JS revokeimage submit "); // TODO alert("Revokeimage submit to do ..., next page Update an id ..."); await Services.instance.displayUpdateAnId(); } public async displayRevoke(): Promise { const html = Services.instance.get_html_revoke(); Services.instance.injectHtml(html); Services.instance.attachClickListener("displayrecover", Services.instance.displayRecover); Services.instance.attachSubmitListener("form4nk", Services.instance.revoke); } public get_html_revoke(): string { return this.sdkClient.inject_html_revoke(); } public async revoke(event: Event): Promise { event.preventDefault(); console.log("JS revoke click "); // TODO alert("revoke click to do ..."); } public async displayUpdateAnId() { let body = ""; let style = ""; let script = ""; try { const indexedDB = await IndexedDB.getInstance(); const db = indexedDB.getDb(); try { let processObject = await indexedDB.getObject(db, indexedDB.getStoreList().AnkProcess, this.current_process!); body = processObject.html; style = processObject.style; script = processObject.script; } catch (error) { console.log("JS Processstore not exist "); } } catch (error) { console.error("Failed to retrieve user object :", error); } Services.instance.injectUpdateAnIdHtml(body, style, script); Services.instance.attachSubmitListener("form4nk", Services.instance.updateAnId); } public injectUpdateAnIdHtml(bodyToInject: string, styleToInject: string, scriptToInject: string) { console.log("JS html : "+bodyToInject); const body = document.getElementsByTagName('body')[0]; if (!body) { console.error("No body tag"); return; } body.innerHTML = styleToInject + bodyToInject; const script = document.createElement("script"); script.innerHTML = scriptToInject; document.body.appendChild(script); script.onload = () => { console.log('Script loaded successfuly'); }; script.onerror = () => { console.log('Error loading script'); }; } public async updateAnId(event: Event): Promise { event.preventDefault(); // TODO get values const firstNameElement = 'firstName'; const lastNameElement = 'lastName'; const firstName = document.getElementById(firstNameElement) as HTMLInputElement; const lastName = document.getElementById(lastNameElement) as HTMLInputElement; console.log("JS updateAnId submit "); // TODO alert("updateAnId submit to do ... Name : "+firstName.value + " "+lastName.value); // TODO Mock add user member to process } public displayProcess(processList: string[]): void { console.log("JS processList : "+processList); const selectProcess = document.getElementById("selectProcess"); if (selectProcess) { processList.forEach((process) => { let child = new Option(process, process); if (!selectProcess.contains(child)) { selectProcess.appendChild(child); } }) } } public async getAllUserProcess(): Promise { let userProcessList: string[] = []; try { const indexedDB = await IndexedDB.getInstance(); const db = indexedDB.getDb(); let processListObject = await indexedDB.getAll(db, indexedDB.getStoreList().AnkProcess); processListObject.forEach(async (processObject) => { const listMember = processObject.listMember; const processName = processObject.process; listMember.forEach(async (member) => { if (member == "user1") { userProcessList.push(processName); console.log("JS UserProcess found"); } }) }) } catch (error) { console.log("JS Processstore not found"); } return userProcessList; } public async getAllProcess(): Promise { // if indexedDB is empty, get list from wasm let processList: string[] = []; try { const indexedDB = await IndexedDB.getInstance(); const db = indexedDB.getDb(); let processListObject = await indexedDB.getAll(db, indexedDB.getStoreList().AnkProcess); processListObject.forEach(async (processObject) => { const processName = processObject.process; processList.push(processName); console.log("JS Processstore found"); }) } catch (error) { console.log("JS Processstore not found"); } if (processList.length == 0) { processList = await this.addProcessStore(); } return processList; } public async addProcessStore(): Promise { const processList = this.sdkClient.get_process() processList.forEach(async (process: string) => { // TODO process mock let processstore = new Processstore; processstore.process = process; const indexedDB = await IndexedDB.getInstance(); const db = indexedDB.getDb(); await indexedDB.writeObject(db, indexedDB.getStoreList().AnkProcess, processstore, process); console.log("JS Processstore mock added"); }) return processList; } public attachClickListener(elementId: string, callback: (event: Event) => void): void { const element = document.getElementById(elementId); element?.removeEventListener("click", callback); element?.addEventListener("click", callback); } public attachSubmitListener(elementId: string, callback: (event: Event) => void): void { const element = document.getElementById(elementId); element?.removeEventListener("submit", callback); element?.addEventListener("submit", callback); } public injectHtml(html: string) { console.log("JS html : "+html); const container = document.getElementById('containerId'); if (!container) { console.error("No html container"); return; } container.innerHTML = html; } // public async getCurrentProcess(): Promise { // let currentProcess = ""; // try { // const indexedDB = await IndexedDB.getInstance(); // const db = indexedDB.getDb(); // currentProcess = await indexedDB.getObject(db, indexedDB.getStoreList().AnkSession, Services.CURRENT_PROCESS); // } catch (error) { // console.error("Failed to retrieve currentprocess object :", error); // } // return currentProcess; // } public isPasswordValid(password: string) { var alertElem = document.getElementById("passwordalert"); var success = true; var strength = 0; if (password.match(/[a-z]+/)) { var strength = 0; strength += 1; } if (password.match(/[A-Z]+/)) { strength += 1; } if (password.match(/[0-9]+/)) { strength += 1; } if (password.match(/[$@#&!]+/)) { strength += 1; } if (alertElem !== null) { // TODO Passer à 18 if (password.length < 4) { alertElem.innerHTML = "Password size is < 4"; success = false; } else { if (password.length > 30) { alertElem.innerHTML = "Password size is > 30"; success = false; } else { if (strength < 4) { alertElem.innerHTML = "Password need [a-z] [A-Z] [0-9]+ [$@#&!]+"; success = false; } } } } return success; } } export default Services;