@aladas-org/cryptocalc
Version:
Cryptocurrency wallet generator
511 lines (445 loc) • 16.7 kB
JavaScript
// ======================================================================================================================
// ================================================ sqlite_util.js ================================================
// ======================================================================================================================
;
const sqlite3 = require('sqlite3').verbose();
const bcrypt = require('bcrypt');
const fs = require('fs');
const path = require('path');
const os = require('os');
const CRYPTOCALC_DB_LANGS = [ "EN","DE","FR","ES","PT","IT","EO","LA","CS","RU","EL","SC","TC","JP","KO","HI","BN","GU" ];
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" ];
class SqLiteUtils {
static #Key = Symbol();
static #Singleton = new SqLiteUtils( this.#Key );
static #InstanceCount = 0;
static get This() {
if ( SqLiteUtils.#Singleton == undefined ) {
this.#Singleton = new SqLiteUtils( this.#Key );
if ( this.#InstanceCount > 0 ) {
throw new TypeError("'SqLiteUtils' constructor called more than once");
}
this.#InstanceCount++;
}
return SqLiteUtils.#Singleton;
} // SqLiteUtils '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;
// console.log(' Chemin LOCALAPPDATA: ' + this.local_app_data_path);
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.db_obj = undefined;
this.db_file_path = '';
this.initialize();
} // ** Private constructor **
initialize() {
console.log('>> initialize');
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('✅ Fichier DB créé: ' + this.db_file_path);
}
// Initialize database connection
this.db_obj = new sqlite3.Database(this.db_file_path, (err) => {
if (err) {
console.error('Erreur connection DB:', err);
return;
}
console.log('✅ Connecté à la base de données');
// Enable WAL mode and foreign keys
this.db_obj.serialize(() => {
this.db_obj.run('PRAGMA journal_mode = WAL', (err) => {
if (err) console.error('Erreur WAL mode:', err);
});
this.db_obj.run('PRAGMA foreign_keys = ON', (err) => {
if (err) {
console.error('Erreur activation Foreign Keys:', err);
} else {
console.log('✅ Clés étrangères activées');
}
});
});
});
this.initSchema();
this.initDB();
} // initialize()
initDB() {
console.error('> SqLiteUtils.initDB');
this.db_obj.serialize(
() => {
this.initAdminUser();
// Create WALLET table
this.db_obj.run(
"CREATE TABLE IF NOT EXISTS WALLET ("
+ "id INTEGER PRIMARY KEY AUTOINCREMENT,"
+ "name TEXT,"
+ "version VARCHAR(10),"
+ "time_stamp TIMESTAMP,"
+ "wallet_mode VARCHAR(15),"
+ "blockchain TEXT,"
+ "balance REAL,"
+ "coin VARCHAR(7),"
+ "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),"
+ "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, entropy)"
+ ")"
),
(err) => {
if (err) {
console.error('Erreur création table WALLET:', err);
} else {
console.log('✅ Table WALLET créée/verifiée');
}
}
});
} // initDB()
initSchema() {
console.error('> SqLiteUtils.initSchema');
// Check if LANG table exists
this.db_obj.get("SELECT name FROM sqlite_master WHERE type='table' AND name='LANG'", (err, row) => {
if (err) {
console.error('Erreur vérification table LANG:', err);
return;
}
if (!row) {
this.initConstantTables();
}
});
} // initSchema()
initAdminUser() {
console.error('> SqLiteUtils.initAdminUser');
// Check if USERS table exists
this.db_obj.get("SELECT name FROM sqlite_master WHERE type='table' AND name='USERS'", (err, row) => {
if (err) {
console.error('Erreur vérification table USERS:', err);
return;
}
if (!row) {
// Create USERS table
this.db_obj.run(
"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"
+ ")"
),
(err) => {
if (err) {
console.error('Erreur création table USERS:', err);
return;
}
// Insert admin user
const hashed_password = '$2b$10$viyvP9YIQs0E4.sZN0feIeBrPbHTpCnLLc.ldWgCHDg4BCoHgm2Fi';
this.db_obj.run(
"INSERT 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],
(err) => {
if (err) {
console.error('Erreur insertion admin:', err);
} else {
console.log('✅ Utilisateur admin créé');
}
}
);
}
}
});
} // initAdminUser()
initConstantTables() {
console.error('> SqLiteUtils.initConstantTables');
// Execute all operations in serial order
this.db_obj.serialize(() => {
// WALLET_MODE table
this.db_obj.run(
'CREATE TABLE IF NOT EXISTS WALLET_MODE (id VARCHAR(15) PRIMARY KEY)',
(err) => {
if (err) {
console.error('Erreur création WALLET_MODE:', err);
return;
}
// Insert wallet modes
const walletModes = ['Simple Wallet', 'SWORD Wallet', 'HD Wallet'];
let insertedCount = 0;
walletModes.forEach(mode => {
this.db_obj.run(
'INSERT INTO WALLET_MODE (id) VALUES (?)',
[mode],
(err) => {
if (err && !err.message.includes('UNIQUE constraint')) {
console.error('Erreur insertion WALLET_MODE:', err);
}
insertedCount++;
}
);
});
console.log('✅ Table WALLET_MODE initialisée');
}
);
// COIN table
this.db_obj.run(
'CREATE TABLE IF NOT EXISTS COIN (id VARCHAR(7) PRIMARY KEY)',
(err) => {
if (err) {
console.error('Erreur création COIN:', err);
return;
}
// Insert coins
CRYPTOCALC_DB_COINS.forEach(coin => {
this.db_obj.run(
'INSERT INTO COIN (id) VALUES (?)',
[coin],
(err) => {
if (err && !err.message.includes('UNIQUE constraint')) {
console.error('Erreur insertion COIN:', err);
}
}
);
});
console.log('✅ Table COIN initialisée');
}
);
// BLOCKCHAIN table
this.db_obj.run(
'CREATE TABLE IF NOT EXISTS BLOCKCHAIN (id TEXT PRIMARY KEY)',
(err) => {
if (err) {
console.error('Erreur création BLOCKCHAIN:', err);
return;
}
// Insert blockchains
CRYPTOCALC_DB_BLOCKCHAINS.forEach(blockchain => {
this.db_obj.run(
'INSERT INTO BLOCKCHAIN (id) VALUES (?)',
[blockchain],
(err) => {
if (err && !err.message.includes('UNIQUE constraint')) {
console.error('Erreur insertion BLOCKCHAIN:', err);
}
}
);
});
console.log('✅ Table BLOCKCHAIN initialisée');
}
);
// LANG table
this.db_obj.run(
'CREATE TABLE IF NOT EXISTS LANG (id VARCHAR(3) PRIMARY KEY)',
(err) => {
if (err) {
console.error('Erreur création LANG:', err);
return;
}
// Insert languages
CRYPTOCALC_DB_LANGS.forEach(lang => {
this.db_obj.run(
'INSERT INTO LANG (id) VALUES (?)',
[lang],
(err) => {
if (err && !err.message.includes('UNIQUE constraint')) {
console.error('Erreur insertion LANG:', err);
}
}
);
});
console.log('✅ Table LANG initialisée');
}
);
});
} // initConstantTables()
importWallets( folder_path ) {
try {
const sub_folders = fs.readdirSync( folder_path, { withFileTypes: true } );
for ( let i=0; i < sub_folders.length; i++ ) {
let folder_name = sub_folders[i].name;
console.log('> folder_name[' + i + ']: ' + folder_name);
let json_file_path = folder_path + '\\' + folder_name + '\\wallet_info.wits';
// console.log('> json_file_path[' + i + ']: ' + json_file_path);
const wallet_info_content = fs.readFileSync( json_file_path, 'utf8' );
const wallet_json_data = JSON.parse( wallet_info_content );
this.addWallet( wallet_json_data, folder_name );
}
} catch ( err ) {
console.error('Erreur de lecture du dossier :', err.message);
}
} // importWallets()
addWallet( wallet_data, sub_folder_name ) {
// If no wallet_data provided, just return (this was likely a test call)
if (!wallet_data) return;
try {
let name = sub_folder_name;
let version = wallet_data['Version'];
let time_stamp = wallet_data['timestamp'];
let wallet_mode = wallet_data['Wallet Mode'];
let blockchain = wallet_data['Blockchain'];
let coin = wallet_data['Coin'];
let balance = 0;
let entropy = wallet_data['Entropy'];
let entropy_size = wallet_data['Entropy Size'];
let wallet_address = wallet_data['Wallet Address'];
let bc_explorer_url = wallet_data['Blockchain Explorer'];
let private_key = wallet_data['Private Key'] != undefined ? wallet_data['Private Key'] : '';
let bip38_passphrase = wallet_data['Bip38 Passphrase'] != undefined ? wallet_data['Bip38 Passphrase'] : '';
let bip38_encrypted_pk = wallet_data['Bip38 Encrypted PK'] != undefined ? wallet_data['Bip38 Encrypted PK'] : '';
let wif = wallet_data['WIF'] != undefined ? wallet_data['WIF'] : '';
let secret_phrase = wallet_data['Secret phrase'];
let word_indexes = wallet_data['Word indexes'];
let bip32_passphrase = wallet_data['Bip32 Passphrase'] != undefined ? wallet_data['Bip32 Passphrase'] : '';
let derivation_path = wallet_data['Derivation Path'];
let account = wallet_data['account'];
let address_index = wallet_data['address_index'];
let lang = wallet_data['lang'];
this.db_obj.run(
`INSERT OR IGNORE INTO WALLET
(name, version, time_stamp, wallet_mode, blockchain, coin, balance, 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)
VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)`,
[
name, version, time_stamp, wallet_mode, blockchain, coin, balance, 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
],
(err) => {
if (err && !err.message.includes('UNIQUE constraint')) {
console.error('Erreur insertion wallet:', err);
}
}
);
} catch (err) {
console.error('Erreur dans addWallet:', err);
}
} // addWallet()
existsDBTable( db_obj, table_name ) {
return new Promise((resolve) => {
db_obj.get(
`SELECT name FROM sqlite_master WHERE type='table' AND name=?`,
[table_name],
(err, row) => {
if (err) {
console.error('Erreur vérification table:', err);
resolve(false);
} else {
resolve(!!row);
}
}
);
});
} // existsDBTable()
// Helper method for synchronous version (for backward compatibility)
existsDBTableSync(table_name) {
let exists = false;
this.db_obj.get(
`SELECT name FROM sqlite_master WHERE type='table' AND name=?`,
[table_name],
(err, row) => {
if (!err && row) {
exists = true;
}
}
);
return exists;
}
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
// Helper method to run queries with promises
runQuery(sql, params = []) {
return new Promise((resolve, reject) => {
this.db_obj.run(sql, params, function(err) {
if (err) reject(err);
else resolve({ lastID: this.lastID, changes: this.changes });
});
});
} // runQuery()
// Helper method to get a single row with promises
getRow(sql, params = []) {
return new Promise((resolve, reject) => {
this.db_obj.get(sql, params, (err, row) => {
if (err) reject(err);
else resolve(row);
});
});
}
// Helper method to get all rows with promises
getAll(sql, params = []) {
return new Promise((resolve, reject) => {
this.db_obj.all(sql, params, (err, rows) => {
if (err) reject(err);
else resolve(rows);
});
});
} // getAll()
} // SqLiteUtils class
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 + "'");
}; // test_hash_pwd
// test_hash_pwd();
function test_initialize() {
console.log('**SqLiteUtils** ---------- test_initialize ----------');
SqLiteUtils.This;
}; // test_initialize
// test_initialize();
function test_import_wallets() {
console.log('**SqLiteUtils** ---------- test_import_wallets ----------');
let path = "E:\\_00_Michel\\_00_Lab\\_00_GitHub\\Cryptocalc\\_output";
SqLiteUtils.This.importWallets( path );
}; // test_import_wallets
test_import_wallets();
if ( typeof exports === 'object' ) {
exports.SqLiteUtils = SqLiteUtils
} // exports of 'bip38_utils.js'