Add receivePIN and lookupPIN commands for Wowlet VR

This commit is contained in:
dsc 2021-04-07 01:24:46 +02:00
parent dea2100bd9
commit 39845238fc
4 changed files with 115 additions and 1 deletions

View file

@ -26,7 +26,7 @@ async def _setup_nodes(app: Quart):
global cache global cache
with open('data/nodes.json', 'r') as f: with open('data/nodes.json', 'r') as f:
nodes = json.loads(f.read()).get(settings.COIN_SYMBOL) nodes = json.loads(f.read()).get(settings.COIN_SYMBOL)
cache.execute('JSON.SET', 'nodes', '.', json.dumps(nodes)) await cache.set('nodes', json.dumps(nodes).encode())
async def _setup_user_agents(app: Quart): async def _setup_user_agents(app: Quart):

View file

@ -32,6 +32,8 @@ class RPCNodeCheckTask(FeatherTask):
heights = {} heights = {}
rpc_nodes = await self.cache_json_get("nodes") rpc_nodes = await self.cache_json_get("nodes")
if not rpc_nodes:
rpc_nodes = {}
nodes = [] nodes = []
for network_type_coin, _ in rpc_nodes.items(): for network_type_coin, _ in rpc_nodes.items():

View file

@ -2,6 +2,7 @@
# Copyright (c) 2020, The Monero Project. # Copyright (c) 2020, The Monero Project.
# Copyright (c) 2020, dsc@xmr.pm # Copyright (c) 2020, dsc@xmr.pm
import re
import json import json
import asyncio import asyncio
import os import os
@ -20,6 +21,9 @@ from PIL import Image
import settings import settings
RE_ADDRESS = r"^[a-zA-Z0-9]{97}$"
def print_banner(): def print_banner():
print(f"""\033[91m print(f"""\033[91m
_______________ |*\_/*|________ _______________ |*\_/*|________

View file

@ -2,12 +2,31 @@
# Copyright (c) 2020, The Monero Project. # Copyright (c) 2020, The Monero Project.
# Copyright (c) 2020, dsc@xmr.pm # Copyright (c) 2020, dsc@xmr.pm
import random
import time
import json
from datetime import datetime, timedelta
from typing import Dict, Union, Optional
from copy import deepcopy
import asyncio
import re
from wowlet_backend.utils import RE_ADDRESS
PIN_SPACE_AMOUNT = list(range(1, 10000))
PIN_CODES = {str(k): None for k in PIN_SPACE_AMOUNT}
class WebsocketParse: class WebsocketParse:
@staticmethod @staticmethod
async def parser(cmd: str, data=None): async def parser(cmd: str, data=None):
if cmd == "txFiatHistory": if cmd == "txFiatHistory":
return await WebsocketParse.txFiatHistory(data) return await WebsocketParse.txFiatHistory(data)
elif cmd == "requestPIN":
return await WebsocketParse.requestPIN(data)
elif cmd == "lookupPIN":
return await WebsocketParse.lookupPIN(data)
@staticmethod @staticmethod
async def txFiatHistory(data=None): async def txFiatHistory(data=None):
@ -23,3 +42,92 @@ class WebsocketParse:
from wowlet_backend.tasks.historical_prices import HistoricalPriceTask from wowlet_backend.tasks.historical_prices import HistoricalPriceTask
return await HistoricalPriceTask.get(year, month) return await HistoricalPriceTask.get(year, month)
@staticmethod
async def requestPIN(data=None) -> str:
from wowlet_backend.factory import cache
if not data or not isinstance(data, dict):
return ""
if "address" not in data or not isinstance(data['address'], str):
return ""
if "signature" not in data or not isinstance(data['signature'], str):
return ""
signature = data.get('signature')
address = data.get('address')
if not re.match(RE_ADDRESS, address) or not signature.startswith("Sig"):
return ""
cache_key_address = f"pin_{address}"
cache_key_lookups = "pin_space"
ttl = 600
lock = asyncio.Lock()
async with lock:
result = await cache.get(cache_key_address)
if result:
return result.decode().zfill(4)
lookups = await cache.get(cache_key_lookups)
if not lookups:
await cache.set(cache_key_lookups, json.dumps(PIN_CODES).encode())
lookups: Dict[str, Optional[dict]] = PIN_CODES
else:
lookups: Dict[str, Optional[dict]] = json.loads(lookups)
space = deepcopy(PIN_SPACE_AMOUNT)
random.shuffle(space)
now = int(time.time())
for number in space:
_blob = lookups[str(number)]
if _blob:
until = _blob.get('until')
if now > until:
_blob = None # expired, mark as writeable
if not _blob:
valid_until = int(time.time()) + ttl
lookups[str(number)] = {
"address": address,
"until": valid_until
}
await cache.setex(cache_key_address, ttl, number)
await cache.set(cache_key_lookups, json.dumps(lookups).encode())
return str(number).zfill(4)
return ""
@staticmethod
async def lookupPIN(data=None) -> dict:
from wowlet_backend.factory import cache
if not data or not isinstance(data, dict):
return {}
if "PIN" not in data or not isinstance(data['PIN'], str) or not len(data['PIN']) == 4:
return {}
PIN = data['PIN']
if not re.match("^\d{4}$", PIN):
return {}
cache_key_lookups = "pin_space"
lookups = await cache.get(cache_key_lookups)
if not lookups:
await cache.set(cache_key_lookups, json.dumps(PIN_CODES).encode())
lookups: Dict[str, Optional[dict]] = PIN_CODES
else:
lookups: Dict[str, Optional[dict]] = json.loads(lookups)
blob = lookups.get(str(int(PIN)))
if not blob:
return {"address": "", "PIN": PIN} # undefined behavior
address = blob.get('address')
until = blob.get('until')
now = int(time.time())
if now > until:
return {"address": "", "PIN": PIN} # entry expired
return {
"address": address,
"PIN": PIN
}