ui: Add wallet encryption templates.

tests: Test wallet encryption.
This commit is contained in:
tecnovert 2022-11-18 00:58:14 +02:00
parent 0f7df9e5f1
commit c5f31f0d1e
No known key found for this signature in database
GPG Key ID: 8ED6D8750C4E3F93
28 changed files with 430 additions and 113 deletions

View File

@ -748,6 +748,9 @@ class BasicSwap(BaseApp):
if len(self.swaps_in_progress) > 0: if len(self.swaps_in_progress) > 0:
raise ValueError('Can\'t change passwords while swaps are in progress') raise ValueError('Can\'t change passwords while swaps are in progress')
if old_password == new_password:
raise ValueError('Passwords must differ')
# Unlock all wallets to ensure they all have the same password. # Unlock all wallets to ensure they all have the same password.
for c in self.activeCoins(): for c in self.activeCoins():
ci = self.ci(c) ci = self.ci(c)

View File

@ -375,7 +375,7 @@ class CoinInterface:
return ticker return ticker
def getExchangeTicker(self, exchange_name): def getExchangeTicker(self, exchange_name):
return self.ticker() return chainparams[self.coin_type()]['ticker']
def getExchangeName(self, exchange_name): def getExchangeName(self, exchange_name):
return chainparams[self.coin_type()]['name'] return chainparams[self.coin_type()]['name']

View File

