def decrypt(self, memo): """ Decrypt a memo :param str memo: encrypted memo message :returns: encrypted memo :rtype: str """ if not memo: return None # We first try to decode assuming we received the memo try: memo_wif = self.blockchain.wallet.getPrivateKeyForPublicKey( memo["to"]) pubkey = memo["from"] except KeyNotFound: try: # if that failed, we assume that we have sent the memo memo_wif = self.blockchain.wallet.getPrivateKeyForPublicKey( memo["from"]) pubkey = memo["to"] except KeyNotFound: # if all fails, raise exception raise MissingKeyError( "Non of the required memo keys are installed!" "Need any of {}".format([memo["to"], memo["from"]])) if not hasattr(self, 'chain_prefix'): self.chain_prefix = self.blockchain.prefix return BtsMemo.decode_memo(PrivateKey(memo_wif), PublicKey(pubkey, prefix=self.chain_prefix), memo.get("nonce"), memo.get("message"))
def decodeMemo(self, **kwargs): from_pubkey = kwargs.get('from') to_pubkey = kwargs.get('to') nonce = kwargs.get('nonce') cipher_text = kwargs.get('message') # local_privkey = self.privkeys[0] if not isinstance(from_pubkey, PublicKey): from_pubkey = PublicKey(from_pubkey, prefix=from_pubkey[0:3]) if not isinstance(to_pubkey, PublicKey): to_pubkey = PublicKey(to_pubkey, prefix=to_pubkey[0:3]) # if str(self.pubkey) == str(from_pubkey): # other_pubkey = to_pubkey # elif str(self.pubkey) == str(to_pubkey): # other_pubkey = from_pubkey if str(from_pubkey) in self.privkeys: local_privkey = self.privkeys[str(from_pubkey)] other_pubkey = to_pubkey elif str(to_pubkey) in self.privkeys: local_privkey = self.privkeys[str(to_pubkey)] other_pubkey = from_pubkey else: raise MissingKey( "No Private Key found for neither %s nor %s public keys" % (str(from_pubkey), str(to_pubkey))) clear = BTSMemo.decode_memo(local_privkey, other_pubkey, nonce, cipher_text) return clear
def test_decrypt_bugged_padding(self): for memo in not_enough_padding: dec = decode_memo( PrivateKey(memo["wif"]), PublicKey(memo["to"], prefix="GPH"), memo["nonce"], memo["message"], ) self.assertEqual(memo["plain"], dec)
def test_decrypt(self): for memo in test_cases: dec = decode_memo( PrivateKey(memo["wif"]), PublicKey(memo["to"], prefix="GPH"), memo["nonce"], memo["message"], ) self.assertEqual(memo["plain"], dec)
def decrypt(self, memo): """ Decrypt a memo :param str memo: encrypted memo message :returns: encrypted memo :rtype: str """ if not memo: return None memo_wif = self.bitshares.wallet.getPrivateKeyForPublicKey( self.to_account["options"]["memo_key"]) if not memo_wif: raise MissingKeyError("Memo key for %s missing!" % self.to_account["name"]) # TODO: Use pubkeys of the message, not pubkeys of account! return BtsMemo.decode_memo( PrivateKey(memo_wif), PublicKey(self.from_account["options"]["memo_key"], prefix=self.bitshares.rpc.chain_params["prefix"]), memo.get("nonce"), memo.get("message"))
def clean_txs(self, account: Account, symbol: str, transactions: Iterable[dict]) -> Generator[dict, None, None]: """ Filters a list of transactions by the receiving account, yields dict's conforming with :class:`payments.models.Deposit` :param str account: The 'to' account to filter by :param str symbol: The symbol of the token being filtered :param list<dict> transactions: A list<dict> of transactions to filter :return: A generator yielding ``dict`` s conforming to :class:`payments.models.Deposit` """ for tx in transactions: try: data = tx['op'][ 1] # unwrap the transaction structure to get at the data within if data['to'] != account['id'] or data['from'] == account['id']: continue # cache asset data for 5 mins, so we aren't spamming the RPC node for data amount_info = data['amount'] asset_id = amount_info['asset_id'] asset_key = 'btsasset:%s' % (asset_id, ) asset = cache.get(asset_key, default=None) if asset is None: asset_obj = self.get_asset_obj(asset_id) if asset_obj is not None: asset = { 'symbol': asset_obj.symbol, 'precision': asset_obj.precision } cache.set(asset_key, asset, 300) else: continue if asset['symbol'] != symbol: continue raw_amount = Decimal(int(amount_info['amount'])) transfer_quantity = raw_amount / (10**asset['precision']) # cache account data for 5 mins, so we aren't spamming the RPC node for data account_key = 'btsacc:%s' % (data['from'], ) from_account_name = cache.get(account_key, default=data['from']) if from_account_name == data['from']: from_account = self.get_account_obj(data['from']) if from_account is not None: from_account_name = from_account.name cache.set(account_key, from_account_name, 300) else: log.exception( 'From account not found for transaction %s', tx) # decrypt the transaction memo memo_msg = '' if 'memo' in data: memo = data['memo'] try: memokey = self.get_private_key(account.name, 'memo') privkey = PrivateKey(memokey) pubkey = PublicKey(memo['from'], prefix='BTS') memo_msg = decode_memo(privkey, pubkey, memo['nonce'], memo['message']) except Exception as e: memo_msg = '--cannot decode memo--' log.exception( 'Error decoding memo %s, got exception %s', memo['message'], e) # fetch timestamp from the block containing this transaction # (a hugely inefficient lookup but unfortunately no other way to do this) tx_datetime = datetime.fromtimestamp( self.get_block_timestamp(tx['block_num'])) tx_datetime = timezone.make_aware(tx_datetime, pytz.UTC) clean_tx = dict(txid=tx['id'], coin=self.coins[symbol].symbol, tx_timestamp=tx_datetime, from_account=from_account_name, to_account=account.name, memo=memo_msg, amount=transfer_quantity) yield clean_tx except Exception as e: log.exception( 'Error parsing transaction data. Skipping this TX. tx = %s, exception = %s', tx, e) continue
def decrypt_msg(priv_key, pub_key, nonce, msg): dec = decode_memo(PrivateKey(priv_key), PublicKey(pub_key, prefix="NEST"), nonce, msg) return dec
async def process_operations(self, op_id): """ 处理操作 """ op_info = await self.node_api.get_objects([op_id]) for operation in op_info[::-1]: if operation["op"][0] != 0: return # 操作基本信息 trx = {} op = operation['op'][1] trx['trx_id'] = operation['id'] # 获取区块信息 trx['block_num'] = operation['block_num'] block_info = await self.node_api.get_block(trx['block_num']) trx['timestamp'] = block_info['timestamp'] # 获取转账金额 asset = await self.get_asset_info(op['amount']['asset_id']) trx['asset'] = asset['symbol'] trx['asset_id'] = op['amount']['asset_id'] trx['amount'] = float(op['amount']['amount']) / float(10**int( asset['precision'])) # 获取转账手续费 trx['fee'] = {} fee = await self.get_asset_info(op['fee']['asset_id']) trx['fee']['asset'] = fee['symbol'] trx['fee']['asset_id'] = op['fee']['asset_id'] trx['fee']['amount'] = float(op['fee']['amount']) / float(10**int( fee['precision'])) # 获取涉案账户 trx['to_id'] = op['to'] trx['from_id'] = op['from'] trx['to'] = (await self.node_api.get_objects([op['to']]))[0]['name'] trx['from'] = (await self.node_api.get_objects([op['from']]))[0]['name'] # 解码备注信息 if 'memo' in op: memo = op['memo'] trx['nonce'] = memo['nonce'] try: privkey = PrivateKey(self.wifkey) prefix = self.node_api.chain_params['prefix'] if trx['to_id'] == self.account['id']: pubkey = PublicKey(memo['from'], prefix=prefix) else: pubkey = PublicKey(memo['to'], prefix=prefix) trx['memo'] = BtsMemo.decode_memo(privkey, pubkey, memo['nonce'], memo['message']) except Exception: trx['memo'] = None else: trx['memo'] = None trx['nonce'] = None # 触发转账事件 if trx['from_id'] == self.account['id']: await self.on_sent(trx) elif trx['to_id'] == self.account['id']: await self.on_receive(trx)
async def _process_transfer_operations(self, client, operation): ''' 处理转账操作 ''' # 筛选操作类型 if operation['op'][0] != self.TRANSFER_OPERATION: return # 操作基本信息 trx = {} op = operation['op'][1] # 获取区块信息 trx['heigth'] = operation['block_num'] block_info = await client.get_block(trx['heigth']) trx['timestamp'] = block_info['timestamp'] # 获取交易ID trx_in_block = operation['trx_in_block'] transaction = block_info['transactions'][trx_in_block] trx['txid'] = await self._get_transaction_id(transaction) # 获取转账金额 asset = await self._get_asset_info(client, op['amount']['asset_id']) trx['asset'] = asset['symbol'] trx['asset_id'] = op['amount']['asset_id'] trx['amount'] = str( float(op['amount']['amount']) / float(10**int(asset['precision']))) # 获取转账手续费 trx['fee'] = {} fee = await self._get_asset_info(client, op['fee']['asset_id']) trx['fee']['asset'] = fee['symbol'] trx['fee']['asset_id'] = op['fee']['asset_id'] trx['fee']['amount'] = str( float(op['fee']['amount']) / float(10**int(fee['precision']))) # 获取涉案账户 trx['to_id'] = op['to'] trx['from_id'] = op['from'] trx['to'] = (await client.get_objects([op['to']]))[0]['name'] trx['from'] = (await client.get_objects([op['from']]))[0]['name'] # 解码备注信息 if 'memo' in op: memo = op['memo'] trx['nonce'] = memo['nonce'] try: privkey = PrivateKey(SysConfig().memo_key) prefix = client.chain_params['prefix'] if trx['to_id'] == self._account['id']: pubkey = PublicKey(memo['from'], prefix=prefix) else: pubkey = PublicKey(memo['to'], prefix=prefix) trx['memo'] = BtsMemo.decode_memo(privkey, pubkey, memo['nonce'], memo['message']) except Exception as e: logging.warn('Failed to decode memo, %s, %s', operation['id'], str(e)) trx['memo'] = None else: trx['memo'] = None trx['nonce'] = None return trx
json.dumps(trx, indent=4))) return False for f in account_history_b20: if not is_valid_bit20_publication(f): print('Hijacking attempt of the bit20 feed? trx: {}'.format( json.dumps(f, indent=4))) continue memo = f['op'][1]['memo'] privkey = PrivateKey(wifkey_announce) pubkey = PublicKey(Account(f['op'][1]['from'])['options']['memo_key']) memomsg = BtsMemo.decode_memo(privkey, pubkey, memo["nonce"], memo["message"]) #print(memomsg) if memomsg.startswith('COMPOSITION'): # last_updated = re.search('\((.*)\)', memomsg) # if last_updated: # last_updated = pendulum.from_format(last_updated.group(1), '%Y/%m/%d') # #print(last_updated) bit20 = json.loads(memomsg.split(')', maxsplit=1)[1]) break else: print( "Did not find any bit20 composition in the last {} messages to account bittwenty.feed" .format(len(bit20feed)))