async def wrapper(*args, **kwargs): with open(os.path.join(settings.BASE_DIR, "keys.json")) as f: keys = json.load(f) pubkey = keys["pubkey"] message = kwargs.get("message") signature = kwargs.get("signature") try: flag = Qtum.verify_message(message, signature, pubkey) except: flag = None if not flag: result = {"error": 403, "reason": "Invalid signature"} else: result = await func(*args, **kwargs) return result
#Third-party import tornado from jsonrpcserver.aio import methods import ujson # Locals from utils.tornado_components import web from utils.bip32keys.r8_ethereum.r8_eth import R8_Ethereum from utils.qtum_utils.qtum import Qtum from utils import billing from utils.models.account import Account import settings validator = { "QTUM": lambda x: Qtum.public_key_to_hex_address(x), "ETH": lambda x: R8_Ethereum.public_key_to_checksum_address(x) } class AllContentHandler(web.ManagementSystemHandler): """Handles all blockchain content requests Endpoint: /api/blockchain/content Allowed methods: GET """ def set_default_headers(self): self.set_header("Access-Control-Allow-Origin", "*") self.set_header("Access-Control-Allow-Headers", "Content-Type")
class Account(GenesisClass): balance = Balance() blockchain = Blockchain() permissions = Permissions() mailer = Mail() client_storage = TornadoClient(settings.storageurl) client_withdraw = TornadoClient(settings.withdrawhost) validator = { "QTUM": lambda x: Qtum.public_key_to_hex_address(x), "ETH": lambda x: R8_Ethereum.public_key_to_checksum_address(x), "PUT": lambda x: Qtum.public_key_to_hex_address(x), } withdraw_address = { "PUTTEST": lambda x: bip32addresses.Bip32Addresses.address_to_hex(x), "QTUMTEST": lambda x: x } ident_offer = {0: "read_access", 1: "write_access"} async def withdraw_fee(self, coinid): if not isinstance(coinid, str): return { "error": 400, "reason": "Coinid type error. Must be string." } fees = { "BTCTEST": 0.001 * pow(10, 8), "ETH": 0.01 * pow(10, 8), "QTUMTEST": 0.5 * pow(10, 8), "PUTTEST": 50 * pow(10, 8), "LTCTEST": 0.05 * pow(10, 8) } try: fee = fees[coinid] except KeyError: fee = 0 return fee async def logsource(self, **params): result = await self.client_storage.request(method_name="logsource", **params) return result async def createaccount(self, **params): result = await self.client_storage.request(method_name="createaccount", **params) return result async def getaccountdata(self, **params): result = await self.client_storage.request( method_name="getaccountdata", **params) return result async def createwallet(self, **params): result = await self.client_storage.request(method_name="createwallet", **params) return result async def getnews(self, **params): result = await self.client_storage.request(method_name="getnews", **params) return result async def setnews(self, **params): result = await self.client_storage.request(method_name="setnews", **params) return result async def getaccountbywallet(self, **params): result = await self.client_storage.request( method_name="getaccountbywallet", **params) return result async def updatelevel(self, **params): result = await self.client_storage.request(method_name="updatelevel", **params) return result async def insertoffer(self, **params): result = await self.client_storage.request(method_name="insertoffer", **params) return result async def getoffer(self, **params): result = await self.client_storage.request(method_name="getoffer", **params) return result async def removeoffer(self, **params): result = await self.client_storage.request(method_name="removeoffer", **params) return result async def updateoffer(self, **params): result = await self.client_storage.request(method_name="updateoffer", **params) return result async def mailedconfirm(self, **params): result = await self.client_storage.request(method_name="mailedconfirm", **params) return result async def getoffers(self, **params): result = await self.client_storage.request(method_name="getoffers", **params) return result async def getuserscontent(self, **params): result = await self.client_storage.request( method_name="getuserscontent", **params) return result async def setuserscontent(self, **params): result = await self.client_storage.request( method_name="setuserscontent", **params) return result async def updateuserscontent(self, **params): result = await self.client_storage.request( method_name="updateuserscontent", **params) return result async def getallcontent(self): result = await self.client_storage.request(method_name="getallcontent") return result async def getsinglecontent(self, cid): result = await self.client_storage.request( method_name="getsinglecontent", cid=cid) return result async def changecontentowner(self, **params): result = await self.client_storage.request( method_name="changecontentowner", **params) return result async def setaccessstring(self, **params): result = await self.client_storage.request( method_name="setaccessstring", **params) return result async def getreviews(self, **params): result = await self.client_storage.request(method_name="getreviews", **params) return result async def setreview(self, **params): result = await self.client_storage.request(method_name="setreview", **params) return result async def updatereview(self, **params): result = await self.client_storage.request(method_name="updatereview", **params) return result async def writedeal(self, **params): result = await self.client_storage.request(method_name="writedeal", **params) return result async def getdeals(self, **params): result = await self.client_storage.request(method_name="getdeals", **params) return result async def updatedescription(self, **params): result = await self.client_storage.request( method_name="updatedescription", **params) return result async def setwriteprice(self, **params): result = await self.client_storage.request(method_name="setwriteprice", **params) return result async def setreadprice(self, **params): result = await self.client_storage.request(method_name="setreadprice", **params) return result async def changeowner(self, **params): result = await self.client_storage.request(method_name="changeowner", **params) return result async def sharecontent(self, **params): result = await self.client_storage.request(method_name="sharecontent", **params) return result async def withdraw(self, **params): result = await self.client_withdraw.request(method_name="withdraw", **params) return result
async def create_account(self, **params): """Describes, validates data. """ model = { "unique": ["email", "public_key"], "required": ("public_key", "device_id"), "default": { "count": len(settings.AVAILABLE_COIN_ID), "level": 2, "news_count": 0, "email": None }, "optional": ("phone", ) } message = json.loads(params.get("message", "{}")) data = {**message.get("message"), "public_key": message["public_key"]} # check if all required required = all( [True if i in data.keys() else False for i in model["required"]]) if not required: return {"error": 400, "reason": "Missed required fields"} # Unique constraint get_account = await self.collection.find_one( {"public_key": data.get("public_key")}) # Try get account with current public key if get_account: return {"error": 400, "reason": "Unique violation error"} # Reload data. row = { i: data[i] for i in data if i in model["required"] or i in model["optional"] } row.update({i: model["default"][i] for i in model["default"]}) if data.get("email"): row["email"] = data.get("email") row.update({"id": await self.autoincrement()}) await self.collection.insert_one(row) account = await self.collection.find_one( {"public_key": row["public_key"]}) logging.debug("[+] -- Creating new wallet ") # Create wallets validator = { "QTUM": lambda x: Qtum.public_key_to_hex_address(x), "ETH": lambda x: R8_Ethereum.public_key_to_checksum_address(x), "PUT": lambda x: Qtum.public_key_to_hex_address(x), } for coinid in settings.AVAILABLE_COIN_ID: database = client[coinid] wallet_collection = database[settings.WALLET] await wallet_collection.insert_one({ "account_id": account["id"], "wallet": validator[coinid](account["public_key"]) }) wallet = await wallet_collection.find_one({ "account_id": account["id"], "wallet": validator[coinid](account["public_key"]) }) return account
class Balance(object): async def generate_token(self, length=16, chars=string.ascii_letters + string.punctuation + string.digits): return "".join(choice(chars) for x in range(0, length)) coin_ids = settings.AVAILABLE_COIN_ID + ["PUT"] create_address = { "QTUM": lambda x: Qtum(x, mainnet=False).get_address(), "ETH": lambda x: R8_Ethereum(x).get_address(), "PUT": lambda x: Qtum(x, mainnet=False).get_address() } @verify async def addaddr(self, *args, **kwargs): """ Adding wallet address to database during account registration Accepts: - message (signed dictionary): - "uid" - int (id of just created account) Returns: {"result": "ok"} Verified: True """ message = json.loads(kwargs.get("message")) uid = message.get("uid") entropy = await self.generate_token() for coinid in self.coin_ids: client = MotorClient() db = client[coinid] balances = db[settings.BALANCE] # Create wallet address = self.create_address[coinid](entropy) # Check if current address does exist balance = await balances.find_one({"address": address}) if balance: return {"error": 400, "reason": "Current address does exist."} # Create new wallet new_balance = { "address": address, "coinid": coinid, "amount": 0, "uid": uid, "unconfirmed": 0, "deposit": 0, "txid": None } await balances.insert_one(new_balance) return {"result": "ok"} #@verify async def incbalance(self, *args, **kwargs): """ Increments users balance Accepts: - message (signed dictionary): - "address" - str - "amount" - int - "uid" - str - "coinid" - str Returns: - dictionary with following fields: - "address" - str - "coinid" - str - "amount" - int - "uid" - int - "unconfirmed" - int (0 by default) - "deposit" - int (0 by default) - "txid" - None """ # Get data from message message = json.loads(kwargs.get("message", "{}")) address = message.get("address") amount = int(message.get("amount", 0)) uid = message.get("uid") coinid = message.get("coinid") txid = message.get("txid") # Connect to database db = client[coinid] balances = db[settings.BALANCE] # Check if amount if not amount: return {"error": 400, "reason": "Funds is zero"} # Get account by uid or address if uid: balance = await balances.find_one({"uid": int(uid)}) elif address: balance = await balances.find_one({"address": address}) # Increment balance if account exists if not balance: return { "error": 404, "reason": "Increment balance. Balance not found" } # Update balance if not txid: await balances.find_one_and_update( {"address": balance["address"]}, {"$inc": { "amount": int(amount) }}) result = await balances.find_one({"address": balance["address"]}) else: db = client["PUT"] balances = db[settings.BALANCE] await balances.find_one_and_update( {"uid": balance["uid"]}, {"$inc": { "unconfirmed": int(amount) }}) result = await balances.find_one({"uid": balance["uid"]}) await balances.find_one_and_update({"uid": balance["uid"]}, {"$set": { "txid": txid }}) account_client = SignedTornadoClient(settings.storageurl) account = await account_client.request(method_name="getaccountdata", **{"id": balance["uid"]}) # Send mail to user if account.get("email"): client_email = TornadoClient(settings.emailurl) email_data = { "to": account["email"], "subject": "Robin8 Support", "optional": "You`ve got %s tokens. Now your balance is %s" % (amount / pow(10, 8), int(result["amount"]) / pow(10, 8)) } await client_email.request(method_name="sendmail", **email_data) # Return result result = {i: result[i] for i in result if i != "_id"} result["amount"] = int(result["amount"]) return result @verify async def decbalance(self, *args, **kwargs): """ Decrements users balance Accepts: - message (signed dictionary): - "address" - str - "amount" - int - "uid" - str - "coinid" - str Returns: - dictionary with following fields: - "address" - str - "coinid" - str - "amount" - int - "uid" - int - "unconfirmed" - int (0 by default) - "deposit" - int (0 by default) - "txid" - None """ message = json.loads(kwargs.get("message", "{}")) uid = message.get("uid") address = message.get("address") amount = int(message.get("amount", 0)) coinid = message.get("coinid", "PUT") client = MotorClient() db = client[coinid] balances = db[settings.BALANCE] # Check if required fields exist if not uid and not address: return { "error": 400, "reason": "Missed required fields or amount is not digit" } # check if amount is not 0 if not amount: return {"error": 400, "reason": "Decrement balance. Funds is zero"} # Get account if uid: balance = await balances.find_one({"uid": int(uid)}) elif address: balance = await balances.find_one({"address": address}) # Check if balance is enough if balance and (int(balance["amount"]) - amount) < 0: return { "error": 400, "reason": "Address does not exist or amount is not enough" } # Update account await balances.find_one_and_update({"uid": balance["uid"]}, {"$inc": { "amount": -amount }}) result = await balances.find_one({"uid": balance["uid"]}) # Return balance balance = {i: result[i] for i in result if i != "_id"} balance["amount"] = int(balance["amount"]) return balance @verify async def getbalance(self, *args, **kwargs): """ Returns users balance Accepts: - message (signed dictionary) - "address" - str - "amount" - int - "uid" - str - "coinid" - str Returns: - list of dictionaries with following fields: - "address" - str - "coinid" - str - "amount" - int - "uid" - int - "unconfirmed" - int (0 by default) - "deposit" - int (0 by default) Verified: True """ # Get data from messaqe message = json.loads(kwargs.get("message", "{}")) address = message.get("address") uid = message.get("uid") # Check if required parameters exist if not address and not uid: return {"error": 400, "reason": "Missed required fields"} wallets = [] # Iter available coin id`s for coinid in self.coin_ids: logging.debug("\n Coin id") logging.debug(coinid) # Connect to appropriate database db = client[coinid] balances = db[settings.BALANCE] # Get balance if address: balance = await balances.find_one({"address": address}) elif uid: balance = await balances.find_one({"uid": uid}) try: wallets.append({ "address": balance["address"], "amount": balance["amount"], "deposit": balance["deposit"], "unconfirmed": balance["unconfirmed"], "coinid": coinid }) except: continue if not wallets: return {"error": 404, "reason": "Current address does not exist"} return wallets @verify async def depositbalance(self, *args, **kwargs): """ Freeze partial balance. Amount equals to offer`s price. Accepts: - message (sogned dictionary): - "address" - str - "uid" - str - "coinid" - str Returns: - "address" - str - "coinid" - str - "amount" - int - "uid" - int - "unconfirmed" - int (0 by default) - "deposit" - int (0 by default) Verified: True """ # Get data from request message = json.loads(kwargs.get("message", "{}")) uid = int(message.get("uid", 0)) amount = int(message.get("amount", 0)) coinid = message.get("coinid") coinid = "PUT" # Connect to database db = client[coinid] balances = db[settings.BALANCE] # Check if current balance exists balance = await balances.find_one({"uid": uid}) if not balance: return {"error": 404, "reason": "Current user was not found"} # Decrement amount updated_amount = await balances.find_one_and_update( {"uid": balance["uid"]}, {"$inc": { "amount": -amount }}) # Increment deposit updated_deposit = await balances.find_one_and_update( {"uid": balance["uid"]}, {"$inc": { "deposit": amount }}) updated = await balances.find_one({"uid": balance["uid"]}) return {i: updated[i] for i in updated if i != "_id" and i != "txid"} @verify async def undepositbalance(self, *args, **kwargs): """ Returns deposit amount to the base balance Accepts: - message (signed dict): - "uid" - str - "amount" - int - "coinid" - str Returns: - "address" - str - "coinid" - str - "amount" - int - "uid" - int - "unconfirmed" - int (0 by default) - "deposit" - int (0 by default) Verified: True """ # Get data from request message = json.loads(kwargs.get("message", "{}")) uid = int(message.get("uid", 0)) amount = int(message.get("amount", 0)) coinid = message.get("coinid") coinid = "PUT" # Connect to database db = client[coinid] balances = db[settings.BALANCE] # Try to get current balance balance = await balances.find_one({"uid": uid}) if not balance: return {"error": 404, "reason": "Current user was not found"} difference = int(balance["deposit"]) - int(amount) if difference < 0: return { "error": 400, "reason": "Undeposit balance. Can not set value below zero." } # Decrement from deposit await balances.find_one_and_update({"uid": balance["uid"]}, {"$inc": { "deposit": -amount }}) # Increment dase balance await balances.find_one_and_update({"uid": balance["uid"]}, {"$inc": { "amount": amount }}) # Get just updated balance updated = await balances.find_one({"uid": balance["uid"]}) return {i: updated[i] for i in updated if i != "_id" and i != "txid"} #@verify async def confirmbalance(self, *args, **kwargs): """ Confirm balance after trading Accepts: - message (signed dictionary): - "txid" - str - "coinid" - str - "amount" - int Returns: - "address" - str - "coinid" - str - "amount" - int - "uid" - int - "unconfirmed" - int (0 by default) - "deposit" - int (0 by default) Verified: True """ # Get data from request #if message.get() message = json.loads(kwargs.get("message", "{}")) txid = message.get("txid") coinid = message.get("coinid") buyer_address = message.get("buyer_address") cid = message.get("cid") # Check if required fields exists if not all([txid, coinid, cid, buyer_address]): return { "error": 400, "reason": "Confirm balance. Missed required fields" } client_bridge = SignedTornadoClient(settings.bridges[coinid]) offer = await client_bridge.request(method_name="get_offer", cid=cid, buyer_address=buyer_address) # Connect to database coinid = "PUT" database = client[coinid] balance_collection = database[settings.BALANCE] amount = int(offer["price"]) # Try to update balance if exists updated = await balance_collection.find_one_and_update( {"txid": txid}, {"$inc": { "amount": int(amount) }}) if not updated: return { "error": 404, "reason": "Confirm balance. Not found current transaction id" } # Decrement unconfirmed await balance_collection.find_one_and_update( {"txid": txid}, {"$inc": { "unconfirmed": -amount }}) # Update users level if it is equal two client_storage = SignedTornadoClient(settings.storageurl) account = await client_storage.request(method_name="getaccountdata", **{"id": updated["uid"]}) if "error" in account.keys(): return { "error": 500, "reason": "While incrementing balance current user was not found" } if int(account["level"]) == 2: await client_storage.request(method_name="updatelevel", **{ "id": account["id"], "level": 3 }) return {i: updated[i] for i in updated if i != "_id" and i != "txid"}
def verify(self): """Abstract method. Signature verifying logic. """ logging.debug("\n\n") logging.debug("[+] -- Verify debugging") logging.debug("\n\n") if self.request.body: logging.debug("\n Request body") logging.debug(self.request.body) data = json.loads(self.request.body) message = json.dumps(data.get("message")).replace(" ", "") logging.debug("\n") logging.debug(message) elif self.request.arguments: logging.debug("\n Arguments") logging.debug(self.request.arguments) data = {i: self.get_argument(i) for i in self.request.arguments} message = data.get("message", "{}") logging.debug(message) try: # Check if required fields exist assert "public_key" in data.keys( ), "Missed public key in parameters" assert "message" in data.keys(), "Missed message in parameters" assert "signature" in data.keys(), "Missed signature in parameters" public_key = data["public_key"] signature = data["signature"] timestamp = data.get("timestamp", None) # Check if #assert ManagementSystemHandler.get_time_stamp() == timestamp, "Timestamps does not match. Try again." except Exception as e: self.set_status(403) self.write({"error": 403, "reason": "Missing signature " + str(e)}) raise tornado.web.Finish else: # Check if message and signature exist # If not - return 403 error code if not all([message, public_key, signature]): raise tornado.web.HTTPError(403) # If exist - call verifying static method try: logging.debug("\n[] Try block. Verifying") logging.debug(message) logging.debug(signature) logging.debug(public_key) flag = Qtum.verify_message(message, signature, public_key) except Exception as e: # If public key is not valid or it`s missing - return 404 error #self.set_status(403) #self.write({"error":403, # "reason":"Forbidden. Invalid signature." + str(e)}) #raise tornado.web.Finish logging.debug("\n Exception") logging.debug(str(e)) pass