@ -17,6 +17,7 @@ from . import __version__
from .util import ( from .util import (
dumpj, dumpj,
ensure, ensure,
LockedCoinError,
format_timestamp, format_timestamp,
) )
from .chainparams import ( from .chainparams import (
@ -50,6 +51,7 @@ from .ui.page_offers import page_offers, page_offer, page_newoffer
from .ui.page_tor import page_tor, get_tor_established_state from .ui.page_tor import page_tor, get_tor_established_state
from .ui.page_wallet import page_wallets, page_wallet from .ui.page_wallet import page_wallets, page_wallet
from .ui.page_settings import page_settings from .ui.page_settings import page_settings
from .ui.page_encryption import page_changepassword, page_unlock, page_lock
env = Environment(loader=PackageLoader('basicswap', 'templates')) env = Environment(loader=PackageLoader('basicswap', 'templates'))
env.filters['formatts'] = format_timestamp env.filters['formatts'] = format_timestamp
@ -623,9 +625,17 @@ class HttpHandler(BaseHTTPRequestHandler):
return page_automation_strategy_new(self, url_split, post_string) return page_automation_strategy_new(self, url_split, post_string)
if page == 'shutdown': if page == 'shutdown':
return self.page_shutdown(url_split, post_string) return self.page_shutdown(url_split, post_string)
if page == 'changepassword':
return page_changepassword(self, url_split, post_string)
if page == 'unlock':
return page_unlock(self, url_split, post_string)
if page == 'lock':
return page_lock(self, url_split, post_string)
if page != '': if page != '':
return self.page_404(url_split) return self.page_404(url_split)
return self.page_index(url_split) return self.page_index(url_split)
except LockedCoinError:
return page_unlock(self, url_split, post_string)
except Exception as ex: except Exception as ex:
if swap_client.debug is True: if swap_client.debug is True:
swap_client.log.error(traceback.format_exc()) swap_client.log.error(traceback.format_exc())

View File

@ -1305,6 +1305,8 @@ class BTCInterface(CoinInterface):
def changeWalletPassword(self, old_password, new_password): def changeWalletPassword(self, old_password, new_password):
self._log.info('changeWalletPassword - {}'.format(self.ticker())) self._log.info('changeWalletPassword - {}'.format(self.ticker()))
if old_password == '': if old_password == '':
if self.isWalletEncrypted():
raise ValueError('Old password must be set')
return self.rpc_callback('encryptwallet', [new_password]) return self.rpc_callback('encryptwallet', [new_password])
self.rpc_callback('walletpassphrasechange', [old_password, new_password]) self.rpc_callback('walletpassphrasechange', [old_password, new_password])

View File

@ -481,7 +481,7 @@ def js_unlock(self, url_split, post_string, is_json):
def js_lock(self, url_split, post_string, is_json): def js_lock(self, url_split, post_string, is_json):
swap_client = self.server.swap_client swap_client = self.server.swap_client
post_data = getFormData(post_string, is_json) post_data = {} if post_string == '' else getFormData(post_string, is_json)
if have_data_entry(post_data, 'coin'): if have_data_entry(post_data, 'coin'):
coin = getCoinType(get_data_entry(post_data, 'coin')) coin = getCoinType(get_data_entry(post_data, 'coin'))

View File

@ -0,0 +1,27 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<link rel=icon sizes="32x32" type="image/png" href="/static/images/favicon-32.png">
<title>{{ title }}</title>
</head>
<body>
<h2>Change password</h2>
{% for m in messages %}
<p>{{ m }}</p>
{% endfor %}
{% for m in err_messages %}
<p class="error_msg">Error: {{ m }}</p>
{% endfor %}
<form method="post">
<table>
<tr><td>Old Password</td><td><input type="text" name="oldpassword"></td></tr>
<tr><td>New Password</td><td><input type="text" name="newpassword"></td></tr>
<tr><td>Confirm Password</td><td><input type="text" name="confirmpassword"></td></tr>
<tr><td><input type="submit" name="unlock" value="Unlock"></td></tr>
</table>
<input type="hidden" name="formid" value="{{ form_id }}">
</form>
<p><a href="/">home</a></p>
</body>
</html>

View File

@ -0,0 +1,23 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<link rel=icon sizes="32x32" type="image/png" href="/static/images/favicon-32.png">
<title>{{ title }}</title>
</head>
<body>
<h2>Unlock wallet</h2>
{% for m in messages %}
<p>{{ m }}</p>
{% endfor %}
{% for m in err_messages %}
<p class="error_msg">Error: {{ m }}</p>
{% endfor %}
<form method="post">
<input type="text" name="password"><br/>
<input type="submit" name="unlock" value="Unlock">
<input type="hidden" name="formid" value="{{ form_id }}">
</form>
<p><a href="/">home</a></p>
</body>
</html>

View File

@ -0,0 +1,87 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2022 tecnovert
# Distributed under the MIT software license, see the accompanying
# file LICENSE or http://www.opensource.org/licenses/mit-license.php.
from .util import (
get_data_entry_or,
)
def page_changepassword(self, url_split, post_string):
server = self.server
swap_client = server.swap_client
swap_client.checkSystemStatus()
messages = []
err_messages = []
form_data = self.checkForm(post_string, 'changepassword', err_messages)
if form_data:
old_password = get_data_entry_or(form_data, 'oldpassword', '')
new_password = get_data_entry_or(form_data, 'newpassword', '')
confirm_password = get_data_entry_or(form_data, 'confirmpassword', '')
try:
if new_password == '':
raise ValueError('New password must be entered.')
if new_password != confirm_password:
raise ValueError('New password and confirm password must match.')
swap_client.changeWalletPasswords(old_password, new_password)
messages.append('Password changed')
except Exception as e:
err_messages.append(str(e))
template = server.env.get_template('changepassword.html')
return self.render_template(template, {
'messages': messages,
'err_messages': err_messages,
})
def page_unlock(self, url_split, post_string):
server = self.server
swap_client = server.swap_client
messages = []
err_messages = []
form_data = self.checkForm(post_string, 'unlock', err_messages)
if form_data:
password = get_data_entry_or(form_data, 'password', '')
try:
if password == '':
raise ValueError('Password must be entered.')
swap_client.unlockWallets(password)
self.send_response(302)
self.send_header('Location', '/')
self.end_headers()
return bytes()
except Exception as e:
err_messages.append(str(e))
template = server.env.get_template('unlock.html')
return self.render_template(template, {
'messages': messages,
'err_messages': err_messages,
})
def page_lock(self, url_split, post_string):
server = self.server
swap_client = server.swap_client
swap_client.checkSystemStatus()
swap_client.lockWallets()
messages = []
err_messages = []
template = server.env.get_template('info.html')
return self.render_template(template, {
'messages': messages,
'err_messages': err_messages,
'message_str': 'Wallets locked'
})

View File

@ -7,11 +7,11 @@
import os import os
import json import json
import urllib
import signal import signal
import logging import logging
from urllib.request import urlopen from urllib.request import urlopen
from .util import read_json_api
from basicswap.rpc import callrpc from basicswap.rpc import callrpc
from basicswap.contrib.rpcauth import generate_salt, password_to_hmac from basicswap.contrib.rpcauth import generate_salt, password_to_hmac
from bin.basicswap_prepare import downloadPIVXParams from bin.basicswap_prepare import downloadPIVXParams
@ -215,38 +215,6 @@ def wait_for_in_progress(delay_event, swap_client, bid_id, sent=False):
raise ValueError('wait_for_in_progress timed out.') raise ValueError('wait_for_in_progress timed out.')
def post_json_req(url, json_data):
req = urllib.request.Request(url)
req.add_header('Content-Type', 'application/json; charset=utf-8')
post_bytes = json.dumps(json_data).encode('utf-8')
req.add_header('Content-Length', len(post_bytes))
return urlopen(req, post_bytes, timeout=300).read()
def read_text_api(port, path=None):
url = f'http://127.0.0.1:{port}/json'
if path is not None:
url += '/' + path
return urlopen(url, timeout=300).read().decode('utf-8')
def read_json_api(port, path=None, json_data=None):
url = f'http://127.0.0.1:{port}/json'
if path is not None:
url += '/' + path
if json_data is not None:
return json.loads(post_json_req(url, json_data))
return json.loads(urlopen(url, timeout=300).read())
def post_json_api(port, path, json_data):
url = f'http://127.0.0.1:{port}/json'
if path is not None:
url += '/' + path
return json.loads(post_json_req(url, json_data))
def wait_for_none_active(delay_event, port, wait_for=30): def wait_for_none_active(delay_event, port, wait_for=30):
for i in range(wait_for): for i in range(wait_for):
if delay_event.is_set(): if delay_event.is_set():
@ -258,19 +226,6 @@ def wait_for_none_active(delay_event, port, wait_for=30):
raise ValueError('wait_for_none_active timed out.') raise ValueError('wait_for_none_active timed out.')
def waitForServer(delay_event, port, wait_for=20):
for i in range(wait_for):
if delay_event.is_set():
raise ValueError('Test stopped.')
try:
delay_event.wait(1)
summary = read_json_api(port)
return
except Exception as e:
print('waitForServer, error:', str(e))
raise ValueError('waitForServer failed')
def waitForNumOffers(delay_event, port, offers, wait_for=20): def waitForNumOffers(delay_event, port, offers, wait_for=20):
for i in range(wait_for): for i in range(wait_for):
if delay_event.is_set(): if delay_event.is_set():
@ -321,10 +276,6 @@ def delay_for(delay_event, delay_for=60):
delay_event.wait(delay_for) delay_event.wait(delay_for)
def make_boolean(s):
return s.lower() in ['1', 'true']
def make_rpc_func(node_id, base_rpc_port=BASE_RPC_PORT): def make_rpc_func(node_id, base_rpc_port=BASE_RPC_PORT):
node_id = node_id node_id = node_id
auth = 'test{0}:test_pass{0}'.format(node_id) auth = 'test{0}:test_pass{0}'.format(node_id)

View File

@ -22,8 +22,10 @@ from basicswap.rpc_xmr import (
callrpc_xmr_na, callrpc_xmr_na,
) )
from tests.basicswap.mnemonics import mnemonics from tests.basicswap.mnemonics import mnemonics
from tests.basicswap.common import ( from tests.basicswap.util import (
waitForServer, waitForServer,
)
from tests.basicswap.common import (
BASE_PORT, BASE_RPC_PORT, BASE_PORT, BASE_RPC_PORT,
BTC_BASE_PORT, BTC_BASE_RPC_PORT, BTC_BASE_TOR_PORT, BTC_BASE_PORT, BTC_BASE_RPC_PORT, BTC_BASE_TOR_PORT,
LTC_BASE_PORT, LTC_BASE_PORT,

View File

@ -48,6 +48,9 @@ from basicswap.contrib.key import (
from basicswap.http_server import ( from basicswap.http_server import (
HttpThread, HttpThread,
) )
from tests.basicswap.util import (
read_json_api,
)
from tests.basicswap.common import ( from tests.basicswap.common import (
checkForks, checkForks,
stopDaemons, stopDaemons,
@ -55,7 +58,6 @@ from tests.basicswap.common import (
wait_for_bid, wait_for_bid,
wait_for_bid_tx_state, wait_for_bid_tx_state,
wait_for_in_progress, wait_for_in_progress,
read_json_api,
TEST_HTTP_HOST, TEST_HTTP_HOST,
TEST_HTTP_PORT, TEST_HTTP_PORT,
BASE_PORT, BASE_PORT,

View File

@ -29,11 +29,13 @@ from basicswap.rpc import (
callrpc_cli, callrpc_cli,
waitForRPC, waitForRPC,
) )
from tests.basicswap.util import (
read_json_api,
)
from tests.basicswap.common import ( from tests.basicswap.common import (
stopDaemons, stopDaemons,
wait_for_bid, wait_for_bid,
make_rpc_func, make_rpc_func,
read_json_api,
TEST_HTTP_PORT, TEST_HTTP_PORT,
wait_for_offer, wait_for_offer,
wait_for_in_progress, wait_for_in_progress,

View File

@ -39,13 +39,15 @@ from basicswap.contrib.key import (
from basicswap.http_server import ( from basicswap.http_server import (
HttpThread, HttpThread,
) )
from tests.basicswap.util import (
read_json_api,
)
from tests.basicswap.common import ( from tests.basicswap.common import (
prepareDataDir, prepareDataDir,
make_rpc_func, make_rpc_func,
checkForks, checkForks,
stopDaemons, stopDaemons,
delay_for, delay_for,
read_json_api,
TEST_HTTP_HOST, TEST_HTTP_HOST,
TEST_HTTP_PORT, TEST_HTTP_PORT,
BASE_P2P_PORT, BASE_P2P_PORT,

View File

@ -47,6 +47,9 @@ from basicswap.contrib.key import (
from basicswap.http_server import ( from basicswap.http_server import (
HttpThread, HttpThread,
) )
from tests.basicswap.util import (
read_json_api,
)
from tests.basicswap.common import ( from tests.basicswap.common import (
checkForks, checkForks,
stopDaemons, stopDaemons,
@ -54,7 +57,6 @@ from tests.basicswap.common import (
wait_for_bid, wait_for_bid,
wait_for_bid_tx_state, wait_for_bid_tx_state,
wait_for_in_progress, wait_for_in_progress,
read_json_api,
TEST_HTTP_HOST, TEST_HTTP_HOST,
TEST_HTTP_PORT, TEST_HTTP_PORT,
BASE_PORT, BASE_PORT,

View File

@ -47,6 +47,9 @@ from basicswap.contrib.key import (
from basicswap.http_server import ( from basicswap.http_server import (
HttpThread, HttpThread,
) )
from tests.basicswap.util import (
read_json_api,
)
from tests.basicswap.common import ( from tests.basicswap.common import (
checkForks, checkForks,
stopDaemons, stopDaemons,
@ -54,7 +57,6 @@ from tests.basicswap.common import (
wait_for_bid, wait_for_bid,
wait_for_bid_tx_state, wait_for_bid_tx_state,
wait_for_in_progress, wait_for_in_progress,
read_json_api,
TEST_HTTP_HOST, TEST_HTTP_HOST,
TEST_HTTP_PORT, TEST_HTTP_PORT,
BASE_PORT, BASE_PORT,

View File

@ -1,7 +1,7 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Copyright (c) 2019 tecnovert # Copyright (c) 2019-2022 tecnovert
# Distributed under the MIT software license, see the accompanying # Distributed under the MIT software license, see the accompanying
# file LICENSE or http://www.opensource.org/licenses/mit-license.php. # file LICENSE or http://www.opensource.org/licenses/mit-license.php.
@ -11,39 +11,80 @@ import json
import shutil import shutil
import logging import logging
import unittest import unittest
import threading
import multiprocessing
from io import StringIO from io import StringIO
from unittest.mock import patch from unittest.mock import patch
import basicswap.config as cfg import basicswap.config as cfg
import bin.basicswap_prepare as prepareSystem from tests.basicswap.util import (
test_path = os.path.expanduser(os.getenv('TEST_PREPARE_PATH', '~/test_basicswap')) read_json_api,
waitForServer,
)
bin_path = os.path.expanduser(os.getenv('TEST_BIN_PATH', ''))
test_base_path = os.path.expanduser(os.getenv('TEST_PREPARE_PATH', '~/test_basicswap'))
test_path_plain = os.path.join(test_base_path, 'plain')
test_path_encrypted = os.path.join(test_base_path, 'encrypted')
test_path_encrypt = os.path.join(test_base_path, 'encrypt')
delay_event = threading.Event()
logger = logging.getLogger() logger = logging.getLogger()
logger.level = logging.DEBUG logger.level = logging.DEBUG
if not len(logger.handlers): logger.addHandler(logging.StreamHandler(sys.stdout))
logger.addHandler(logging.StreamHandler(sys.stdout))
def start_prepare(args, env_pairs=[]):
for pair in env_pairs:
os.environ[pair[0]] = pair[1]
print(pair[0], os.environ[pair[0]])
import bin.basicswap_prepare as prepareSystemThread
with patch.object(sys, 'argv', args):
prepareSystemThread.main()
del prepareSystemThread
def start_run(args, env_pairs=[]):
for pair in env_pairs:
os.environ[pair[0]] = pair[1]
print(pair[0], os.environ[pair[0]])
import bin.basicswap_run as runSystemThread
with patch.object(sys, 'argv', args):
runSystemThread.main()
del runSystemThread
class Test(unittest.TestCase): class Test(unittest.TestCase):
@classmethod @classmethod
def tearDownClass(self): def tearDownClass(self):
try: try:
shutil.rmtree(test_path) for test_dir in (test_path_plain, test_path_encrypted, test_path_encrypt):
if os.path.exists(test_dir):
shutil.rmtree(test_dir)
except Exception as ex: except Exception as ex:
logger.warning('tearDownClass %s', str(ex)) logger.warning('tearDownClass %s', str(ex))
super(Test, self).tearDownClass() super(Test, self).tearDownClass()
def test(self): def test_plain(self):
testargs = ['basicswap-prepare', '-datadir=' + test_path, '-withcoin=litecoin'] if os.path.exists(test_path_plain):
with patch.object(sys, 'argv', testargs): shutil.rmtree(test_path_plain)
prepareSystem.main() if bin_path != '':
os.makedirs(test_path_plain)
os.symlink(bin_path, os.path.join(test_path_plain, 'bin'))
config_path = os.path.join(test_path, cfg.CONFIG_FILENAME) testargs = ('basicswap-prepare', '-datadir=' + test_path_plain, '-withcoin=litecoin')
process = multiprocessing.Process(target=start_prepare, args=(testargs,))
process.start()
process.join()
config_path = os.path.join(test_path_plain, cfg.CONFIG_FILENAME)
self.assertTrue(os.path.exists(config_path)) self.assertTrue(os.path.exists(config_path))
logger.info('Test no overwrite') import bin.basicswap_prepare as prepareSystem
testargs = ['basicswap-prepare', '-datadir=' + test_path, '-withcoin=litecoin'] try:
logging.info('Test no overwrite')
testargs = ['basicswap-prepare', '-datadir=' + test_path_plain, '-withcoin=litecoin']
with patch('sys.stderr', new=StringIO()) as fake_stderr: with patch('sys.stderr', new=StringIO()) as fake_stderr:
with patch.object(sys, 'argv', testargs): with patch.object(sys, 'argv', testargs):
with self.assertRaises(SystemExit) as cm: with self.assertRaises(SystemExit) as cm:
@ -54,7 +95,7 @@ class Test(unittest.TestCase):
self.assertTrue('exists, exiting' in fake_stderr.getvalue()) self.assertTrue('exists, exiting' in fake_stderr.getvalue())
logger.info('Test addcoin new') logger.info('Test addcoin new')
testargs = ['basicswap-prepare', '-datadir=' + test_path, '-addcoin=namecoin'] testargs = ['basicswap-prepare', '-datadir=' + test_path_plain, '-addcoin=namecoin']
with patch.object(sys, 'argv', testargs): with patch.object(sys, 'argv', testargs):
prepareSystem.main() prepareSystem.main()
with open(config_path) as fs: with open(config_path) as fs:
@ -62,7 +103,7 @@ class Test(unittest.TestCase):
self.assertTrue(settings['chainclients']['namecoin']['connection_type'] == 'rpc') self.assertTrue(settings['chainclients']['namecoin']['connection_type'] == 'rpc')
logger.info('Test disablecoin') logger.info('Test disablecoin')
testargs = ['basicswap-prepare', '-datadir=' + test_path, '-disablecoin=namecoin'] testargs = ['basicswap-prepare', '-datadir=' + test_path_plain, '-disablecoin=namecoin']
with patch.object(sys, 'argv', testargs): with patch.object(sys, 'argv', testargs):
prepareSystem.main() prepareSystem.main()
with open(config_path) as fs: with open(config_path) as fs:
@ -70,12 +111,92 @@ class Test(unittest.TestCase):
self.assertTrue(settings['chainclients']['namecoin']['connection_type'] == 'none') self.assertTrue(settings['chainclients']['namecoin']['connection_type'] == 'none')
logger.info('Test addcoin existing') logger.info('Test addcoin existing')
testargs = ['basicswap-prepare', '-datadir=' + test_path, '-addcoin=namecoin'] testargs = ['basicswap-prepare', '-datadir=' + test_path_plain, '-addcoin=namecoin']
with patch.object(sys, 'argv', testargs): with patch.object(sys, 'argv', testargs):
prepareSystem.main() prepareSystem.main()
with open(config_path) as fs: with open(config_path) as fs:
settings = json.load(fs) settings = json.load(fs)
self.assertTrue(settings['chainclients']['namecoin']['connection_type'] == 'rpc') self.assertTrue(settings['chainclients']['namecoin']['connection_type'] == 'rpc')
finally:
del prepareSystem
def test_encrypted(self):
if os.path.exists(test_path_encrypted):
shutil.rmtree(test_path_encrypted)
if bin_path != '':
os.makedirs(test_path_encrypted)
os.symlink(bin_path, os.path.join(test_path_encrypted, 'bin'))
env_vars = [('WALLET_ENCRYPTION_PWD', 'test123'), ]
testargs = ('basicswap-prepare', '-datadir=' + test_path_encrypted, '-withcoin=litecoin,monero')
process = multiprocessing.Process(target=start_prepare, args=(testargs, env_vars))
process.start()
process.join()
assert (process.exitcode == 0)
logger.info('Should not be able to add a coin without setting WALLET_ENCRYPTION_PWD')
testargs = ('basicswap-prepare', '-datadir=' + test_path_encrypted, '-addcoin=bitcoin')
process = multiprocessing.Process(target=start_prepare, args=(testargs, []))
process.start()
process.join()
assert (process.exitcode == 1)
testargs = ('basicswap-prepare', '-datadir=' + test_path_encrypted, '-addcoin=bitcoin')
process = multiprocessing.Process(target=start_prepare, args=(testargs, env_vars))
process.start()
process.join()
assert (process.exitcode == 0)
def test_encrypt(self):
if os.path.exists(test_path_encrypt):
shutil.rmtree(test_path_encrypt)
if bin_path != '':
os.makedirs(test_path_encrypt)
os.symlink(bin_path, os.path.join(test_path_encrypt, 'bin'))
testargs = ('basicswap-prepare', '-regtest=1', '-datadir=' + test_path_encrypt, '-withcoin=litecoin,monero')
process = multiprocessing.Process(target=start_prepare, args=(testargs, ))
process.start()
process.join()
assert (process.exitcode == 0)
logger.info('basicswap-run should fail if WALLET_ENCRYPTION_PWD is set')
env_vars = [('WALLET_ENCRYPTION_PWD', 'test123'), ]
testargs = ('basicswap-run', '-regtest=1', '-datadir=' + test_path_encrypt)
process = multiprocessing.Process(target=start_run, args=(testargs, env_vars))
process.start()
process.join()
assert (process.exitcode == 1)
testargs = ('basicswap-run', '-regtest=1', '-datadir=' + test_path_encrypt)
process = multiprocessing.Process(target=start_run, args=(testargs, ))
process.start()
waitForServer(delay_event, 12700)
rv = read_json_api(12700, 'setpassword', {'oldpassword': 'wrongpass', 'newpassword': 'test123'})
assert ('error' in rv)
rv = read_json_api(12700, 'setpassword', {'oldpassword': '', 'newpassword': 'test123'})
assert ('success' in rv)
rv = read_json_api(12700, 'setpassword', {'oldpassword': 'test123', 'newpassword': 'next123'})
assert ('success' in rv)
rv = read_json_api(12700, 'lock')
assert ('success' in rv)
rv = read_json_api(12700, 'wallets')
assert ('error' in rv)
rv = read_json_api(12700, 'unlock', {'password': 'next123'})
assert ('success' in rv)
rv = read_json_api(12700, 'wallets')
assert ('PART' in rv)
process.terminate()
process.join()
assert (process.exitcode == 0)
if __name__ == '__main__': if __name__ == '__main__':

View File

@ -27,7 +27,7 @@ import multiprocessing
from unittest.mock import patch from unittest.mock import patch
from tests.basicswap.mnemonics import mnemonics from tests.basicswap.mnemonics import mnemonics
from tests.basicswap.common import ( from tests.basicswap.util import (
read_json_api, read_json_api,
waitForServer, waitForServer,
) )

View File

@ -26,10 +26,12 @@ import traceback
import multiprocessing import multiprocessing
from unittest.mock import patch from unittest.mock import patch
from tests.basicswap.common import ( from tests.basicswap.util import (
read_json_api, read_json_api,
post_json_api, post_json_api,
waitForServer, waitForServer,
)
from tests.basicswap.common import (
waitForNumOffers, waitForNumOffers,
waitForNumBids, waitForNumBids,
) )

View File

@ -34,11 +34,13 @@ from basicswap.rpc import (
callrpc, callrpc,
) )
from tests.basicswap.common import ( from tests.basicswap.common import (
BASE_RPC_PORT,
BTC_BASE_RPC_PORT,
)
from tests.basicswap.util import (
make_boolean, make_boolean,
read_json_api, read_json_api,
waitForServer, waitForServer,
BASE_RPC_PORT,
BTC_BASE_RPC_PORT,
) )
from tests.basicswap.common_xmr import ( from tests.basicswap.common_xmr import (
prepare_nodes, prepare_nodes,

View File

@ -22,9 +22,11 @@ from basicswap.util import (
make_int, make_int,
format_amount, format_amount,
) )
from tests.basicswap.util import (
read_json_api,
)
from tests.basicswap.common import ( from tests.basicswap.common import (
wait_for_bid, wait_for_bid,
read_json_api,
wait_for_offer, wait_for_offer,
wait_for_none_active, wait_for_none_active,
BTC_BASE_RPC_PORT, BTC_BASE_RPC_PORT,

View File

@ -17,9 +17,11 @@ from basicswap.basicswap import (
from basicswap.util import ( from basicswap.util import (
COIN, COIN,
) )
from tests.basicswap.util import (
read_json_api,
)
from tests.basicswap.common import ( from tests.basicswap.common import (
wait_for_bid, wait_for_bid,
read_json_api,
wait_for_offer, wait_for_offer,
wait_for_in_progress, wait_for_in_progress,
LTC_BASE_RPC_PORT, LTC_BASE_RPC_PORT,

View File

@ -25,13 +25,15 @@ from basicswap.util import (
make_int, make_int,
format_amount, format_amount,
) )
from tests.basicswap.util import (
post_json_req,
read_json_api,
)
from tests.basicswap.common import ( from tests.basicswap.common import (
wait_for_bid, wait_for_bid,
read_json_api,
wait_for_offer, wait_for_offer,
wait_for_none_active, wait_for_none_active,
wait_for_balance, wait_for_balance,
post_json_req,
) )
from .test_xmr import BaseTest, test_delay_event from .test_xmr import BaseTest, test_delay_event

View File

@ -26,10 +26,12 @@ from unittest.mock import patch
from basicswap.rpc import ( from basicswap.rpc import (
callrpc_cli, callrpc_cli,
) )
from tests.basicswap.common import ( from tests.basicswap.util import (
read_json_api, read_json_api,
post_json_api, post_json_api,
waitForServer, waitForServer,
)
from tests.basicswap.common import (
waitForNumOffers, waitForNumOffers,
waitForNumBids, waitForNumBids,
waitForNumSwapping, waitForNumSwapping,

View File

@ -36,13 +36,15 @@ from basicswap.util import (
make_int, make_int,
format_amount, format_amount,
) )
from tests.basicswap.util import (
read_json_api,
)
from tests.basicswap.common import ( from tests.basicswap.common import (
wait_for_offer, wait_for_offer,
wait_for_bid, wait_for_bid,
wait_for_balance, wait_for_balance,
wait_for_bid_tx_state, wait_for_bid_tx_state,
wait_for_in_progress, wait_for_in_progress,
read_json_api,
TEST_HTTP_PORT, TEST_HTTP_PORT,
LTC_BASE_RPC_PORT, LTC_BASE_RPC_PORT,
BTC_BASE_RPC_PORT, BTC_BASE_RPC_PORT,

View File

@ -57,9 +57,15 @@ from basicswap.contrib.key import (
from basicswap.http_server import ( from basicswap.http_server import (
HttpThread, HttpThread,
) )
from tests.basicswap.util import (
make_boolean,
post_json_req,
)
from tests.basicswap.util import (
read_json_api,
)
from tests.basicswap.common import ( from tests.basicswap.common import (
prepareDataDir, prepareDataDir,
make_boolean,
make_rpc_func, make_rpc_func,
checkForks, checkForks,
stopDaemons, stopDaemons,
@ -69,8 +75,6 @@ from tests.basicswap.common import (
wait_for_no_offer, wait_for_no_offer,
wait_for_none_active, wait_for_none_active,
wait_for_balance, wait_for_balance,
post_json_req,
read_json_api,
compare_bid_states, compare_bid_states,
extract_states_from_xu_file, extract_states_from_xu_file,
TEST_HTTP_HOST, TEST_HTTP_HOST,

View File

@ -23,9 +23,11 @@ import multiprocessing
from urllib import parse from urllib import parse
from urllib.request import urlopen from urllib.request import urlopen
from tests.basicswap.common import ( from tests.basicswap.util import (
read_json_api, read_json_api,
waitForServer, waitForServer,
)
from tests.basicswap.common import (
waitForNumOffers, waitForNumOffers,
waitForNumBids, waitForNumBids,
) )

View File

@ -20,10 +20,12 @@ import logging
import unittest import unittest
import multiprocessing import multiprocessing
from tests.basicswap.common import ( from tests.basicswap.util import (
read_json_api, read_json_api,
post_json_api, post_json_api,
waitForServer, waitForServer,
)
from tests.basicswap.common import (
waitForNumOffers, waitForNumOffers,
waitForNumBids, waitForNumBids,
waitForNumSwapping, waitForNumSwapping,

59
tests/basicswap/util.py Normal file
View File

@ -0,0 +1,59 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Copyright (c) 2022 tecnovert
# Distributed under the MIT software license, see the accompanying
# file LICENSE.txt or http://www.opensource.org/licenses/mit-license.php.
import json
import urllib
from urllib.request import urlopen
def make_boolean(s):
return s.lower() in ['1', 'true']
def post_json_req(url, json_data):
req = urllib.request.Request(url)
req.add_header('Content-Type', 'application/json; charset=utf-8')
post_bytes = json.dumps(json_data).encode('utf-8')
req.add_header('Content-Length', len(post_bytes))
return urlopen(req, post_bytes, timeout=300).read()
def read_text_api(port, path=None):
url = f'http://127.0.0.1:{port}/json'
if path is not None:
url += '/' + path
return urlopen(url, timeout=300).read().decode('utf-8')
def read_json_api(port, path=None, json_data=None):
url = f'http://127.0.0.1:{port}/json'
if path is not None:
url += '/' + path
if json_data is not None:
return json.loads(post_json_req(url, json_data))
return json.loads(urlopen(url, timeout=300).read())
def post_json_api(port, path, json_data):
url = f'http://127.0.0.1:{port}/json'
if path is not None:
url += '/' + path
return json.loads(post_json_req(url, json_data))
def waitForServer(delay_event, port, wait_for=20):
for i in range(wait_for):
if delay_event.is_set():
raise ValueError('Test stopped.')
try:
delay_event.wait(1)
summary = read_json_api(port)
return
except Exception as e:
print('waitForServer, error:', str(e))
raise ValueError('waitForServer failed')