def create_payment_request_response(wallet_addr, amount, id_obj): # TODO: This might not work with remote keys if not id_obj.x509_cert: raise ValueError('id_obj missing x509_cert') signer = PluginManager.get_plugin('SIGNER', config.signer_type) signer.set_id_obj(id_obj) if not id_obj.payment_url: log.info('Creating Addressimo payment_url [ID: %s]' % id_obj.id) resolver = PluginManager.get_plugin('RESOLVER', config.resolver_type) try: payment_url_uuid = resolver.set_payment_request_meta_data(id_obj.get_expires(), wallet_addr, amount * 100000000) except Exception: return create_json_response(False, 'Internal Server Error. Please try again.', 500) # Setup PaymentRequest pr = generate_payment_request( wallet_addr, id_obj.x509_cert, id_obj.get_expires(), signer, amount, id_obj.memo, id_obj.payment_url or 'https://%s/payment/%s' % (config.site_url, payment_url_uuid), id_obj.merchant_data if id_obj.payment_url else payment_url_uuid ) return Response(response=pr, status=200, content_type=PR_MIMETYPE, headers={'Content-Transfer-Encoding': 'binary', 'Access-Control-Allow-Origin': '*'})
def generate_payment_request(crypto_addr, x509_cert, expires, signer=None, amount=0, memo=None, payment_url=None, merchant_data=None): # Setup & Populate PaymentDetails payment_details = PaymentDetails() # Setup Single PaymentDetails Output output = payment_details.outputs.add() output.amount = amount * 100000000 # BTC to Satoshis if crypto_addr[0] == '1': output.script = serialize_script([OP_DUP, OP_HASH160, b58check_to_hex(crypto_addr), OP_EQUALVERIFY, OP_CHECKSIG]).decode('hex') else: try: int(crypto_addr, 16) output.script = str(crypto_addr).decode('hex') except ValueError: output.script = str(crypto_addr) # Add current and expiration epoch time values payment_details.time = int(datetime.utcnow().strftime('%s')) payment_details.expires = expires # Handle Various Optional Fields in PaymentDetails payment_details.memo = memo if memo else '' payment_details.payment_url = payment_url if payment_url else '' payment_details.merchant_data = str(merchant_data) if merchant_data else '' # Setup & Populate PaymentRequest payment_request = PaymentRequest() payment_request.payment_details_version = 1 payment_request.serialized_payment_details = payment_details.SerializeToString() # Set PKI Type / Data if not x509_cert or not signer: payment_request.pki_type = 'none' payment_request.pki_data = '' else: payment_request.pki_type = signer.get_pki_type() pki_data = X509Certificates() for cert in get_certs(x509_cert): pki_data.certificate.append(cert) payment_request.pki_data = pki_data.SerializeToString() # Sign PaymentRequest if signer and x509_cert: payment_request.signature = '' payment_request.signature = signer.sign(payment_request.SerializeToString()) # Log Payment Request to Logging System logger = PluginManager.get_plugin('LOGGER', config.logger_type) logger.log_payment_request(crypto_addr, signer.__class__.__name__, amount, expires, memo, payment_url, merchant_data) log.debug('Generated Payment Request [Address: %s | Signer: %s | Amount: %s | Expires: %s | Memo: %s | Payment URL: %s | Merchant Data: %s]' % (crypto_addr, signer.__class__.__name__, amount, expires, memo, payment_url, merchant_data)) return payment_request.SerializeToString()
def get_unused_presigned_payment_request(id_obj): redis_conn = Redis.from_url(config.redis_addr_cache_uri) resolver = PluginManager.get_plugin('RESOLVER', config.resolver_type) return_pr = None used_pr = [] if config.store_and_forward_only and id_obj.presigned_payment_requests: return_pr = id_obj.presigned_payment_requests[0] id_obj.presigned_payment_requests.remove(return_pr) resolver.save(id_obj) return return_pr for pr in id_obj.presigned_payment_requests: if any([redis_conn.get(x) for x in get_addrs_from_paymentrequest(pr.decode('hex'))]): used_pr.append(pr) continue return_pr = pr break for pr in used_pr: id_obj.presigned_payment_requests.remove(pr) if used_pr: resolver.save(id_obj) return return_pr
def update_id_obj(id): resolver = PluginManager.get_plugin('RESOLVER', config.resolver_type) if not id: id_obj = IdObject() else: id_obj = resolver.get_id_obj(id) if not id_obj: return create_json_response(False, 'Object not found for this ID.', 404) rdata = request.get_json() if not set(rdata.keys()).issubset(id_obj.keys()): return create_json_response(False, 'Unknown key submitted', 400) for key, value in rdata.items(): if key == 'id': continue if key == 'private_key' and not value: continue id_obj[key] = value try: resolver.save(id_obj) except: return create_json_response(False, 'Exception occurred attempting to save id object', 500) return create_json_response(True, 'Update succeeded', 200, {'id': id_obj.id})
def get_count(): resolver = PluginManager.get_plugin('RESOLVER', config.resolver_type) id_obj = resolver.get_id_obj(get_id()) if not id_obj: return create_json_response(False, 'Invalid Identifier', 404) return create_json_response(data={'payment_request_count': len(id_obj.presigned_payment_requests)})
def delete(): resolver = PluginManager.get_plugin('RESOLVER', config.resolver_type) id_obj = resolver.get_id_obj(get_id()) if not id_obj: return create_json_response(False, 'Invalid Identifier', 404) resolver.delete(id_obj) return create_json_response(status=204)
def register(): resolver = PluginManager.get_plugin('RESOLVER', config.resolver_type) id_obj = IdObject() id_obj.auth_public_key = request.headers.get('x-identity') resolver.save(id_obj) return create_json_response(data={'id': id_obj.id, 'endpoint': 'https://%s/resolve/%s' % (config.site_url, id_obj.id)})
def return_used_branches(id): if not config.admin_public_key: log.info('No key provided in config, Failing [ID: %s]' % id) return create_json_response(False, 'ID Not Recognized', 404) if request.headers.get('x-identity') == config.admin_public_key: return create_json_response(data={'branches': PluginManager.get_plugin('RESOLVER', config.resolver_type).get_branches(id)}) return create_json_response(False, 'ID Not Recognized', 404)
def get_count(): resolver = PluginManager.get_plugin('RESOLVER', config.resolver_type) id_obj = resolver.get_id_obj(get_id()) if not id_obj: return create_json_response(False, 'Invalid Identifier', 404) return create_json_response( data={ 'payment_request_count': len(id_obj.presigned_payment_requests) })
def get_unused_bip32_address(id_obj): if not id_obj.master_public_key: raise ValueError('Master public key missing. Unable to generate bip32 address.') # Determine correct branch based on derive logic branch = derive_branch() # Get last generated index for the branch if it exists. lg_index = PluginManager.get_plugin('RESOLVER', config.resolver_type).get_lg_index(id_obj.id, branch) while True: wallet_addr = generate_bip32_address_from_extended_pubkey(id_obj.master_public_key, branch, lg_index) if not redis_conn.get(wallet_addr): log.info('New Wallet Address created [Address: %s | Branch: %s | GenIndex: %s]' % (wallet_addr, branch, lg_index)) PluginManager.get_plugin('RESOLVER', config.resolver_type).set_lg_index(id_obj.id, branch, lg_index) return wallet_addr else: log.debug('Used Wallet Address found! Trying next index [Branch: %s | GenIndex: %s]' % (branch, lg_index)) lg_index += 1
def register(**kwargs): resolver = PluginManager.get_plugin('RESOLVER', config.resolver_type) id_obj = IdObject() id_obj.auth_public_key = request.headers.get('x-identity') for k,v in kwargs.items(): setattr(id_obj, k, v) resolver.save(id_obj) return create_json_response(data={'id': id_obj.id, 'endpoint': 'https://%s/address/%s/resolve' % (config.site_url, id_obj.id)})
def tearDownClass(cls): time.sleep(1) resolver = PluginManager.get_plugin('RESOLVER', config.resolver_type) log.info('Clean Up Functest') log.info('Deleting All testid InvoiceRequests if any exist') for message_type in ProtocolMessageType.keys(): resolver.delete_paymentprotocol_message(cls.identifier, message_type, id='testid') log.info('Deleting Test IdObj') resolver.delete(BIP75FunctionalTest.test_id_obj)
def delete_id_obj(id): resolver = PluginManager.get_plugin('RESOLVER', config.resolver_type) id_obj = resolver.get_id_obj(id) if not id_obj: return create_json_response(False, 'Object not found for this ID.', 404) try: resolver.delete(id_obj) except: return create_json_response(False, 'Exception occurred attempting to delete id object', 500) return create_json_response(True, 'Delete succeeded', 204)
def get_id_objs(id): resolver = PluginManager.get_plugin('RESOLVER', config.resolver_type) if id: raw = resolver.get_id_obj(id) if not raw: return create_json_response(False, 'Object not found for this ID.', 404) raw['private_key'] = '' result = {'data': raw} else: result = {'keys': resolver.get_all_keys()} return create_json_response(True, '', 200, result)
def register(**kwargs): resolver = PluginManager.get_plugin('RESOLVER', config.resolver_type) id_obj = IdObject() id_obj.auth_public_key = request.headers.get('x-identity') for k, v in kwargs.items(): setattr(id_obj, k, v) resolver.save(id_obj) return create_json_response( data={ 'id': id_obj.id, 'endpoint': 'https://%s/address/%s/resolve' % (config.site_url, id_obj.id) })
def setUpClass(cls): log.info('Generating ECDSA Keypairs for Testing') cls.sender_sk = SigningKey.generate(curve=curves.SECP256k1) cls.receiver_sk = SigningKey.generate(curve=curves.SECP256k1) log.info('Setup IdObj for testid') cls.test_id_obj = IdObject() cls.test_id_obj.auth_public_key = cls.receiver_sk.get_verifying_key().to_der().encode('hex') cls.test_id_obj.id = 'testid' cls.test_id_obj.paymentprotocol_only = True cls.resolver = PluginManager.get_plugin('RESOLVER', config.resolver_type) cls.resolver.save(cls.test_id_obj) log.info('Save testid IdObj') log.info('Setup Class Identifier') cls.identifier = None
def setUp(self): # Generate a signing key used for refund output retrieval in get_refund_addresses() self.receiver_sk = SigningKey.generate(curve=curves.SECP256k1) log.info('Setup IdObj for testid') self.test_id_obj = IdObject() self.test_id_obj.id = 'testid' self.test_id_obj.bip70_enabled = True self.test_id_obj.wallet_address = '1MSK1PMnDZN4SLDQ6gB4c6GKRExfGD6Gb3' self.test_id_obj.x509_cert = TEST_CERT self.test_id_obj.private_key = TEST_CERT_PRIVKEY self.test_id_obj.auth_public_key = self.receiver_sk.get_verifying_key().to_string().encode('hex') self.resolver = PluginManager.get_plugin('RESOLVER', config.resolver_type) self.resolver.save(self.test_id_obj) log.info('Save testid IdObj') # Keep track of PaymentRequest meta data stored in Redis so it can be cleaned up later self.redis_pr_store_cleanup = []
def verify_public_key(): id = get_id() if not id: log.info('ID Unavailable from request: %s' % request.url) return create_json_response(False, 'Unknown Endpoint', 404) if not request.headers.get('x-identity'): log.info('No Pubkey Exists in Request, Returning False [ID: %s]' % id) return create_json_response(False, 'Missing x-identity header', 400) resolver = PluginManager.get_plugin('RESOLVER', config.resolver_type) id_obj = resolver.get_id_obj(id) if not id_obj: log.info('No Data Exists for Given ID, Failing [ID: %s]' % id) return create_json_response(False, 'ID Not Recognized', 404) if request.headers.get('x-identity') == id_obj.auth_public_key: return None return create_json_response(False, 'ID Not Recognized', 404)
def setUpClass(cls): log.info('Generating ECDSA Keypairs for Testing') cls.sender_sk = SigningKey.generate(curve=curves.SECP256k1) cls.receiver_sk = SigningKey.generate(curve=curves.SECP256k1) log.info('Setup IdObj for testid') cls.test_id_obj = IdObject() cls.test_id_obj.auth_public_key = cls.receiver_sk.get_verifying_key( ).to_der().encode('hex') cls.test_id_obj.id = 'testid' cls.test_id_obj.paymentprotocol_only = True cls.resolver = PluginManager.get_plugin('RESOLVER', config.resolver_type) cls.resolver.save(cls.test_id_obj) log.info('Save testid IdObj') log.info('Setup Class Identifier') cls.identifier = None
def setUp(self): # Generate a signing key used for refund output retrieval in get_refund_addresses() self.receiver_sk = SigningKey.generate(curve=curves.SECP256k1) log.info('Setup IdObj for testid') self.test_id_obj = IdObject() self.test_id_obj.id = 'testid' self.test_id_obj.bip70_enabled = True self.test_id_obj.wallet_address = '1MSK1PMnDZN4SLDQ6gB4c6GKRExfGD6Gb3' self.test_id_obj.x509_cert = TEST_CERT self.test_id_obj.private_key = TEST_CERT_PRIVKEY self.test_id_obj.auth_public_key = self.receiver_sk.get_verifying_key( ).to_string().encode('hex') self.resolver = PluginManager.get_plugin('RESOLVER', config.resolver_type) self.resolver.save(self.test_id_obj) log.info('Save testid IdObj') # Keep track of PaymentRequest meta data stored in Redis so it can be cleaned up later self.redis_pr_store_cleanup = []
def create_payment_request_response(wallet_addr, amount, id_obj): # TODO: This might not work with remote keys if not id_obj.x509_cert: raise ValueError('id_obj missing x509_cert') signer = PluginManager.get_plugin('SIGNER', config.signer_type) signer.set_id_obj(id_obj) # Setup PaymentRequest pr = generate_payment_request( wallet_addr, id_obj.x509_cert, signer, amount, id_obj.expires, id_obj.memo, id_obj.payment_url, id_obj.merchant_data ) return Response(response=pr, status=200, content_type=PR_MIMETYPE, headers={'Content-Transfer-Encoding': 'binary', 'Access-Control-Allow-Origin': '*'})
def get_unused_presigned_payment_request(id_obj): redis_conn = Redis.from_url(config.redis_addr_cache_uri) return_pr = None used_pr = [] for pr in id_obj.presigned_payment_requests: if any([redis_conn.get(x) for x in get_addrs_from_paymentrequest(pr.decode('hex'))]): used_pr.append(pr) continue return_pr = pr break for pr in used_pr: id_obj.presigned_payment_requests.remove(pr) if used_pr: resolver = PluginManager.get_plugin('RESOLVER', config.resolver_type) resolver.save(id_obj) return return_pr
def generate_payment_request(crypto_addr, x509_cert, signer=None, amount=0, expires=None, memo=None, payment_url=None, merchant_data=None): # Setup & Populate PaymentDetails payment_details = PaymentDetails() # Setup Single PaymentDetails Output output = payment_details.outputs.add() output.amount = amount * 100000000 # BTC to Satoshis if crypto_addr[0] == '1': output.script = serialize_script([OP_DUP, OP_HASH160, b58check_to_hex(crypto_addr), OP_EQUALVERIFY, OP_CHECKSIG]).decode('hex') else: try: int(crypto_addr, 16) output.script = str(crypto_addr).decode('hex') except ValueError: output.script = str(crypto_addr) # Add current and expiration epoch time values payment_details.time = int(datetime.utcnow().strftime('%s')) if expires: if isinstance(expires, int) or isinstance(expires, long): payment_details.expires = int((datetime.utcnow() + timedelta(seconds=expires)).strftime('%s')) elif isinstance(expires, datetime.__class__): payment_details.expires = int(expires.strftime('%s')) else: payment_details.expires = int((datetime.utcnow() + timedelta(seconds=config.bip70_default_expiration)).strftime('%s')) # Handle Various Optional Fields in PaymentDetails payment_details.memo = memo if memo else '' payment_details.payment_url = payment_url if payment_url else '' payment_details.merchant_data = str(merchant_data) if merchant_data else '' # Setup & Populate PaymentRequest payment_request = PaymentRequest() payment_request.payment_details_version = 1 payment_request.serialized_payment_details = payment_details.SerializeToString() # Set PKI Type / Data if not x509_cert or not signer: payment_request.pki_type = 'none' payment_request.pki_data = '' else: payment_request.pki_type = signer.get_pki_type() pki_data = X509Certificates() for cert in get_certs(x509_cert): pki_data.certificate.append(cert) payment_request.pki_data = pki_data.SerializeToString() # Sign PaymentRequest if signer and x509_cert: payment_request.signature = '' payment_request.signature = signer.sign(payment_request.SerializeToString()) # Log Payment Request to Logging System logger = PluginManager.get_plugin('LOGGER', config.logger_type) logger.log_payment_request(crypto_addr, signer.__class__.__name__, amount, expires, memo, payment_url, merchant_data) log.debug('Generated Payment Request [Address: %s | Signer: %s | Amount: %s | Expires: %s | Memo: %s | Payment URL: %s | Merchant Data: %s]' % (crypto_addr, signer.__class__.__name__, amount, expires, memo, payment_url, merchant_data)) return payment_request.SerializeToString()
__author__ = 'frank' from addressimo.config import config from addressimo.plugin import PluginManager from addressimo.util import LogUtil log = LogUtil.setup_logging() PluginManager.register_plugins() resolver = PluginManager.get_plugin('RESOLVER', config.resolver_type) log.info('Starting Stale PaymentRequest Meta Data Cleanup') resolver.cleanup_stale_payment_request_meta_data() log.info('Completed Stale PaymentRequest Meta Data Cleanup') log.info('Starting Stale Payment Meta Data Cleanup') resolver.cleanup_stale_payment_meta_data() log.info('Completed Stale Payment Meta Data Cleanup') log.info('Starting Stale InvoiceRequest Data Cleanup') resolver.cleanup_stale_invoicerequest_data() log.info('Completed Stale InvoiceRequest Data Cleanup') log.info('Starting Stale EncryptedPaymentRequest Data Cleanup') resolver.cleanup_stale_encrypted_paymentrequest_data() log.info('Completed Stale EncryptedPaymentRequest Data Cleanup')
def resolve(id): ################################### # Verify Resolver and Request Data ################################### if not config.store_and_forward_only and not cache_up_to_date(): log.critical('Address cache not up to date. Refresh Redis cache.') return create_json_response(False, 'Address cache not up to date. Please try again later.', 500) try: id_obj = PluginManager.get_plugin('RESOLVER', config.resolver_type).get_id_obj(id) except Exception as e: log.error('Exception retrieving id_obj [ID: %s | Exception: %s]' % (id, str(e))) return create_json_response(False, 'Exception occurred when retrieving id_obj from database', 500) if not id_obj: log.error('Unable to retrieve id_obj [ID: %s]' % id) return create_json_response(False, 'Unable to retrieve id_obj from database', 404) # Handle InvoiceRequests if id_obj.paymentprotocol_only: return create_json_response(False, 'Endpoint Requires a valid POST to create a PaymentRequest Request', 405, headers={'Allow': 'POST'}) # Handle Store & Forward-Only Mode if config.store_and_forward_only and not id_obj.presigned_payment_requests: return create_json_response(False, 'Endpoint Unavaiable, This is a Store & Forward ONLY Service', 404) ################################################################################# # Determine Wallet Address to Return or Use in BIP70 PaymentRequest Generation ################################################################################# if not id_obj.bip32_enabled and not id_obj.wallet_address: log.error('bip32_enabled is False and static wallet_address is missing [ID: %s]' % id) return create_json_response(False, 'Unable to retrieve wallet_address', 400) if id_obj.bip32_enabled: try: waddr = get_unused_bip32_address(id_obj) except Exception as e: log.error('Exception occurred retrieving unused bip32 address [EXCEPTION: %s | ID: %s]' % (str(e), id)) return create_json_response(False, 'Unable to retrieve wallet_address', 500) else: waddr = id_obj.wallet_address ########################### # Determine Response Type ########################### bip70_arg = request.args.get('bip70','').lower() # BIP70 Forced Request, but endpoint is not BIP70 capable if bip70_arg == 'true' and not id_obj.bip70_enabled: log.error('Required bip70_enabled value is missing or disabled [ID: %s | bip70_enabled: %s]' % (id, id_obj.get('bip70_enabled', None))) return create_json_response(False, 'Required bip70_enabled value is missing or disabled', 400) # BIP70-enabled Endpoint and BIP70 Request Forced or Accept-able by Client if id_obj.bip70_enabled and (bip70_arg == 'true' or PR_MIMETYPE in request.headers.get('accept')): # Handle Pre-signed PaymentRequests if id_obj.presigned_payment_requests: valid_pr = get_unused_presigned_payment_request(id_obj) if not valid_pr: return create_json_response(False, 'No PaymentRequests available for this ID', 404) return Response(response=valid_pr, status=200, content_type=PR_MIMETYPE, headers={'Content-Transfer-Encoding': 'binary', 'Access-Control-Allow-Origin': '*'}) elif id_obj.presigned_only: log.warn('Presigned PaymentRequests list empty [ID: %s]' % id) return create_json_response(False, 'No PaymentRequests available for this ID', 404) # Handle Non-Presigned PaymentRequests log.info('Creating bip70 payment request [ADDRESS: %s | AMOUNT: %s | ID: %s]' % (waddr, get_bip70_amount(id_obj), id)) try: return create_payment_request_response(waddr, get_bip70_amount(id_obj), id_obj) except Exception as e: log.error('Exception occurred creating payment request [EXCEPTION: %s | ID: %s]' % (str(e), id_obj.id)) return create_json_response(False, 'Unable to create payment request', 500) # BIP70-enabled Endpoint, but not BIP70-specific Request if id_obj.bip70_enabled and bip70_arg != 'false': # Handle Pre-signed Payment Requests if not id_obj.presigned_payment_requests and id_obj.presigned_only: log.warn('Presigned PaymentRequests list empty [ID: %s]' % id) return create_json_response(False, 'No PaymentRequests available for this ID', 404) elif id_obj.presigned_payment_requests: valid_pr = get_unused_presigned_payment_request(id_obj) if not valid_pr: return create_json_response(False, 'No PaymentRequests available for this ID', 404) return create_bip72_response(None, None, 'https://%s/address/%s/resolve?bip70=true' % (config.site_url, id)) # Handle Non-Presigned PaymentRequests log.info('Returning BIP72 URI [Address: %s | ID: %s]' % (waddr, id)) return create_bip72_response(waddr, get_bip70_amount(id_obj), 'https://%s/address/%s/resolve?bip70=true&amount=%s' % (config.site_url, id_obj.id, get_bip70_amount(id_obj))) # Return Standard BIP72 URI Response without a PaymentRequest URI log.info('Returning Wallet Address [Address: %s | ID: %s]' % (waddr, id)) return create_bip72_response(waddr, 0)
def add(): resolver = PluginManager.get_plugin('RESOLVER', config.resolver_type) id_obj = resolver.get_id_obj(get_id()) if not id_obj: return create_json_response(False, 'Invalid Identifier', 404) rdata = None try: rdata = request.get_json() except Exception as e: log.warn("Exception Parsing JSON: %s" % str(e)) return create_json_response(False, 'Invalid Request', 400) if not rdata: return create_json_response(False, 'Invalid Request', 400) pr_list = rdata.get('presigned_payment_requests') if not pr_list: return create_json_response( False, 'Missing presigned_payment_requests data', 400) if not isinstance(pr_list, list): return create_json_response( False, 'presigned_payment_requests data must be a list', 400) # Validate PaymentRequests for pr in pr_list: try: int(pr, 16) except ValueError: return create_json_response( False, 'Payment Request Must Be Hex Encoded', 400) verify_pr = PaymentRequest() try: hex_decoded_pr = pr.decode('hex') if len(hex_decoded_pr) > PAYMENT_REQUEST_SIZE_MAX: log.warn( 'Rejecting Payment Request for Size [ACCEPTED: %d bytes | ACTUAL: %d bytes]' % (PAYMENT_REQUEST_SIZE_MAX, len(hex_decoded_pr))) return create_json_response( False, 'Invalid Payment Request Submitted', 400) verify_pr.ParseFromString(hex_decoded_pr) except Exception as e: log.warn( 'Unable to Parse Submitted Payment Request [ID: %s]: %s' % (id_obj.id, str(e))) return create_json_response( False, 'Invalid Payment Request Submitted', 400) verify_pd = PaymentDetails() try: verify_pd.ParseFromString(verify_pr.serialized_payment_details) except Exception as e: log.warn( 'Unable to Parse Submitted Payment Request [ID: %s]: %s' % (id_obj.id, str(e))) return create_json_response( False, 'Invalid Payment Request Submitted', 400) # Validated! add_count = 0 for pr in pr_list: id_obj.presigned_payment_requests.append(pr) add_count += 1 if add_count == config.presigned_pr_limit: log.info('Presigned Payment Limit Reached [ID: %s]' % id_obj.id) break log.info('Added %d Pre-Signed Payment Requests [ID: %s]' % (add_count, id_obj.id)) resolver.save(id_obj) return create_json_response(data={'payment_requests_added': add_count})
def add(): resolver = PluginManager.get_plugin('RESOLVER', config.resolver_type) id_obj = resolver.get_id_obj(get_id()) if not id_obj: return create_json_response(False, 'Invalid Identifier', 404) rdata = None try: rdata = request.get_json() except Exception as e: log.warn("Exception Parsing JSON: %s" % str(e)) return create_json_response(False, 'Invalid Request', 400) if not rdata: return create_json_response(False, 'Invalid Request', 400) pr_list = rdata.get('presigned_payment_requests') if not pr_list: return create_json_response(False, 'Missing presigned_payment_requests data', 400) if not isinstance(pr_list, list): return create_json_response(False, 'presigned_payment_requests data must be a list', 400) # Validate PaymentRequests for pr in pr_list: try: int(pr, 16) except ValueError: return create_json_response(False, 'Payment Request Must Be Hex Encoded', 400) verify_pr = PaymentRequest() try: hex_decoded_pr = pr.decode('hex') if len(hex_decoded_pr) > PAYMENT_REQUEST_SIZE_MAX: log.warn('Rejecting Payment Request for Size [ACCEPTED: %d bytes | ACTUAL: %d bytes]' % (PAYMENT_REQUEST_SIZE_MAX, len(hex_decoded_pr))) return create_json_response(False, 'Invalid Payment Request Submitted', 400) verify_pr.ParseFromString(hex_decoded_pr) except Exception as e: log.warn('Unable to Parse Submitted Payment Request [ID: %s]: %s' % (id_obj.id, str(e))) return create_json_response(False, 'Invalid Payment Request Submitted', 400) verify_pd = PaymentDetails() try: verify_pd.ParseFromString(verify_pr.serialized_payment_details) except Exception as e: log.warn('Unable to Parse Submitted Payment Request [ID: %s]: %s' % (id_obj.id, str(e))) return create_json_response(False, 'Invalid Payment Request Submitted', 400) # Validated! add_count = 0 for pr in pr_list: id_obj.presigned_payment_requests.append(pr) add_count += 1 if add_count == config.presigned_pr_limit: log.info('Presigned Payment Limit Reached [ID: %s]' % id_obj.id) break log.info('Added %d Pre-Signed Payment Requests [ID: %s]' % (add_count, id_obj.id)) resolver.save(id_obj) return create_json_response(data={'payment_requests_added': add_count})