diff --git a/.gitignore b/.gitignore index 56cc628..47884dd 100644 --- a/.gitignore +++ b/.gitignore @@ -132,4 +132,3 @@ dmypy.json # Local data data -config.py diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..fbd5dd6 --- /dev/null +++ b/Makefile @@ -0,0 +1,6 @@ +setup: + python3 -m venv .venv + .venv/bin/pip install -r requirements.txt + +up: + .venv/bin/python3 -m tipbot diff --git a/bin/wallet.sh b/bin/wallet.sh new file mode 100644 index 0000000..f45e43f --- /dev/null +++ b/bin/wallet.sh @@ -0,0 +1,32 @@ +#!/bin/bash + +export $(cat .env) + +if [ ! -d "$WALLET_PATH" ]; then + # initialize new wow wallet and retain seed + mkdir -p $WALLET_PATH + docker run --rm -it --name tgbot-wallet-init \ + -v $WALLET_PATH:/root \ + lalanza808/wownero:latest \ + wownero-wallet-cli \ + --daemon-address $DAEMON_URI \ + --generate-new-wallet /root/wow \ + --password $WALLET_PASS \ + --trusted-daemon +fi + +# setup rpc process +docker run --rm -d --name tgbot-wallet \ + -v $WALLET_PATH:/root \ + -p 127.0.0.1:9999:9999 \ + lalanza808/wownero:latest \ + wownero-wallet-rpc \ + --daemon-address $DAEMON_URI \ + --wallet-file /root/wow \ + --password $WALLET_PASS \ + --rpc-bind-port 9999 \ + --rpc-bind-ip 0.0.0.0 \ + --confirm-external-bind \ + --rpc-login "$WALLET_RPC_USER:$WALLET_RPC_PASS" \ + --log-file /root/rpc.log \ + --trusted-daemon diff --git a/env-example b/env-example new file mode 100644 index 0000000..9ffc115 --- /dev/null +++ b/env-example @@ -0,0 +1,9 @@ +WALLET_PATH=xxx +DAEMON_URI=xxx +WALLET_PASS=xxx +WALLET_RPC_USER=xxx +WALLET_RPC_PASS=xxx +TG_TOKEN=xxx +TG_ADMIN_ID=xxx +SQLITE_DB_PATH=xxx +DEBUG=xxx diff --git a/requirements.txt b/requirements.txt index 57cf7a0..6d8efac 100644 --- a/requirements.txt +++ b/requirements.txt @@ -6,8 +6,11 @@ cryptography==2.9.2 decorator==4.4.2 idna==2.10 peewee==3.13.3 +Pillow==8.2.0 pycparser==2.20 +python-dotenv==0.17.1 python-telegram-bot==12.8 +qrcode==6.1 requests==2.24.0 six==1.15.0 tornado==6.0.4 diff --git a/tipbot/commands/__init__.py b/tipbot/commands/__init__.py index 4344eb2..4842fea 100644 --- a/tipbot/commands/__init__.py +++ b/tipbot/commands/__init__.py @@ -5,7 +5,6 @@ from tipbot.commands.tip import tip from tipbot.commands.withdraw import withdraw from tipbot.commands.balance import balance from tipbot.commands.deposit import deposit -from tipbot.commands.qr import qr all_commands = { @@ -39,11 +38,6 @@ all_commands = { 'example': '/help', 'help': 'Show available commands for the bot', }, - 'qr': { - 'func': qr, - 'example': '/qr
', - 'help': 'Provides a helpful URL for generating QR code for a Wownero address' - }, 'debug': { 'func': debug, 'admin': True diff --git a/tipbot/commands/debug.py b/tipbot/commands/debug.py index 99e6a7f..b4e4b36 100644 --- a/tipbot/commands/debug.py +++ b/tipbot/commands/debug.py @@ -1,5 +1,6 @@ from tipbot.helpers.decorators import wallet_rpc_required, log_event, check_debug from tipbot.helpers.utils import is_tg_admin +from tipbot.wownero import Wallet @wallet_rpc_required @@ -7,6 +8,6 @@ from tipbot.helpers.utils import is_tg_admin @check_debug def debug(update, context): if is_tg_admin(update.message.from_user['id']): - pass + update.message.reply_text('ohai') else: update.message.reply_text('you cant do that.') diff --git a/tipbot/commands/deposit.py b/tipbot/commands/deposit.py index daf2395..16ebfff 100644 --- a/tipbot/commands/deposit.py +++ b/tipbot/commands/deposit.py @@ -1,7 +1,9 @@ import logging +from telegram import ParseMode from tipbot import wownero from tipbot import db from tipbot.helpers.decorators import wallet_rpc_required, log_event, registration_required, check_debug +from tipbot.helpers.utils import generate_qr @wallet_rpc_required @@ -12,3 +14,8 @@ def deposit(update, context): u = db.User.get(telegram_id=update.message.from_user['id']) address = wownero.Wallet().addresses(account=u.account_index)[0] update.message.reply_text(f'Deposit address for {u.telegram_user}: {address}') + update.message.reply_photo( + photo=generate_qr(address), + caption=f'{u.telegram_user} deposit address: {address}', + quote=False + ) diff --git a/tipbot/commands/qr.py b/tipbot/commands/qr.py deleted file mode 100644 index e5444ff..0000000 --- a/tipbot/commands/qr.py +++ /dev/null @@ -1,13 +0,0 @@ -def qr(update, context): - if len(context.args) < 1: - update.message.reply_text('Not enough arguments passed.') - return False - - # validate address - if len(context.args[0]) in [97, 108]: - address = context.args[0] - else: - update.message.reply_text('This does not look like a valid Wownero address. Try again.') - return False - - update.message.reply_text(f'https://wownero.club/address/{address}') diff --git a/tipbot/config.example.py b/tipbot/config.example.py deleted file mode 100644 index 26377b0..0000000 --- a/tipbot/config.example.py +++ /dev/null @@ -1,9 +0,0 @@ -DEBUG = True -TG_TOKEN = 'tttttttttttt' -TG_ADMIN_ID = 0000000000 -WALLET_PROTO = 'http' -WALLET_HOST = 'localhost' -WALLET_PORT = 8888 -WALLET_USER = 'yyyy' -WALLET_PASS = 'xxxxxxxxx' -SQLITE_DB_PATH = '/tmp/db.sqlite' diff --git a/tipbot/config.py b/tipbot/config.py new file mode 100644 index 0000000..32d9345 --- /dev/null +++ b/tipbot/config.py @@ -0,0 +1,19 @@ +from dotenv import load_dotenv +from os import getenv + +load_dotenv() + +TG_TOKEN = getenv('TG_TOKEN') +TG_ADMIN_ID = int(getenv('TG_ADMIN_ID')) +WALLET_RPC_USER = getenv('WALLET_RPC_USER') +WALLET_RPC_PASS = getenv('WALLET_RPC_PASS') +SQLITE_DB_PATH = getenv('SQLITE_DB_PATH') +DAEMON_URI = getenv('DAEMON_URI') +_d = getenv('DEBUG', True) + +if isinstance(_d, str): + print(_d) + if _d.lower() == 'false': + DEBUG = False + else: + DEBUG = True diff --git a/tipbot/helpers/decorators.py b/tipbot/helpers/decorators.py index 61660d2..247edfa 100644 --- a/tipbot/helpers/decorators.py +++ b/tipbot/helpers/decorators.py @@ -22,8 +22,11 @@ def check_debug(f): def log_event(f): @wraps(f) def decorated_function(*args, **kwargs): + _d = '' + if config.DEBUG: + _d = ' (debug mode on)' msg = args[0].message - logging.info(f'"{f.__name__}" invoked from {msg.from_user["id"]} ({msg.from_user["first_name"]}) - Full command: "{msg.text}"') + logging.info(f'"{f.__name__}" invoked from {msg.from_user["id"]} ({msg.from_user["first_name"]}) - Full command: "{msg.text}"{_d}') return f(*args, **kwargs) return decorated_function diff --git a/tipbot/helpers/utils.py b/tipbot/helpers/utils.py index df974eb..fb3bcd0 100644 --- a/tipbot/helpers/utils.py +++ b/tipbot/helpers/utils.py @@ -1,3 +1,9 @@ +from io import BytesIO + +from PIL import Image +from base64 import b64encode +from qrcode import make as qrcode_make + from tipbot import config def is_tg_admin(chat_id): @@ -5,3 +11,9 @@ def is_tg_admin(chat_id): return True else: return False + +def generate_qr(s): + _address_qr = BytesIO() + qrcode_make(s).save(_address_qr, format="PNG") + _address_qr.seek(0) + return _address_qr diff --git a/tipbot/wownero.py b/tipbot/wownero.py index 9169a00..c6c7d40 100644 --- a/tipbot/wownero.py +++ b/tipbot/wownero.py @@ -10,16 +10,9 @@ PICOWOW = Decimal('0.00000000001') class Wallet(object): def __init__(self): - self.host = config.WALLET_HOST - self.port = config.WALLET_PORT - self.proto = config.WALLET_PROTO - self.username = config.WALLET_USER - self.password = config.WALLET_PASS - self.endpoint = '{}://{}:{}/json_rpc'.format( - self.proto, self.host, self.port - ) + self.endpoint = f'http://127.0.0.1:9999/json_rpc' self.auth = requests.auth.HTTPDigestAuth( - self.username, self.password + config.WALLET_RPC_USER, config.WALLET_RPC_PASS ) try: @@ -35,7 +28,6 @@ class Wallet(object): data=json.dumps({'method': method, 'params': params}), auth=self.auth ) - # print(r.status_code) if 'error' in r.json(): return r.json()['error'] else: @@ -54,15 +46,8 @@ class Wallet(object): return self.make_wallet_rpc('query_key', {'key_type': 'mnemonic'})['key'] def accounts(self): - accounts = [] _accounts = self.make_wallet_rpc('get_accounts') - idx = 0 - self.master_address = _accounts['subaddress_accounts'][0]['base_address'] - for _acc in _accounts['subaddress_accounts']: - assert idx == _acc['account_index'] - accounts.append(_acc['account_index']) - idx += 1 - return accounts + return [i['account_index'] for i in _accounts['subaddress_accounts']] def new_account(self, label=None): _account = self.make_wallet_rpc('create_account', {'label': label})