@aladas-org/cryptocalc
Version:
Cryptocurrency wallet generator
797 lines (657 loc) • 32.1 kB
JavaScript
// ======================================================================================================================
// ================================================ sqlite_util.js ================================================
// ======================================================================================================================
"use strict";
// const sqlite3 = require('sqlite3');
const bcrypt = require('bcrypt');
let sqlite3 = undefined; // require in openDatabase()
const fs = require('fs');
const path = require('path');
const os = require('os');
const { getDayTimestamp } = require('../../util/system/timestamp.js');
const { DatabaseStateChecker } = require('./db_state_checker');
const CRYPTOCALC_DB_LANGS = [ ['EN','English',1], ['FR','French',1], ['ES','Spanish',1], ['IT','Italian',1],
['PT','Portuguese',1], ['CS','Czech',1],
['JP','Japanese',1], ['SC','Simplified Chinese',1], ['TC','Traditional Chinese',1], ['KO','Korean',1],
['DE','Deutsch',0], ['EO','Esperanto',0], ['LA','Latin',0], ['EL','Greek',0], ['EL','Greek',0],
['RU','Russian',0], ['HI','Hindi',0], ['BN','Bengali',0], ['GU','Gujarati',0]
];
const CRYPTOCALC_DB_COINS = [ "BTC", "ETH", "XRP", "BNB", "SOL", "DOGE", "TRX", "ADA", "XLM", "SUI", "BCH",
"AVAX", "TON", "LTC", "ETC", "POL", "VET", "BSV", "DASH", "RVN", "ZEN", "LUNA", "FIRO" ];
const CRYPTOCALC_DB_BLOCKCHAINS = [ "Bitcoin", "Ethereum", "Ripple", "Binance Smart Chain", "Solana", "Dogecoin", "TRON",
"Cardano", "Stellar", "Sui", "Bitcoin Cash)", "Avalanche", "Toncoin", "Litecoin", "Ethereum Classic",
"Polygon", "VeChain", "Bitcoin SV", "Dash", "Ravencoin", "Horizen", "Terra", "Firo" ];
// ERC-20: The standard for fungible tokens. This is what people mean by "ERC tokens" 95% of the time (USDT, UNI, LINK, SHIB, etc.).
// ERC-721: The standard for Non-Fungible Tokens (NFTs). Each token is unique (BAYC, CryptoPunks).
// ERC-1155: A multi-token standard allowing for both fungible and non-fungible tokens in a single contract (common in gaming).
// ERC-4337: The new standard for "account abstraction," enabling smart contract wallets for better UX and security (gaining traction in 2024).
const CRYPTOCALC_DB_TOKEN_TYPES = [ 'ERC-20', 'ERC-721', 'ERC-1155', 'ERC-4337' ];
const CRYPTOCALC_DB_PREDEFINED_SQL_QUERIES = [ [ "Extract by Coin Type",
"SELECT * FROM WALLET WHERE coin = 'BTC'" ],
[ "Extract by Wallet Mode",
"SELECT * FROM WALLET WHERE wallet_mode = 'HD Wallet'" ],
[ "Extract by Wallet Mode + Entropy + Account",
"SELECT * FROM WALLET WHERE wallet_mode = 'HD Wallet' "
+ "AND entropy='80422dac5cd7aa60cf45c01b4b71abcc09ba23cc29feabe2f50d7ff478b27180'"
+ "AND account='33'" ],
[ "Extract between 2 Timestamps",
"SELECT * FROM WALLET "
+ "WHERE time_stamp "
+ "BETWEEN '2025-12-18 19:44:28.500' "
+ "AND '2025-12-20 13:08:45.000' "
+ "ORDER BY time_stamp ASC" ]
];
const CRYPTOCALC_DB_ORGANIZATIONS = [ [ "The Pile of Leaves", "A fictional organization.\nIndeed it's a Geek's reference to Zork\nthe (in)famous Text Adventure Game",
'https://iplayif.com/?story=http%3A%2F%2Fwww.ifarchive.org%2Fif-archive%2Fgames%2Fzcode%2Fzdungeon.z5', '', '', '' ],
[ 'Aladas.org', 'Protection of Wild Bees', 'https://aladas.org/', '', '', '' ]
];
const CRYPTOCALC_DB_DEFAULT_OWNER_ID = 'Nobody';
const CRYPTOCALC_DB_OWNERS = [ [ CRYPTOCALC_DB_DEFAULT_OWNER_ID, "The Pile of Leaves", '', '', '' ]
];
// =========================================================================================================
// ======================================== SQLiteUtils class ========================================
// =========================================================================================================
class SqLiteUtils {
static #Key = Symbol();
static #Singleton = null;
static #InstanceCount = 0;
static #isInitializing = false;
static async GetInstance() {
if (! SqLiteUtils.#Singleton) {
SqLiteUtils.#Singleton = new SqLiteUtils(SqLiteUtils.#Key);
if (SqLiteUtils.#InstanceCount > 0) {
throw new TypeError("'SqLiteUtils' constructor called more than once");
}
SqLiteUtils.#InstanceCount++;
await SqLiteUtils.#Singleton.initialize();
}
return SqLiteUtils.#Singleton;
} // static GetInstance()
static get This() {
if ( ! SqLiteUtils.#Singleton ) {
throw new Error("SqLiteUtils not initialized. Use GetInstance() instead.");
}
return SqLiteUtils.#Singleton;
} // 'This' getter
// ** Private constructor **
constructor( key ) {
if ( key !== SqLiteUtils.#Key ) {
throw new TypeError("'SqLiteUtils' constructor is private");
}
this.local_app_data_path = process.env.LOCALAPPDATA;
this.app_folder_path = path.join( this.local_app_data_path, 'Aladas-org/Cryptocalc');
// Créer le dossier (ne fait rien s'il existe)
if ( ! fs.existsSync( this.app_folder_path ) ) {
fs.mkdirSync( this.app_folder_path, { recursive: true } );
}
this.DEBUG = true;
this.db_obj = null;
this.db_file_path = '';
this.initialized = false;
} // ** Private constructor **
async initialize() {
console.log('>> SqLiteUtils.initialize() this.initialized: ' + this.initialized);
if ( this.initialized ) return;
this.db_file_path = path.join( this.app_folder_path, 'Cryptocalc.db');
if ( this.existsFileSync( this.db_file_path ) ) {
// console.log(' file already created: ' + this.db_file_path);
}
else {
console.log(" Create File: '"+ this.db_file_path + "'");
fs.writeFileSync( this.db_file_path, '' );
console.log('<Done> Fichier DB créé: ' + this.db_file_path);
}
// Initialize database connection
this.db_obj = await this.openDatabase( this.DEBUG );
console.log('<Done> Connecté à la base de données');
let db_state = await DatabaseStateChecker.CheckDatabaseState( this.db_obj );
console.log( '>> SqLiteUtils.initialize(): db_state["isOpen"]: ' + db_state["isOpen"] + ' db_state["isClosed"]: ' + db_state["isClosed"]);
let db_is_opened = await this.isDatabaseOpened();
console.log('>> SqLiteUtils.initialize(): Check if Database Opened: ' + db_is_opened);
if ( db_is_opened ) {
await this.closeDatabase();
}
// Enable WAL mode and foreign keys
await this.dbRun(`PRAGMA journal_mode = WAL`);
await this.dbRun(`PRAGMA foreign_keys = ON`);
await this.dbRun(`PRAGMA foreign_key_check`);
console.log('<Done> Clés étrangères activées');
await this.initSchema();
await this.initDB();
this.initialized = true;
} // async initialize()
async isDatabaseOpened() {
if ( this.db_obj == null ) return false;
let db_state = await DatabaseStateChecker.CheckDatabaseState( this.db_obj );
return ( db_state["isOpen"] == false && db_state["isClosed"] == false );
} // async isDatabaseOpened()
async openDatabase() {
console.error('>> SqLiteUtils.openDatabase() this.DEBUG: ' + this.DEBUG );
// if ( this.DEBUG ) sqlite3 = require('sqlite3').verbose();
// else sqlite3 = require('sqlite3');
sqlite3 = require('sqlite3').verbose();
let result = new Promise( (resolve, reject) => {
this.db_obj = new sqlite3.Database
( this.db_file_path,
( err ) => { if ( err ) { reject( err ); }
else { resolve( this.db_obj ); }
}
);
});
return result;
} // async openDatabase()
// Note: to call this function use 'await' ( eg. this.closeDatabase() )
closeDatabase() {
return new Promise( (resolve, reject) => {
if ( ! this.db_obj ) {
console.warn('<Error> Aucune base à fermer');
resolve();
return;
}
console.log('<TRY> Tentative de fermeture...');
this.db_obj.close( (err) => {
if ( err ) {
console.error('<KO> Erreur fermeture:', err.message);
reject( err );
} else {
console.log('<Done> Base fermée avec succès');
resolve();
}
});
this.initialized = false;
});
} // SQLiteUtils.closeDatabase()
async initDB() {
console.error('>> SqLiteUtils.initDB()');
await this.initAdminUser();
// ============================== Create 'OWNER' table ==============================
try {
await this.dbRun(`CREATE TABLE IF NOT EXISTS "OWNER" (
"id" TEXT PRIMARY KEY,
"organization" TEXT,
"email" TEXT,
"phone" TEXT,
"address" TEXT,
FOREIGN KEY ( organization ) REFERENCES ORGANIZATION( id ) )
`);
let owner_data = CRYPTOCALC_DB_OWNERS[0];
await this.dbRun(
`INSERT OR IGNORE INTO "OWNER" ( id, organization, email, phone, address )
VALUES ( ?, ?, ?, ?, ? )`,
[ owner_data[0], owner_data[1], owner_data[2], owner_data[3], owner_data[4] ]
);
console.log('<Done> Table "OWNER" créée/verifiée');
} catch (err) {
console.error('<Error> création table "OWNER":\n' + err);
throw err;
}
// ============================== Create 'OWNER' table
// =================================== Create 'WALLET' table ===================================
try {
await this.dbRun(`CREATE TABLE IF NOT EXISTS "WALLET" (
"id" INTEGER PRIMARY KEY AUTOINCREMENT,
"name" TEXT,
"owner" TEXT,
"time_stamp" TEXT ,
"wallet_mode" VARCHAR(15),
"blockchain" TEXT,
"coin" VARCHAR(7),
"balance" REAL,
"comment" TEXT,
"entropy" TEXT,
"entropy_size" INTEGER,
"wallet_address" TEXT,
"bc_explorer_url" TEXT,
"private_key" TEXT,
"bip38_passphrase" TEXT,
"bip38_encrypted_pk" TEXT,
"wif" TEXT,
"secret_phrase" TEXT,
"word_indexes" TEXT,
"bip32_passphrase" TEXT,
"derivation_path" TEXT,
"account" INTEGER,
"address_index" INTEGER,
"lang" VARCHAR(3),
"version" VARCHAR(10),
FOREIGN KEY ( owner ) REFERENCES OWNER( id ),
FOREIGN KEY ( coin ) REFERENCES COIN( id ),
FOREIGN KEY ( blockchain ) REFERENCES BLOCKCHAIN( id ),
FOREIGN KEY ( wallet_mode ) REFERENCES WALLET_MODE( id ),
FOREIGN KEY ( lang ) REFERENCES LANG( id ),
UNIQUE( name) )
`);
console.log('<Done> Table "WALLET" créée/verifiée');
} catch (err) {
console.error("<Error> création table 'WALLET': \n" + err);
throw err;
}
// =================================== Create 'WALLET' table
// ============================== Create 'WALLET_TO_TOKEN_TYPE' table ==============================
try {
await this.dbRun(`CREATE TABLE IF NOT EXISTS "WALLET_TO_TOKEN_TYPE" (
"id" INTEGER PRIMARY KEY AUTOINCREMENT,
"quantity" REAL,
"comment" TEXT,
"wallet" TEXT,
"token_type" TEXT,
FOREIGN KEY ( wallet ) REFERENCES WALLET( name ),
FOREIGN KEY ( token_type ) REFERENCES TOKEN_TYPE( id ) )
`);
console.log('<Done> Table "WALLET_TO_TOKEN_TYPE" créée/verifiée');
} catch (err) {
console.error('<Error> création table "WALLET_TO_TOKEN_TYPE":\n' + err);
throw err;
}
// ============================== Create 'WALLET_TO_TOKEN_TYPE' table
} // async initDB()
async initSchema() {
console.error('>> SqLiteUtils.initSchema()');
// Check if "LANG" table exists
const row = await this.dbGet(`SELECT "name" FROM "sqlite_master" WHERE type='table' AND name='LANG'`);
// ( ! row ) {
await this.initConstantTables();
//}
} // async initSchema()
async initAdminUser() {
console.error('>> SqLiteUtils.initAdminUser()');
// Check if USERS table exists
const row = await this.dbGet(`SELECT "name" FROM "sqlite_master" WHERE type='table' AND name='USERS'`);
if ( ! row ) {
// ============================== Create 'USERS' table ==============================
try {
await this.dbRun(`CREATE TABLE IF NOT EXISTS "USERS" (
"id" INTEGER PRIMARY KEY AUTOINCREMENT,
"username" TEXT UNIQUE NOT NULL,
"email" TEXT UNIQUE NOT NULL,
"password_hash" TEXT NOT NULL,
"is_admin" BOOLEAN DEFAULT 0,
"is_active" BOOLEAN DEFAULT 1,
"can_manage_users" BOOLEAN DEFAULT 0,
"can_manage_content" BOOLEAN DEFAULT 0,
"can_view_logs" BOOLEAN DEFAULT 0,
"full_name" TEXT,
"last_login" DATETIME,
"created_at" DATETIME DEFAULT CURRENT_TIMESTAMP,
"updated_at" DATETIME DEFAULT CURRENT_TIMESTAMP )`
);
// Insert admin user
const hashed_password = '$2b$10$viyvP9YIQs0E4.sZN0feIeBrPbHTpCnLLc.ldWgCHDg4BCoHgm2Fi';
await this.dbRun(
`INSERT OR IGNORE INTO "USERS" ( username, email, password_hash, is_admin,
can_manage_users, can_manage_content, can_view_logs,
full_name, is_active )
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,
[ 'admin', 'admin@example.com', hashed_password, 1, 1, 1, 1, 'Super Administrator', 1 ]
);
console.log('<Done> Utilisateur "admin" créé');
} catch ( err ) {
console.error('<Error> création/insertion table "USERS": \n' + err);
throw err;
}
// ============================== Create 'USERS' table
}
} // async initAdminUser()
async initConstantTables() {
console.error('>> SqLiteUtils.initConstantTables()');
// ==================== 'WALLET_MODE' table ====================
try {
await this.dbRun('CREATE TABLE IF NOT EXISTS "WALLET_MODE" ( "id" VARCHAR(15) PRIMARY KEY )');
const walletModes = [ 'Simple Wallet', 'SWORD Wallet', 'HD Wallet' ];
for ( const mode of walletModes ) {
try { await this.dbRun('INSERT OR IGNORE INTO "WALLET_MODE" (id) VALUES (?)', [mode]);
} catch (err) {
if ( ! err.message.includes('UNIQUE constraint') ) {
console.error('Erreur insertion "WALLET_MODE": \n' + err);
}
}
}
console.log('<Done> Table "WALLET_MODE" initialisée');
} catch ( err ) {
console.error('<Error> initConstantTables table "WALLET_MODE"');
throw err;
}
// ==================== 'WALLET_MODE' table
// ======================= 'COIN' table =======================
try {
await this.dbRun('CREATE TABLE IF NOT EXISTS "COIN" ( "id" VARCHAR(7) PRIMARY KEY )');
for ( const coin of CRYPTOCALC_DB_COINS ) {
try { await this.dbRun('INSERT OR IGNORE INTO "COIN" (id) VALUES (?)', [coin]);
} catch (err) {
if ( ! err.message.includes('UNIQUE constraint') ) {
console.error('Erreur insertion "COIN": \n' + err);
}
}
}
console.log('<Done> Table "COIN" initialisée')
} catch ( err ) {
console.error('<Error> initConstantTables table "COIN"');
throw err;
}
// ======================= 'COIN' table
// ==================== 'BLOCKCHAIN' table =====================
try {
await this.dbRun('CREATE TABLE IF NOT EXISTS "BLOCKCHAIN" ( "id" TEXT PRIMARY KEY )');
// Insert blockchains
for ( const blockchain of CRYPTOCALC_DB_BLOCKCHAINS ) {
try { await this.dbRun('INSERT OR IGNORE INTO "BLOCKCHAIN" (id) VALUES (?)', [blockchain]);
} catch (err) {
if ( ! err.message.includes('UNIQUE constraint') ) {
console.error('Erreur insertion "BLOCKCHAIN": \n' + err);
}
}
}
console.log('<Done> Table "BLOCKCHAIN" initialisée');
} catch ( err ) {
console.error('<Error> initConstantTables table "BLOCKCHAIN"');
throw err;
}
// ==================== 'BLOCKCHAIN' table
// ==================== 'TOKEN_TYPE' table =====================
try {
await this.dbRun('CREATE TABLE IF NOT EXISTS "TOKEN_TYPE" ( "id" TEXT PRIMARY KEY )');
for ( const token_type of CRYPTOCALC_DB_TOKEN_TYPES ) {
try { await this.dbRun('INSERT OR IGNORE INTO "TOKEN_TYPE" (id) VALUES (?)', [token_type]);
} catch (err) {
if ( ! err.message.includes('UNIQUE constraint') ) {
console.error('Erreur insertion "TOKEN_TYPE": \n' + err);
}
}
}
console.log('<Done> Table "TOKEN_TYPE" initialisée');
} catch ( err ) {
console.error('<Error> initConstantTables table "TOKEN_TYPE"');
throw err;
}
// ==================== 'TOKEN_TYPE' table
// ======================= 'LANG' table =======================
try {
await this.dbRun(`CREATE TABLE IF NOT EXISTS "LANG" (
"id" VARCHAR(3) PRIMARY KEY,
"name" TEXT,
"bip39_official" INTEGER
)`
);
for ( const lang_data of CRYPTOCALC_DB_LANGS ) {
try { await this.dbRun( 'INSERT OR IGNORE INTO "LANG" ( id, name, bip39_official ) VALUES ( ?, ?, ? )',
[ lang_data[0], lang_data[1], lang_data[2] ] );
} catch ( err ) {
if ( ! err.message.includes('UNIQUE constraint') ) {
console.error('<Error> insertion "LANG": \n' + err);
}
}
}
console.log('<Done> Table "LANG" initialisée');
} catch ( err ) {
console.error('<Error> initConstantTables table "LANG"');
throw err;
}
// ======================= 'LANG' table
// ======================= 'PREDEFINED_SQL_QUERY' table =======================
try {
await this.dbRun(`CREATE TABLE IF NOT EXISTS "PREDEFINED_SQL_QUERY" (
"id" INTEGER PRIMARY KEY AUTOINCREMENT,
"name" TEXT,
"sql_query" TEXT,
"comment" TEXT
)`
);
for ( const sql_query_data of CRYPTOCALC_DB_PREDEFINED_SQL_QUERIES ) {
try { await this.dbRun( 'INSERT OR IGNORE INTO "PREDEFINED_SQL_QUERY" ( name, sql_query ) VALUES ( ?, ? )',
[ sql_query_data[0], sql_query_data[1] ]);
} catch ( err ) {
if ( ! err.message.includes('UNIQUE constraint') ) {
console.error('<Error> insertion "PREDEFINED_SQL_QUERY": \n' + err);
}
}
}
console.log('<Done> Table "PREDEFINED_SQL_QUERY" initialisée');
} catch ( err ) {
console.error('<Error> initConstantTables table "PREDEFINED_SQL_QUERY"');
throw err;
}
// ======================= 'PREDEFINED_SQL_QUERY' table
// ======================= 'ORGANIZATION' table =======================
try {
await this.dbRun(`CREATE TABLE IF NOT EXISTS "ORGANIZATION" (
"id" VARCHAR(35) PRIMARY KEY,
"purpose" TEXT,
"homepage" TEXT,
"email" TEXT,
"phone" TEXT,
"address" TEXT
)`
);
for ( const org_data of CRYPTOCALC_DB_ORGANIZATIONS ) {
try { await this.dbRun( 'INSERT OR IGNORE INTO "ORGANIZATION" ( id, purpose, homepage, email, phone, address ) '
+ 'VALUES ( ?, ?, ?, ?, ?, ? )',
[ org_data[0], org_data[1], org_data[2], org_data[3], org_data[4], org_data[5] ] );
} catch ( err ) {
if ( ! err.message.includes('UNIQUE constraint') ) {
console.error('Erreur insertion "ORGANIZATION": \n' + err);
}
}
}
console.log('<Done> Table "ORGANIZATION" initialisée');
} catch ( err ) {
console.error('<Error> initConstantTables table "ORGANIZATION"');
throw err;
}
// ======================= 'LANG' table
} // async initConstantTables()
async importWallets( output_folders_path ) {
console.log(">> SqLiteUtils.This.importWallets() \n output_folders_path: '" + output_folders_path + "'");
try {
const output_folders = fs.readdirSync( output_folders_path, { withFileTypes: true } );
for ( let i=0; i < output_folders.length; i++ ) {
let output_folder_name = output_folders[i].name;
console.log('> output_folder_name[' + i + ']: ' + output_folder_name);
let wits_file_path = output_folders_path + '\\' + output_folder_name + '\\wallet_info.wits';
if ( fs.existsSync( wits_file_path ) ) {
// console.log('> json_file_path[' + i + ']: ' + json_file_path);
const wits_content = fs.readFileSync( wits_file_path, 'utf8' );
const wallet_json_data = JSON.parse( wits_content );
await this.insertWallet( wallet_json_data, output_folder_name );
}
}
} catch ( err ) {
console.error(">> Erreur de lecture du dossier '" + output_folders_path + "':\n" + err.message);
}
let db_state = await DatabaseStateChecker.CheckDatabaseState( this.db_obj );
// {"exists":true,"isOpen":true,"isClosed":false,"canRead":true,"canWrite":true,"properties":{"type":"object","constructor":"Database"},"errors":[],"warnings":[]}
// console.log( "db_state: " + JSON.stringify(db_state) );
if ( db_state["isOpen"] == false && db_state["isClosed"] ) {
await this.closeDatabase();
}
} // async importWallets()
async insertWallet( wallet_data, output_folder_name ) {
console.log(">> --------------------------------");
console.log(">> SQLiteUtils.insertWallet: '" + output_folder_name + "'" );
// If no wallet_data provided, just return (this was likely a test call)
if ( ! wallet_data ) return;
try {
let name = output_folder_name;
// console.log("name: " + name);
let owner = CRYPTOCALC_DB_DEFAULT_OWNER_ID;
// console.log("name: " + name);
let json_data_time_stamp = wallet_data['timestamp'];
let time_stamp = this.convertToSQLiteTimestamp( json_data_time_stamp );
// console.log("json_data_time_stamp: " + json_data_time_stamp);
// console.log("time_stamp: " + time_stamp);
let wallet_mode = wallet_data['Wallet Mode'];
// console.log("wallet_mode: " + wallet_mode);
let blockchain = wallet_data['Blockchain'];
// console.log("blockchain: " + blockchain);
let coin = wallet_data['Coin'];
// console.log("coin: " + coin);
let balance = 0;
// console.log("balance: " + balance);
let comment = '';
// console.log("comment: " + comment);
let entropy = wallet_data['Entropy'];
// console.log("entropy: " + entropy);
let entropy_size = wallet_data['Entropy Size'];
// console.log("entropy_size: " + entropy_size);
let wallet_address = wallet_data['Wallet Address'];
// console.log("wallet_address: " + wallet_address);
let bc_explorer_url = wallet_data['Blockchain Explorer'];
// console.log("bc_explorer_url: " + bc_explorer_url);
let private_key = wallet_data['Private Key'] != undefined ? wallet_data['Private Key'] : '';
// console.log("private_key: " + private_key);
let bip38_passphrase = wallet_data['Bip38 Passphrase'] != undefined ? wallet_data['Bip38 Passphrase'] : '';
// console.log("bip38_passphrase: " + bip38_passphrase);
let bip38_encrypted_pk = wallet_data['Bip38 Encrypted PK'] != undefined ? wallet_data['Bip38 Encrypted PK'] : '';
// console.log("bip38_encrypted_pk: " + bip38_encrypted_pk);
let wif = wallet_data['WIF'] != undefined ? wallet_data['WIF'] : '';
// console.log("wif: " + wif);
let secret_phrase = wallet_data['Secret phrase'];
// console.log("secret_phrase: " + secret_phrase);
let word_indexes = wallet_data['Word indexes'];
// console.log("word_indexes: " + word_indexes);
let bip32_passphrase = wallet_data['Bip32 Passphrase'] != undefined ? wallet_data['Bip32 Passphrase'] : '';
// console.log("bip32_passphrase: " + bip32_passphrase);
let derivation_path = wallet_data['Derivation Path'] != undefined ? wallet_data['Derivation Path'] : '';
// console.log("derivation_path: " + derivation_path);
let account = wallet_data['account'] != undefined ? wallet_data['account'] : '0\'';
// console.log("account: " + account);
let address_index = wallet_data['address_index'] != undefined ? wallet_data['address_index'] : '0\'';
// console.log("address_index: " + address_index);
let lang = wallet_data['Lang'];
// console.log("lang: " + lang);
let version = wallet_data['Version'];
// console.log("version: " + version);
let values = [ name, owner, time_stamp, wallet_mode, blockchain, coin, balance, comment,
entropy, entropy_size, wallet_address, bc_explorer_url,
private_key, bip38_passphrase, bip38_encrypted_pk, wif, secret_phrase,
word_indexes, bip32_passphrase, derivation_path, account, address_index, lang, version ];
// console.log("values: " + values.length);
await this.dbRun(
`INSERT OR IGNORE INTO "WALLET"
( name, owner, time_stamp, wallet_mode, blockchain, coin, balance, comment,
entropy, entropy_size, wallet_address, bc_explorer_url,
private_key, bip38_passphrase, bip38_encrypted_pk, wif, secret_phrase,
word_indexes, bip32_passphrase, derivation_path, account, address_index, lang, version )
VALUES ( ?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,? )`, values );
} catch ( err ) {
console.log ( '*-*-* Erreur *-*-* insertion "WALLET":\n**Error** ' + err.message );
// if ( ! err.message.includes('UNIQUE constraint')) {
console.error('**Erreur** insertion "WALLET":\n **Error**' + err);
// }
}
} // async insertWallet()
async existsDBTable( table_name ) {
try {
const row = await this.dbGet( `SELECT "name" FROM "sqlite_master" WHERE type='table' AND name=?`, [ table_name ] );
return !! row;
} catch ( err ) {
console.error("Erreur vérification table: '" + table_name + "'\n" + err);
return false;
}
} // async existsDBTable()
existsFileSync( file_path ) {
try {
fs.accessSync( file_path, fs.constants.F_OK );
return true;
} catch ( err ) {
return false;
}
} // existsFileSync()
get appFolderPath() {
return this.app_folder_path;
} // 'appFolderPath' getter
// Database helper methods with async/await
async dbRun( sql, params = [] ) {
return new Promise( (resolve, reject) => {
// console.log( "SQL REquest: \n" + sql );
// console.log( "this.db_obj: " + this.db_obj );
this.db_obj.run( sql, params, function(err) {
if ( err ) reject(err);
else resolve({ lastID: this.lastID, changes: this.changes });
});
});
} // async dbRun()
async dbGet( sql, params = [] ) {
return new Promise((resolve, reject) => {
this.db_obj.get(sql, params, (err, row) => {
if (err) reject(err);
else resolve(row);
});
});
} // async dbGet()
async dbAll( sql, params = [] ) {
return new Promise((resolve, reject) => {
this.db_obj.all(sql, params, (err, rows) => {
if (err) reject(err);
else resolve(rows);
});
});
} // async dbAll()
// For backward compatibility
runQuery( sql, params = [] ) {
return this.dbRun(sql, params);
} // runQuery()
getRow( sql, params = [] ) {
return this.dbGet(sql, params);
} // getRow()
getAll( sql, params = [] ) {
return this.dbAll(sql, params);
} // getAll()
// 2025_12_18_16h-45m-44s-3 to TEXT 'ISO 8601' ('YYYY-MM-DD HH:MM:SS.SSS')
convertToSQLiteTimestamp( timestamp_str ) {
// Parse the input string
const [ date_part, time_part ] = timestamp_str.split('_').slice(0, 4).join('_').split('_16h')[0];
// Alternative parsing: split by underscores and hyphens
const ts_parts = timestamp_str.split(/[_-]/);
// parts: ['2025', '12', '18', '16h', '45m', '44s', '3']
const year = ts_parts[0];
const month = ts_parts[1];
const day = ts_parts[2];
const hour = ts_parts[3].replace('h', '');
const minute = ts_parts[4].replace('m', '');
const second = ts_parts[5].replace('s', '');
const tenth_of_second = ts_parts[6]; // Math.round(today_milliseconds/100)
// Convert fraction to milliseconds (assuming .3 = 300ms)
// console.log("++++ tenth_of_second: " + tenth_of_second);
const milliseconds = tenth_of_second * 100;
// console.log("++++ milliseconds: " + milliseconds);
const timestamp_value = `${year}-${month}-${day} ${hour}:${minute}:${second}.${milliseconds}`;
return timestamp_value;
} // convertToSQLiteTimestamp()
} // 'SqLiteUtils' class
// =================================================================
// ======================================== SQLiteUtils class
// =================================================================
async function test_convertTimeStamp_to_SQL() {
await SqLiteUtils.GetInstance();
let ts_str = getDayTimestamp();
let SQL_ts = SqLiteUtils.This.convertToSQLiteTimestamp( ts_str );
console.log("ts_str: " + ts_str + " SQL_ts: " + SQL_ts );
} // test_convertTimeStamp_to_SQL()
async function test_hash_pwd() {
console.log('**SqLiteUtils** ---------- test_hash_pwd ----------');
const hashed_password = await bcrypt.hash('admin', 10);
console.log("hashed_password: '" + hashed_password + "'");
}
async function test_initialize() {
console.log('**SqLiteUtils** ---------- test_initialize ----------');
await SqLiteUtils.GetInstance();
}
async function test_import_wallets() {
console.log('**SqLiteUtils** ---------- test_import_wallets ----------');
// First ensure we're initialized
await SqLiteUtils.GetInstance();
let path = "E:\\_00_Michel\\_00_Lab\\_00_GitHub\\Cryptocalc\\_output";
await SqLiteUtils.This.importWallets( path );
}
// IIFE (Immediately Invoked Function Expression)
( async () => {
await SqLiteUtils.GetInstance(); // Caution !! Don't put this line in comments
// ---- Uncomment the test you want to run ----
// await test_hash_pwd();
// await test_initialize();
// await test_import_wallets();
// await test_convertTimeStamp_to_SQL();
} )();
if ( typeof exports === 'object' ) {
exports.SqLiteUtils = SqLiteUtils
} // exports of 'sqlite_utils.js'