def test_to_xdr(self): # GDF5O4OWEMVBY5FLDHWA5RZTYSV2U276XGKZZ6VSHDDR3THSQ6OQS7UM source = Keypair.from_secret( "SCCS5ZBI7WVIJ4SW36WGOQQIWJYCL3VOAULSXX3FB57USIO25EDOYQHH") destination = "GDJJRRMBK4IWLEPJGIE6SXD2LP7REGZODU7WDC3I2D6MR37F4XSHBKX2" amount = "1000.0" sequence = 1 memo = IdMemo(100) fee = 200 asset = Asset.native() time_bounds = TimeBounds(12345, 56789) ops = [ Payment(destination, asset, amount), ManageData("hello", "world") ] tx = Transaction(source, sequence, fee, ops, memo, time_bounds) network = Network.public_network() te = TransactionEnvelope(tx, network) assert binascii.hexlify(te.hash()).decode() == te.hash_hex() te.sign(source) hashx = bytes.fromhex( "94e8223a518ac16a8cb110ab1952ef14da2c10b264645c38c8b3d82bd2b20000") te.sign_hashx(hashx) te_xdr = "AAAAAMvXcdYjKhx0qxnsDsczxKuqa/65lZz6sjjHHczyh50JAAAAyAAAAAAAAAABAAAAAQAAAAAAADA5AAAAAAAA3dUAAAACAAAAAAAAAGQAAAACAAAAAAAAAAEAAAAA0pjFgVcRZZHpMgnpXHpb/xIbLh0/YYto0PzI7+Xl5HAAAAAAAAAAAlQL5AAAAAAAAAAACgAAAAVoZWxsbwAAAAAAAAEAAAAFd29ybGQAAAAAAAAAAAAAAvKHnQkAAABAM4dg0J1LEFBmbDESJ5d+60WCuZC8lnA80g45qyEgz2oRBSNw1mOfZETnL/BgrebkG/K03oI2Wqcs9lvDKrDGDE0sOBsAAAAglOgiOlGKwWqMsRCrGVLvFNosELJkZFw4yLPYK9KyAAA=" assert te.to_xdr() == te_xdr restore_te = TransactionEnvelope.from_xdr(te_xdr, network) assert restore_te.to_xdr() == te_xdr
def deserialize(value): """ Validation function for Transaction.envelope_xdr """ from polaris import settings try: TransactionEnvelope.from_xdr(value, settings.STELLAR_NETWORK_PASSPHRASE) except SdkError as e: raise ValidationError( _("Cannot decode envelope XDR for transaction: %(error)s"), params={"error": str(e)}, )
def test_verify_challenge_transaction_signed_by_client_master_key_raise_unrecognized_signatures( self, ): server_kp = Keypair.random() client_kp_a = Keypair.random() client_kp_unrecognized = Keypair.random() timeout = 600 network_passphrase = Network.PUBLIC_NETWORK_PASSPHRASE anchor_name = "SDF" challenge = build_challenge_transaction( server_secret=server_kp.secret, client_account_id=client_kp_a.public_key, anchor_name=anchor_name, network_passphrase=network_passphrase, timeout=timeout, ) transaction = TransactionEnvelope.from_xdr(challenge, network_passphrase) transaction.sign(client_kp_a) transaction.sign(client_kp_unrecognized) challenge_tx = transaction.to_xdr() with pytest.raises(InvalidSep10ChallengeError, match="Transaction has unrecognized signatures."): verify_challenge_transaction_signed_by_client_master_key( challenge_tx, server_kp.public_key, network_passphrase)
def test_auth_get_account(client): """`GET <auth>` succeeds with a valid TransactionEnvelope XDR.""" response = client.get(f"{endpoint}?account={STELLAR_ACCOUNT_1}", follow=True) content = json.loads(response.content) assert content["network_passphrase"] == "Test SDF Network ; September 2015" assert content["transaction"] envelope_xdr = content["transaction"] envelope_object = TransactionEnvelope.from_xdr( envelope_xdr, network_passphrase=settings.STELLAR_NETWORK_PASSPHRASE) transaction_object = envelope_object.transaction assert transaction_object.sequence == 0 assert len(transaction_object.operations) == 1 manage_data_op = transaction_object.operations[0] assert manage_data_op.type_code() == Xdr.const.MANAGE_DATA assert manage_data_op.data_name == f"{urlparse(settings.HOST_URL).netloc} auth" assert len(manage_data_op.data_value) <= 64 assert len(base64.b64decode(manage_data_op.data_value)) == 48 signatures = envelope_object.signatures assert len(signatures) == 1 server_signature = signatures[0] tx_hash = envelope_object.hash() server_public_key = Keypair.from_public_key(settings.SIGNING_KEY) server_public_key.verify(tx_hash, server_signature.signature)
def test_verify_challenge_tx_source_is_different_to_server_account_id( self): server_kp = Keypair.random() client_kp = Keypair.random() network_passphrase = Network.TESTNET_NETWORK_PASSPHRASE anchor_name = "SDF" challenge = build_challenge_transaction(server_kp.secret, client_kp.public_key, anchor_name, network_passphrase) transaction = TransactionEnvelope.from_xdr(challenge, Network(network_passphrase)) transaction.sign(client_kp) challenge_tx = transaction.to_xdr() with pytest.raises( InvalidSep10ChallengeError, match= "Transaction source account is not equal to server's account.", ): verify_challenge_transaction(challenge_tx, Keypair.random().public_key, network_passphrase)
def test_verify_challenge_transaction_signed_by_client_raise_not_signed( self): server_kp = Keypair.random() client_kp = Keypair.random() timeout = 600 network_passphrase = Network.PUBLIC_NETWORK_PASSPHRASE home_domain = "example.com" challenge = build_challenge_transaction( server_secret=server_kp.secret, client_account_id=client_kp.public_key, home_domain=home_domain, network_passphrase=network_passphrase, timeout=timeout, ) transaction = TransactionEnvelope.from_xdr(challenge, network_passphrase) challenge_tx = transaction.to_xdr() with pytest.raises( InvalidSep10ChallengeError, match="Transaction not signed by any client signer.", ): verify_challenge_transaction_signed_by_client_master_key( challenge_tx, server_kp.public_key, home_domain, network_passphrase)
def test_challenge_transaction(self): server_kp = Keypair.random() client_account_id = "GBDIT5GUJ7R5BXO3GJHFXJ6AZ5UQK6MNOIDMPQUSMXLIHTUNR2Q5CFNF" timeout = 600 network_passphrase = Network.TESTNET_NETWORK_PASSPHRASE anchor_name = "SDF" challenge = build_challenge_transaction( server_secret=server_kp.secret, client_account_id=client_account_id, anchor_name=anchor_name, network_passphrase=network_passphrase, timeout=timeout, ) transaction = TransactionEnvelope.from_xdr( challenge, network_passphrase ).transaction assert len(transaction.operations) == 1 op = transaction.operations[0] assert isinstance(op, ManageData) assert op.data_name == "SDF auth" assert len(op.data_value) == 64 assert len(base64.b64decode(op.data_value)) == 48 assert op.source == client_account_id now = int(time.time()) assert now - 3 < transaction.time_bounds.min_time < now + 3 assert ( transaction.time_bounds.max_time - transaction.time_bounds.min_time == timeout ) assert transaction.source.public_key == server_kp.public_key assert transaction.sequence == 0
def test_auth_get_success(client): """`GET <auth>` succeeds with a valid TransactionEnvelope XDR.""" response = client.get(f"{endpoint}?account={STELLAR_ACCOUNT_1}", follow=True) content = json.loads(response.content) assert content["network_passphrase"] == "Test SDF Network ; September 2015" assert content["transaction"] envelope_xdr = content["transaction"] envelope_object = TransactionEnvelope.from_xdr( envelope_xdr, network_passphrase=settings.STELLAR_NETWORK_PASSPHRASE) transaction_object = envelope_object.transaction assert transaction_object.sequence == 0 assert len(transaction_object.operations) == 2 home_domain_op = transaction_object.operations[0] assert isinstance(home_domain_op, ManageData) assert home_domain_op.data_name == f"{urlparse(settings.HOST_URL).netloc} auth" assert len(home_domain_op.data_value) <= 64 assert len(base64.b64decode(home_domain_op.data_value)) == 48 web_auth_domain_op = transaction_object.operations[1] assert isinstance(web_auth_domain_op, ManageData) assert web_auth_domain_op.data_name == "web_auth_domain" assert (web_auth_domain_op.data_value == f"{urlparse(settings.HOST_URL).netloc}".encode()) signatures = envelope_object.signatures assert len(signatures) == 1 tx_hash = envelope_object.hash() server_public_key = Keypair.from_public_key(settings.SIGNING_KEY) server_public_key.verify(tx_hash, signatures[0].signature)
def sign_challenge(content): envelope_xdr = content["transaction"] envelope_object = TransactionEnvelope.from_xdr( envelope_xdr, network_passphrase=settings.STELLAR_NETWORK_PASSPHRASE) client_signing_key = Keypair.from_secret(CLIENT_SEED) envelope_object.sign(client_signing_key) return envelope_object.to_xdr()
def test_verify_challenge_transaction_domain_name_mismatch_raise(self): server_kp = Keypair.random() client_kp = Keypair.random() timeout = 600 network_passphrase = Network.PUBLIC_NETWORK_PASSPHRASE domain_name = "example.com" invalid_domain_name = "invalid_example.com" challenge = build_challenge_transaction( server_secret=server_kp.secret, client_account_id=client_kp.public_key, domain_name=domain_name, network_passphrase=network_passphrase, timeout=timeout, ) transaction = TransactionEnvelope.from_xdr(challenge, network_passphrase) transaction.sign(client_kp) challenge_tx = transaction.to_xdr() with pytest.raises( InvalidSep10ChallengeError, match="The transaction's operation key name " "does not include the expected home domain.", ): verify_challenge_transaction( challenge_tx, server_kp.public_key, invalid_domain_name, network_passphrase, )
def test_verify_transaction_signatures(self): server_kp = Keypair.random() client_kp_a = Keypair.random() client_kp_b = Keypair.random() client_kp_c = Keypair.random() timeout = 600 network_passphrase = Network.PUBLIC_NETWORK_PASSPHRASE anchor_name = "SDF" challenge = build_challenge_transaction( server_secret=server_kp.secret, client_account_id=client_kp_a.public_key, anchor_name=anchor_name, network_passphrase=network_passphrase, timeout=timeout, ) transaction = TransactionEnvelope.from_xdr(challenge, network_passphrase) transaction.sign(client_kp_a) transaction.sign(client_kp_b) transaction.sign(client_kp_c) signers = [ Ed25519PublicKeySigner(client_kp_a.public_key, 1), Ed25519PublicKeySigner(client_kp_b.public_key, 2), Ed25519PublicKeySigner(client_kp_c.public_key, 3), Ed25519PublicKeySigner(Keypair.random().public_key, 4), ] signers_found = _verify_transaction_signatures(transaction, signers) assert signers_found == [ Ed25519PublicKeySigner(client_kp_a.public_key, 1), Ed25519PublicKeySigner(client_kp_b.public_key, 2), Ed25519PublicKeySigner(client_kp_c.public_key, 3), ]
def test_verify_challenge_transaction_signed_by_client_raise_not_signed(self): server_kp = Keypair.random() client_kp = Keypair.random() timeout = 600 network_passphrase = Network.PUBLIC_NETWORK_PASSPHRASE anchor_name = "SDF" challenge = build_challenge_transaction( server_secret=server_kp.secret, client_account_id=client_kp.public_key, anchor_name=anchor_name, network_passphrase=network_passphrase, timeout=timeout, ) transaction = TransactionEnvelope.from_xdr(challenge, network_passphrase) challenge_tx = transaction.to_xdr() with pytest.raises( InvalidSep10ChallengeError, match="Transaction not signed by client: {}.".format(client_kp.public_key), ): verify_challenge_transaction_signed_by_client_master_key( challenge_tx, server_kp.public_key, network_passphrase )
def test_verify_challenge_transaction_signers_raise_no_signers(self): server_kp = Keypair.random() client_kp_a = Keypair.random() client_kp_b = Keypair.random() client_kp_c = Keypair.random() timeout = 600 network_passphrase = Network.PUBLIC_NETWORK_PASSPHRASE anchor_name = "SDF" challenge = build_challenge_transaction( server_secret=server_kp.secret, client_account_id=client_kp_a.public_key, anchor_name=anchor_name, network_passphrase=network_passphrase, timeout=timeout, ) transaction = TransactionEnvelope.from_xdr(challenge, network_passphrase) transaction.sign(client_kp_a) transaction.sign(client_kp_b) transaction.sign(client_kp_c) challenge_tx = transaction.to_xdr() signers = [] with pytest.raises(InvalidSep10ChallengeError, match="No signers provided."): verify_challenge_transaction_signers( challenge_tx, server_kp.public_key, network_passphrase, signers )
def test_withdraw_authenticated_success( client, acc1_usd_withdrawal_transaction_factory): """`GET /withdraw` succeeds with the SEP 10 authentication flow.""" client_address = "GDKFNRUATPH4BSZGVFDRBIGZ5QAFILVFRIRYNSQ4UO7V2ZQAPRNL73RI" client_seed = "SDKWSBERDHP3SXW5A3LXSI7FWMMO5H7HG33KNYBKWH2HYOXJG2DXQHQY" acc1_usd_withdrawal_transaction_factory() # SEP 10. response = client.get(f"/auth?account={client_address}", follow=True) content = json.loads(response.content) envelope_xdr = content["transaction"] envelope_object = TransactionEnvelope.from_xdr( envelope_xdr, network_passphrase=settings.STELLAR_NETWORK_PASSPHRASE) client_signing_key = Keypair.from_secret(client_seed) envelope_object.sign(client_signing_key) client_signed_envelope_xdr = envelope_object.to_xdr() response = client.post( "/auth", data={"transaction": client_signed_envelope_xdr}, content_type="application/json", ) content = json.loads(response.content) encoded_jwt = content["token"] assert encoded_jwt header = {"HTTP_AUTHORIZATION": f"Bearer {encoded_jwt}"} response = client.post(WITHDRAW_PATH, {"asset_code": "USD"}, follow=True, **header) content = json.loads(response.content) assert content["type"] == "interactive_customer_info_needed"
def test_auth_get_account(client): """`GET <auth>` succeeds with a valid TransactionEnvelope XDR.""" response = client.get(f"/auth?account={STELLAR_ACCOUNT_1}", follow=True) content = json.loads(response.content) assert content["network_passphrase"] == "Test SDF Network ; September 2015" assert content["transaction"] envelope_xdr = content["transaction"] envelope_object = TransactionEnvelope.from_xdr( envelope_xdr, network_passphrase=settings.STELLAR_NETWORK_PASSPHRASE) transaction_object = envelope_object.transaction assert transaction_object.sequence == 0 assert len(transaction_object.operations) == 1 manage_data_op = transaction_object.operations[0] assert manage_data_op.type_code() == Xdr.const.MANAGE_DATA assert manage_data_op.data_name == "SEP 24 Reference auth" assert len(manage_data_op.data_value) == 64 signatures = envelope_object.signatures assert len(signatures) == 1 server_signature = signatures[0] tx_hash = envelope_object.hash() server_public_key = Keypair.from_public_key( settings.STELLAR_DISTRIBUTION_ACCOUNT_ADDRESS) server_public_key.verify(tx_hash, server_signature.signature)
def test_verify_challenge_tx_transaction_is_not_signed_by_the_server(self): server_kp = Keypair.random() client_kp = Keypair.random() network_passphrase = Network.PUBLIC_NETWORK_PASSPHRASE anchor_name = "SDF" timeout = 900 now = int(time.time()) server_keypair = Keypair.from_secret(server_kp.secret) server_account = Account(account_id=server_keypair.public_key, sequence=-1) transaction_builder = TransactionBuilder( server_account, network_passphrase, 100 ) transaction_builder.add_time_bounds(min_time=now, max_time=now + timeout) nonce = os.urandom(48) nonce_encoded = base64.b64encode(nonce) transaction_builder.append_manage_data_op( data_name="{} auth".format(anchor_name), data_value=nonce_encoded, source=client_kp.public_key, ) challenge = transaction_builder.build().to_xdr() transaction = TransactionEnvelope.from_xdr(challenge, network_passphrase) transaction.sign(client_kp) challenge_tx = transaction.to_xdr() with pytest.raises( InvalidSep10ChallengeError, match="Transaction not signed by server: {}".format(server_kp.public_key), ): verify_challenge_transaction( challenge_tx, server_kp.public_key, network_passphrase )
def test_auth_post_success_client_attribution_required_allowlist_provided( client): response = client.get( f"{endpoint}?account={CLIENT_ADDRESS}&client_domain={CLIENT_ATTRIBUTION_DOMAIN}", follow=True, ) content = json.loads(response.content) # Sign the XDR with the client. envelope_xdr = content["transaction"] envelope = TransactionEnvelope.from_xdr( envelope_xdr, network_passphrase=settings.STELLAR_NETWORK_PASSPHRASE) envelope.sign(CLIENT_SEED) envelope.sign(CLIENT_ATTRIBUTION_SEED) response = client.post( endpoint, data={"transaction": envelope.to_xdr()}, content_type="application/json", ) content = json.loads(response.content) assert content["token"] jwt_contents = jwt.decode(content["token"], settings.SERVER_JWT_KEY, algorithms=["HS256"]) assert jwt_contents["client_domain"] == CLIENT_ATTRIBUTION_DOMAIN mock_request.META["HTTP_AUTHORIZATION"] = auth_str.format(content["token"]) mock_view_function = Mock() check_auth(mock_request, mock_view_function) mock_view_function.assert_called_once_with(CLIENT_ADDRESS, CLIENT_ATTRIBUTION_DOMAIN, mock_request)
async def test_submit_transaction_with_te(self): xdr = "AAAAAHI7fpgo+b7tgpiFyYWimjV7L7IOYLwmQS7k7F8SronXAAAAZAE+QT4AAAAJAAAAAQAAAAAAAAAAAAAAAF1MG8cAAAAAAAAAAQAAAAAAAAAAAAAAAOvi1O/HEn+QgZJw+EMZBtwvTVNmpgvE9p8IRfwp0GY4AAAAAAExLQAAAAAAAAAAARKuidcAAABAJVc1ASGp35hUquGNbzzSqWPoTG0zgc89zc4p+19QkgbPqsdyEfHs7+ng9VJA49YneEXRa6Fv7pfKpEigb3VTCg==" te = TransactionEnvelope.from_xdr(xdr, Network.PUBLIC_NETWORK_PASSPHRASE) horizon_url = "https://horizon.stellar.org" client = AiohttpClient() async with Server(horizon_url, client) as server: resp = await server.submit_transaction(te, True) assert resp["envelope_xdr"] == xdr
def test_transaction_authenticated_success( mock_render, client, acc1_usd_deposit_transaction_factory, acc2_eth_withdrawal_transaction_factory, ): """ Succeeds with expected response if authentication required. Though it filters using the stellar transaction ID, the logic should apply in any case. """ del mock_render client_address = "GDKFNRUATPH4BSZGVFDRBIGZ5QAFILVFRIRYNSQ4UO7V2ZQAPRNL73RI" client_seed = "SDKWSBERDHP3SXW5A3LXSI7FWMMO5H7HG33KNYBKWH2HYOXJG2DXQHQY" acc1_usd_deposit_transaction_factory() withdrawal = acc2_eth_withdrawal_transaction_factory() withdrawal.stellar_address = client_address withdrawal.save() # SEP 10. response = client.get(f"/auth?account={client_address}", follow=True) content = json.loads(response.content) envelope_xdr = content["transaction"] envelope_object = TransactionEnvelope.from_xdr( envelope_xdr, network_passphrase=settings.STELLAR_NETWORK_PASSPHRASE) client_signing_key = Keypair.from_secret(client_seed) envelope_object.sign(client_signing_key) client_signed_envelope_xdr = envelope_object.to_xdr() response = client.post( "/auth", data={"transaction": client_signed_envelope_xdr}, content_type="application/json", ) content = json.loads(response.content) encoded_jwt = content["token"] assert encoded_jwt # For testing, we make the key `HTTP_AUTHORIZATION`. This is the value that # we expect due to the middleware. header = {"HTTP_AUTHORIZATION": f"Bearer {encoded_jwt}"} response = client.get( f"/transaction?stellar_transaction_id={withdrawal.stellar_transaction_id}", follow=True, **header, ) content = json.loads(response.content) assert response.status_code == 200 withdrawal_transaction = content.get("transaction") assert withdrawal_transaction["kind"] == "withdrawal" assert withdrawal_transaction["status"] == Transaction.STATUS.completed
def match_transaction(cls, response: Dict, transaction: Transaction) -> bool: """ Determines whether or not the given ``response`` represents the given ``transaction``. Polaris does this by constructing the transaction memo from the transaction ID passed in the initial withdrawal request to ``/transactions/withdraw/interactive``. To be sure, we also check for ``transaction``'s payment operation in ``response``. :param response: a response body returned from Horizon for the transaction :param transaction: a database model object representing the transaction """ try: memo_type = response["memo_type"] response_memo = response["memo"] successful = response["successful"] stellar_transaction_id = response["id"] envelope_xdr = response["envelope_xdr"] except KeyError: logger.warning( f"Stellar response for transaction missing expected arguments" ) return False if memo_type != "hash": logger.warning( f"Transaction memo for {transaction.id} was not of type hash" ) return False # The memo on the response will be base 64 string, due to XDR, while # the memo parameter is base 16. Thus, we convert the parameter # from hex to base 64, and then to a string without trailing whitespace. if response_memo != format_memo_horizon(transaction.withdraw_memo): return False horizon_tx = TransactionEnvelope.from_xdr( response["envelope_xdr"], network_passphrase=settings.STELLAR_NETWORK_PASSPHRASE, ).transaction found_matching_payment_op = False for operation in horizon_tx.operations: if cls._check_payment_op( operation, transaction.asset.code, transaction.amount_in ): transaction.stellar_transaction_id = stellar_transaction_id transaction.from_address = horizon_tx.source.public_key transaction.save() found_matching_payment_op = True break return found_matching_payment_op
def process_withdrawal(response, transaction): """ Check if a Stellar transaction's memo matches the ID of a database transaction. """ # Validate the Horizon response. try: memo_type = response["memo_type"] response_memo = response["memo"] successful = response["successful"] stellar_transaction_id = response["id"] envelope_xdr = response["envelope_xdr"] except KeyError: return False if memo_type != "hash": return False # The memo on the response will be base 64 string, due to XDR, while # the memo parameter is base 16. Thus, we convert the parameter # from hex to base 64, and then to a string without trailing whitespace. if response_memo != format_memo_horizon(transaction.withdraw_memo): return False horizon_tx = TransactionEnvelope.from_xdr( envelope_xdr, network_passphrase=settings.STELLAR_NETWORK_PASSPHRASE).transaction found_matching_payment_op = False for operation in horizon_tx.operations: if _check_payment_op(operation, transaction.asset.code, transaction.amount_in): found_matching_payment_op = True break # If no matching payment operation is found in the Stellar response, return. if not found_matching_payment_op: return False # If the Stellar transaction succeeded, we mark the corresponding `Transaction` # accordingly in the database. Else, we mark it `pending_stellar`, so the wallet # knows to resubmit. if successful: transaction.completed_at = now() transaction.status = Transaction.STATUS.completed transaction.status_eta = 0 transaction.amount_out = transaction.amount_in - transaction.amount_fee else: transaction.status = Transaction.STATUS.pending_stellar transaction.stellar_transaction_id = stellar_transaction_id transaction.save() return True
def test_transactions_authenticated_success( mock_render, client, acc2_eth_withdrawal_transaction_factory, acc2_eth_deposit_transaction_factory, ): """ Response has correct length and status code, if the SEP 10 authentication token is required. """ del mock_render client_address = "GDKFNRUATPH4BSZGVFDRBIGZ5QAFILVFRIRYNSQ4UO7V2ZQAPRNL73RI" client_seed = "SDKWSBERDHP3SXW5A3LXSI7FWMMO5H7HG33KNYBKWH2HYOXJG2DXQHQY" withdrawal = acc2_eth_withdrawal_transaction_factory() withdrawal.stellar_address = client_address withdrawal.save() acc2_eth_deposit_transaction_factory() # SEP 10. response = client.get(f"/auth?account={client_address}", follow=True) content = json.loads(response.content) envelope_xdr = content["transaction"] envelope_object = TransactionEnvelope.from_xdr( envelope_xdr, network_passphrase=settings.STELLAR_NETWORK_PASSPHRASE) client_signing_key = Keypair.from_secret(client_seed) envelope_object.sign(client_signing_key) client_signed_envelope_xdr = envelope_object.to_xdr() response = client.post( "/auth", data={"transaction": client_signed_envelope_xdr}, content_type="application/json", ) content = json.loads(response.content) encoded_jwt = content["token"] assert encoded_jwt # For testing, we make the key `HTTP_AUTHORIZATION`. This is the value that # we expect due to the middleware. header = {"HTTP_AUTHORIZATION": f"Bearer {encoded_jwt}"} response = client.get( f"/transactions?asset_code={withdrawal.asset.code}&account={withdrawal.stellar_account}", follow=True, **header, ) content = json.loads(response.content) assert len(content.get("transactions")) == 2 assert response.status_code == 200
def test_auth_get_no_client_attribution_required_domain_passed_denylist_provided_match( client, ): response = client.get( f"{endpoint}?account={CLIENT_ADDRESS}&client_domain={CLIENT_ATTRIBUTION_DOMAIN}", follow=True, ) content = json.loads(response.content) # Sign the XDR with the client. envelope_xdr = content["transaction"] envelope = TransactionEnvelope.from_xdr( envelope_xdr, network_passphrase=settings.STELLAR_NETWORK_PASSPHRASE) # attribution manage data op not included assert len(envelope.transaction.operations) == 2
def test_verify_challenge_transaction_signers_raise_no_server_signature( self): server_kp = Keypair.random() client_kp_a = Keypair.random() client_kp_b = Keypair.random() client_kp_c = Keypair.random() timeout = 600 network_passphrase = Network.PUBLIC_NETWORK_PASSPHRASE domain_name = "example.com" challenge = build_challenge_transaction( server_secret=server_kp.secret, client_account_id=client_kp_a.public_key, domain_name=domain_name, network_passphrase=network_passphrase, timeout=timeout, ) transaction = TransactionEnvelope.from_xdr(challenge, network_passphrase) transaction.signatures = [] transaction.sign(client_kp_a) transaction.sign(client_kp_b) transaction.sign(client_kp_c) challenge_tx = transaction.to_xdr() signers = [ Ed25519PublicKeySigner(client_kp_a.public_key, 1), Ed25519PublicKeySigner(client_kp_b.public_key, 2), Ed25519PublicKeySigner(client_kp_c.public_key, 4), Ed25519PublicKeySigner(Keypair.random().public_key, 255), ] with pytest.raises( InvalidSep10ChallengeError, match="Transaction not signed by server: {}.".format( server_kp.public_key), ): verify_challenge_transaction_signers( challenge_tx, server_kp.public_key, domain_name, network_passphrase, signers, )
def test_verify_challenge_transaction_threshold(self): server_kp = Keypair.random() client_kp_a = Keypair.random() client_kp_b = Keypair.random() client_kp_c = Keypair.random() timeout = 600 network_passphrase = Network.PUBLIC_NETWORK_PASSPHRASE domain_name = "example.com" challenge = build_challenge_transaction( server_secret=server_kp.secret, client_account_id=client_kp_a.public_key, domain_name=domain_name, network_passphrase=network_passphrase, timeout=timeout, ) transaction = TransactionEnvelope.from_xdr(challenge, network_passphrase) transaction.sign(client_kp_a) transaction.sign(client_kp_b) transaction.sign(client_kp_c) challenge_tx = transaction.to_xdr() signers = [ Ed25519PublicKeySigner(client_kp_a.public_key, 1), Ed25519PublicKeySigner(client_kp_b.public_key, 2), Ed25519PublicKeySigner(client_kp_c.public_key, 4), Ed25519PublicKeySigner(Keypair.random().public_key, 255), ] med_threshold = 7 signers_found = verify_challenge_transaction_threshold( challenge_tx, server_kp.public_key, domain_name, network_passphrase, med_threshold, signers, ) assert signers_found == [ Ed25519PublicKeySigner(client_kp_a.public_key, 1), Ed25519PublicKeySigner(client_kp_b.public_key, 2), Ed25519PublicKeySigner(client_kp_c.public_key, 4), ]
def test_verify_challenge_transaction_threshold_raise_not_meet_threshold( self): server_kp = Keypair.random() client_kp_a = Keypair.random() client_kp_b = Keypair.random() client_kp_c = Keypair.random() timeout = 600 network_passphrase = Network.PUBLIC_NETWORK_PASSPHRASE domain_name = "example.com" challenge = build_challenge_transaction( server_secret=server_kp.secret, client_account_id=client_kp_a.public_key, domain_name=domain_name, network_passphrase=network_passphrase, timeout=timeout, ) transaction = TransactionEnvelope.from_xdr(challenge, network_passphrase) transaction.sign(client_kp_a) transaction.sign(client_kp_b) transaction.sign(client_kp_c) challenge_tx = transaction.to_xdr() signers = [ Ed25519PublicKeySigner(client_kp_a.public_key, 1), Ed25519PublicKeySigner(client_kp_b.public_key, 2), Ed25519PublicKeySigner(client_kp_c.public_key, 4), Ed25519PublicKeySigner(Keypair.random().public_key, 255), ] med_threshold = 10 with pytest.raises( InvalidSep10ChallengeError, match="signers with weight 7 do not meet threshold 10.", ): verify_challenge_transaction_threshold( challenge_tx, server_kp.public_key, domain_name, network_passphrase, med_threshold, signers, )
def test_to_xdr_v1(self): # GDF5O4OWEMVBY5FLDHWA5RZTYSV2U276XGKZZ6VSHDDR3THSQ6OQS7UM source = Keypair.from_secret( "SCCS5ZBI7WVIJ4SW36WGOQQIWJYCL3VOAULSXX3FB57USIO25EDOYQHH") destination = "GDJJRRMBK4IWLEPJGIE6SXD2LP7REGZODU7WDC3I2D6MR37F4XSHBKX2" amount = "1000.0" sequence = 1 memo = IdMemo(100) fee = 200 asset = Asset.native() time_bounds = TimeBounds(12345, 56789) ops = [Payment(destination, asset, amount)] tx = Transaction(source, sequence, fee, ops, memo, time_bounds, True) te = TransactionEnvelope(tx, Network.PUBLIC_NETWORK_PASSPHRASE) assert binascii.hexlify(te.hash()).decode() == te.hash_hex() te.sign(source) te_xdr = "AAAAAgAAAADL13HWIyocdKsZ7A7HM8Srqmv+uZWc+rI4xx3M8oedCQAAAMgAAAAAAAAAAQAAAAEAAAAAAAAwOQAAAAAAAN3VAAAAAgAAAAAAAABkAAAAAQAAAAAAAAABAAAAANKYxYFXEWWR6TIJ6Vx6W/8SGy4dP2GLaND8yO/l5eRwAAAAAAAAAAJUC+QAAAAAAAAAAAHyh50JAAAAQCXOQnmno3he687bKRtDc6+BXRUf8t+RnTuHy+sKf35UjfFiQbIge+txehmg0N61JsFWfwbL0JtgOjzyeZw5JAs=" assert te.to_xdr() == te_xdr restore_te = TransactionEnvelope.from_xdr( te_xdr, Network.PUBLIC_NETWORK_PASSPHRASE) assert restore_te.to_xdr() == te_xdr
def sep10(client, address, seed): response = client.get(f"/auth?account={address}", follow=True) content = json.loads(response.content) envelope_xdr = content["transaction"] envelope_object = TransactionEnvelope.from_xdr( envelope_xdr, network_passphrase=settings.STELLAR_NETWORK_PASSPHRASE) client_signing_key = Keypair.from_secret(seed) envelope_object.sign(client_signing_key) client_signed_envelope_xdr = envelope_object.to_xdr() response = client.post( "/auth", data={"transaction": client_signed_envelope_xdr}, headers={"Content-Type": "application/json"}, ) content = json.loads(response.content) encoded_jwt = content["token"] assert encoded_jwt return encoded_jwt
def _generate_jwt(request, envelope_xdr): """ Generates the JSON web token from the challenge transaction XDR. See: https://github.com/stellar/stellar-protocol/blob/master/ecosystem/sep-0010.md#token """ issued_at = time.time() hash_hex = binascii.hexlify( TransactionEnvelope.from_xdr(envelope_xdr, network_passphrase=settings.STELLAR_NETWORK_PASSPHRASE).hash() ).decode() jwt_dict = { "iss": request.build_absolute_uri("/auth"), "sub": settings.STELLAR_DISTRIBUTION_ACCOUNT_ADDRESS, "iat": issued_at, "exp": issued_at + 24 * 60 * 60, "jti": hash_hex, } encoded_jwt = jwt.encode(jwt_dict, settings.SERVER_JWT_KEY, algorithm="HS256") return encoded_jwt.decode("ascii")
def test_verify_challenge_transaction_signers_raise_unrecognized_signatures( self): server_kp = Keypair.random() client_kp_a = Keypair.random() client_kp_b = Keypair.random() client_kp_c = Keypair.random() client_kp_unrecognized = Keypair.random() timeout = 600 network_passphrase = Network.PUBLIC_NETWORK_PASSPHRASE home_domain = "example.com" challenge = build_challenge_transaction( server_secret=server_kp.secret, client_account_id=client_kp_a.public_key, home_domain=home_domain, network_passphrase=network_passphrase, timeout=timeout, ) transaction = TransactionEnvelope.from_xdr(challenge, network_passphrase) transaction.sign(client_kp_a) transaction.sign(client_kp_b) transaction.sign(client_kp_c) transaction.sign(client_kp_unrecognized) challenge_tx = transaction.to_xdr() signers = [ Ed25519PublicKeySigner(client_kp_a.public_key, 1), Ed25519PublicKeySigner(client_kp_b.public_key, 2), Ed25519PublicKeySigner(client_kp_c.public_key, 4), Ed25519PublicKeySigner(Keypair.random().public_key, 255), ] with pytest.raises(InvalidSep10ChallengeError, match="Transaction has unrecognized signatures."): verify_challenge_transaction_signers( challenge_tx, server_kp.public_key, home_domain, network_passphrase, signers, )