feat(scripts): simple python script to interact with database (#11184)
* fix(scripts): fix `password-hash.py`
This commit is contained in:
parent
61faa2df90
commit
5b5361c9b0
|
@ -0,0 +1,7 @@
|
||||||
|
from Crypto.Hash import keccak
|
||||||
|
|
||||||
|
def hash_password(password, old_desktop=False):
|
||||||
|
hasher = keccak.new(digest_bits=256)
|
||||||
|
hasher.update(password.encode())
|
||||||
|
hash = hasher.hexdigest()
|
||||||
|
return '0x' + (hash.upper() if old_desktop else hash.lower())
|
|
@ -0,0 +1,106 @@
|
||||||
|
import sys, os, re
|
||||||
|
import sqlcipher3
|
||||||
|
from getpass import getpass
|
||||||
|
from common import PasswordFunctions
|
||||||
|
|
||||||
|
def open_db(file_path, passwordHash: str, kdfIterations: int):
|
||||||
|
db = sqlcipher3.connect(file_path)
|
||||||
|
pageSize = 8192 if file_path.endswith("-v4.db") else 1024
|
||||||
|
|
||||||
|
print(f'> Opening database. Selected cipher_page_size: {pageSize}')
|
||||||
|
db.execute(f'PRAGMA key = "{passwordHash}"')
|
||||||
|
db.execute(f'PRAGMA cipher_page_size = {pageSize}') #1024 for older db, 8192 for newer
|
||||||
|
db.execute(f'PRAGMA kdf_iter = {kdfIterations}')
|
||||||
|
db.execute('PRAGMA cipher_hmac_algorithm = HMAC_SHA1')
|
||||||
|
db.execute('PRAGMA cipher_kdf_algorithm = PBKDF2_HMAC_SHA1')
|
||||||
|
# db.execute('PRAGMA cipher_compatibility = 3;')
|
||||||
|
|
||||||
|
return db
|
||||||
|
|
||||||
|
class Account:
|
||||||
|
def __init__(self, name, keyUid, kdfIterations):
|
||||||
|
self.name = name
|
||||||
|
self.keyUid = keyUid
|
||||||
|
self.kdfIterations = kdfIterations
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f"{self.name} - {self.keyUid}, kdfIterations: {self.kdfIterations}"
|
||||||
|
|
||||||
|
class Config:
|
||||||
|
def __init__(self):
|
||||||
|
self.args = sys.argv[1:]
|
||||||
|
|
||||||
|
def input_base_path(self):
|
||||||
|
if len(self.args) > 0:
|
||||||
|
self.base_path = self.args[0]
|
||||||
|
else:
|
||||||
|
self.base_path = input('> Input a base path: ')
|
||||||
|
if not self.base_path.endswith('/'):
|
||||||
|
self.base_path += '/'
|
||||||
|
|
||||||
|
def read_accounts(self):
|
||||||
|
db = sqlcipher3.connect(self.base_path + '/accounts.sql')
|
||||||
|
accounts = db.execute('SELECT name, keyUid, kdfIterations FROM accounts').fetchall()
|
||||||
|
db.close()
|
||||||
|
|
||||||
|
if len(accounts) == 0:
|
||||||
|
print("no accoutns found")
|
||||||
|
exit(0)
|
||||||
|
|
||||||
|
self.accounts = []
|
||||||
|
print(f'> Accounts found: ')
|
||||||
|
for i, a in enumerate(accounts):
|
||||||
|
account = Account(a[0], a[1], a[2])
|
||||||
|
self.accounts.append(account)
|
||||||
|
print(f'{i}: {str(account)}')
|
||||||
|
|
||||||
|
def find_database(self):
|
||||||
|
regex = re.compile(f'{self.selectedAccount.keyUid}(\-v4)?.db$')
|
||||||
|
for _, _, files in os.walk(self.base_path):
|
||||||
|
for file in files:
|
||||||
|
if regex.match(file):
|
||||||
|
return file
|
||||||
|
return ''
|
||||||
|
|
||||||
|
def select_account(self):
|
||||||
|
if len(self.args) > 1:
|
||||||
|
self.account_index = int(self.args[1])
|
||||||
|
else:
|
||||||
|
self.account_index = int(input('> Select an account by index: '))
|
||||||
|
self.selectedAccount = self.accounts[self.account_index]
|
||||||
|
self.database_path = self.base_path + self.find_database()
|
||||||
|
print(f'selected database: {self.database_path}')
|
||||||
|
|
||||||
|
def input_password(self):
|
||||||
|
if len(self.args) > 2:
|
||||||
|
password = self.args[2]
|
||||||
|
else:
|
||||||
|
password = getpass("> Input password: ")
|
||||||
|
config.password_hash = PasswordFunctions.hash_password(password, old_desktop=False)
|
||||||
|
|
||||||
|
|
||||||
|
config = Config()
|
||||||
|
config.input_base_path()
|
||||||
|
config.read_accounts()
|
||||||
|
config.select_account()
|
||||||
|
config.input_password()
|
||||||
|
|
||||||
|
## Select and open database
|
||||||
|
|
||||||
|
db = open_db(config.database_path, config.password_hash, config.selectedAccount.kdfIterations)
|
||||||
|
|
||||||
|
## use the `db` instance to execute queries
|
||||||
|
|
||||||
|
tables = db.execute("SELECT name FROM sqlite_master WHERE type='table';").fetchall()
|
||||||
|
print(f"> Database opened. {len(tables)} tables found.")
|
||||||
|
|
||||||
|
## loop sql operations
|
||||||
|
|
||||||
|
while True:
|
||||||
|
cmd = input("SQL> ")
|
||||||
|
if cmd == "exit":
|
||||||
|
break
|
||||||
|
output = db.execute(cmd).fetchall()
|
||||||
|
print(output)
|
||||||
|
|
||||||
|
db.close()
|
|
@ -1,12 +1,9 @@
|
||||||
import sha3
|
|
||||||
import pyperclip
|
import pyperclip
|
||||||
|
from common import PasswordFunctions
|
||||||
|
|
||||||
print("Type your password...")
|
print("Type your password...")
|
||||||
password = input()
|
password = input()
|
||||||
|
hash = PasswordFunctions.hash_password(password)
|
||||||
hasher = sha3.keccak_256()
|
|
||||||
hasher.update(password.encode())
|
|
||||||
hash = '0x' + hasher.hexdigest()
|
|
||||||
pyperclip.copy(hash)
|
pyperclip.copy(hash)
|
||||||
|
|
||||||
print(f'Hash: {hash} is copied to clipboard')
|
print(f'Hash: {hash} is copied to clipboard')
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue