diff --git a/test_client/README.md b/test_client/README.md index c23b38f..3aaa5eb 100644 --- a/test_client/README.md +++ b/test_client/README.md @@ -6,10 +6,12 @@ A couple example flows so it's clear how it works. We're assuming that we're sta Set up a client for each wallet, but with the same sync account (which won't exist on the server yet). This will simulate clients on two different computers. +For this example we will be working with a locally running server so that we don't care about the data. If you want to communicate with `dev.lbry.id`, simply omit the `local=True`. + ``` >>> from test_client import Client ->>> c1 = Client("joe2@example.com", "123abc2", 'test_wallet_1') ->>> c2 = Client("joe2@example.com", "123abc2", 'test_wallet_2') +>>> c1 = Client("joe2@example.com", "123abc2", 'test_wallet_1', local=True) +>>> c2 = Client("joe2@example.com", "123abc2", 'test_wallet_2', local=True) ``` Register the account on the server with one of the clients. @@ -23,9 +25,9 @@ Now that the account exists, grab an auth token with both clients. ``` >>> c1.get_auth_token() -Got auth token: 3d98076fda58400f3dbd5ea6511184507d5f8637bd5549e5cb0cc9cdbb7102e5 +Got auth token: 2e1c00c0f2f205defc177bd21e64dd01c669e234cf23bbc19f73e720ac1ef12d >>> c2.get_auth_token() -Got auth token: 1385a51bf3ba86a3e1f412908c3b2165cc399e06692a2dc602f5e17fe2c7993c +Got auth token: 07ab32cfac3961d30570537d4082abdf08123de6e5a28670dbf680be45e442d5 ``` ## Syncing @@ -41,7 +43,7 @@ No wallet found on the server for this account. Starting a new one. >>> c1.update_remote_wallet() Successfully updated wallet state on server Got new walletState: -WalletState(sequence=1, encrypted_wallet='czo4MTkyOjE2OjE6ew8QGI/89sz70Oud6NljymaLSUCyNSBYwpTCBZu9gMbwXYuDKqB4YnZeYRJdHhXz+9NQ9qSkRUIPHQ4m6f38R38KvXCE5raRnnozrnmDOt/eGFUl9XYMrFcYqgqYSCxb1kTcWS1cWkkOO6TtrjeBKuc+qriKZr9ggk1pnLmnKQc=') +WalletState(sequence=1, encrypted_wallet='czo4MTkyOjE2OjE6CjZHlCv4ZyHiPKA7PoIOOkQ6Fh9fYUYPe9xwiZRYdLKHDgtEQCIcwkNldP1TN8TwTht4Qj5QEnApwQkd2Y20nVjdCUTKLzu4gmdP8QBz2EEGR+XmZgosX937E8bmmqgC55ttgt8fh0o62cTonF4h1LLI7DoWw1SvEcqIIAEn/dc=') 'Success' ``` @@ -52,7 +54,7 @@ Now, call `init_wallet_state` with the other client. This time, `init_wallet_sta ``` >>> c2.init_wallet_state() Got latest walletState: -WalletState(sequence=1, encrypted_wallet='czo4MTkyOjE2OjE6ew8QGI/89sz70Oud6NljymaLSUCyNSBYwpTCBZu9gMbwXYuDKqB4YnZeYRJdHhXz+9NQ9qSkRUIPHQ4m6f38R38KvXCE5raRnnozrnmDOt/eGFUl9XYMrFcYqgqYSCxb1kTcWS1cWkkOO6TtrjeBKuc+qriKZr9ggk1pnLmnKQc=') +WalletState(sequence=1, encrypted_wallet='czo4MTkyOjE2OjE6CjZHlCv4ZyHiPKA7PoIOOkQ6Fh9fYUYPe9xwiZRYdLKHDgtEQCIcwkNldP1TN8TwTht4Qj5QEnApwQkd2Y20nVjdCUTKLzu4gmdP8QBz2EEGR+XmZgosX937E8bmmqgC55ttgt8fh0o62cTonF4h1LLI7DoWw1SvEcqIIAEn/dc=') ``` ## Updating @@ -63,11 +65,11 @@ Push a new version, GET it with the other client. Even though we haven't edited >>> c2.update_remote_wallet() Successfully updated wallet state on server Got new walletState: -WalletState(sequence=2, encrypted_wallet='czo4MTkyOjE2OjE6DAT6j6JSp0by78XpOOMtGroxFUX5vh6X+oXhIVlHVhvmVgp+09vWt7IP/IGofP4Ua7Dggr9iyxF4A3F9tSNgxKrev08eMP+8W2LAwk3jTAtZPoh5vtz/20tJFWOw+Y+s00NRNXcDeT8GjZvgTfawy+k7WKQMt6ryW6c8liORDfA=') +WalletState(sequence=2, encrypted_wallet='czo4MTkyOjE2OjE6LsWo7O3EQVw+buxGPuqJBBEn3oBM3/sAII2NjpbKi7tEvWxbWmKb+nNyr3fuvQ6YZZda0i0Rb7Veuq7ym+hYAn2pTt/8WrYR8K1HFnxs3y1m91HQIsXrl6NwxU5t+mZ6uInQUfEGEV6JLHfbt1NJ2pYlYvYTelusKZXq/kja8i4=') 'Success' >>> c1.get_remote_wallet() Got latest walletState: -WalletState(sequence=2, encrypted_wallet='czo4MTkyOjE2OjE6DAT6j6JSp0by78XpOOMtGroxFUX5vh6X+oXhIVlHVhvmVgp+09vWt7IP/IGofP4Ua7Dggr9iyxF4A3F9tSNgxKrev08eMP+8W2LAwk3jTAtZPoh5vtz/20tJFWOw+Y+s00NRNXcDeT8GjZvgTfawy+k7WKQMt6ryW6c8liORDfA=') +WalletState(sequence=2, encrypted_wallet='czo4MTkyOjE2OjE6LsWo7O3EQVw+buxGPuqJBBEn3oBM3/sAII2NjpbKi7tEvWxbWmKb+nNyr3fuvQ6YZZda0i0Rb7Veuq7ym+hYAn2pTt/8WrYR8K1HFnxs3y1m91HQIsXrl6NwxU5t+mZ6uInQUfEGEV6JLHfbt1NJ2pYlYvYTelusKZXq/kja8i4=') 'Success' ``` @@ -93,11 +95,11 @@ The wallet is synced between the clients. The client with the changed preference >>> c1.update_remote_wallet() Successfully updated wallet state on server Got new walletState: -WalletState(sequence=3, encrypted_wallet='czo4MTkyOjE2OjE6SQ/9PBDeOs8sOG+QDnOBmgbOKJDUx3TJD1p9r/bIuD2R5lamKmn1UKz/fQynLJexPJj3QCJP5u5OKTZDMBhY6HF5qBV2ndnWmPLjB40KlGj7jjZJaETEMktyJjjKdLbsV8nKLpnB2KpyYZejJVppBS+DRswAFByTE6c5E+8FJ3TTPXhzTvE9L3RqvetQEUxn') +WalletState(sequence=3, encrypted_wallet='czo4MTkyOjE2OjE6l5SVvs2yNDoC5j1316n0xQ5H6K1UEso/JpdpShfLW2bCY3lg9vOcwayO1v085RyItxEwtrtSnD3fnan3kr86GmSI8U6x5DxASHVdgceLBrclVkuCpFXllz6YNtWo5thjbf63PWSg4k6LHI8w50BT2tu9FUufCi67n7sTWnGb/0AjAFYU1sUTJ9aoeiZYrrur') 'Success' >>> c2.get_remote_wallet() Got latest walletState: -WalletState(sequence=3, encrypted_wallet='czo4MTkyOjE2OjE6SQ/9PBDeOs8sOG+QDnOBmgbOKJDUx3TJD1p9r/bIuD2R5lamKmn1UKz/fQynLJexPJj3QCJP5u5OKTZDMBhY6HF5qBV2ndnWmPLjB40KlGj7jjZJaETEMktyJjjKdLbsV8nKLpnB2KpyYZejJVppBS+DRswAFByTE6c5E+8FJ3TTPXhzTvE9L3RqvetQEUxn') +WalletState(sequence=3, encrypted_wallet='czo4MTkyOjE2OjE6l5SVvs2yNDoC5j1316n0xQ5H6K1UEso/JpdpShfLW2bCY3lg9vOcwayO1v085RyItxEwtrtSnD3fnan3kr86GmSI8U6x5DxASHVdgceLBrclVkuCpFXllz6YNtWo5thjbf63PWSg4k6LHI8w50BT2tu9FUufCi67n7sTWnGb/0AjAFYU1sUTJ9aoeiZYrrur') 'Success' >>> c2.get_preferences() {'animal': 'cow', 'car': ''} @@ -124,7 +126,7 @@ One client POSTs its change first. >>> c1.update_remote_wallet() Successfully updated wallet state on server Got new walletState: -WalletState(sequence=4, encrypted_wallet='czo4MTkyOjE2OjE62uWympFofMnLmZSGGPTC5qctGKlWkan/DmOFLVZHktzqY9OndxhY3VCr5QBMXOGyn/Y321zNtL6YNfA+gs3Ov6qhzcneERHJM3ByySjMPwEds4NVDctKW4HAXggZIA1xhga1XlNggrBXlu09Sqro9zEbJdrBwJQI6BeuZHpH2eaJBDI73ljTWgtqoIeLg1WA') +WalletState(sequence=4, encrypted_wallet='czo4MTkyOjE2OjE66nridrsrXcL/DlcudUs7RaAIZ3jRYQJhaacRH3vPNx0TZqkJbDcjMiHbiHY6U2AVhoAsLPIf/zcU+uDTw4IRcOL9Gozupc8tCrIcgm/kwXjnQI9RNzIfDsFxalBKj0u7Xf0c+5f/ntr4Hs9Q/Y7qthseNbUBZKU12KxNlmDcE7knLOui6NQdsUvFpuI/Rzgr') 'Success' ``` @@ -135,7 +137,7 @@ Eventually, the client will be responsible (or at least more responsible) for me ``` >>> c2.get_remote_wallet() Got latest walletState: -WalletState(sequence=4, encrypted_wallet='czo4MTkyOjE2OjE62uWympFofMnLmZSGGPTC5qctGKlWkan/DmOFLVZHktzqY9OndxhY3VCr5QBMXOGyn/Y321zNtL6YNfA+gs3Ov6qhzcneERHJM3ByySjMPwEds4NVDctKW4HAXggZIA1xhga1XlNggrBXlu09Sqro9zEbJdrBwJQI6BeuZHpH2eaJBDI73ljTWgtqoIeLg1WA') +WalletState(sequence=4, encrypted_wallet='czo4MTkyOjE2OjE66nridrsrXcL/DlcudUs7RaAIZ3jRYQJhaacRH3vPNx0TZqkJbDcjMiHbiHY6U2AVhoAsLPIf/zcU+uDTw4IRcOL9Gozupc8tCrIcgm/kwXjnQI9RNzIfDsFxalBKj0u7Xf0c+5f/ntr4Hs9Q/Y7qthseNbUBZKU12KxNlmDcE7knLOui6NQdsUvFpuI/Rzgr') 'Success' >>> c2.get_preferences() {'animal': 'horse', 'car': 'Audi'} @@ -147,11 +149,11 @@ Finally, the client with the merged wallet pushes it to the server, and the othe >>> c2.update_remote_wallet() Successfully updated wallet state on server Got new walletState: -WalletState(sequence=5, encrypted_wallet='czo4MTkyOjE2OjE6ngb8TU1FyKgmzyHLQ8c30yOg/kVFNSDbtquXHKs16vEIQta3zrJLnGiY0WoiXx8Ul4uvYLK1riNaoo+OfZYtJjtpYLWf1oGdn0PDq0ZCHhK6GcX2Zbz/YQEdPcOvDeENjxZ4Pq2qoZYSDcPvwOgbvO2FSOK27OhCWHCA/9LbzAu6Suq6RS3i2p2TpmUHtz2H') +WalletState(sequence=5, encrypted_wallet='czo4MTkyOjE2OjE68NAahtUE4gg2M6Fam/E3brb4sv1TzcXJLvGRh4CY4416haOF1lxmKSdrvIPpOBvpNPS0B5qCbmpaKQ8Pm/WRCLj1yYUDVKgSZx0ru7AJBHiBLtpKA99Ia7XlWl129p6WtjJkbOoW8Ya+PEii72g4nrtM+j40Xe9UbVI463tlKYaRvmKr/BcoFGMJSB10Whh8') 'Success' >>> c1.get_remote_wallet() Got latest walletState: -WalletState(sequence=5, encrypted_wallet='czo4MTkyOjE2OjE6ngb8TU1FyKgmzyHLQ8c30yOg/kVFNSDbtquXHKs16vEIQta3zrJLnGiY0WoiXx8Ul4uvYLK1riNaoo+OfZYtJjtpYLWf1oGdn0PDq0ZCHhK6GcX2Zbz/YQEdPcOvDeENjxZ4Pq2qoZYSDcPvwOgbvO2FSOK27OhCWHCA/9LbzAu6Suq6RS3i2p2TpmUHtz2H') +WalletState(sequence=5, encrypted_wallet='czo4MTkyOjE2OjE68NAahtUE4gg2M6Fam/E3brb4sv1TzcXJLvGRh4CY4416haOF1lxmKSdrvIPpOBvpNPS0B5qCbmpaKQ8Pm/WRCLj1yYUDVKgSZx0ru7AJBHiBLtpKA99Ia7XlWl129p6WtjJkbOoW8Ya+PEii72g4nrtM+j40Xe9UbVI463tlKYaRvmKr/BcoFGMJSB10Whh8') 'Success' >>> c1.get_preferences() {'animal': 'horse', 'car': 'Audi'} @@ -182,12 +184,12 @@ We try to POST both of them to the server, but the second one fails because of t >>> c2.update_remote_wallet() Successfully updated wallet state on server Got new walletState: -WalletState(sequence=6, encrypted_wallet='czo4MTkyOjE2OjE6MnLcl2+VTv8B9MIKJjpwptjF8Ws6NfhFkFBnsTDy8arv7akMSV/jojkvz2bJzOjX+iAKiY0+FKgD2akONsUnQqF95pnbr+TPnpbFxS4TLFUWxbpJMm7+r3FZiOauMZ6ewBfBq3vzI2UA2o3RrSxzucKZ6ZcgZqJsKCnk+rCj/ADmrUJb01kwB6WDATcMlG5A') +WalletState(sequence=6, encrypted_wallet='czo4MTkyOjE2OjE6sh95Bt0OfcDY3QwUWaPgPWD1WPYCkN2yg1+XLD/5puONhNyjzVAnhINqVvPy52pxfkVgkIScLacMQFq4W19d+SC5LConu+fPchBzYj14Wvc3/IEQiQIxbmkv6N9USvYsjAzjGqK7szistRJY4MHC4/wRbWRprfIE7BFcDaisFSe18mRs8D2KlhEzjNJu+X8+') 'Success' >>> c1.update_remote_wallet() Wallet state out of date. Getting updated wallet state. Try posting again after this. Got new walletState: -WalletState(sequence=6, encrypted_wallet='czo4MTkyOjE2OjE6MnLcl2+VTv8B9MIKJjpwptjF8Ws6NfhFkFBnsTDy8arv7akMSV/jojkvz2bJzOjX+iAKiY0+FKgD2akONsUnQqF95pnbr+TPnpbFxS4TLFUWxbpJMm7+r3FZiOauMZ6ewBfBq3vzI2UA2o3RrSxzucKZ6ZcgZqJsKCnk+rCj/ADmrUJb01kwB6WDATcMlG5A') +WalletState(sequence=6, encrypted_wallet='czo4MTkyOjE2OjE6sh95Bt0OfcDY3QwUWaPgPWD1WPYCkN2yg1+XLD/5puONhNyjzVAnhINqVvPy52pxfkVgkIScLacMQFq4W19d+SC5LConu+fPchBzYj14Wvc3/IEQiQIxbmkv6N9USvYsjAzjGqK7szistRJY4MHC4/wRbWRprfIE7BFcDaisFSe18mRs8D2KlhEzjNJu+X8+') 'Success' >>> c1.get_preferences() {'animal': 'beaver', 'car': 'Toyota'} @@ -199,6 +201,6 @@ Now that the merge is complete, the client can make a second POST request contai >>> c1.update_remote_wallet() Successfully updated wallet state on server Got new walletState: -WalletState(sequence=7, encrypted_wallet='czo4MTkyOjE2OjE6uexO9yl0JVsKFo6WeJGOsJ/sm1RJPc+NwLxniaE744lVEihK2HyNxDVbcAFEMxn/vKXgFKtzLV/D7eAzeGrSIyQR5v3YeZrTWPcRzK79rJgHzjcZpjKpytcDMZp2lB5cRHkNg7u8qAa2DnbebMXU0CKblTL++IIteU+CzyuTdW1Uoj4cEOsy6G8HwrZc5drf') +WalletState(sequence=7, encrypted_wallet='czo4MTkyOjE2OjE68J19IGGfoiRDm15Nb1sTj5yP9Mc3jpAeYarh206kLXKMKLKCIahmhLDMqBCXgwDe098uaIqB6IwKDfXbCVJHhWfqzu/5GoWPK1QZjhCu0rGxteFv4Tio0IYGg8CUYCvOhpQA319SXEf4sF9cyC32VwlL6qkJ2TzWTu9bTGUfZRGV3q9Rt9oL4OQHxuNIPEiE') 'Success' ``` diff --git a/test_client/gen-readme.py b/test_client/gen-readme.py index 74f4c93..716a195 100644 --- a/test_client/gen-readme.py +++ b/test_client/gen-readme.py @@ -3,12 +3,16 @@ # NOTE - delete the database before running this, or else you'll get an error for registering. also we want the wallet to start empty # NOTE - in the SDK, create wallets called "test_wallet_1" and "test_wallet_2" +import time from test_client import LBRYSDK # reset all of the preferences so we can run our example for wallet in ['test_wallet_1', 'test_wallet_2']: for pref_key in ['car', 'animal']: LBRYSDK.set_preference(wallet, pref_key, '') +# Make sure the next preference changes have a later timestamp! +time.sleep(3) + def code_block(code): print ("```") for line in code.strip().split('\n'): @@ -29,12 +33,14 @@ A couple example flows so it's clear how it works. We're assuming that we're sta print("""## Initial setup and account recovery Set up a client for each wallet, but with the same sync account (which won't exist on the server yet). This will simulate clients on two different computers. + +For this example we will be working with a locally running server so that we don't care about the data. If you want to communicate with `dev.lbry.id`, simply omit the `local=True`. """) code_block(""" from test_client import Client -c1 = Client("joe2@example.com", "123abc2", 'test_wallet_1') -c2 = Client("joe2@example.com", "123abc2", 'test_wallet_2') +c1 = Client("joe2@example.com", "123abc2", 'test_wallet_1', local=True) +c2 = Client("joe2@example.com", "123abc2", 'test_wallet_2', local=True) """) print(""" @@ -155,7 +161,6 @@ c1.get_preferences() """) # Make sure the next preference changes have a later timestamp! -import time time.sleep(3) print(""" diff --git a/test_client/test_client.py b/test_client/test_client.py index 4d309c6..4c65dff 100755 --- a/test_client/test_client.py +++ b/test_client/test_client.py @@ -58,32 +58,34 @@ class LBRYSDK(): return response.json()['result'] class WalletSync(): - BASE_URL = 'http://localhost:8090' - AUTH_URL = BASE_URL + '/auth/full' - REGISTER_URL = BASE_URL + '/signup' - WALLET_URL = BASE_URL + '/wallet' + def __init__(self, local): + if local: + BASE_URL = 'http://localhost:8090' + else: + BASE_URL = 'https://dev.lbry.id:8091' + self.AUTH_URL = BASE_URL + '/auth/full' + self.REGISTER_URL = BASE_URL + '/signup' + self.WALLET_URL = BASE_URL + '/wallet' - @classmethod - def register(cls, email, password): + def register(self, email, password): body = json.dumps({ 'email': email, 'password': password, }) - response = requests.post(cls.REGISTER_URL, body) + response = requests.post(self.REGISTER_URL, body) if response.status_code != 201: print ('Error', response.status_code) print (response.content) return False return True - @classmethod - def get_auth_token(cls, email, password, device_id): + def get_auth_token(self, email, password, device_id): body = json.dumps({ 'email': email, 'password': password, 'deviceId': device_id, }) - response = requests.post(cls.AUTH_URL, body) + response = requests.post(self.AUTH_URL, body) if response.status_code != 200: print ('Error', response.status_code) print (response.content) @@ -91,12 +93,11 @@ class WalletSync(): return response.json()['token'] - @classmethod - def get_wallet(cls, token): + def get_wallet(self, token): params = { 'token': token, } - response = requests.get(cls.WALLET_URL, params=params) + response = requests.get(self.WALLET_URL, params=params) # TODO check response version on client side now if response.status_code == 404: @@ -116,8 +117,7 @@ class WalletSync(): hmac = response.json()['hmac'] return wallet_state, hmac - @classmethod - def update_wallet(cls, wallet_state, hmac, token): + def update_wallet(self, wallet_state, hmac, token): body = json.dumps({ 'version': CURRENT_VERSION, 'token': token, @@ -126,7 +126,7 @@ class WalletSync(): "hmac": hmac, }) - response = requests.post(cls.WALLET_URL, body) + response = requests.post(self.WALLET_URL, body) # TODO check that response.json().version == CURRENT_VERSION @@ -188,7 +188,7 @@ class Client(): return True - def __init__(self, email, root_password, wallet_id='default_wallet'): + def __init__(self, email, root_password, wallet_id='default_wallet', local=False): # Represents normal client behavior (though a real client will of course save device id) self.device_id = str(uuid.uuid4()) @@ -200,6 +200,8 @@ class Client(): self.root_password = root_password self.wallet_id = wallet_id + self.wallet_sync_api = WalletSync(local=local) + # TODO - This does not deal with the question of tying accounts to wallets. # Does a new wallet state mean a we're creating a new account? What happens # if we create a new wallet state tied to an existing account? Do we merge it @@ -243,7 +245,7 @@ class Client(): ) def register(self): - success = WalletSync.register( + success = self.wallet_sync_api.register( self.email, derive_login_password(self.root_password), ) @@ -251,7 +253,7 @@ class Client(): print ("Registered") def get_auth_token(self): - token = WalletSync.get_auth_token( + token = self.wallet_sync_api.get_auth_token( self.email, derive_login_password(self.root_password), self.device_id, @@ -270,7 +272,7 @@ class Client(): # Returns: status def get_remote_wallet(self): - new_wallet_state, hmac = WalletSync.get_wallet(self.auth_token) + new_wallet_state, hmac = self.wallet_sync_api.get_wallet(self.auth_token) if not new_wallet_state: # Wallet not found, but this is not an error @@ -315,7 +317,7 @@ class Client(): hmac = create_hmac(submitted_wallet_state, hmac_key) # Submit our wallet, get the latest wallet back as a response - new_wallet_state, new_hmac, conflict = WalletSync.update_wallet(submitted_wallet_state, hmac, self.auth_token) + new_wallet_state, new_hmac, conflict = self.wallet_sync_api.update_wallet(submitted_wallet_state, hmac, self.auth_token) # TODO - there's some code in common here with the get_remote_wallet function. factor it out.