mirror of
https://github.com/basicswap/basicswap.git
synced 2025-11-06 02:38:11 +01:00
ui: Refactor offers page / Added TOR <> API / Cache
Restructure / Refactor JS for the Offers page. Added TOR for chart/rates/coin prices/ API requests. New Chart with option of show volume(coin) / refresh chart (will clear cache). Added cache (10min) for all the API's or manual refresh. Disabled notifications show new offers (was spam). New bids and Bid Accepted still active. Various small fixes.
This commit is contained in:
@@ -15,6 +15,9 @@ import logging
|
|||||||
import threading
|
import threading
|
||||||
import traceback
|
import traceback
|
||||||
import subprocess
|
import subprocess
|
||||||
|
import urllib.request
|
||||||
|
import urllib.error
|
||||||
|
import json
|
||||||
|
|
||||||
from sockshandler import SocksiPyHandler
|
from sockshandler import SocksiPyHandler
|
||||||
|
|
||||||
@@ -162,19 +165,41 @@ class BaseApp:
|
|||||||
socket.getaddrinfo = self.default_socket_getaddrinfo
|
socket.getaddrinfo = self.default_socket_getaddrinfo
|
||||||
socket.setdefaulttimeout(self.default_socket_timeout)
|
socket.setdefaulttimeout(self.default_socket_timeout)
|
||||||
|
|
||||||
def readURL(self, url: str, timeout: int = 120, headers=None) -> bytes:
|
def is_tor_available(self):
|
||||||
open_handler = None
|
if not hasattr(self, 'use_tor_proxy'):
|
||||||
if self.use_tor_proxy:
|
return False
|
||||||
open_handler = SocksiPyHandler(socks.PROXY_TYPE_SOCKS5, self.tor_proxy_host, self.tor_proxy_port)
|
if not self.use_tor_proxy:
|
||||||
opener = urllib.request.build_opener(open_handler) if self.use_tor_proxy else urllib.request.build_opener()
|
return False
|
||||||
opener.addheaders = [('User-agent', 'Mozilla/5.0')]
|
try:
|
||||||
request = urllib.request.Request(url, headers=headers)
|
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
return opener.open(request, timeout=timeout).read()
|
result = sock.connect_ex((self.tor_proxy_host, self.tor_proxy_port))
|
||||||
|
sock.close()
|
||||||
|
return result == 0
|
||||||
|
except:
|
||||||
|
return False
|
||||||
|
|
||||||
def logException(self, message) -> None:
|
def readURL(self, url: str, timeout: int = 120, headers={}) -> bytes:
|
||||||
self.log.error(message)
|
use_tor = self.is_tor_available()
|
||||||
if self.debug:
|
try:
|
||||||
self.log.error(traceback.format_exc())
|
if use_tor:
|
||||||
|
proxy_handler = SocksiPyHandler(socks.PROXY_TYPE_SOCKS5, self.tor_proxy_host, self.tor_proxy_port)
|
||||||
|
opener = urllib.request.build_opener(proxy_handler)
|
||||||
|
else:
|
||||||
|
opener = urllib.request.build_opener()
|
||||||
|
|
||||||
|
opener.addheaders = [(key, value) for key, value in headers.items()]
|
||||||
|
request = urllib.request.Request(url)
|
||||||
|
|
||||||
|
with opener.open(request, timeout=timeout) as response:
|
||||||
|
return response.read()
|
||||||
|
except urllib.error.URLError as e:
|
||||||
|
if isinstance(e.reason, ConnectionRefusedError) and use_tor:
|
||||||
|
error_msg = f"Connection refused. Tor proxy might not be running. Error: {str(e)}"
|
||||||
|
else:
|
||||||
|
error_msg = f"URLError: {str(e)}"
|
||||||
|
except Exception as e:
|
||||||
|
error_msg = f"Unexpected error: {str(e)}"
|
||||||
|
return json.dumps({"Error": error_msg}).encode()
|
||||||
|
|
||||||
def torControl(self, query):
|
def torControl(self, query):
|
||||||
try:
|
try:
|
||||||
|
|||||||
@@ -111,7 +111,6 @@ def parse_cmd(cmd: str, type_map: str):
|
|||||||
|
|
||||||
|
|
||||||
class HttpHandler(BaseHTTPRequestHandler):
|
class HttpHandler(BaseHTTPRequestHandler):
|
||||||
|
|
||||||
def log_error(self, format, *args):
|
def log_error(self, format, *args):
|
||||||
super().log_message(format, *args)
|
super().log_message(format, *args)
|
||||||
|
|
||||||
@@ -145,9 +144,12 @@ class HttpHandler(BaseHTTPRequestHandler):
|
|||||||
args_dict['use_tor_proxy'] = True
|
args_dict['use_tor_proxy'] = True
|
||||||
# TODO: Cache value?
|
# TODO: Cache value?
|
||||||
try:
|
try:
|
||||||
args_dict['tor_established'] = True if get_tor_established_state(swap_client) == '1' else False
|
tor_state = get_tor_established_state(swap_client)
|
||||||
except Exception:
|
args_dict['tor_established'] = True if tor_state == '1' else False
|
||||||
|
except Exception as e:
|
||||||
|
args_dict['tor_established'] = False
|
||||||
if swap_client.debug:
|
if swap_client.debug:
|
||||||
|
swap_client.log.error(f"Error getting Tor state: {str(e)}")
|
||||||
swap_client.log.error(traceback.format_exc())
|
swap_client.log.error(traceback.format_exc())
|
||||||
|
|
||||||
if swap_client._show_notifications:
|
if swap_client._show_notifications:
|
||||||
@@ -409,12 +411,10 @@ class HttpHandler(BaseHTTPRequestHandler):
|
|||||||
swap_client = self.server.swap_client
|
swap_client = self.server.swap_client
|
||||||
swap_client.checkSystemStatus()
|
swap_client.checkSystemStatus()
|
||||||
summary = swap_client.getSummary()
|
summary = swap_client.getSummary()
|
||||||
template = env.get_template('index.html')
|
self.send_response(302)
|
||||||
return self.render_template(template, {
|
self.send_header('Location', '/offers')
|
||||||
'refresh': 30,
|
self.end_headers()
|
||||||
'summary': summary,
|
return b''
|
||||||
'use_tor_proxy': swap_client.use_tor_proxy
|
|
||||||
})
|
|
||||||
|
|
||||||
def page_404(self, url_split):
|
def page_404(self, url_split):
|
||||||
swap_client = self.server.swap_client
|
swap_client = self.server.swap_client
|
||||||
|
|||||||
@@ -38,7 +38,6 @@ from .ui.util import (
|
|||||||
from .ui.page_offers import postNewOffer
|
from .ui.page_offers import postNewOffer
|
||||||
from .protocols.xmr_swap_1 import recoverNoScriptTxnWithKey, getChainBSplitKey
|
from .protocols.xmr_swap_1 import recoverNoScriptTxnWithKey, getChainBSplitKey
|
||||||
|
|
||||||
|
|
||||||
def getFormData(post_string: str, is_json: bool):
|
def getFormData(post_string: str, is_json: bool):
|
||||||
if post_string == '':
|
if post_string == '':
|
||||||
raise ValueError('No post data')
|
raise ValueError('No post data')
|
||||||
@@ -764,6 +763,25 @@ def js_help(self, url_split, post_string, is_json) -> bytes:
|
|||||||
commands.append(k)
|
commands.append(k)
|
||||||
return bytes(json.dumps({'commands': commands}), 'UTF-8')
|
return bytes(json.dumps({'commands': commands}), 'UTF-8')
|
||||||
|
|
||||||
|
def js_readurl(self, url_split, post_string, is_json) -> bytes:
|
||||||
|
swap_client = self.server.swap_client
|
||||||
|
post_data = {} if post_string == '' else getFormData(post_string, is_json)
|
||||||
|
if have_data_entry(post_data, 'url'):
|
||||||
|
url = get_data_entry(post_data, 'url')
|
||||||
|
default_headers = {
|
||||||
|
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36',
|
||||||
|
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
|
||||||
|
'Accept-Language': 'en-US,en;q=0.5',
|
||||||
|
}
|
||||||
|
response = swap_client.readURL(url, headers=default_headers)
|
||||||
|
try:
|
||||||
|
error = json.loads(response.decode())
|
||||||
|
if "Error" in error:
|
||||||
|
return json.dumps({"Error": error['Error']}).encode()
|
||||||
|
except json.JSONDecodeError:
|
||||||
|
pass
|
||||||
|
return response
|
||||||
|
raise ValueError('Requires URL.')
|
||||||
|
|
||||||
pages = {
|
pages = {
|
||||||
'coins': js_coins,
|
'coins': js_coins,
|
||||||
@@ -789,9 +807,9 @@ pages = {
|
|||||||
'unlock': js_unlock,
|
'unlock': js_unlock,
|
||||||
'lock': js_lock,
|
'lock': js_lock,
|
||||||
'help': js_help,
|
'help': js_help,
|
||||||
|
'readurl': js_readurl,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def js_url_to_function(url_split):
|
def js_url_to_function(url_split):
|
||||||
if len(url_split) > 2:
|
if len(url_split) > 2:
|
||||||
return pages.get(url_split[2], js_404)
|
return pages.get(url_split[2], js_404)
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
<div class="w-full md:w-auto p-3 md:py-0 md:px-6"><a class="inline-block text-coolGray-500 dark:text-gray-300 font-medium" href="https://academy.particl.io/en/latest/basicswap-dex/basicswap_explained.html" target="_blank">BasicSwap Explained</a></div>
|
<div class="w-full md:w-auto p-3 md:py-0 md:px-6"><a class="inline-block text-coolGray-500 dark:text-gray-300 font-medium" href="https://academy.particl.io/en/latest/basicswap-dex/basicswap_explained.html" target="_blank">BasicSwap Explained</a></div>
|
||||||
<div class="w-full md:w-auto p-3 md:py-0 md:px-6"><a class="inline-block text-coolGray-500 dark:text-gray-300 font-medium" href="https://academy.particl.io/en/latest/basicswap-guides/basicswapguides_installation.html" target="_blank">Tutorials and Guides</a></div>
|
<div class="w-full md:w-auto p-3 md:py-0 md:px-6"><a class="inline-block text-coolGray-500 dark:text-gray-300 font-medium" href="https://academy.particl.io/en/latest/basicswap-guides/basicswapguides_installation.html" target="_blank">Tutorials and Guides</a></div>
|
||||||
<div class="w-full md:w-auto p-3 md:py-0 md:px-6"><a class="inline-block text-coolGray-500 dark:text-gray-300 font-medium" href="https://academy.particl.io/en/latest/faq/get_support.html" target="_blank">Get Support</a></div>
|
<div class="w-full md:w-auto p-3 md:py-0 md:px-6"><a class="inline-block text-coolGray-500 dark:text-gray-300 font-medium" href="https://academy.particl.io/en/latest/faq/get_support.html" target="_blank">Get Support</a></div>
|
||||||
|
<div class="w-full md:w-auto p-3 md:py-0 md:px-6"><a class="inline-block text-coolGray-500 dark:text-gray-300 font-medium" href="https://basicswapdex.com/terms" target="_blank">Terms and Conditions</a></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="w-full md:w-1/4 px-4"> </div>
|
<div class="w-full md:w-1/4 px-4"> </div>
|
||||||
|
|||||||
@@ -519,38 +519,55 @@
|
|||||||
</section>
|
</section>
|
||||||
{% if ws_url %}
|
{% if ws_url %}
|
||||||
<script>
|
<script>
|
||||||
var ws = new WebSocket("{{ ws_url }}"),
|
// Configuration object
|
||||||
|
const notificationConfig = {
|
||||||
|
showNewOffers: false,
|
||||||
|
showNewBids: true,
|
||||||
|
showBidAccepted: true
|
||||||
|
};
|
||||||
|
|
||||||
|
var ws = new WebSocket("{{ ws_url }}"),
|
||||||
floating_div = document.createElement('div');
|
floating_div = document.createElement('div');
|
||||||
floating_div.classList.add('floatright');
|
floating_div.classList.add('floatright');
|
||||||
messages = document.createElement('ul');
|
messages = document.createElement('ul');
|
||||||
messages.setAttribute('id', 'ul_updates');
|
messages.setAttribute('id', 'ul_updates');
|
||||||
ws.onmessage = function(event) {
|
|
||||||
let json = JSON.parse(event.data);
|
floating_div.appendChild(messages);
|
||||||
let event_message = 'Unknown event';
|
|
||||||
if (json['event'] == 'new_offer') {
|
ws.onmessage = function(event) {
|
||||||
|
let json = JSON.parse(event.data);
|
||||||
|
let event_message = 'Unknown event';
|
||||||
|
let should_display = false;
|
||||||
|
|
||||||
|
if (json['event'] == 'new_offer' && notificationConfig.showNewOffers) {
|
||||||
event_message = '<div id="hide"><div id="toast-success" class="flex items-center p-4 mb-4 w-full max-w-xs text-gray-500 bg-white rounded-lg shadow" role="alert"><div class="inline-flex flex-shrink-0 justify-center items-center w-10 h-10 bg-blue-500 rounded-lg"><svg class="w-5 h-5" xmlns="http://www.w3.org/2000/svg" height="18" width="18" viewBox="0 0 24 24"><g stroke-linecap="round" stroke-width="2" fill="none" stroke="#ffffff" stroke-linejoin="round"><circle cx="5" cy="5" r="4"></circle> <circle cx="19" cy="19" r="4"></circle> <polyline data-cap="butt" points="13,5 21,5 21,11 " stroke="#ffffff"></polyline> <polyline data-cap="butt" points="11,19 3,19 3,13 " stroke="#ffffff"></polyline> <polyline points=" 16,2 13,5 16,8 " stroke="#ffffff"></polyline> <polyline points=" 8,16 11,19 8,22 " stroke="#ffffff"></polyline></g></svg></div><div class="uppercase w-40 ml-3 text-sm font-semibold text-gray-900">New network <a class="underline" href=/offer/' + json['offer_id'] + '>offer</a></div><button type="button" onclick="closeAlert(event)" class="ml-auto -mx-1.5 -my-1.5 bg-white text-gray-400 hover:text-gray-900 rounded-lg focus:ring-0 focus:outline-none focus:ring-gray-300 p-1.5 hover:bg-gray-100 inline-flex h-8 w-8" data-dismiss="#toast-success" aria-label="Close"><span class="sr-only">Close</span><svg aria-hidden="true" class="w-5 h-5" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clip-rule="evenodd"></path></svg></button></div></div>';
|
event_message = '<div id="hide"><div id="toast-success" class="flex items-center p-4 mb-4 w-full max-w-xs text-gray-500 bg-white rounded-lg shadow" role="alert"><div class="inline-flex flex-shrink-0 justify-center items-center w-10 h-10 bg-blue-500 rounded-lg"><svg class="w-5 h-5" xmlns="http://www.w3.org/2000/svg" height="18" width="18" viewBox="0 0 24 24"><g stroke-linecap="round" stroke-width="2" fill="none" stroke="#ffffff" stroke-linejoin="round"><circle cx="5" cy="5" r="4"></circle> <circle cx="19" cy="19" r="4"></circle> <polyline data-cap="butt" points="13,5 21,5 21,11 " stroke="#ffffff"></polyline> <polyline data-cap="butt" points="11,19 3,19 3,13 " stroke="#ffffff"></polyline> <polyline points=" 16,2 13,5 16,8 " stroke="#ffffff"></polyline> <polyline points=" 8,16 11,19 8,22 " stroke="#ffffff"></polyline></g></svg></div><div class="uppercase w-40 ml-3 text-sm font-semibold text-gray-900">New network <a class="underline" href=/offer/' + json['offer_id'] + '>offer</a></div><button type="button" onclick="closeAlert(event)" class="ml-auto -mx-1.5 -my-1.5 bg-white text-gray-400 hover:text-gray-900 rounded-lg focus:ring-0 focus:outline-none focus:ring-gray-300 p-1.5 hover:bg-gray-100 inline-flex h-8 w-8" data-dismiss="#toast-success" aria-label="Close"><span class="sr-only">Close</span><svg aria-hidden="true" class="w-5 h-5" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clip-rule="evenodd"></path></svg></button></div></div>';
|
||||||
}
|
should_display = true;
|
||||||
else
|
}
|
||||||
if (json['event'] == 'new_bid') {
|
else if (json['event'] == 'new_bid' && notificationConfig.showNewBids) {
|
||||||
event_message = '<div id="hide"><div id="toast-success" class="flex items-center p-4 mb-4 w-full max-w-xs text-gray-500 bg-white rounded-lg shadow" role="alert"><div class="inline-flex flex-shrink-0 justify-center items-center w-10 h-10 bg-violet-500 rounded-lg"><svg class="w-5 h-5" xmlns="http://www.w3.org/2000/svg" height="18" width="18" viewBox="0 0 24 24"><g stroke-linecap="round" stroke-width="2" fill="none" stroke="#ffffff" stroke-linejoin="round"><rect x="9.843" y="5.379" transform="matrix(0.7071 -0.7071 0.7071 0.7071 -0.7635 13.1569)" width="11.314" height="4.243"></rect> <polyline points="3,23 3,19 15,19 15,23 "></polyline> <line x1="4" y1="15" x2="1" y2="15" stroke="#ffffff"></line> <line x1="5.757" y1="10.757" x2="3.636" y2="8.636" stroke="#ffffff"></line> <line x1="1" y1="23" x2="17" y2="23"></line> <line x1="17" y1="9" x2="23" y2="15"></line></g></svg></div><div class="uppercase w-40 ml-3 text-sm font-normal"><span class="mb-1 text-sm font-semibold text-gray-900"><a class="underline" href=/bid/' + json['bid_id'] + '>New bid</a> on <a class="underline" href=/offer/' + json['offer_id'] + '>offer</a></span></div><button type="button" onclick="closeAlert(event)" class="ml-auto -mx-1.5 -my-1.5 bg-white text-gray-400 hover:text-gray-900 rounded-lg focus:ring-0 focus:outline-nonefocus:ring-gray-300 p-1.5 hover:bg-gray-100 inline-flex h-8 w-8" data-dismiss="#toast-success" aria-label="Close"><svg aria-hidden="true" class="w-5 h-5" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clip-rule="evenodd"></path></svg></button></div></div>';
|
event_message = '<div id="hide"><div id="toast-success" class="flex items-center p-4 mb-4 w-full max-w-xs text-gray-500 bg-white rounded-lg shadow" role="alert"><div class="inline-flex flex-shrink-0 justify-center items-center w-10 h-10 bg-violet-500 rounded-lg"><svg class="w-5 h-5" xmlns="http://www.w3.org/2000/svg" height="18" width="18" viewBox="0 0 24 24"><g stroke-linecap="round" stroke-width="2" fill="none" stroke="#ffffff" stroke-linejoin="round"><rect x="9.843" y="5.379" transform="matrix(0.7071 -0.7071 0.7071 0.7071 -0.7635 13.1569)" width="11.314" height="4.243"></rect> <polyline points="3,23 3,19 15,19 15,23 "></polyline> <line x1="4" y1="15" x2="1" y2="15" stroke="#ffffff"></line> <line x1="5.757" y1="10.757" x2="3.636" y2="8.636" stroke="#ffffff"></line> <line x1="1" y1="23" x2="17" y2="23"></line> <line x1="17" y1="9" x2="23" y2="15"></line></g></svg></div><div class="uppercase w-40 ml-3 text-sm font-normal"><span class="mb-1 text-sm font-semibold text-gray-900"><a class="underline" href=/bid/' + json['bid_id'] + '>New bid</a> on <a class="underline" href=/offer/' + json['offer_id'] + '>offer</a></span></div><button type="button" onclick="closeAlert(event)" class="ml-auto -mx-1.5 -my-1.5 bg-white text-gray-400 hover:text-gray-900 rounded-lg focus:ring-0 focus:outline-nonefocus:ring-gray-300 p-1.5 hover:bg-gray-100 inline-flex h-8 w-8" data-dismiss="#toast-success" aria-label="Close"><svg aria-hidden="true" class="w-5 h-5" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clip-rule="evenodd"></path></svg></button></div></div>';
|
||||||
}
|
should_display = true;
|
||||||
else
|
}
|
||||||
if (json['event'] == 'bid_accepted') {
|
else if (json['event'] == 'bid_accepted' && notificationConfig.showBidAccepted) {
|
||||||
event_message = '<div id="hide"><div id="toast-success" class="flex items-center p-4 mb-4 w-full max-w-xs text-gray-500 bg-white rounded-lg shadow" role="alert"><div class="inline-flex flex-shrink-0 justify-center items-center w-10 h-10 bg-violet-500 rounded-lg"><svg class="w-5 h-5" xmlns="http://www.w3.org/2000/svg" height="18" width="18" viewBox="0 0 24 24"><g fill="#ffffff"><path d="M8.5,20a1.5,1.5,0,0,1-1.061-.439L.379,12.5,2.5,10.379l6,6,13-13L23.621,5.5,9.561,19.561A1.5,1.5,0,0,1,8.5,20Z" fill="#ffffff"></path></g></svg></div><div class="uppercase w-40 ml-3 text-sm font-semibold text-gray-900"><a class="underline" href=/bid/' + json['bid_id'] + '>Bid</a> accepted</div><button type="button" onclick="closeAlert(event)" class="ml-auto -mx-1.5 -my-1.5 bg-white text-gray-400 hover:text-gray-900 rounded-lg focus:ring-0 focus:outline-none focus:ring-gray-300 p-1.5 hover:bg-gray-100 inline-flex h-8 w-8" data-dismiss="#toast-success" aria-label="Close"><span class="sr-only">Close</span><svg aria-hidden="true" class="w-5 h-5" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clip-rule="evenodd"></path></svg></button></div></div>';
|
event_message = '<div id="hide"><div id="toast-success" class="flex items-center p-4 mb-4 w-full max-w-xs text-gray-500 bg-white rounded-lg shadow" role="alert"><div class="inline-flex flex-shrink-0 justify-center items-center w-10 h-10 bg-violet-500 rounded-lg"><svg class="w-5 h-5" xmlns="http://www.w3.org/2000/svg" height="18" width="18" viewBox="0 0 24 24"><g fill="#ffffff"><path d="M8.5,20a1.5,1.5,0,0,1-1.061-.439L.379,12.5,2.5,10.379l6,6,13-13L23.621,5.5,9.561,19.561A1.5,1.5,0,0,1,8.5,20Z" fill="#ffffff"></path></g></svg></div><div class="uppercase w-40 ml-3 text-sm font-semibold text-gray-900"><a class="underline" href=/bid/' + json['bid_id'] + '>Bid</a> accepted</div><button type="button" onclick="closeAlert(event)" class="ml-auto -mx-1.5 -my-1.5 bg-white text-gray-400 hover:text-gray-900 rounded-lg focus:ring-0 focus:outline-none focus:ring-gray-300 p-1.5 hover:bg-gray-100 inline-flex h-8 w-8" data-dismiss="#toast-success" aria-label="Close"><span class="sr-only">Close</span><svg aria-hidden="true" class="w-5 h-5" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clip-rule="evenodd"></path></svg></button></div></div>';
|
||||||
}
|
should_display = true;
|
||||||
let messages = document.getElementById('ul_updates'),
|
}
|
||||||
message = document.createElement('li');
|
|
||||||
message.innerHTML = event_message;
|
if (should_display) {
|
||||||
messages.appendChild(message);
|
let messages = document.getElementById('ul_updates'),
|
||||||
};
|
message = document.createElement('li');
|
||||||
floating_div.appendChild(messages);
|
message.innerHTML = event_message;
|
||||||
document.body.appendChild(floating_div);
|
messages.appendChild(message);
|
||||||
function closeAlert(event){
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
document.body.appendChild(floating_div);
|
||||||
|
|
||||||
|
function closeAlert(event){
|
||||||
let element = event.target;
|
let element = event.target;
|
||||||
while(element.nodeName !== "BUTTON"){
|
while(element.nodeName !== "BUTTON"){
|
||||||
element = element.parentNode;
|
element = element.parentNode;
|
||||||
}
|
}
|
||||||
element.parentNode.parentNode.removeChild(element.parentNode);
|
element.parentNode.parentNode.removeChild(element.parentNode);
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -6,25 +6,25 @@
|
|||||||
{% if refresh %}
|
{% if refresh %}
|
||||||
<meta http-equiv="refresh" content="{{ refresh }}">
|
<meta http-equiv="refresh" content="{{ refresh }}">
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<link type="text/css" media="all" href="/static/css/libs/flowbite.min.css" rel="stylesheet" />
|
<link type="text/css" media="all" href="/static/css/libs/flowbite.min.css" rel="stylesheet" />
|
||||||
<link type="text/css" media="all" href="/static/css/libs/tailwind.min.css" rel="stylesheet">
|
<link type="text/css" media="all" href="/static/css/libs/tailwind.min.css" rel="stylesheet">
|
||||||
<link type="text/css" media="all" href="/static/css/style.css" rel="stylesheet">
|
<link type="text/css" media="all" href="/static/css/style.css" rel="stylesheet">
|
||||||
<script src="/static/js/main.js"></script>
|
<script src="/static/js/main.js"></script>
|
||||||
<script src="/static/js/libs/flowbite.js"></script>
|
<script src="/static/js/libs/flowbite.js"></script>
|
||||||
<script>
|
<script>
|
||||||
const isDarkMode =
|
const isDarkMode =
|
||||||
localStorage.getItem('color-theme') === 'dark' ||
|
localStorage.getItem('color-theme') === 'dark' ||
|
||||||
(!localStorage.getItem('color-theme') &&
|
(!localStorage.getItem('color-theme') &&
|
||||||
window.matchMedia('(prefers-color-scheme: dark)').matches);
|
window.matchMedia('(prefers-color-scheme: dark)').matches);
|
||||||
|
|
||||||
if (!localStorage.getItem('color-theme')) {
|
if (!localStorage.getItem('color-theme')) {
|
||||||
localStorage.setItem('color-theme', isDarkMode ? 'dark' : 'light');
|
localStorage.setItem('color-theme', isDarkMode ? 'dark' : 'light');
|
||||||
}
|
}
|
||||||
|
|
||||||
document.documentElement.classList.toggle('dark', isDarkMode);
|
document.documentElement.classList.toggle('dark', isDarkMode);
|
||||||
</script>
|
</script>
|
||||||
<link rel=icon sizes="32x32" type="image/png" href="/static/images/favicon/favicon-32.png">
|
<link rel=icon sizes="32x32" type="image/png" href="/static/images/favicon/favicon-32.png">
|
||||||
<title>(BSX) BasicSwap - v{{ version }}</title>
|
<title>(BSX) BasicSwap - v{{ version }}</title>
|
||||||
</head>
|
</head>
|
||||||
<body class="dark:bg-gray-700">
|
<body class="dark:bg-gray-700">
|
||||||
<section class="py-24 md:py-32">
|
<section class="py-24 md:py-32">
|
||||||
@@ -32,10 +32,10 @@
|
|||||||
<div class="max-w-sm mx-auto">
|
<div class="max-w-sm mx-auto">
|
||||||
<div class="mb-3 text-center">
|
<div class="mb-3 text-center">
|
||||||
<a class="inline-block mb-6" href="#">
|
<a class="inline-block mb-6" href="#">
|
||||||
<img src="/static/images/logos/basicswap-logo.svg" class="h-20 imageshow dark-image">
|
<img src="/static/images/logos/basicswap-logo.svg" class="h-20 imageshow dark-image">
|
||||||
<img src="/static/images/logos/basicswap-logo-dark.svg" class="h-20 imageshow light-image">
|
<img src="/static/images/logos/basicswap-logo-dark.svg" class="h-20 imageshow light-image">
|
||||||
</a>
|
</a>
|
||||||
<p class="text-lg text-coolGray-500 font-medium mb-6 dark:text-white" contenteditable="false">Unlock your wallets</p>
|
<p class="text-lg text-coolGray-500 font-medium mb-6 dark:text-white">Unlock your wallets</p>
|
||||||
{% for m in messages %}
|
{% for m in messages %}
|
||||||
<section class="py-4" id="messages_{{ m[0] }}" role="alert">
|
<section class="py-4" id="messages_{{ m[0] }}" role="alert">
|
||||||
<div class="container px-4 mx-auto">
|
<div class="container px-4 mx-auto">
|
||||||
@@ -77,7 +77,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<form method="post" autocomplete="off">
|
<form method="post" autocomplete="off">
|
||||||
<div class="mb-4">
|
<div class="mb-4">
|
||||||
<label class="block mb-2 text-coolGray-800 font-medium dark:text-white" for="" contenteditable="false">Your Password</label>
|
<label class="block mb-2 text-coolGray-800 font-medium dark:text-white" for="">Your Password</label>
|
||||||
<div class="relative w-full">
|
<div class="relative w-full">
|
||||||
<div class="absolute inset-y-0 right-0 flex items-center px-2">
|
<div class="absolute inset-y-0 right-0 flex items-center px-2">
|
||||||
<input class="hidden js-password-toggle" id="toggle" type="checkbox" />
|
<input class="hidden js-password-toggle" id="toggle" type="checkbox" />
|
||||||
@@ -94,41 +94,40 @@
|
|||||||
</div>
|
</div>
|
||||||
<button type="submit" name="unlock" value="Unlock" class="appearance-none focus:outline-none inline-block py-3 px-7 mb-6 w-full text-base text-blue-50 font-medium text-center leading-6 bg-blue-500 hover:bg-blue-600 focus:ring-0 rounded-md shadow-sm">Unlock</button>
|
<button type="submit" name="unlock" value="Unlock" class="appearance-none focus:outline-none inline-block py-3 px-7 mb-6 w-full text-base text-blue-50 font-medium text-center leading-6 bg-blue-500 hover:bg-blue-600 focus:ring-0 rounded-md shadow-sm">Unlock</button>
|
||||||
<p class="text-center">
|
<p class="text-center">
|
||||||
<span class="text-xs font-medium dark:text-white" contenteditable="false">Need help?</span>
|
<span class="text-xs font-medium dark:text-white">Need help?</span>
|
||||||
<a class="inline-block text-xs font-medium text-blue-500 hover:text-blue-600 hover:underline" href="https://academy.particl.io/en/latest/faq/get_support.html" target="_blank" contenteditable="false">Help / Tutorials</a>
|
<a class="inline-block text-xs font-medium text-blue-500 hover:text-blue-600 hover:underline" href="https://academy.particl.io/en/latest/faq/get_support.html" target="_blank">Help / Tutorials</a>
|
||||||
</p>
|
</p>
|
||||||
<p class="text-center">
|
<p class="text-center">
|
||||||
<span class="text-xs font-medium text-coolGray-500 dark:text-gray-500" contenteditable="false">{{ title }}</span>
|
<span class="text-xs font-medium text-coolGray-500 dark:text-gray-500">{{ title }}</span>
|
||||||
</p>
|
</p>
|
||||||
<input type="hidden" name="formid" value="{{ form_id }}">
|
<input type="hidden" name="formid" value="{{ form_id }}">
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
<script>
|
|
||||||
const passwordToggle = document.querySelector('.js-password-toggle')
|
|
||||||
passwordToggle.addEventListener('change', function() {
|
|
||||||
const password = document.querySelector('.js-password'),
|
|
||||||
passwordLabel = document.querySelector('.js-password-label')
|
|
||||||
if (password.type === 'password') {
|
|
||||||
password.type = 'text'
|
|
||||||
passwordLabel.innerHTML = '<svg xmlns="http://www.w3.org/2000/svg" height="20" width="20" viewBox="0 0 24 24"><g fill="#8896ab"><path d="M23.444,10.239a22.936,22.936,0,0,0-2.492-2.948l-4.021,4.021A5.026,5.026,0,0,1,17,12a5,5,0,0,1-5,5,5.026,5.026,0,0,1-.688-.069L8.055,20.188A10.286,10.286,0,0,0,12,21c5.708,0,9.905-5.062,11.445-7.24A3.058,3.058,0,0,0,23.444,10.239Z" fill="#8896ab"></path><path d="M12,3C6.292,3,2.1,8.062.555,10.24a3.058,3.058,0,0,0,0,3.52h0a21.272,21.272,0,0,0,4.784,4.9l3.124-3.124a5,5,0,0,1,7.071-7.072L8.464,15.536l10.2-10.2A11.484,11.484,0,0,0,12,3Z" fill="#8896ab"></path><path data-color="color-2" d="M1,24a1,1,0,0,1-.707-1.707l22-22a1,1,0,0,1,1.414,1.414l-22,22A1,1,0,0,1,1,24Z"></path></g></svg>'
|
|
||||||
} else {
|
|
||||||
password.type = 'password'
|
|
||||||
passwordLabel.innerHTML = '<svg xmlns="http://www.w3.org/2000/svg" height="20" width="20" viewBox="0 0 24 24"><g fill="#8896ab" ><path d="M23.444,10.239C21.905,8.062,17.708,3,12,3S2.1,8.062.555,10.24a3.058,3.058,0,0,0,0,3.52h0C2.1,15.938,6.292,21,12,21s9.905-5.062,11.445-7.24A3.058,3.058,0,0,0,23.444,10.239ZM12,17a5,5,0,1,1,5-5A5,5,0,0,1,12,17Z" fill="#8896ab"></path></g></svg>'
|
|
||||||
}
|
|
||||||
password.focus()
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
<script>
|
<script>
|
||||||
window.onload = () => {
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
toggleImages();
|
// Password toggle functionality
|
||||||
};
|
const passwordToggle = document.querySelector('.js-password-toggle');
|
||||||
|
if (passwordToggle) {
|
||||||
document.getElementById('theme-toggle').addEventListener('click', () => {
|
passwordToggle.addEventListener('change', function() {
|
||||||
toggleImages();
|
const password = document.querySelector('.js-password');
|
||||||
});
|
const passwordLabel = document.querySelector('.js-password-label');
|
||||||
|
if (password && passwordLabel) {
|
||||||
|
if (password.type === 'password') {
|
||||||
|
password.type = 'text';
|
||||||
|
passwordLabel.innerHTML = '<svg xmlns="http://www.w3.org/2000/svg" height="20" width="20" viewBox="0 0 24 24"><g fill="#8896ab"><path d="M23.444,10.239a22.936,22.936,0,0,0-2.492-2.948l-4.021,4.021A5.026,5.026,0,0,1,17,12a5,5,0,0,1-5,5,5.026,5.026,0,0,1-.688-.069L8.055,20.188A10.286,10.286,0,0,0,12,21c5.708,0,9.905-5.062,11.445-7.24A3.058,3.058,0,0,0,23.444,10.239Z" fill="#8896ab"></path><path d="M12,3C6.292,3,2.1,8.062.555,10.24a3.058,3.058,0,0,0,0,3.52h0a21.272,21.272,0,0,0,4.784,4.9l3.124-3.124a5,5,0,0,1,7.071-7.072L8.464,15.536l10.2-10.2A11.484,11.484,0,0,0,12,3Z" fill="#8896ab"></path><path data-color="color-2" d="M1,24a1,1,0,0,1-.707-1.707l22-22a1,1,0,0,1,1.414,1.414l-22,22A1,1,0,0,1,1,24Z"></path></g></svg>';
|
||||||
|
} else {
|
||||||
|
password.type = 'password';
|
||||||
|
passwordLabel.innerHTML = '<svg xmlns="http://www.w3.org/2000/svg" height="20" width="20" viewBox="0 0 24 24"><g fill="#8896ab" ><path d="M23.444,10.239C21.905,8.062,17.708,3,12,3S2.1,8.062.555,10.24a3.058,3.058,0,0,0,0,3.52h0C2.1,15.938,6.292,21,12,21s9.905-5.062,11.445-7.24A3.058,3.058,0,0,0,23.444,10.239ZM12,17a5,5,0,1,1,5-5A5,5,0,0,1,12,17Z" fill="#8896ab"></path></g></svg>';
|
||||||
|
}
|
||||||
|
password.focus();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Image toggling function
|
||||||
function toggleImages() {
|
function toggleImages() {
|
||||||
const html = document.querySelector('html');
|
const html = document.querySelector('html');
|
||||||
const darkImages = document.querySelectorAll('.dark-image');
|
const darkImages = document.querySelectorAll('.dark-image');
|
||||||
@@ -148,17 +147,8 @@ passwordToggle.addEventListener('change', function() {
|
|||||||
img.style.display = display;
|
img.style.display = display;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
</script>
|
|
||||||
<script>
|
|
||||||
var themeToggleDarkIcon = document.getElementById('theme-toggle-dark-icon');
|
|
||||||
var themeToggleLightIcon = document.getElementById('theme-toggle-light-icon');
|
|
||||||
|
|
||||||
if (localStorage.getItem('color-theme') === 'dark' || (!('color-theme' in localStorage) && window.matchMedia('(prefers-color-scheme: dark)').matches)) {
|
|
||||||
themeToggleLightIcon.classList.remove('hidden');
|
|
||||||
} else {
|
|
||||||
themeToggleDarkIcon.classList.remove('hidden');
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// Theme toggle functionality
|
||||||
function setTheme(theme) {
|
function setTheme(theme) {
|
||||||
if (theme === 'light') {
|
if (theme === 'light') {
|
||||||
document.documentElement.classList.remove('dark');
|
document.documentElement.classList.remove('dark');
|
||||||
@@ -169,17 +159,33 @@ passwordToggle.addEventListener('change', function() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
document.getElementById('theme-toggle').addEventListener('click', () => {
|
// Initialize theme
|
||||||
if (localStorage.getItem('color-theme') === 'dark') {
|
const themeToggle = document.getElementById('theme-toggle');
|
||||||
setTheme('light');
|
const themeToggleDarkIcon = document.getElementById('theme-toggle-dark-icon');
|
||||||
} else {
|
const themeToggleLightIcon = document.getElementById('theme-toggle-light-icon');
|
||||||
setTheme('dark');
|
|
||||||
}
|
|
||||||
themeToggleDarkIcon.classList.toggle('hidden');
|
|
||||||
themeToggleLightIcon.classList.toggle('hidden');
|
|
||||||
toggleImages();
|
|
||||||
});
|
|
||||||
|
|
||||||
</script>
|
if (themeToggle && themeToggleDarkIcon && themeToggleLightIcon) {
|
||||||
</body>
|
if (localStorage.getItem('color-theme') === 'dark' || (!('color-theme' in localStorage) && window.matchMedia('(prefers-color-scheme: dark)').matches)) {
|
||||||
|
themeToggleLightIcon.classList.remove('hidden');
|
||||||
|
} else {
|
||||||
|
themeToggleDarkIcon.classList.remove('hidden');
|
||||||
|
}
|
||||||
|
|
||||||
|
themeToggle.addEventListener('click', () => {
|
||||||
|
if (localStorage.getItem('color-theme') === 'dark') {
|
||||||
|
setTheme('light');
|
||||||
|
} else {
|
||||||
|
setTheme('dark');
|
||||||
|
}
|
||||||
|
themeToggleDarkIcon.classList.toggle('hidden');
|
||||||
|
themeToggleLightIcon.classList.toggle('hidden');
|
||||||
|
toggleImages();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Call toggleImages on load
|
||||||
|
toggleImages();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
# Copyright (c) 2022 tecnovert
|
# Copyright (c) 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.
|
||||||
|
|
||||||
def extract_data(bytes_in):
|
def extract_data(bytes_in):
|
||||||
|
if bytes_in is None:
|
||||||
|
return None
|
||||||
str_in = bytes_in.decode('utf-8')
|
str_in = bytes_in.decode('utf-8')
|
||||||
start = str_in.find('=')
|
start = str_in.find('=')
|
||||||
if start < 0:
|
if start < 0:
|
||||||
@@ -15,37 +16,29 @@ def extract_data(bytes_in):
|
|||||||
return None
|
return None
|
||||||
return str_in[start: end]
|
return str_in[start: end]
|
||||||
|
|
||||||
|
|
||||||
def get_tor_established_state(swap_client):
|
def get_tor_established_state(swap_client):
|
||||||
rv = swap_client.torControl('GETINFO status/circuit-established')
|
rv = swap_client.torControl('GETINFO status/circuit-established')
|
||||||
return extract_data(rv)
|
return extract_data(rv)
|
||||||
|
|
||||||
|
|
||||||
def page_tor(self, url_split, post_string):
|
def page_tor(self, url_split, post_string):
|
||||||
swap_client = self.server.swap_client
|
swap_client = self.server.swap_client
|
||||||
summary = swap_client.getSummary()
|
summary = swap_client.getSummary()
|
||||||
|
|
||||||
page_data = {}
|
page_data = {}
|
||||||
|
|
||||||
try:
|
try:
|
||||||
page_data['circuit_established'] = get_tor_established_state(swap_client)
|
page_data['circuit_established'] = get_tor_established_state(swap_client)
|
||||||
except Exception:
|
except Exception:
|
||||||
page_data['circuit_established'] = 'error'
|
page_data['circuit_established'] = 'error'
|
||||||
|
|
||||||
try:
|
try:
|
||||||
rv = swap_client.torControl('GETINFO traffic/read')
|
rv = swap_client.torControl('GETINFO traffic/read')
|
||||||
page_data['bytes_written'] = extract_data(rv)
|
page_data['bytes_written'] = extract_data(rv)
|
||||||
except Exception:
|
except Exception:
|
||||||
page_data['bytes_written'] = 'error'
|
page_data['bytes_written'] = 'error'
|
||||||
|
|
||||||
try:
|
try:
|
||||||
rv = swap_client.torControl('GETINFO traffic/written')
|
rv = swap_client.torControl('GETINFO traffic/written')
|
||||||
page_data['bytes_read'] = extract_data(rv)
|
page_data['bytes_read'] = extract_data(rv)
|
||||||
except Exception:
|
except Exception:
|
||||||
page_data['bytes_read'] = 'error'
|
page_data['bytes_read'] = 'error'
|
||||||
|
|
||||||
messages = []
|
messages = []
|
||||||
|
|
||||||
template = self.server.env.get_template('tor.html')
|
template = self.server.env.get_template('tor.html')
|
||||||
return self.render_template(template, {
|
return self.render_template(template, {
|
||||||
'messages': messages,
|
'messages': messages,
|
||||||
|
|||||||
Reference in New Issue
Block a user