@aladas-org/cryptocalc
Version:
Cryptocurrency wallet generator
1,244 lines (1,008 loc) • 69.9 kB
JavaScript
// ====================================================================================
// =============================== electron_main.js ===============================
// ====================================================================================
// https://www.electronjs.org/docs/latest/tutorial/quick-start
"use strict";
// =============================== ElectronMain class ===============================
// NB: "Singleton" class
// * static GetInstance()
// createBrowserWindow( url )
// * getMainWindow()
// * getMenuTemplate()
// * createWindow()
// updateWindowTitle()
//
// * async doFileNew()
// * doFileSave()
// * async doFileOpen()
// * async doFileRead( json_data )
//
// * async selectFileOrDirectoryPathWithDialogBox()
// showFolderInExplorer()
//
// * getNewFortuneCookie()
// * toggleDebugPanel()
// * getUserSelectedFile()
//
// readOptionsFile()
// * async loadOptions()
// * async setDefaultOptions()
// * async updateOptions( options_data )
// * async saveOptions( options_data )
// * async resetOptions()
//
// * setCallbacks()
// ------------------------------------------------------
const MAIN_WINDOW_WIDTH = 1040; // NB: 'width' is wider because of 'Cardano'
const MAIN_WINDOW_HEIGHT = 651;
const { app, Menu, BrowserWindow, ipcMain,
shell, remote, dialog } = require('electron');
// https://stackoverflow.com/questions/35916158/how-to-prevent-multiple-instances-in-electron
require('v8-compile-cache');
const os = require('os');
const { exec } = require('child_process');
// https://nodejs.org/api/os.html#os_os_platform
// 'aix', 'darwin', 'freebsd', 'linux', 'openbsd', 'sunos', 'win32'
const WINDOWS = "win32";
const LINUX = "linux";
const FREE_BSD = "freebsd";
const OPEN_BSD = "openbsd";
const fs = require('fs');
const path = require('path');
const { v4: uuidv4 } = require('uuid');
const checkInternetConnected = require('check-internet-connected');
const PasswordGenerator = require('generate-password');
const { _CYAN_, _RED_, _PURPLE_, _YELLOW_, _END_
} = require('../util/color/color_console_codes.js');
const { pretty_func_header_log,
pretty_log } = require('../util/log/log_utils.js');
const { Skribi } = require('../util/log/skribi.js');
const { APP_VERSION,
PROGRAM, ELECTRON_LAUNCHER, EXE_LAUNCHER,
OUTPUT_DIR_PATH, INVALID_OUTPUT_DIR_PATH,
SELECT_DIRECTORY_PATH_MODE, SELECT_FILE_PATH_MODE,
WITS_PATH, PATH, ARGS,
BLOCKCHAIN, BIP32_PASSPHRASE, BIP32_PROTOCOL, ACCOUNT, ADDRESS_INDEX,
TO_RAW_TEXT, TO_BASE64, TO_BASE58, TO_MNEMONICS, TO_BINARY,
FROM_RAW_TEXT, FROM_BASE64, FROM_BASE58, FROM_MNEMONICS, FROM_BINARY
} = require('../const_keywords.js');
const { CRYPTO_NET
} = require('../crypto/const_wallet.js');
const { CMD_OPEN_WALLET,
VIEW_TOGGLE_DEVTOOLS,
TOOLS_OPTIONS, TOOLS_DATABASE_MANAGEMENT,
TOOLS_BIP38_ENCRYPTER_DECRYTER, TOOLS_SECRET_PHRASE_TRANSLATOR,
ToMain_RQ_QUIT_APP,
ToMain_RQ_LOG_2_MAIN, ToMain_RQ_LOG_2_MAIN_SYNC,
ToMain_RQ_GET_APP_PATH,
ToMain_RQ_EXEC_CMD,
ToMain_RQ_SET_WINDOW_TITLE, ToMain_RQ_TOGGLE_DEBUG_PANEL,
ToMain_RQ_SELECT_FILE_OR_DIRECTORY_PATH_DIALOG,
ToMain_RQ_IMPORT_OUTPUT_FILES_IN_DATABASE,
ToMain_RQ_NEW_WALLET_INFO, ToMain_RQ_OPEN_WALLET_INFO, ToMain_RQ_SAVE_WALLET_INFO,
ToMain_RQ_OPEN_URL, ToMain_RQ_SHOW_OUTPUT_FOLDER_IN_EXPLORER,
ToMain_RQ_LOAD_IMG_FROM_FILE, ToMain_RQ_DRAW_RND_CRYPTO_LOGO,
ToMain_RQ_MNEMONICS_TO_ENTROPY_INFO, ToMain_RQ_MNEMONICS_TO_ENTROPY_INFO_CUSTOM,
ToMain_RQ_MNEMONICS_TO_HD_WALLET_INFO,
ToMain_RQ_GET_SIMPLE_WALLET,
ToMain_RQ_ENTROPY_TO_MNEMONICS, ToMain_RQ_ENTROPY_TO_CHECKSUM,
ToMain_RQ_ENTROPY_SRC_TO_ENTROPY,
ToMain_RQ_MNEMONICS_AS_4LETTER, ToMain_RQ_MNEMONICS_AS_TWO_PARTS,
ToMain_RQ_GET_UUID,
ToMain_RQ_GET_L10N_KEYPAIRS, ToMain_RQ_GET_L10N_MSG,
ToMain_RQ_SET_MENU_ITEM_STATE,
ToMain_RQ_CHECK_MNEMONICS,
ToMain_RQ_WORD_INDEX_TO_MNEMONIC, ToMain_RQ_WORD_INDEXES_TO_MNEMONICS,
ToMain_RQ_MNEMONIC_TO_WORD_INDEX, ToMain_RQ_MNEMONICS_TO_WORD_INDEXES,
ToMain_RQ_GUESS_MNEMONICS_LANG,
ToMain_RQ_SAVE_OPTIONS, ToMain_RQ_RESET_OPTIONS, ToMain_RQ_UPDATE_OPTIONS,
ToMain_RQ_GET_FORTUNE_COOKIE,
ToMain_RQ_GENERATE_ENTROPY, ToMain_RQ_GENERATE_PASSWORD,
ToMain_RQ_FROM_HEX_CONVERSIONS, ToMain_RQ_TO_HEX_CONVERSIONS,
ToMain_RQ_GET_HD_WALLET,
ToMain_RQ_BIP38_ENCRYPT, ToMain_RQ_BIP38_DECRYPT,
ToMain_RQ_GET_PASSWORD_STRENGTH,
FromMain_DID_FINISH_LOAD, FromMain_EXEC_CMD,
FromMain_FILE_NEW, FromMain_FILE_OPEN, FromMain_FILE_SAVE,
FromMain_HELP_ABOUT,
FromMain_TOOLS_OPTIONS_DIALOG,
FromMain_TOOLS_DB_MANAGEMENT_DIALOG,
FromMain_TOOLS_BIP38_ENCRYPT_DECRYPT_DIALOG,
FromMain_TOOLS_SECRET_PHRASE_TRANSLATOR_DIALOG,
FromMain_TOOLS_ENTROPY_CONVERTER_DIALOG,
FromMain_UPDATE_OPTIONS,
FromMain_SEND_IMG_URL,
FromMain_SET_FORTUNE_COOKIE,
FromMain_SET_VARIABLE,
FromMain_INTERNET_CONNECTED
} = require('../const_events.js');
const { ENTROPY_SOURCE_IMG_ID,
ENTROPY_CONVERTER_DIALOG_ID
} = require('../view/const_gui.js');
const { DEFAULT_OPTIONS
} = require('../crypto/const_default_options.js');
const { getShortenedString } = require('../util/values/string_utils.js');
const { FileUtils } = require('../util/system/file_utils.js');
const { Bip39Utils } = require('../crypto/bip39_utils.js');
const { Bip38Utils } = require('../crypto/bip38_utils.js');
const { PasswordStrengthEvaluator } = require('../crypto/password_strength_evaluator.js');
const { isHexString, hexToB64, b64ToHex,
hexToBinary, binaryToHex,
getRandomInt, getRandomHexValue } = require('../crypto/hex_utils.js');
const { hexToB58, b58ToHex } = require('../crypto/base58_utils.js');
const { getFortuneCookie } = require('../util/fortune/fortune.js');
const { L10nUtils } = require('../L10n/L10n_utils.js');
const { Bip32Utils } = require('../crypto/HDWallet/bip32_utils.js');
const { HDWallet } = require('../crypto/HDWallet/hd_wallet.js');
const { SimpleWallet } = require('../crypto/SimpleWallet/simple_wallet.js');
const { MainModel } = require('../model/main_model.js');
const { SqLiteUtils } = require('./db/sqlite_utils.js');
const DEFAULT_APP_CONFIG = {
"ToFile": true
}; // DEFAULT_APP_CONFIG
const gotTheLock = app.requestSingleInstanceLock();
const error_handler = (err) => {
if (err) return Skribi.log("error: " + err);
Skribi.log('saving file... '+ filename);
}; // error_handler()
class ElectronMain {
static #Key = Symbol();
static #Singleton = new ElectronMain( this.#Key );
static #InstanceCount = 0;
// Note: KO static get This() {
static GetInstance() {
if ( ElectronMain.#Singleton == undefined ) {
this.#Singleton = new ElectronMain( this.#Key );
if ( this.#InstanceCount > 0 ) {
throw new TypeError("'ElectronMain' constructor called more than once");
}
this.#InstanceCount++;
}
return ElectronMain.#Singleton;
} // ElectronMain.GetInstance()
// ** Private constructor **
constructor( key ) {
if ( key !== ElectronMain.#Key ) {
throw new TypeError("'ElectronMain' constructor is private");
}
this.cryptowallet_version = "x.x.x";
this.app_config = DEFAULT_APP_CONFIG;
this.cmd_line = {};
this.cmd_line[PROGRAM] = ELECTRON_LAUNCHER;
this.cmd_line[PATH] = ".";
this.cmd_line[ARGS] = "";
this.DidFinishLoad_FiredCount = 0;
this.Show_DebugPanel = false;
this.MainWindow = undefined;
this.Options = {};
this.SupportedBlockchains = {};
this.FirstImageAsEntropySource = true;
this.output_path = "";
} // ** Private constructor **
createBrowserWindow( url ) {
const win = new BrowserWindow(
{ height: 900, width: 1200 }
);
win.loadURL( url );
} // createBrowserWindow
getMainWindow() {
return this.MainWindow;
} // getMainWindow()
isLaunchedFromExe() {
if ( this.cmd_line[PROGRAM] == EXE_LAUNCHER ) return true;
return false;
} // isLaunchedFromExe()
getCmdLineArgs() {
let nb_args = process.argv.length;
if ( nb_args > 0 ) {
this.cmd_line[PROGRAM] = path.basename( process.argv[0] );
};
if ( nb_args > 1 ) {
this.cmd_line[PATH] = process.argv[1];
};
if ( nb_args > 2 ) {
this.cmd_line[ARGS] = process.argv[2];
};
let msg = "nb_args: " + nb_args
+ PROGRAM + ": " + this.cmd_line[PROGRAM]
+ PATH + ": " + this.cmd_line[PATH]
+ ARGS + ": " + this.cmd_line[ARGS];
return msg;
} // getCmdLineArgs()
// https://github.com/electron/electron/issues/19775
// https://stackoverflow.com/questions/44391448/electron-require-is-not-defined
getMenuTemplate() {
let ELECTRON_MAIN_MENU_TEMPLATE = [
{ label: L10nUtils.GetLocalizedMsg("File"),
submenu: [ { label: L10nUtils.GetLocalizedMsg("New"),
async click() { await ElectronMain.GetInstance().doFileNew(); }
},
{ label: L10nUtils.GetLocalizedMsg("Open"),
async click() { await ElectronMain.GetInstance().doFileOpen(); }
},
{ label: L10nUtils.GetLocalizedMsg("Save"),
click() { ElectronMain.GetInstance().doFileSave(); },
id: "file_save_menu_item_id"
},
{ label: L10nUtils.GetLocalizedMsg("SaveAs"),
click() { ElectronMain.GetInstance().doFileSaveAs(); },
id: "file_save_as_menu_item_id"
},
{ label: L10nUtils.GetLocalizedMsg("Quit"),
click() { app.quit(); }
}
]
},
{ label: L10nUtils.GetLocalizedMsg("View"),
submenu: [ { label: L10nUtils.GetLocalizedMsg("ToggleDebug"), type: 'checkbox',
click() {
pretty_func_header_log( "[Electron]", VIEW_TOGGLE_DEVTOOLS );
ElectronMain.GetInstance().toggleDebugPanel(); }
}
]
},
{ label: L10nUtils.GetLocalizedMsg("Tools"),
submenu: [ { label: "Options...",
click() {
pretty_func_header_log( "[Electron]", TOOLS_OPTIONS );
ElectronMain.GetInstance().getMainWindow()
.webContents.send
( 'fromMain',
[ FromMain_TOOLS_OPTIONS_DIALOG,
ElectronMain.GetInstance().Options ]
);
}
},
{ label: L10nUtils.GetLocalizedMsg("DatabaseManagementTool"),
click() {
pretty_func_header_log( "[Electron]", TOOLS_DATABASE_MANAGEMENT );
ElectronMain.GetInstance().getMainWindow()
.webContents.send
( 'fromMain',
[ FromMain_TOOLS_DB_MANAGEMENT_DIALOG, SqLiteUtils.This.appFolderPath ]
);
}
},
{ label: L10nUtils.GetLocalizedMsg("SecretPhraseTranslatorTool"),
click() {
pretty_func_header_log( "[Electron]", TOOLS_SECRET_PHRASE_TRANSLATOR );
ElectronMain.GetInstance().getMainWindow()
.webContents.send
( 'fromMain',
[ FromMain_TOOLS_SECRET_PHRASE_TRANSLATOR_DIALOG,
ElectronMain.GetInstance().Options ]
);
}
},
{ label: L10nUtils.GetLocalizedMsg("EntropyConverterTool"),
click() {
pretty_func_header_log( "[Electron]", ENTROPY_CONVERTER_DIALOG_ID );
ElectronMain.GetInstance().getMainWindow()
.webContents.send
( 'fromMain',
[ FromMain_TOOLS_ENTROPY_CONVERTER_DIALOG,
ElectronMain.GetInstance().Options ]
);
}
},
{ label: L10nUtils.GetLocalizedMsg("Bip38EncryptDecryptTool"),
click() {
pretty_func_header_log( "[Electron]", TOOLS_BIP38_ENCRYPTER_DECRYTER );
ElectronMain.GetInstance().getMainWindow()
.webContents.send
( 'fromMain',
[ FromMain_TOOLS_BIP38_ENCRYPT_DECRYPT_DIALOG,
ElectronMain.GetInstance().Options ]
);
}
}
]
},
{ label: L10nUtils.GetLocalizedMsg("Help"), //"Help"
submenu: [ { label: "Setup guide and User's Manual",
click() {
ElectronMain.GetInstance()
.createBrowserWindow( app.getAppPath() + "/_doc/README.html");
}
},
{ label: "Cryptocalc Test protocols",
click() {
ElectronMain.GetInstance()
.createBrowserWindow( app.getAppPath() + "/tests/_doc/index.html");
}
},
{ label: L10nUtils.GetLocalizedMsg("Resources"),
submenu:
[
{ label: "Ian Coleman BIP39",
click() {
// https://stackoverflow.com/questions/53390798/opening-new-window-electron
ElectronMain.GetInstance()
.createBrowserWindow("https://iancoleman.io/bip39/");
}
},
{ label: "Guarda",
click() {
// https://stackoverflow.com/questions/53390798/opening-new-window-electron
ElectronMain.GetInstance()
.createBrowserWindow("https://guarda.com/");
}
}
]
},
{ label: L10nUtils.GetLocalizedMsg("About"), //'About...',
click() {
ElectronMain.GetInstance().getMainWindow()
.webContents.send('fromMain', [ FromMain_HELP_ABOUT ]);
}
}
]
}
]; // menu_template
return ELECTRON_MAIN_MENU_TEMPLATE;
} // getMenuTemplate()
//==================== createWindow() ====================
// https://stackoverflow.com/questions/44391448/electron-require-is-not-defined
createWindow() {
pretty_func_header_log( "ElectronMain.createWindow" );
// Hide 'Security Warning'
process.env['ELECTRON_DISABLE_SECURITY_WARNINGS'] = 'true';
this.MainWindow = new BrowserWindow(
{ width: MAIN_WINDOW_WIDTH,
height: MAIN_WINDOW_HEIGHT,
icon: path.join(__dirname, "../../icons/Cryptocalc_Icon.png"),
webPreferences: {
contextIsolation: true, // NB: 'true' is default value but keep it there anyway
preload: path.join(__dirname, "./preload.js")
}
}
);
console.log( "ElectronMain.createWindow() this.MainWindow: " + typeof this.MainWindow );
MainModel.This.setMainWindow( this.MainWindow );
const menu_bar = Menu.buildFromTemplate( this.getMenuTemplate() );
Menu.setApplicationMenu( menu_bar );
// https://www.electronjs.org/docs/latest/api/web-contents#instance-events
// https://stackoverflow.com/questions/42284627/electron-how-to-know-when-renderer-window-is-ready
// Note: index.html loaded twice (first index.html redirect)
// ==================== 'did-finish-load' event handler ====================
this.MainWindow.webContents.on( 'did-finish-load',
async () => {
Skribi.Initialize( this.app_config );
//Skribi.log(">> " + _CYAN_ + "[*Electron*] " + _YELLOW_ + " did-finish-load --" + _END_);
this.app_config = this.readAppConfig();
// Skribi.log(">> " + _CYAN_ + "eMain.evtH('did-finish-load')> FiredCount: " + this.DidFinishLoad_FiredCount + _END_ );
this.getCmdLineArgs();
// Skribi.log(" ** this.cmd_line: " + JSON.stringify(this.cmd_line) );
Skribi.log(">> " + _CYAN_ + "eMain.evtH('" + _YELLOW_ + "'did-finish-load'"
+ _CYAN_ + ")> this.cmd_line[PROGRAM]: " + _END_ + this.cmd_line[PROGRAM]);
//---------- Set 'Cryptowallet_version' in Renderer GUI ----------
this.cryptowallet_version = MainModel.This.getAppVersion();
//Skribi.log(">> " + _CYAN_ + "eMain.evtH('" + _YELLOW_ + "'did-finish-load'"
// + _CYAN_ + ")> cryptowallet_version: " + _END_ + this.cryptowallet_version);
this.updateWindowTitle();
//---------- Set 'this.cryptowallet_version' in Renderer GUI
this.MainWindow.webContents.send
( "fromMain", [ FromMain_DID_FINISH_LOAD ] );
this.MainWindow.webContents.send
( "fromMain", [ FromMain_SET_VARIABLE, APP_VERSION, this.cryptowallet_version ] );
// https://stackoverflow.com/questions/31749625/make-a-link-from-electron-open-in-browser
// Open urls in the user's browser
// nB: Triggered by 'MainGUI.OnExploreWallet()'
this.MainWindow.webContents.setWindowOpenHandler( (edata) => {
shell.openExternal(edata.url);
return { action: "deny" };
} );
this.setCallbacks();
this.Options = await this.loadOptions();
// =================== Open file by association ===================
let wits_path = this.cmd_line[PATH];
if ( wits_path.endsWith(".wits") ) {
Skribi.log(">> " + _CYAN_ + "eMain.evtH('" + _RED_ + "'did-finish-load'"
+ _CYAN_ + ")> SET_VARIABLE(" + WITS_PATH + ") in Renderer" + _END_ + wits_path);
// await this.openWits( wits_path );
await this.MainWindow.webContents.send
( "fromMain", [ FromMain_SET_VARIABLE, WITS_PATH, wits_path ] );
}
// =================== Open file by association
// Note: will require 'Main' to 'Open Wits' if:
// - 'wits_path' in Renderer is not empty
// and
// - not 'first_time' in Renderer
await this.doFileNew();
} // 'did-finish-load' callback
); // ==================== 'did-finish-load' event handler
// let index_html_path = app.getAppPath() + '/www/index.html';
let index_html_path = path.join(__dirname, '../../../www/index.html');
this.MainWindow.loadFile( index_html_path );
} // createWindow()
async openWits( wits_path ) {
if ( wits_path == undefined ) {
throw new Error("**ERROR** in Cryptowallet: '.wits' path is undefined");
}
Skribi.log(">> " + _CYAN_ + "eMain.evtH('" + _YELLOW_ + "'openWits'"
+ _CYAN_ + ")> *TEST* Trying to Open '.wits': " + _END_ + wits_path);
if ( wits_path.endsWith(".wits") ) {
const json_data_str = fs.readFileSync( wits_path, { encoding: 'utf8', flag: 'r' });
let wits_json_data = JSON.parse( json_data_str );
this.Options = await this.loadOptions();
await this.MainWindow.webContents.send
( "fromMain", [ FromMain_EXEC_CMD, CMD_OPEN_WALLET, wits_json_data ] );
}
} // openWits()
updateWindowTitle( coin, wallet_mode ) {
//pretty_func_header_log( "ElectronMain.updateWindowTitle" );
let window_title = 'Cryptowallet ' + this.cryptowallet_version;
if ( wallet_mode != undefined && wallet_mode != "" ) window_title += " - " + wallet_mode;
if ( coin != undefined && coin != "" ) window_title += ": " + coin;
this.MainWindow.setTitle( window_title );
} // updateWindowTitle()
async doFileNew() {
Skribi.log( ">> " + _CYAN_ + "ElectronMain.doFileNew" + _END_ );
//this.Options = this.readOptionsFile();
this.Options = await this.loadOptions();
await this.MainWindow.webContents
.send( "fromMain", [ FromMain_FILE_NEW, this.Options ] );
} // doFileNew()
doFileSave() {
// pretty_func_header_log( "ElectronMain.doFileSave" );
Skribi.log( ">> " + _CYAN_ + "ElectronMain.doFileSave" + _END_ );
this.MainWindow.webContents.send( "fromMain", [ FromMain_FILE_SAVE ] );
} // doFileSave()
doFileSaveAs() {
// pretty_func_header_log( "ElectronMain.doFileSaveAs" );
Skribi.log( ">> " + _CYAN_ + "ElectronMain.doFileSaveAs" + _END_ );
this.MainWindow.webContents.send( "fromMain", [ FromMain_FILE_SAVE ] );
} // doFileSaveAs()
async doFileOpen( in_file_path ) {
// pretty_func_header_log( "ElectronMain.doFileOpen" );
Skribi.log( ">> " + _CYAN_ + "ElectronMain.doFileOpen" + _END_ );
if ( in_file_path == undefined ) {
let input_path = app.getAppPath() + "\\_output";
in_file_path = await this.selectFileWithDialogBox( input_path, "Wallet Informations", "wits" );
pretty_log( "in_file_path", in_file_path );
if ( in_file_path == "" ) return;
}
const json_data_str = fs.readFileSync( in_file_path, { encoding: 'utf8', flag: 'r' });
//pretty_log( "json_data_str", json_data_str );
let json_data = JSON.parse( json_data_str );
await this.MainWindow.webContents
.send( "fromMain", [ FromMain_FILE_OPEN, json_data ] );
} // doFileOpen()
async selectFileWithDialogBox( input_path, label, extension ) {
pretty_func_header_log( "ElectronMain.selectFileWithDialogBox" );
let in_file_path = "";
// Modal window
let result = await dialog.showOpenDialog( this.MainWindow, {
defaultPath: input_path,
filters: [ { name: label, extensions: [extension] } ],
properties: ['openFile']
});
//.then( result => {
//pretty_log( "result", JSON.stringify(result));
if ( result.filePaths.length > 0 ) {
//pretty_log( "filePaths", JSON.stringify(result.filePaths));
in_file_path = result.filePaths[0];
// pretty_log( "in_file_path", in_file_path);
}
//}).catch(err => {
// Skribi.log(err)
//});
// pretty_log( "in_file_path", in_file_path);
return in_file_path;
} // selectFileWithDialogBox()
async selectFileOrDirectoryPathWithDialogBox( default_path, title, select_mode, path_type ) {
pretty_func_header_log( "ElectronMain.selectFileOrDirectoryPathWithDialogBox" );
if ( select_mode == undefined ) select_mode = SELECT_DIRECTORY_PATH_MODE;
if ( path_type == undefined ) path_type = '';
pretty_log( ">> -=-=-=-=-=-= selectFileOrDirectoryPathWithDialogBox path_type: '" + path_type + "'");
// pretty_log( ">> selectFileOrDirectoryPathWithDialogBox default_path: '" + default_path + "'");
let out_dir_path = "";
let result = undefined;
let selected_file_path = undefined;
if ( select_mode == SELECT_DIRECTORY_PATH_MODE ) {
// ===== Modal window =====
// pretty_log( "====----====----====----====----==== dialog.showOpenDialog");
result = await dialog.showOpenDialog( this.MainWindow, {
'title': title,
'defaultPath': default_path,
properties: ['openDirectory'],
buttonLabel: 'Select'
});
}
else if ( select_mode == SELECT_FILE_PATH_MODE ) {
result = await dialog.showSaveDialog( this.MainWindow, {
'title': title,
'defaultPath': default_path,
filters: [ { name: 'Fichier SQLite', extensions: ['db'] } ],
buttonLabel: 'Select',
showsTagField: false
});
if ( !result.canceled && result.filePath ) {
console.log('Selected file path:', result.filePath);
selected_file_path = result.filePath;
// Handle the save operation
}
}
pretty_log( ">> ---------------- selected_file_path: '" + selected_file_path + "'");
pretty_log( ">> ---------------- result.filePaths: '" + result.filePaths + "'");
pretty_log( ">> ---------------- result.filePath: '" + result.filePath + "'");
pretty_log( ">> ---------------- selected_file_path: '" + selected_file_path + "'");
if ( result.filePaths == undefined ) {
console.log(">> ********* result.filePaths == undefined\n selected_file_path: " + selected_file_path);
out_dir_path = selected_file_path;
if ( ! fs.existsSync( out_dir_path ) ) {
try {
fs.writeFileSync(out_dir_path, '');
console.log('✓ Fichier créé avec succès');
}
catch (err) {
console.error('✗ Erreur:', err.message);
}
}
}
else {
pretty_log( ">> ---------------- result.filePaths.length: '" + result.filePaths.length + "'");
if ( result.filePaths.length > 0 ) {
pretty_log( "filePaths: " + JSON.stringify(result.filePaths));
out_dir_path = result.filePaths[0];
// pretty_log( ">> -------- out_dir_path: '" + out_dir_path + "'");
}
}
// console.log( ">> +++++++++++++++ path_type: '" + path_type + "' vs '" + OUTPUT_DIR_PATH + "'");
if ( path_type == OUTPUT_DIR_PATH ) {
const validate_output_path = ( in_path ) => {
// 2025_ 12_ 15_ 16h- 26m- 24s- 6_ BTC_ EN
// 1 2 3 4 5 6 7 8 9
const pattern = /^(\d{4})_(\d{2})_(\d{2})_(\d{2})h-(\d{2})m-(\d{2})s-(\d+)_([A-Z]{3,4})_([A-Z]{2})$/;
try {
const pattern_match = in_path.match( pattern );
if (! pattern_match ) return false;
const year = parseInt( pattern_match[1], 10 );
// console.log("> year: " + year );
const month = parseInt( pattern_match[2], 10 );
// console.log("> month: " + month );
const day = parseInt( pattern_match[3], 10 );
// console.log("> day: " + day );
const hour = parseInt( pattern_match[4], 10 );
// console.log("> hour: " + hour );
const minute = parseInt( pattern_match[5], 10 );
// console.log("> minute: " + minute );
const second = parseInt( pattern_match[6], 10 );
// console.log("> second: " + second );
const milli_second = parseInt( pattern_match[7], 10 );
// console.log("> milli_second: " + milli_second );
// Validate ranges
if ( month < 1 || month > 12 ) return false;
if ( day < 1 || day > 31 ) return false;
if ( hour < 0 || hour > 23 ) return false;
if ( minute < 0 || minute > 59 ) return false;
if ( second < 0 || second > 59 ) return false;
const coin = pattern_match[8];
// console.log("> coin: " + coin );
const lang = pattern_match[9];
// console.log("> lang: " + lang );
}
catch ( err ) {
console.log("** Parsing Error ** in ElectronMain.selectFileOrDirectoryPathWithDialogBox.validate_output_path" );
return false;
}
return true;
} // validate_output_path()
let at_least_one_wits_file = false;
const sub_dirs = fs.readdirSync( out_dir_path, { withFileTypes: true } );
for ( let i=0; i < sub_dirs.length; i++ ) {
let current_sub_dir = sub_dirs[i];
console.log('> -------- current_sub_dir.path[' + i + ']: ' + current_sub_dir.path);
let subdir_name = current_sub_dir.name;
console.log('> -------- subdir_name[' + i + ']: ' + subdir_name);
let valid_as_ouput_dir_path = validate_output_path( subdir_name );
console.log('> -------- valid_as_ouput_dir_path[' + i + ']: ' + valid_as_ouput_dir_path);
if ( valid_as_ouput_dir_path ) {
let wits_file_path = current_sub_dir.path + '\\' + subdir_name + '\\wallet_info.wits';
console.log('> wits_file_path[' + i + ']: ' + wits_file_path);
if ( fs.existsSync( wits_file_path ) ) {
at_least_one_wits_file = true;
return out_dir_path;
}
}
}
if ( ! at_least_one_wits_file ) return INVALID_OUTPUT_DIR_PATH;
} // if ( path_type == OUTPUT_DIR_PATH )
return out_dir_path;
} // selectFileOrDirectoryPathWithDialogBox()
// https://stackoverflow.com/questions/43991267/electron-open-file-directory-in-specific-application
showFolderInExplorer() {
pretty_func_header_log( "ElectronMain.showFolderInExplorer" );
// Detect OS
// https://www.freecodecamp.org/news/how-to-write-os-specific-code-in-electron-bf6379c62ff6/
let os_platform = os.platform();
// console.log("this.output_path: '" + this.output_path + "'");
let path_separator = '/';
let output_path = this.output_path;
if (os_platform == WINDOWS) {
path_separator = '\\';
}
else if (os_platform == LINUX) {
path_separator = '/';
}
output_path = this.output_path.replaceAll('\\','\0').replaceAll('/','\0');
let output_path_items = output_path.split('\0');
// console.log("output_path_items: '" + JSON.stringify(output_path_items) + "'");
let popped = output_path_items.pop();
output_path = output_path_items.join(path_separator);
// console.log("output_path: '" + output_path + "'");
const open_folder_LINUX = (path) => {
exec(`xdg-open "${path}"`, (error) => {
if (error) {
console.error(`Error opening folder: ${error}`);
}
});
}; // open_folder_LINUX()
// console.log("output_path: 1: '" + output_path + "'");
if (os_platform == WINDOWS) {
// console.log("output_path: '" + output_path + "'");
shell.openPath( output_path );
}
else if (os_platform == LINUX) {
output_path = output_path.replaceAll('\\','/');
// console.log("output_path: '" + output_path + "'");
open_folder_LINUX( output_path );
}
} // showFolderInExplorer()
// File/Import/Random Fortune Cookie
getNewFortuneCookie() {
pretty_func_header_log( "ElectronMain.getNewFortuneCookie" );
let fortune_cookie = getFortuneCookie();
Skribi.log(" fortune_cookie: " + getShortenedString( fortune_cookie) );
this.MainWindow.webContents
.send( "fromMain", [ FromMain_SET_FORTUNE_COOKIE, fortune_cookie ] );
} // getNewFortuneCookie()
toggleDebugPanel() {
pretty_func_header_log( "ElectronMain.toggleDebugPanel" );
this.Show_DebugPanel = ! this.Show_DebugPanel;
if ( this.Show_DebugPanel )
this.MainWindow.webContents.openDevTools();
else
this.MainWindow.webContents.closeDevTools();
} // toggleDebugPanel()
readAppConfig() {
pretty_func_header_log( "ElectronMain.readAppConfig" );
let app_config = DEFAULT_APP_CONFIG;
let config_path = app.getAppPath() + '/www/config';
let app_config_path = config_path + '/app_config.json';
if ( fs.existsSync( app_config_path ) ) {
const app_config_str = fs.readFileSync( app_config_path );
if ( app_config_str != "" && app_config_str != "[]" && app_config_str != "{}" ) {
app_config = JSON.parse( app_config_str );
}
}
return app_config;
} // readAppConfig()
readOptionsFile() {
pretty_func_header_log( "ElectronMain.readOptionsFile" );
let current_options = DEFAULT_OPTIONS;
let config_path = app.getAppPath() + '/www/config';
//Skribi.log("config_path: " + config_path);
let options_path = config_path + '/options.json';
if ( fs.existsSync( options_path ) ) {
const options_str = fs.readFileSync( options_path );
//Skribi.log(" options_str: " + options_str);
if ( options_str != "" && options_str != "[]" && options_str != "{}" ) {
current_options = JSON.parse( options_str );
}
}
return current_options;
} // readOptionsFile()
async loadOptions() {
pretty_func_header_log( "ElectronMain.loadOptions" );
this.Options = this.readOptionsFile();
//Skribi.log(" A this.Options: " + JSON.stringify( this.Options ));
await this.MainWindow.webContents
.send('fromMain', [ FromMain_UPDATE_OPTIONS, this.Options ]);
return this.Options;
} // async loadOptions()
async setDefaultOptions() {
pretty_func_header_log( "ElectronMain.setDefaultOptions" );
this.Options = DEFAULT_OPTIONS;
await this.saveOptions( this.Options );
} // async setDefaultOptions()
async updateOptions( options_data ) {
pretty_func_header_log( "ElectronMain.updateOptions" );
this.Options = options_data;
Skribi.log(" this.Options: " + JSON.stringify( this.Options ));
} // async updateOptions()
async saveOptions( options_data ) {
pretty_func_header_log( "ElectronMain.saveOptions" );
this.Options = options_data;
let config_path = app.getAppPath() + '/www/config';
let options_path = config_path + '/options.json';
fs.writeFileSync( options_path, JSON.stringify( this.Options ) );
Skribi.log(" B this.Options: " + JSON.stringify( this.Options ));
await this.MainWindow.webContents
.send('fromMain', [ FromMain_UPDATE_OPTIONS, options_data ]);
} // async saveOptions()
async resetOptions() {
pretty_func_header_log( "ElectronMain.resetOptions" );
let config_path = app.getAppPath() + '/www/config';
let default_options_path = config_path + '/defaults/options.json';
let default_options_str = fs.readFileSync( default_options_path ).toString();
Skribi.log(" default_options_str: " + default_options_str);
this.Options = JSON.parse( default_options_str );
await this.saveOptions( this.Options );
} // async resetOptions()
setCallbacks() {
Skribi.log(">> " + _CYAN_ + "ElectronMain.setCallbacks" + _END_);
// ====================== ToMain_RQ_QUIT_APP ======================
//Skribi.log(">> register: " + ToMain_RQ_QUIT_APP);
// called like this by Renderer: await window.ipcMain.QuitApp(data)
ipcMain.handle( ToMain_RQ_QUIT_APP, async (event, data) => {
pretty_func_header_log( "[Electron]", ToMain_RQ_QUIT_APP );
app.quit();
}); // "ToMain:Request/quit_app" event handler
// ====================== ToMain_RQ_EXEC_CMD ======================
// called like this by Renderer: await window.ipcMain.ExecuteCommand(data)
ipcMain.handle( ToMain_RQ_EXEC_CMD, async (event, data) => {
pretty_func_header_log( "[Electron]", ToMain_RQ_EXEC_CMD );
const { cmd_name, cmd_args } = data;
Skribi.log( "eMain.evtH('ExecCmd')> cmd_name: " + cmd_name );
Skribi.log( "eMain.evtH('ExecCmd')> cmd_args: " + cmd_args );
if ( cmd_name == CMD_OPEN_WALLET ) {
await ElectronMain.GetInstance().openWits( cmd_args );
}
}); // "ToMain:Request/ExecCmd" event handler
// ====================== ToMain_RQ_LOG_2_MAIN_SYNC ======================
// called like this by Renderer: window.ipcMain.logToMain(data)
ipcMain.on( ToMain_RQ_LOG_2_MAIN, (event, data) => {
Skribi.log( data );
}); // "ToMain:Request/log2main" event handler
// ====================== ToMain_RQ_LOG_2_MAIN_SYNC ======================
// called like this by Renderer: await window.ipcMain.logToMainSync(data)
ipcMain.handle( ToMain_RQ_LOG_2_MAIN_SYNC, async (event, data) => {
Skribi.log( data );
}); // "ToMain:Request/log2main_sync" event handler
// ====================== ToMain_RQ_GET_APP_PATH ======================
// called like this by Renderer: await window.ipcMain.GetAppPath(data)
ipcMain.handle( ToMain_RQ_GET_APP_PATH, async (event, data) => {
pretty_func_header_log( "[Electron]", ToMain_RQ_GET_APP_PATH );
return app.getAppPath();
}); // "ToMain:Request/get_app_path" event handler
// ====================== ToMain_RQ_SET_WINDOW_TITLE ======================
// called like this by Renderer: window.ipcMain.SetWindowTitle(data)
ipcMain.on( ToMain_RQ_SET_WINDOW_TITLE, (event, data) => {
// pretty_func_header_log( "[Electron]", ToMain_RQ_SET_WINDOW_TITLE );
const { coin, wallet_mode } = data;
ElectronMain.GetInstance().updateWindowTitle( coin, wallet_mode );
}); // "ToMain:Request/set_window_title" event handler
// ========================== ToMain_RQ_TOGGLE_DEBUG_PANEL ==========================
// called like this by Renderer: window.ipcMain.ToggleDebugPanel(data)
ipcMain.on( ToMain_RQ_TOGGLE_DEBUG_PANEL, (event, data) => {
ElectronMain.GetInstance().toggleDebugPanel();
}); // "ToMain:Request/toggle_debug_panel" event handler
// ==================== ToMain_RQ_SHOW_OUTPUT_FOLDER_IN_EXPLORER ====================
// called like this by Renderer: window.ipcMain.ShowOutputFolderInExplorer()
ipcMain.on( ToMain_RQ_SHOW_OUTPUT_FOLDER_IN_EXPLORER, (event, data) => {
pretty_func_header_log( "[Electron]", ToMain_RQ_SHOW_OUTPUT_FOLDER_IN_EXPLORER );
// let output_path = app.getAppPath() + "\\_output";
this.showFolderInExplorer();
}); // "ToMain:Request/show_output_folder_in_explorer" event handler
// ====================== ToMain_RQ_OPEN_URL ======================
// called like this by Renderer: window.ipcMain.OpenURL(url)
ipcMain.on( ToMain_RQ_OPEN_URL, (event, url) => {
pretty_func_header_log( "[Electron]", ToMain_RQ_OPEN_URL );
Skribi.log("eMain.evtH('OpnURL')> " + url);
// https://stackoverflow.com/questions/31749625/make-a-link-from-electron-open-in-browser
this.MainWindow.location = url;
}); // "ToMain:Request/open_URL" event handler
// ====================== ToMain_RQ_SELECT_FILE_OR_DIRECTORY_PATH_DIALOG ======================
Skribi.log(">> register ToMain_RQ_SELECT_FILE_OR_DIRECTORY_PATH_DIALOG: '" + ToMain_RQ_SELECT_FILE_OR_DIRECTORY_PATH_DIALOG + "'");
// called like this by Renderer: await window.ipcMain.selectFileOrDirectoryPathWithDialogBox( data )
ipcMain.handle( ToMain_RQ_SELECT_FILE_OR_DIRECTORY_PATH_DIALOG, async ( event, data ) => {
pretty_func_header_log( "[Electron]", ToMain_RQ_SELECT_FILE_OR_DIRECTORY_PATH_DIALOG );
Skribi.log( "eMain.evtH('selectFileOrDirPath')>" );
let { default_path, title, select_mode, path_type } = data;
return await ElectronMain.GetInstance().selectFileOrDirectoryPathWithDialogBox( default_path, title, select_mode, path_type );
}); // "ToMain:Request/select_file_of_directory_path_dialog" event handler
// ====================== ToMain_RQ_IMPORT_OUTPUT_FILES_IN_DATABASE ======================
Skribi.log(">> register ToMain_RQ_IMPORT_OUTPUT_FILES_IN_DATABASE: '" + ToMain_RQ_IMPORT_OUTPUT_FILES_IN_DATABASE + "'");
// called like this by Renderer: await window.ipcMain.ImportOutputFilesInDatabase( data )
ipcMain.handle( ToMain_RQ_IMPORT_OUTPUT_FILES_IN_DATABASE, async ( event, data ) => {
pretty_func_header_log( "[Electron]", ToMain_RQ_IMPORT_OUTPUT_FILES_IN_DATABASE );
Skribi.log( "eMain.evtH(importOutpuFilesInDB')>" );
let { output_dirs_path, db_path } = data;
await SqLiteUtils.This.importWallets( output_dirs_path, db_path );
}); // "ToMain:Request/import_output_files_in_database" event handler
// ====================== ToMain_RQ_NEW_WALLET_INFO ======================
//Skribi.log(">> register: " + ToMain_RQ_NEW_WALLET_INFO);
// called like this by Renderer: await window.ipcMain.NewWalletInfo( data )
ipcMain.handle( ToMain_RQ_NEW_WALLET_INFO, async ( event, data ) => {
pretty_func_header_log( "[Electron]", ToMain_RQ_NEW_WALLET_INFO );
Skribi.log( "eMain.evtH('NewWinf')>" );
await ElectronMain.GetInstance().doFileNew();
}); // "ToMain:Request/new_wallet_info" event handler
// ====================== ToMain_RQ_OPEN_WALLET_INFO ======================
// called like this by Renderer: await window.ipcMain.OpenWalletInfo( data )
ipcMain.handle( ToMain_RQ_OPEN_WALLET_INFO, async ( event, data ) => {
pretty_func_header_log( "[Electron]", ToMain_RQ_OPEN_WALLET_INFO );
await ElectronMain.GetInstance().doFileOpen();
}); // "ToMain:Request/open_wallet_info" event handler
// ====================== ToMain_RQ_SAVE_WALLET_INFO ======================
//Skribi.log(">> register: " + ToMain_RQ_SAVE_WALLET_INFO);
// called like this by Renderer: window.ipcMain.SaveWalletInfo( data )
ipcMain.handle( ToMain_RQ_SAVE_WALLET_INFO, async ( event, crypto_info ) => {
pretty_func_header_log( "[Electron]", ToMain_RQ_SAVE_WALLET_INFO );
Skribi.log( "eMain.evtH('SaveWinf')>" );
this.output_path = await MainModel.This.saveWalletInfo( crypto_info );
}); // "ToMain:Request/save_wallet_info" event handler
// ====================== ToMain_RQ_RESET_OPTIONS ======================
// called like this by Renderer: await window.ipcMain.ResetOptions( data )
ipcMain.handle( ToMain_RQ_RESET_OPTIONS, async (event, data) => {
pretty_func_header_log( "[Electron]", ToMain_RQ_RESET_OPTIONS );
Skribi.log( "eMain.evtH('RstOpt')>" );
ElectronMain.GetInstance().resetOptions();
}); // "ToMain:Request/reset_options" event handler
// ====================== ToMain_RQ_UPDATE_OPTIONS ======================
// called like this by Renderer: await window.ipcMain.UpdateOptions( options_data )
ipcMain.handle( ToMain_RQ_UPDATE_OPTIONS, async (event, options_data) => {
pretty_func_header_log( "[Electron]", ToMain_RQ_UPDATE_OPTIONS );
if ( options_data == undefined ) {
Skribi.log(">> " + _RED_ + ToMain_RQ_QUIT_APP + _END_);
app.quit();
}
// Skribi.log( "eMain.evtH('UpOpt')> options_data: " + JSON.stringify(options_data));
this.Options = options_data;
Skribi.log( "eMain.evtH('UpOpt')> this.Options: " + JSON.stringify( this.Options ));
await this.MainWindow.webContents
.send('fromMain', [ FromMain_UPDATE_OPTIONS, this.Options ]);
}); // "ToMain:Request/update_options" event handler
// ====================== ToMain_RQ_SAVE_OPTIONS ======================
//Skribi.log(">> register: " + ToMain_RQ_SAVE_OPTIONS);
// called like this by Renderer: await window.ipcMain.SaveOptions( options_data )
ipcMain.handle( ToMain_RQ_SAVE_OPTIONS, async (event, data) => {
pretty_func_header_log( "[Electron]", ToMain_RQ_SAVE_OPTIONS );
let options_data = data;
pretty_log( "eMain.evtH('SaveOpt')> options_data: " + JSON.stringify(options_data) );
ElectronMain.GetInstance().saveOptions( options_data );
pretty_log( "eMain.evtH('SaveOpt')> this.Options: " + JSON.stringify( this.Options ) );
await this.MainWindow.webContents
.send( 'fromMain', [ FromMain_UPDATE_OPTIONS, options_data ] );
}); // "ToMain:Request/save_options" event handler
const loadImageFromFile = ( image_file_path ) => {
let img_data_asURL = fs.readFileSync( image_file_path, {encoding: 'base64'} );
let image_file_path_items = image_file_path.split('.');
let image_file_extension = "png";
let items_count = image_file_path_items.length;
if (items_count > 1) {
image_file_extension = image_file_path_items[items_count-1].toLowerCase();
if (image_file_extension == "jpg") {
image_file_extension = "jpeg";
}
else if (image_file_extension == "svg") {
image_file_extension = "svg+xml";
}
}
//Skribi.log(" image_file_extension: " + image_file_extension);
//Skribi.log(" img_data_asURL:\n" + img_data_asURL);
this.MainWindow.webContents
.send('fromMain',
[ FromMain_SEND_IMG_URL, ENTROPY_SOURCE_IMG_ID,
img_data_asURL, image_file_extension ]);
return img_data_asURL;
}; // loadImageFromFile
// ====================== ToMain_RQ_LOAD_IMG_FROM_FILE ======================
// called like this by Renderer: await window.ipcMain.LoadImageFromFile(data)
ipcMain.handle( ToMain_RQ_LOAD_IMG_FROM_FILE, async (event, image_file_path) => {
pretty_func_header_log( "[Electron]", ToMain_RQ_LOAD_IMG_FROM_FILE );
let img_data_asURL = loadImageFromFile( image_file_path );
return img_data_asURL;
}); // "ToMain:Request/load_image_from_file" event handler
// ====================== ToMain_RQ_DRAW_RND_CRYPTO_LOGO ======================
//Skribi.log(">> register: " + ToMain_RQ_DRAW_RND_CRYPTO_LOGO);
// called like this by Renderer: await window.ipcMain.DrawRandomCryptoLogo(data)
ipcMain.handle( ToMain_RQ_DRAW_RND_CRYPTO_LOGO, (event, data) => {
pretty_func_header_log( "[Electron]", ToMain_RQ_DRAW_RND_CRYPTO_LOGO );
let app_path = app.getAppPath();
//Skribi.log(" app_path: " + app_path);
let crypto_logos_path = app_path + "/www/img/CryptoCurrency";
let crypto_logos = FileUtils.GetFilesInFolder( crypto_logos_path );
//Skribi.log(" crypto_logos.length: " + crypto_logos.length);
let image_file_path = crypto_logos_path + "/";
let crypto_logo_filename = "Zilver_64px.svg";
if (! this.FirstImageAsEntropySource ) {
let random_index = getRandomInt( crypto_logos.length );
crypto_logo_filename = crypto_logos[random_index];
}
this.FirstImageAsEntropySource = false;
image_file_path += crypto_logo_filename;
let img_data_asURL = loadImageFromFile( image_file_path );
return img_data_asURL;
}); // "ToMain:Request/drop_rnd_crypto_logo" event handler
// ================== ToMain_RQ_GENERATE_ENTROPY ==================
// called like this by Renderer: await window.ipcMain.GenerateEntropy( data )
// https://www.npmjs.com/package/generate-password
ipcMain.handle( ToMain_RQ_GENERATE_ENTROPY, async (event, data) => {
pretty_func_header_log( "[Electron]", ToMain_RQ_GENERATE_ENTROPY );
let entropy_size = data;
let bytes_count = data / 8;
let random_entropy_hex = getRandomHexValue( bytes_count );
return random_entropy_hex;
}); // "ToMain:Request/GenerateEntropy event handler
// ================== ToMain_RQ_GENERATE_PASSWORD ==================
// called like this by Renderer: await window.ipcMain.GeneratePassword( data )
// https://www.npmjs.com/package/generate-password
ipcMain.handle( ToMain_RQ_GENERATE_PASSWORD, async (event, data) => {
pretty_func_header_log( "[Electron]", ToMain_RQ_GENERATE_PASSWORD );
// const {} = data;
let new_password = PasswordGenerator.generate({
length: 24,
numbers: true,
symbols: true,
uppercase: true,
lowercase: true,
excludeSimilarCharacters : true,
strict: true
});
return new_password;
}); // "ToMain:Request/GeneratePassword event handler
// ================== ToMain_RQ_FROM_HEX_CONVERSIONS ==================
// called like this by Renderer: await window.ipcMain.ConvertFromHexToBases( data )
// https://www.npmjs.com/package/generate-password
ipcMain.handle( ToMain_RQ_FROM_HEX_CONVERSIONS, async (event, data) => {
pretty_func_header_log( "[Electron]", ToMain_RQ_FROM_HEX_CONVERSIONS );
let hex_str = data;
const validateString = ( in_str ) => {
// Cette regex accepte :
// - Lettres majuscules/minuscules (incluant accentuées)
// - Chiffres
// - Caractères spéciaux courants
const regex = /^[a-zA-Z0-9À-ÿ\s\p{P}\p{S}]+$/u;
return regex.test( in_str );
}; // validateString()
const hex_to_ascii = ( hex_value ) => {
let hex_str = hex_value.toString(); // force conversion
console.log(" hex_str: " + hex_str);
let ascii_str = '';
for (let i = 0; i < hex_str.length; i += 2) {
let hex_byte = hex_str.substr(i, 2);
// console.log(" hex_byte(" + i + "): " + hex_byte);
let char_code = parseInt( hex_byte, 16 );
// console.log(" char_code(" + i + "): " + char_code);
// if ( char_code >= 32 ) {
let new_character = String.fromCharCode(char_code);
if ( validateString( new_character ) ) {
ascii_str += new_character;
// console.log(" ascii_str(" + i + "): " + ascii_str);
}
}
return ascii_str;
}; // hex_to_ascii()
let raw_text_value = '';
let base64_value = '';
let base58_value = '';
// let mnemonics_value = '';
let binary_value = '';
raw_text_value = hex_to_ascii( hex_str );
base64_value = hexToB64( hex_str );
base58_value = hexToB58( hex_str );
binary_value = hexToBinary( hex_str );
// mnemonics_value = hexa_to_ascii( hex_str );
let conversions_to_bases = {
[TO_RAW_TEXT]: raw_text_value,
[TO_BASE64]: base64_value,
[TO_BASE58]: base58_value,
[TO_BINARY]: binary_value
};
// console.log(" conversions_to_bases: " + JSON.stringify(conversions_to_bases));
return conversions_to_bases;
}); // "ToMain:Request/from_hex_conversions event handler
// ================== ToMain_RQ_TO_HEX_CONVERSIONS ==================
// called like this by Renderer: await window.ipcMain.ConvertFromBasesToHex( data )
// https://www.npmjs.com/package/generate-password
ipcMain.handle( ToMain_RQ_TO_HEX_CONVERSIONS, async (event, data) => {
pretty_func_header_log( "[Electron]", ToMain_RQ_TO_HEX_CONVERSIONS );
let bases_data = data;
const ascii_to_hex = ( in_str ) => {
// Initialize an empty array to store the hexadecimal values
let hex_str = [];
// Iterate through each character in the input string
for (let i = 0; i < in_str.length; i++) {
// Convert the ASCII value of the current character to its hexadecimal re