def test_create_and_store_my_did__with_seed(self):
     conn = WalletConnection(self.WALLET_UID, self.WALLET_PASS_PHRASE)
     wallet = Wallet.objects.create(uid=self.WALLET_UID, owner=self.account)
     url = self.live_server_url + '/agent/admin/wallets/%s/did/create_and_store_my_did/' % wallet.uid
     # first: create wallet
     run_async(conn.create())
     try:
         cred = dict(pass_phrase=self.WALLET_PASS_PHRASE,
                     seed='000000000000000000000000Steward1')
         # open
         url_open = self.live_server_url + reverse(
             'admin-wallets-open', kwargs=dict(uid=self.WALLET_UID))
         resp = requests.post(url_open,
                              json=cred,
                              auth=HTTPBasicAuth(self.IDENTITY, self.PASS))
         self.assertEqual(200, resp.status_code)
         # FIRE!!!
         resp = requests.post(url,
                              json=cred,
                              auth=HTTPBasicAuth(self.IDENTITY, self.PASS))
         self.assertEqual(201, resp.status_code)
         info = resp.json()
         self.assertTrue(info.get('did'))
         self.assertTrue(info.get('verkey'))
         # Fire second time
         resp = requests.post(url,
                              json=cred,
                              auth=HTTPBasicAuth(self.IDENTITY, self.PASS))
         self.assertIn(resp.status_code, [201, 409])
     finally:
         os.popen("pkill -f run_wallet_agent")
         sleep(1)
         run_async(conn.delete())
 def test_create_invitation__with_label(self):
     conn = WalletConnection(self.WALLET_UID, self.WALLET_PASS_PHRASE)
     wallet = Wallet.objects.create(uid=self.WALLET_UID, owner=self.account)
     endpoint = Endpoint.objects.create(uid='endpoint_uid',
                                        owner=self.account,
                                        wallet=wallet,
                                        url='http://example.com/endpoint')
     # first: create wallet
     run_async(conn.create())
     try:
         label = 'My Test Label'
         cred = dict(pass_phrase=self.WALLET_PASS_PHRASE, label=label)
         url = self.live_server_url + '/agent/admin/wallets/%s/endpoints/%s/invitations/' % (
             self.WALLET_UID, endpoint.uid)
         resp = requests.post(url,
                              json=cred,
                              auth=HTTPBasicAuth(self.IDENTITY, self.PASS))
         self.assertEqual(201, resp.status_code)
         entity = resp.json()
         self.assertTrue(entity['url'])
         invite_url = entity['url']
         matches = re.match("(.+)?c_i=(.+)", invite_url)
         self.assertTrue(matches)
         _ = base64.urlsafe_b64decode(matches.group(2)).decode('utf-8')
         invite_msg = json.loads(_)
         self.assertEqual(label, invite_msg.get('label'))
     finally:
         os.popen("pkill -f run_wallet_agent")
         sleep(1)
         run_async(conn.delete())
 def test_create_invitation_with_seed(self):
     conn = WalletConnection(self.WALLET_UID, self.WALLET_PASS_PHRASE)
     wallet = Wallet.objects.create(uid=self.WALLET_UID, owner=self.account)
     endpoint = Endpoint.objects.create(uid='endpoint_uid',
                                        owner=self.account,
                                        wallet=wallet,
                                        url='http://example.com/endpoint')
     # first: create wallet
     run_async(conn.create())
     try:
         seed = 'blablabla-seed-'
         expected_key = '3XvPjB4EDpmBBF4sRmqVbrQXQY5vk7zjiggSCGxSkPpV'
         cred = dict(pass_phrase=self.WALLET_PASS_PHRASE, seed=seed)
         url = self.live_server_url + '/agent/admin/wallets/%s/endpoints/%s/invitations/' % (
             self.WALLET_UID, endpoint.uid)
         resp = requests.post(url,
                              json=cred,
                              auth=HTTPBasicAuth(self.IDENTITY, self.PASS))
         self.assertEqual(201, resp.status_code)
         instance = Invitation.objects.get(endpoint=endpoint)
         connection_key = resp.json()['connection_key']
         self.assertEqual(expected_key, connection_key)
         self.assertEqual(instance.connection_key, connection_key)
         self.assertEqual(instance.seed, seed)
         resp = requests.post(url,
                              json=cred,
                              auth=HTTPBasicAuth(self.IDENTITY, self.PASS))
         self.assertEqual(409, resp.status_code)
     finally:
         os.popen("pkill -f run_wallet_agent")
         sleep(1)
         run_async(conn.delete())
 def test_ensure_exists(self):
     conn = WalletConnection(self.WALLET_UID, self.WALLET_PASS_PHRASE)
     try:
         url = self.live_server_url + '/agent/admin/wallets/ensure_exists/'
         cred = dict(pass_phrase=self.WALLET_PASS_PHRASE,
                     uid=self.WALLET_UID)
         resp = requests.post(url,
                              json=cred,
                              auth=HTTPBasicAuth(self.IDENTITY, self.PASS))
         self.assertIn(resp.status_code, [200, 201])
     finally:
         os.popen("pkill -f run_wallet_agent")
         sleep(1)
         run_async(conn.delete())
 def test_list_my_dids_with_meta(self):
     conn = WalletConnection(self.WALLET_UID, self.WALLET_PASS_PHRASE)
     wallet = Wallet.objects.create(uid=self.WALLET_UID, owner=self.account)
     url = self.live_server_url + '/agent/admin/wallets/%s/did/list_my_dids_with_meta/' % wallet.uid
     # first: create wallet
     run_async(conn.create())
     try:
         # create did from seed
         run_async(conn.open())
         did, verkey = run_async(
             conn.create_and_store_my_did(
                 seed='000000000000000000000000Steward1'))
         run_async(conn.close())
         cred = dict(pass_phrase=self.WALLET_PASS_PHRASE)
         # open
         url_open = self.live_server_url + reverse(
             'admin-wallets-open', kwargs=dict(uid=self.WALLET_UID))
         resp = requests.post(url_open,
                              json=cred,
                              auth=HTTPBasicAuth(self.IDENTITY, self.PASS))
         self.assertEqual(200, resp.status_code)
         # FIRE!!!
         resp = requests.post(url,
                              json=cred,
                              auth=HTTPBasicAuth(self.IDENTITY, self.PASS))
         self.assertEqual(200, resp.status_code)
         raw = json.dumps(resp.json())
         self.assertIn(did, raw)
         self.assertIn(verkey, raw)
     finally:
         os.popen("pkill -f run_wallet_agent")
         sleep(1)
         run_async(conn.delete())
 def test_create_invitation_with_did(self):
     conn = WalletConnection(self.WALLET_UID, self.WALLET_PASS_PHRASE)
     wallet = Wallet.objects.create(uid=self.WALLET_UID, owner=self.account)
     endpoint = Endpoint.objects.create(uid='endpoint_uid',
                                        owner=self.account,
                                        wallet=wallet,
                                        url='http://example.com/endpoint')
     # first: create wallet
     run_async(conn.create())
     run_async(conn.open())
     my_did, my_verkey = run_async(conn.create_and_store_my_did())
     run_async(conn.close())
     try:
         cred = dict(pass_phrase=self.WALLET_PASS_PHRASE, my_did=my_did)
         url = self.live_server_url + '/agent/admin/wallets/%s/endpoints/%s/invitations/' % (
             self.WALLET_UID, endpoint.uid)
         resp = requests.post(url,
                              json=cred,
                              auth=HTTPBasicAuth(self.IDENTITY, self.PASS))
         self.assertEqual(201, resp.status_code)
         instance = Invitation.objects.get(endpoint=endpoint)
         self.assertEqual(my_did, instance.my_did)
         resp = requests.post(url,
                              json=cred,
                              auth=HTTPBasicAuth(self.IDENTITY, self.PASS))
         self.assertEqual(201, resp.status_code)
     finally:
         os.popen("pkill -f run_wallet_agent")
         sleep(1)
         run_async(conn.delete())
 async def start_agent(agent_name, pass_phrase):
     conn = WalletConnection(agent_name, pass_phrase)
     await conn.create()
     try:
         print('Agent "%s" is started' % agent_name)
         await WalletAgent.process(agent_name)
     finally:
         await conn.delete()
         print('Wallet "%s" is deleted' % agent_name)
 def test_open_close__via_http_header(self):
     conn = WalletConnection(self.WALLET_UID, self.WALLET_PASS_PHRASE)
     Wallet.objects.create(uid=self.WALLET_UID, owner=self.account)
     # first: create wallet
     run_async(conn.create())
     headers = dict()
     headers[HEADER_PASS_PHRASE] = self.WALLET_PASS_PHRASE
     try:
         # open
         url = self.live_server_url + reverse(
             'admin-wallets-open', kwargs=dict(uid=self.WALLET_UID))
         resp = requests.post(url,
                              auth=HTTPBasicAuth(self.IDENTITY, self.PASS),
                              headers=headers)
         self.assertEqual(200, resp.status_code)
         # is_open
         url = self.live_server_url + reverse(
             'admin-wallets-is-open', kwargs=dict(uid=self.WALLET_UID))
         resp = requests.get(url,
                             auth=HTTPBasicAuth(self.IDENTITY, self.PASS))
         self.assertEqual(200, resp.status_code)
         stat = resp.json()
         self.assertTrue(stat['is_open'])
         # close
         url = self.live_server_url + reverse(
             'admin-wallets-close', kwargs=dict(uid=self.WALLET_UID))
         resp = requests.post(url,
                              auth=HTTPBasicAuth(self.IDENTITY, self.PASS),
                              headers=headers)
         self.assertEqual(200, resp.status_code)
         # is_open
         url = self.live_server_url + reverse(
             'admin-wallets-is-open', kwargs=dict(uid=self.WALLET_UID))
         resp = requests.get(url,
                             auth=HTTPBasicAuth(self.IDENTITY, self.PASS))
         self.assertEqual(200, resp.status_code)
         stat = resp.json()
         self.assertFalse(stat['is_open'])
     finally:
         os.popen("pkill -f run_wallet_agent")
         sleep(1)
         run_async(conn.delete())
 def test_create_invitation(self):
     conn = WalletConnection(self.WALLET_UID, self.WALLET_PASS_PHRASE)
     wallet = Wallet.objects.create(uid=self.WALLET_UID, owner=self.account)
     endpoint = Endpoint.objects.create(uid='endpoint_uid',
                                        owner=self.account,
                                        wallet=wallet,
                                        url='http://example.com/endpoint')
     # first: create wallet
     run_async(conn.create())
     try:
         cred = dict(pass_phrase=self.WALLET_PASS_PHRASE)
         url = self.live_server_url + '/agent/admin/wallets/%s/endpoints/%s/invitations/' % (
             self.WALLET_UID, endpoint.uid)
         resp = requests.post(url,
                              json=cred,
                              auth=HTTPBasicAuth(self.IDENTITY, self.PASS))
         self.assertEqual(201, resp.status_code)
         instance = Invitation.objects.get(endpoint=endpoint)
         entity = resp.json()
         self.assertTrue(entity['url'])
         invite_url = entity['url']
         self.assertTrue(resp.json()['connection_key'])
         connection_key = resp.json()['connection_key']
         self.assertIn(instance.invitation_string, invite_url)
         self.assertIn(settings.INDY['INVITATION_URL_BASE'], invite_url)
         self.assertEqual(1, invite_url.count('c_i='))
         # check list
         resp = requests.get(url,
                             auth=HTTPBasicAuth(self.IDENTITY, self.PASS))
         self.assertEqual(200, resp.status_code)
         raw = str(resp.json())
         self.assertIn(invite_url, raw)
         self.assertIn(connection_key, raw)
     finally:
         os.popen("pkill -f run_wallet_agent")
         sleep(1)
         run_async(conn.delete())
    async def create_wallet(self):

        def clean():
            with connection.cursor() as cursor:
                cursor.execute("DROP DATABASE  IF EXISTS %s" % self.WALLET_UID)

        await database_sync_to_async(clean)()

        self.wallet = WalletConnection(self.WALLET_UID, self.PASS_PHRASE)
        await self.wallet.create()

        def create_db_model():
            Wallet.objects.create(uid=self.WALLET_UID, owner=self.account)

        await database_sync_to_async(create_db_model)()
async def test_feature_interfaces():
    await database_sync_to_async(remove_agent_databases)('inviter', 'invitee')
    inviter_wallet = WalletConnection('inviter', 'pass')
    invitee_wallet = WalletConnection('invitee', 'pass')
    inviter_endpoint = await ReadOnlyChannel.create('inviter')
    invitee_endpoint = await ReadOnlyChannel.create('invitee')

    await inviter_wallet.create()
    await invitee_wallet.create()
    try:
        asyncio.ensure_future(WalletAgent.process('inviter'))
        asyncio.ensure_future(WalletAgent.process('invitee'))
        await asyncio.sleep(10)
        await WalletAgent.open('inviter', 'pass')
        await WalletAgent.open('invitee', 'pass')
        try:
            # Step 1: generate invitation link
            link, msg = await ConnectionProtocol.generate_invite_link(
                'Inviter', inviter_endpoint.name, 'inviter', 'pass')
            invite_link = 'http://example.com/invitations' + link
            print(
                '\n--- Invite Link --------------------------------------------------------\n'
            )
            print(invite_link)
            print(
                '\n------------------------------------------------------------------------\n'
            )
            # check pairwise lists
            inviter_pairwise_list = await WalletAgent.list_pairwise(
                'inviter', 'pass')
            invitee_pairwise_list = await WalletAgent.list_pairwise(
                'invitee', 'pass')
            assert len(inviter_pairwise_list) == 0
            assert len(invitee_pairwise_list) == 0
            # Invitee received invitation link
            log_channel = await ConnectionProtocol.receive_invite_link(
                invite_link, 'invitee', 'pass', 'Invitee',
                invitee_endpoint.name, 10)
            assert type(log_channel) is str
            # Wait answer (connection request) on Inviter endpoint
            success, data = await inviter_endpoint.read(timeout=10)
            assert success is True
            content_type, wire_message = data
            wire_message = wire_message.encode()
            ok = await ConnectionProtocol.handle('inviter', wire_message,
                                                 'Inviter',
                                                 inviter_endpoint.name)
            assert ok is True
            # Wait answer (connection response) on Invitee endpoint
            success, data = await invitee_endpoint.read(timeout=10)
            assert success is True
            content_type, wire_message = data
            wire_message = wire_message.encode()
            # Emulate Invitee receiving connection response
            ok = await ConnectionProtocol.handle('invitee', wire_message,
                                                 'Invitee',
                                                 invitee_endpoint.name)
            assert ok is True
            success, data = await inviter_endpoint.read(timeout=10)
            assert success is True
            content_type, wire_message = data
            wire_message = wire_message.encode()
            # Emulate Inviter received ack message
            ok = await ConnectionProtocol.handle('inviter', wire_message,
                                                 'Inviter',
                                                 inviter_endpoint.name)
            assert ok is True
            await asyncio.sleep(1)
            inviter_pairwise_list = await WalletAgent.list_pairwise(
                'inviter', 'pass')
            invitee_pairwise_list = await WalletAgent.list_pairwise(
                'invitee', 'pass')
            assert len(inviter_pairwise_list) == 1
            assert len(invitee_pairwise_list) == 1
        finally:
            await WalletAgent.close('inviter', 'pass')
            await WalletAgent.close('invitee', 'pass')
            await asyncio.sleep(1)
    finally:
        pass
async def test_state_machines():
    await database_sync_to_async(remove_agent_databases)('inviter', 'invitee')
    inviter_wallet = WalletConnection('inviter', 'pass')
    invitee_wallet = WalletConnection('invitee', 'pass')
    inviter_endpoint = await ReadOnlyChannel.create('inviter')
    invitee_endpoint = await ReadOnlyChannel.create('invitee')

    await inviter_wallet.create()
    await invitee_wallet.create()
    try:
        # step 1: generate invite message
        invite_msg = None

        async def generator():
            await asyncio.sleep(0.5)
            await WalletAgent.open('inviter', 'pass')
            try:
                msg = await ConnectionProtocol.generate_invite_message(
                    'Inviter', inviter_endpoint.name, 'inviter', 'pass')
                nonlocal invite_msg
                invite_msg = msg
            finally:
                await WalletAgent.close('inviter', 'pass')

        await asyncio.wait(
            [generator(), WalletAgent.process('inviter')], timeout=5)
        assert invite_msg is not None
        print(
            '\n--- Invite message --------------------------------------------------------\n'
        )
        print(invite_msg.pretty_print())
        print(
            '\n---------------------------------------------------------------------------\n'
        )
        asyncio.sleep(1)

        await inviter_wallet.open()
        await invitee_wallet.open()
        try:
            # check pairwise lists
            inviter_pairwise_list = await inviter_wallet.list_pairwise()
            invitee_pairwise_list = await invitee_wallet.list_pairwise()
            assert len(inviter_pairwise_list) == 0
            assert len(invitee_pairwise_list) == 0
            # Setup state machines
            inviter_state_machine = ConnectionProtocol.ConnProtocolInviterStateMachine(
                'inviter_state_machine')
            inviter_state_machine.label = 'Inviter'
            inviter_state_machine.endpoint = inviter_endpoint.name
            invitee_state_machine = ConnectionProtocol.ConnProtocolInviteeStateMachine(
                'invitee_state_machine')
            invitee_state_machine.label = 'Invitee'
            invitee_state_machine.endpoint = invitee_endpoint.name
            invitee_state_machine.log_channel_name = 'xxx'
            # invitee received invite message
            await invitee_state_machine.invoke(
                ConnectionProtocol.MESSAGE_CONTENT_TYPE, invite_msg.as_json(),
                invitee_wallet)
            success, data = await inviter_endpoint.read(timeout=10)
            assert success is True
            content_type, wire_message = data
            wire_message = wire_message.encode()
            assert content_type == EndpointTransport.DEFAULT_WIRE_CONTENT_TYPE
            # inviter receive connection request
            await inviter_state_machine.invoke(content_type, wire_message,
                                               inviter_wallet)
            success, data = await invitee_endpoint.read(timeout=10)
            assert success is True
            content_type, wire_message = data
            wire_message = wire_message.encode()
            assert content_type == EndpointTransport.DEFAULT_WIRE_CONTENT_TYPE
            # Invitee receive connection response
            try:
                await invitee_state_machine.invoke(content_type, wire_message,
                                                   invitee_wallet)
            except MachineIsDone:
                pass
            else:
                raise RuntimeError('Unexpected termination')
            success, data = await inviter_endpoint.read(timeout=10)
            assert success is True
            content_type, wire_message = data
            wire_message = wire_message.encode()
            assert content_type == EndpointTransport.DEFAULT_WIRE_CONTENT_TYPE
            # Inviter receive ack
            try:
                await inviter_state_machine.invoke(content_type, wire_message,
                                                   inviter_wallet)
            except MachineIsDone:
                pass
            else:
                raise RuntimeError('Unexpected termination')
            # check pairwise lists
            inviter_pairwise_list = await inviter_wallet.list_pairwise()
            invitee_pairwise_list = await invitee_wallet.list_pairwise()
            assert len(inviter_pairwise_list) == 1
            assert len(invitee_pairwise_list) == 1
        finally:
            await inviter_wallet.close()
            await invitee_wallet.close()
    finally:
        await inviter_wallet.delete()
        await invitee_wallet.delete()
class Agent2AgentCommunicationTest(LiveServerTestCase):

    IDENTITY_AGENT1 = 'agent1_user'
    IDENTITY_AGENT2 = 'agent2_user'
    IDENTITY_PASS = '******'
    WALLET_AGENT1 = 'wallet_1'
    WALLET_AGENT2 = 'wallet_2'
    WALLET_PASS_PHRASE = 'pass'
    WALLET_AGENT1_DB_NAME = WalletConnection.make_wallet_address(WALLET_AGENT1)
    WALLET_AGENT2_DB_NAME = WalletConnection.make_wallet_address(WALLET_AGENT2)
    DEF_TIMEOUT = 5

    def setUp(self):
        for identity in [self.IDENTITY_AGENT1, self.IDENTITY_AGENT2]:
            account = AgentAccount.objects.create(username=identity,
                                                  is_active=True,
                                                  is_staff=True)
            account.set_password(self.IDENTITY_PASS)
            account.save()
        os.popen("pkill -f run_wallet_agent")
        sleep(0.1)
        psax = get_ps_ax()
        self.assertNotIn('run_wallet_agent', psax, psax)
        with connection.cursor() as cursor:
            for db_name in [
                    self.WALLET_AGENT1_DB_NAME, self.WALLET_AGENT2_DB_NAME
            ]:
                cursor.execute("DROP DATABASE  IF EXISTS %s" % db_name)
        self.agents = []
        self.agents_logs = dict()
        self.agents_logs[self.IDENTITY_AGENT1] = list()
        self.agents_logs[self.IDENTITY_AGENT2] = list()
        self.start_agents()

    def tearDown(self):
        self.stop_agents()
        sleep(1)
        os.popen("pkill -f run_wallet_agent")
        sleep(1)

    def start_agents(self):
        async def start_agent(agent_name, pass_phrase):
            conn = WalletConnection(agent_name, pass_phrase)
            await conn.create()
            try:
                print('Agent "%s" is started' % agent_name)
                await WalletAgent.process(agent_name)
            finally:
                await conn.delete()
                print('Wallet "%s" is deleted' % agent_name)

        for agent, identity in [(self.WALLET_AGENT1, self.IDENTITY_AGENT1),
                                (self.WALLET_AGENT2, self.IDENTITY_AGENT2)]:
            thread = ThreadScheduler()
            self.agents.append(thread)
            thread.start()
            asyncio.run_coroutine_threadsafe(start_agent(
                agent, self.WALLET_PASS_PHRASE),
                                             loop=thread.loop)
            account = AgentAccount.objects.get(username=identity)
            model_wallet = WalletModel.objects.create(uid=agent, owner=account)
            endpoint_uid = 'endpoint_for_' + agent
            EndpointModel.objects.create(uid=endpoint_uid,
                                         owner=account,
                                         wallet=model_wallet,
                                         url=reverse(
                                             'endpoint',
                                             kwargs=dict(uid=endpoint_uid)))

        sleep(10)

    pass

    def stop_agents(self):
        async def stop_agent(agent_name, pass_phrase):
            try:
                await WalletAgent.close(agent_name, pass_phrase)
            except AgentTimeOutError:
                pass

        for agent in [self.WALLET_AGENT1, self.WALLET_AGENT2]:
            run_async(stop_agent(agent, self.WALLET_PASS_PHRASE))
        sleep(5)
        for thread in self.agents:
            thread.stop()

    pass

    def create_did(self, wallet_uid: str, seed: str = None):
        run_async(WalletAgent.open(wallet_uid, self.WALLET_PASS_PHRASE))
        did, verkey = run_async(
            WalletAgent.create_and_store_my_did(wallet_uid,
                                                self.WALLET_PASS_PHRASE, seed))
        run_async(
            WalletAgent.add_wallet_record(wallet_uid, self.WALLET_PASS_PHRASE,
                                          WALLET_KEY_TO_DID_KEY, verkey, did))
        return did, verkey

    async def register_schema(self, wallet_uid: str, schema: dict, did: str):
        await WalletAgent.open(wallet_uid, self.WALLET_PASS_PHRASE)
        schema_request, schema_json = await WalletAgent.build_schema_request(
            wallet_uid, self.WALLET_PASS_PHRASE, did, schema['name'],
            schema['version'], schema['attributes'])
        schema_response = await WalletAgent.sign_and_submit_request(
            wallet_uid, self.WALLET_PASS_PHRASE, did, schema_request)
        assert schema_response['op'] == 'REPLY'

        cred_def_id, cred_def_json, cred_def_request, schema = await WalletAgent.issuer_create_credential_def(
            wallet_uid, self.WALLET_PASS_PHRASE, did, schema_json['id'], 'TAG',
            False)
        return cred_def_id, cred_def_json, cred_def_request, schema_json

    async def register_pairwise(self, wallet_uid: str, their_did: str,
                                my_did: str, their_vk: str, my_vk: str,
                                their_endpoint: str, label: str):
        metadata = {
            'label': label,
            'their_endpoint': their_endpoint,
            'their_vk': their_vk,
            'my_vk': my_vk,
        }
        await WalletAgent.create_pairwise_statically(wallet_uid,
                                                     self.WALLET_PASS_PHRASE,
                                                     their_did, their_vk,
                                                     my_did, metadata)

    def test_invite_feature_0023(self):
        cred = dict(pass_phrase=self.WALLET_PASS_PHRASE)
        endpoint_inviter = AgentAccount.objects.get(
            username=self.IDENTITY_AGENT1).endpoints.first()
        endpoint_inviter.url = self.live_server_url + reverse(
            'endpoint',
            kwargs=dict(uid=AgentAccount.objects.get(
                username=self.IDENTITY_AGENT1).endpoints.first().uid))
        endpoint_inviter.save()
        inviter = dict(
            identity=self.IDENTITY_AGENT1,
            password=self.IDENTITY_PASS,
            wallet_uid=AgentAccount.objects.get(
                username=self.IDENTITY_AGENT1).wallets.first().uid,
            endpoint_uid=AgentAccount.objects.get(
                username=self.IDENTITY_AGENT1).endpoints.first().uid,
            endpoint_url=endpoint_inviter.url)
        endpoint_invitee = AgentAccount.objects.get(
            username=self.IDENTITY_AGENT2).endpoints.first()
        endpoint_invitee.url = self.live_server_url + reverse(
            'endpoint',
            kwargs=dict(uid=AgentAccount.objects.get(
                username=self.IDENTITY_AGENT2).endpoints.first().uid))
        endpoint_invitee.save()
        invitee = dict(
            identity=self.IDENTITY_AGENT2,
            password=self.IDENTITY_PASS,
            wallet_uid=AgentAccount.objects.get(
                username=self.IDENTITY_AGENT2).wallets.first().uid,
            endpoint_uid=AgentAccount.objects.get(
                username=self.IDENTITY_AGENT2).endpoints.first().uid,
            endpoint_url=endpoint_invitee.url)
        # Step 1: generate invitation link
        url = self.live_server_url + '/agent/admin/wallets/%s/endpoints/%s/invitations/' % \
              (inviter['wallet_uid'], inviter['endpoint_uid'])
        invitation_kwargs = dict(**cred)
        invitation_kwargs['feature'] = 'feature_0023'
        resp = requests.post(url,
                             json=invitation_kwargs,
                             auth=HTTPBasicAuth(inviter['identity'],
                                                inviter['password']))
        self.assertEqual(201, resp.status_code, resp.text)
        invite_url_string = resp.json()['url']
        print('Invitation LINK: %s' % invite_url_string)
        # Step 2: send invite to Invitee
        url = self.live_server_url + '/agent/admin/wallets/%s/endpoints/%s/invite/' % \
              (invitee['wallet_uid'], invitee['endpoint_uid'])
        invite = dict(**cred)
        invite['url'] = invite_url_string
        resp = requests.post(url,
                             json=invite,
                             auth=HTTPBasicAuth(invitee['identity'],
                                                invitee['password']))
        self.assertEqual(200, resp.status_code)
        log = resp.json()
        self.assertTrue(log)
        print('======== INVITE LOG =========')
        print(json.dumps(log, indent=2, sort_keys=True))
        print('===============================')
        # Check pairwise list
        all_pairwises = []
        for actor in [inviter, invitee]:
            url = self.live_server_url + '/agent/admin/wallets/%s/pairwise/all/' % actor[
                'wallet_uid']
            resp = requests.post(url,
                                 json=cred,
                                 auth=HTTPBasicAuth(actor['identity'],
                                                    actor['password']))
            self.assertEqual(200, resp.status_code, resp.text)
            ret = resp.json()
            self.assertEqual(1, len(ret))
            pairwise = ret[0]
            all_pairwises.append(pairwise)
            url = self.live_server_url + '/agent/admin/wallets/%s/pairwise/get_metadata/' % actor[
                'wallet_uid']
            did_access = dict(**cred)
            did_access['their_did'] = pairwise['their_did']
            resp = requests.post(url,
                                 json=did_access,
                                 auth=HTTPBasicAuth(actor['identity'],
                                                    actor['password']))
            self.assertEqual(200, resp.status_code, resp.text)
            ret = resp.json()
            did_access['their_did'] = pairwise['my_did']
            resp = requests.post(url,
                                 json=did_access,
                                 auth=HTTPBasicAuth(actor['identity'],
                                                    actor['password']))
            self.assertEqual(400, resp.status_code, resp.text)
            pass
        print('======== ALL PAIRWISE =========')
        print(json.dumps(all_pairwises, indent=2, sort_keys=True))
        print('===============================')
        pass

    def test_invite_feature_0160(self):
        cred = dict(pass_phrase=self.WALLET_PASS_PHRASE)
        endpoint_inviter = AgentAccount.objects.get(
            username=self.IDENTITY_AGENT1).endpoints.first()
        endpoint_inviter.url = self.live_server_url + reverse(
            'endpoint',
            kwargs=dict(uid=AgentAccount.objects.get(
                username=self.IDENTITY_AGENT1).endpoints.first().uid))
        endpoint_inviter.save()
        inviter = dict(
            identity=self.IDENTITY_AGENT1,
            password=self.IDENTITY_PASS,
            wallet_uid=AgentAccount.objects.get(
                username=self.IDENTITY_AGENT1).wallets.first().uid,
            endpoint_uid=AgentAccount.objects.get(
                username=self.IDENTITY_AGENT1).endpoints.first().uid,
            endpoint_url=endpoint_inviter.url)
        endpoint_invitee = AgentAccount.objects.get(
            username=self.IDENTITY_AGENT2).endpoints.first()
        endpoint_invitee.url = self.live_server_url + reverse(
            'endpoint',
            kwargs=dict(uid=AgentAccount.objects.get(
                username=self.IDENTITY_AGENT2).endpoints.first().uid))
        endpoint_invitee.save()
        invitee = dict(
            identity=self.IDENTITY_AGENT2,
            password=self.IDENTITY_PASS,
            wallet_uid=AgentAccount.objects.get(
                username=self.IDENTITY_AGENT2).wallets.first().uid,
            endpoint_uid=AgentAccount.objects.get(
                username=self.IDENTITY_AGENT2).endpoints.first().uid,
            endpoint_url=endpoint_invitee.url)
        # Step 1: generate invitation link
        url = self.live_server_url + '/agent/admin/wallets/%s/endpoints/%s/invitations/' % \
              (inviter['wallet_uid'], inviter['endpoint_uid'])
        invitation_kwargs = dict(**cred)
        invitation_kwargs['feature'] = 'feature_0160'
        resp = requests.post(url,
                             json=invitation_kwargs,
                             auth=HTTPBasicAuth(inviter['identity'],
                                                inviter['password']))
        self.assertEqual(201, resp.status_code, resp.text)
        invite_url_string = resp.json()['url']
        print('Invitation LINK: %s' % invite_url_string)
        # Step 2: send invite to Invitee
        url = self.live_server_url + '/agent/admin/wallets/%s/endpoints/%s/invite/' % \
              (invitee['wallet_uid'], invitee['endpoint_uid'])
        invite = dict(**cred)
        invite['url'] = invite_url_string
        resp = requests.post(url,
                             json=invite,
                             auth=HTTPBasicAuth(invitee['identity'],
                                                invitee['password']))
        self.assertEqual(200, resp.status_code)
        log = resp.json()
        self.assertTrue(log)
        print('======== INVITE LOG =========')
        print(json.dumps(log, indent=2, sort_keys=True))
        print('===============================')
        # Check pairwise list
        all_pairwises = []
        for actor in [inviter, invitee]:
            url = self.live_server_url + '/agent/admin/wallets/%s/pairwise/all/' % actor[
                'wallet_uid']
            resp = requests.post(url,
                                 json=cred,
                                 auth=HTTPBasicAuth(actor['identity'],
                                                    actor['password']))
            self.assertEqual(200, resp.status_code, resp.text)
            ret = resp.json()
            self.assertEqual(1, len(ret))
            pairwise = ret[0]
            all_pairwises.append(pairwise)
            url = self.live_server_url + '/agent/admin/wallets/%s/pairwise/get_metadata/' % actor[
                'wallet_uid']
            did_access = dict(**cred)
            did_access['their_did'] = pairwise['their_did']
            resp = requests.post(url,
                                 json=did_access,
                                 auth=HTTPBasicAuth(actor['identity'],
                                                    actor['password']))
            self.assertEqual(200, resp.status_code, resp.text)
            ret = resp.json()
            did_access['their_did'] = pairwise['my_did']
            resp = requests.post(url,
                                 json=did_access,
                                 auth=HTTPBasicAuth(actor['identity'],
                                                    actor['password']))
            self.assertEqual(400, resp.status_code, resp.text)
            pass
        print('======== ALL PAIRWISE =========')
        print(json.dumps(all_pairwises, indent=2, sort_keys=True))
        print('===============================')
        pass

    def test_invite_feature_0160_fixed_did(self):
        cred = dict(pass_phrase=self.WALLET_PASS_PHRASE)
        endpoint_inviter = AgentAccount.objects.get(
            username=self.IDENTITY_AGENT1).endpoints.first()
        endpoint_inviter.url = self.live_server_url + reverse(
            'endpoint',
            kwargs=dict(uid=AgentAccount.objects.get(
                username=self.IDENTITY_AGENT1).endpoints.first().uid))
        endpoint_inviter.save()
        inviter = dict(
            identity=self.IDENTITY_AGENT1,
            password=self.IDENTITY_PASS,
            wallet_uid=AgentAccount.objects.get(
                username=self.IDENTITY_AGENT1).wallets.first().uid,
            endpoint_uid=AgentAccount.objects.get(
                username=self.IDENTITY_AGENT1).endpoints.first().uid,
            endpoint_url=endpoint_inviter.url)
        endpoint_invitee = AgentAccount.objects.get(
            username=self.IDENTITY_AGENT2).endpoints.first()
        endpoint_invitee.url = self.live_server_url + reverse(
            'endpoint',
            kwargs=dict(uid=AgentAccount.objects.get(
                username=self.IDENTITY_AGENT2).endpoints.first().uid))
        endpoint_invitee.save()
        invitee = dict(
            identity=self.IDENTITY_AGENT2,
            password=self.IDENTITY_PASS,
            wallet_uid=AgentAccount.objects.get(
                username=self.IDENTITY_AGENT2).wallets.first().uid,
            endpoint_uid=AgentAccount.objects.get(
                username=self.IDENTITY_AGENT2).endpoints.first().uid,
            endpoint_url=endpoint_invitee.url)
        # Step 1: generate invitation link
        did_inviter, verkey_inviter = self.create_did(inviter['wallet_uid'])
        url = self.live_server_url + '/agent/admin/wallets/%s/endpoints/%s/invitations/ensure_exists/' % \
              (inviter['wallet_uid'], inviter['endpoint_uid'])
        invitation_kwargs = dict(**cred)
        invitation_kwargs['my_did'] = did_inviter
        invitation_kwargs['seed'] = 'invitation-seed'
        resp = requests.post(url,
                             json=invitation_kwargs,
                             auth=HTTPBasicAuth(inviter['identity'],
                                                inviter['password']))
        self.assertEqual(200, resp.status_code, resp.text)
        invite_url_string = resp.json()['url']
        print('Invitation LINK: %s' % invite_url_string)
        # Step 2: send invite to Invitee
        did_invitee, verkey_invitee = self.create_did(invitee['wallet_uid'])
        url = self.live_server_url + '/agent/admin/wallets/%s/endpoints/%s/invite/' % \
              (invitee['wallet_uid'], invitee['endpoint_uid'])
        invite = dict(**cred)
        invite['url'] = invite_url_string
        invite['my_did'] = did_invitee
        resp = requests.post(url,
                             json=invite,
                             auth=HTTPBasicAuth(invitee['identity'],
                                                invitee['password']))
        self.assertEqual(200, resp.status_code)
        log = resp.json()
        self.assertTrue(log)
        print('======== INVITE LOG =========')
        print(json.dumps(log, indent=2, sort_keys=True))
        print('===============================')
        # Check pairwise list
        url = self.live_server_url + '/agent/admin/wallets/%s/pairwise/all/' % invitee[
            'wallet_uid']
        resp = requests.post(url,
                             json=cred,
                             auth=HTTPBasicAuth(invitee['identity'],
                                                invitee['password']))
        self.assertEqual(200, resp.status_code, resp.text)
        ret = resp.json()
        self.assertIn(did_inviter, str(ret))
        url = self.live_server_url + '/agent/admin/wallets/%s/pairwise/all/' % inviter[
            'wallet_uid']
        resp = requests.post(url,
                             json=cred,
                             auth=HTTPBasicAuth(inviter['identity'],
                                                inviter['password']))
        self.assertEqual(200, resp.status_code, resp.text)
        ret = resp.json()
        self.assertIn(did_invitee, str(ret))

    def test_invite_feature_0160_update_pairwise(self):
        cred = dict(pass_phrase=self.WALLET_PASS_PHRASE)
        endpoint_inviter = AgentAccount.objects.get(
            username=self.IDENTITY_AGENT1).endpoints.first()
        endpoint_inviter.url = self.live_server_url + reverse(
            'endpoint',
            kwargs=dict(uid=AgentAccount.objects.get(
                username=self.IDENTITY_AGENT1).endpoints.first().uid))
        endpoint_inviter.save()
        inviter = dict(
            identity=self.IDENTITY_AGENT1,
            password=self.IDENTITY_PASS,
            wallet_uid=AgentAccount.objects.get(
                username=self.IDENTITY_AGENT1).wallets.first().uid,
            endpoint_uid=AgentAccount.objects.get(
                username=self.IDENTITY_AGENT1).endpoints.first().uid,
            endpoint_url=endpoint_inviter.url)
        endpoint_invitee = AgentAccount.objects.get(
            username=self.IDENTITY_AGENT2).endpoints.first()
        endpoint_invitee.url = self.live_server_url + reverse(
            'endpoint',
            kwargs=dict(uid=AgentAccount.objects.get(
                username=self.IDENTITY_AGENT2).endpoints.first().uid))
        endpoint_invitee.save()
        invitee = dict(
            identity=self.IDENTITY_AGENT2,
            password=self.IDENTITY_PASS,
            wallet_uid=AgentAccount.objects.get(
                username=self.IDENTITY_AGENT2).wallets.first().uid,
            endpoint_uid=AgentAccount.objects.get(
                username=self.IDENTITY_AGENT2).endpoints.first().uid,
            endpoint_url=endpoint_invitee.url)
        # Step 1: generate pairwices statically
        headers = dict()
        headers[HEADER_PASS_PHRASE] = self.WALLET_PASS_PHRASE
        did_inviter, verkey_inviter = self.create_did(inviter['wallet_uid'])
        did_invitee, verkey_invitee = self.create_did(invitee['wallet_uid'])
        url = self.live_server_url + '/agent/admin/wallets/%s/pairwise/create_pairwise_statically/' % inviter[
            'wallet_uid']
        pairwise_inviter = dict(my_did=did_inviter,
                                their_did=did_invitee,
                                their_verkey=verkey_invitee,
                                metadata={
                                    'their_endpoint': invitee['endpoint_url'],
                                    'their_vk': verkey_invitee,
                                    'my_vk': verkey_inviter,
                                })
        resp = requests.post(url,
                             json=pairwise_inviter,
                             auth=HTTPBasicAuth(inviter['identity'],
                                                inviter['password']),
                             headers=headers)
        self.assertEqual(200, resp.status_code, resp.text)
        url = self.live_server_url + '/agent/admin/wallets/%s/pairwise/create_pairwise_statically/' % invitee[
            'wallet_uid']
        pairwise_invitee = dict(my_did=did_invitee,
                                their_did=did_inviter,
                                their_verkey=verkey_inviter,
                                metadata={
                                    'their_endpoint': inviter['endpoint_url'],
                                    'their_vk': verkey_inviter,
                                    'my_vk': verkey_invitee,
                                })
        resp = requests.post(url,
                             json=pairwise_invitee,
                             auth=HTTPBasicAuth(invitee['identity'],
                                                invitee['password']),
                             headers=headers)
        self.assertEqual(200, resp.status_code, resp.text)

        # Step 2: generate invitation link
        url = self.live_server_url + '/agent/admin/wallets/%s/endpoints/%s/invitations/ensure_exists/' % \
              (inviter['wallet_uid'], inviter['endpoint_uid'])
        invitation_kwargs = dict(**cred)
        invitation_kwargs['my_did'] = did_inviter
        invitation_kwargs['seed'] = 'invitation-seed'
        resp = requests.post(url,
                             json=invitation_kwargs,
                             auth=HTTPBasicAuth(inviter['identity'],
                                                inviter['password']))
        self.assertEqual(200, resp.status_code, resp.text)
        invite_url_string = resp.json()['url']
        print('Invitation LINK: %s' % invite_url_string)
        # Step 3: send invite to Invitee
        url = self.live_server_url + '/agent/admin/wallets/%s/endpoints/%s/invite/' % \
              (invitee['wallet_uid'], invitee['endpoint_uid'])
        invite = dict(**cred)
        invite['url'] = invite_url_string
        invite['my_did'] = did_invitee
        resp = requests.post(url,
                             json=invite,
                             auth=HTTPBasicAuth(invitee['identity'],
                                                invitee['password']))
        self.assertEqual(200, resp.status_code)
        log = resp.json()
        self.assertTrue(log)
        print('======== INVITE LOG =========')
        print(json.dumps(log, indent=2, sort_keys=True))
        print('===============================')

    def test_credential_propose(self):
        actor = dict(
            identity=self.IDENTITY_AGENT1,
            password=self.IDENTITY_PASS,
            wallet_uid=AgentAccount.objects.get(
                username=self.IDENTITY_AGENT1).wallets.first().uid,
        )
        url = self.live_server_url + '/agent/admin/wallets/%s/proving/propose_credential/' % actor[
            'wallet_uid']

        request = {
            'comment':
            'My Comment',
            'locale':
            'ru',
            'schema_id':
            'some-schema-id',
            'schema_name':
            'some-schema-name',
            'schema_version':
            '1.5',
            'schema_issuer_did':
            'some-issuer-did',
            'cred_def_id':
            'some-sred-def-id',
            'issuer_did':
            'some-issuer-did',
            'proposal_attrib': [{
                'name': 'attrib1',
                'value': 'value1'
            }, {
                'name':
                'attrib2',
                'mime_type':
                'image/pmg',
                'value':
                base64.b64encode('blablabla'.encode()).decode()
            }],
            'proposal_attrib_translation': [{
                'attrib_name': 'attrib1',
                'translation': 'Имя'
            }, {
                'attrib_name': 'attrib1',
                'translation': 'Аватар'
            }]
        }

        resp = requests.post(url,
                             json=request,
                             auth=HTTPBasicAuth(actor['identity'],
                                                actor['password']))
        self.assertEqual(200, resp.status_code, resp.text)
        message = resp.json()
        self.assertTrue(message)

    def test_issue_feature_0036_0037(self):
        # Setup issuer
        endpoint_issuer = AgentAccount.objects.get(
            username=self.IDENTITY_AGENT1).endpoints.first()
        endpoint_issuer.url = self.live_server_url + reverse(
            'endpoint',
            kwargs=dict(uid=AgentAccount.objects.get(
                username=self.IDENTITY_AGENT1).endpoints.first().uid))
        endpoint_issuer.save()
        issuer = dict(account=self.IDENTITY_AGENT1,
                      wallet=AgentAccount.objects.get(
                          username=self.IDENTITY_AGENT1).wallets.first().uid,
                      password=self.IDENTITY_PASS,
                      endpoint_uid=AgentAccount.objects.get(
                          username=self.IDENTITY_AGENT1).endpoints.first().uid,
                      endpoint_url=endpoint_issuer.url)
        # Setup holder
        endpoint_holder = AgentAccount.objects.get(
            username=self.IDENTITY_AGENT2).endpoints.first()
        endpoint_holder.url = self.live_server_url + reverse(
            'endpoint',
            kwargs=dict(uid=AgentAccount.objects.get(
                username=self.IDENTITY_AGENT2).endpoints.first().uid))
        endpoint_holder.save()
        holder = dict(account=self.IDENTITY_AGENT2,
                      wallet=AgentAccount.objects.get(
                          username=self.IDENTITY_AGENT2).wallets.first().uid,
                      password=self.IDENTITY_PASS,
                      endpoint_uid=AgentAccount.objects.get(
                          username=self.IDENTITY_AGENT2).endpoints.first().uid,
                      endpoint_url=endpoint_holder.url)
        # Setup DID, VerKeys and schemas
        trustee_seed = '000000000000000000000000Trustee1'
        did_issuer, verkey_issuer = self.create_did(issuer['wallet'],
                                                    trustee_seed)
        did_holder, verkey_holder = self.create_did(holder['wallet'])

        # Exchange pairwise dids
        run_async(
            self.register_pairwise(wallet_uid=issuer['wallet'],
                                   their_did=did_holder,
                                   their_vk=verkey_holder,
                                   my_did=did_issuer,
                                   my_vk=verkey_issuer,
                                   their_endpoint=holder['endpoint_url'],
                                   label='Holder'))
        run_async(
            self.register_pairwise(wallet_uid=holder['wallet'],
                                   their_did=did_issuer,
                                   their_vk=verkey_issuer,
                                   my_did=did_holder,
                                   my_vk=verkey_holder,
                                   their_endpoint=issuer['endpoint_url'],
                                   label='Issuer'))

        # Register schemas and cred defs
        schema = {
            'name': 'test_schema_' + uuid.uuid4().hex,
            'version': '1.2',
            'attributes': ["age", "sex", "height", "name"]
        }
        cred_def_id, cred_def_json, cred_def_request, schema = run_async(
            self.register_schema(issuer['wallet'], schema, did_issuer),
            timeout=30)

        # Issuer: start
        credential = dict(sex='male', name='Alex', height=175, age=28)
        cred_id = 'my-cred-id-' + uuid.uuid4().hex
        data = dict(cred_def=cred_def_json,
                    cred_def_id=cred_def_id,
                    issuer_schema=schema,
                    values=credential,
                    comment='My Comment',
                    locale='ru',
                    preview={'age': '28'},
                    translation={'age': 'Возраст'},
                    their_did=did_holder,
                    pass_phrase=self.WALLET_PASS_PHRASE,
                    cred_id=cred_id)
        url = self.live_server_url + '/agent/admin/wallets/%s/messaging/issue_credential/' % issuer[
            'wallet']
        resp = requests.post(url,
                             json=data,
                             auth=HTTPBasicAuth(issuer['account'],
                                                issuer['password']))
        self.assertEqual(resp.status_code, 200, resp.text)
        log = resp.json()
        self.assertTrue(log)
        print('------- LOG -----------')
        print(json.dumps(log, indent=2))
        print('------------------------')
        # Stop issuer state machine
        url = self.live_server_url + '/agent/admin/wallets/%s/messaging/stop_issue_credential/' % issuer[
            'wallet']
        data = dict(their_did=did_holder, pass_phrase=self.WALLET_PASS_PHRASE)
        resp = requests.post(url,
                             json=data,
                             auth=HTTPBasicAuth(issuer['account'],
                                                issuer['password']))
        self.assertTrue(400 >= resp.status_code < 500, resp.text)
        # Verify Proof OK
        print('------ Verify Proof OK ------')
        proof_request = {
            'nonce': '123432421212',
            'name': 'proof_req_1',
            'version': '0.1',
            'requested_attributes': {
                'attr1_referent': {
                    'name': 'name',
                    "restrictions": {
                        "issuer_did": did_issuer,
                        "schema_id": schema['id']
                    }
                }
            },
            'requested_predicates': {
                'predicate1_referent': {
                    'name': 'age',
                    'p_type': '>=',
                    'p_value': 18,
                    "restrictions": {
                        "issuer_did": did_issuer
                    }
                }
            }
        }
        data = dict(translation={
            'age': 'Возраст',
            'name': 'Имя'
        },
                    their_did=did_holder,
                    pass_phrase=self.WALLET_PASS_PHRASE,
                    proof_request=proof_request)
        url = self.live_server_url + '/agent/admin/wallets/%s/messaging/verify_proof/' % issuer[
            'wallet']
        print('>')
        resp = requests.post(url,
                             json=data,
                             auth=HTTPBasicAuth(issuer['account'],
                                                issuer['password']))
        print('<')
        self.assertEqual(resp.status_code, 200, resp.text)
        stat = resp.json()
        self.assertTrue(stat.get('success'))
        proof = stat.get('proof')
        print(json.dumps(proof, indent=2, sort_keys=True))
        self.assertEqual(
            'Alex',
            str(proof['requested_proof']['revealed_attrs']['attr1_referent']
                ['raw']))

    def test_issue_feature_0036_0037_verify_error(self):
        # Setup issuer
        endpoint_issuer = AgentAccount.objects.get(
            username=self.IDENTITY_AGENT1).endpoints.first()
        endpoint_issuer.url = self.live_server_url + reverse(
            'endpoint',
            kwargs=dict(uid=AgentAccount.objects.get(
                username=self.IDENTITY_AGENT1).endpoints.first().uid))
        endpoint_issuer.save()
        issuer = dict(account=self.IDENTITY_AGENT1,
                      wallet=AgentAccount.objects.get(
                          username=self.IDENTITY_AGENT1).wallets.first().uid,
                      password=self.IDENTITY_PASS,
                      endpoint_uid=AgentAccount.objects.get(
                          username=self.IDENTITY_AGENT1).endpoints.first().uid,
                      endpoint_url=endpoint_issuer.url)
        # Setup holder
        endpoint_holder = AgentAccount.objects.get(
            username=self.IDENTITY_AGENT2).endpoints.first()
        endpoint_holder.url = self.live_server_url + reverse(
            'endpoint',
            kwargs=dict(uid=AgentAccount.objects.get(
                username=self.IDENTITY_AGENT2).endpoints.first().uid))
        endpoint_holder.save()
        holder = dict(account=self.IDENTITY_AGENT2,
                      wallet=AgentAccount.objects.get(
                          username=self.IDENTITY_AGENT2).wallets.first().uid,
                      password=self.IDENTITY_PASS,
                      endpoint_uid=AgentAccount.objects.get(
                          username=self.IDENTITY_AGENT2).endpoints.first().uid,
                      endpoint_url=endpoint_holder.url)
        # Setup DID, VerKeys and schemas
        trustee_seed = '000000000000000000000000Trustee1'
        did_issuer, verkey_issuer = self.create_did(issuer['wallet'],
                                                    trustee_seed)
        did_holder, verkey_holder = self.create_did(holder['wallet'])

        # Exchange pairwise dids
        run_async(
            self.register_pairwise(wallet_uid=issuer['wallet'],
                                   their_did=did_holder,
                                   their_vk=verkey_holder,
                                   my_did=did_issuer,
                                   my_vk=verkey_issuer,
                                   their_endpoint=holder['endpoint_url'],
                                   label='Holder'))
        run_async(
            self.register_pairwise(wallet_uid=holder['wallet'],
                                   their_did=did_issuer,
                                   their_vk=verkey_issuer,
                                   my_did=did_holder,
                                   my_vk=verkey_holder,
                                   their_endpoint=issuer['endpoint_url'],
                                   label='Issuer'))

        # Register schemas and cred defs
        schema = {
            'name': 'test_schema_' + uuid.uuid4().hex,
            'version': '1.0',
            'attributes': ["age", "sex", "height", "name"]
        }
        cred_def_id, cred_def_json, cred_def_request, schema = run_async(
            self.register_schema(issuer['wallet'], schema, did_issuer),
            timeout=30)

        # Issuer: start
        credential = dict(sex='male', name='Alex', height=175, age=28)
        data = dict(cred_def=cred_def_json,
                    cred_def_id=cred_def_id,
                    issuer_schema=schema,
                    values=credential,
                    comment='My Comment',
                    locale='ru',
                    preview={'age': '28'},
                    translation={'age': 'Возраст'},
                    their_did=did_holder,
                    pass_phrase=self.WALLET_PASS_PHRASE)
        url = self.live_server_url + '/agent/admin/wallets/%s/messaging/issue_credential/' % issuer[
            'wallet']
        resp = requests.post(url,
                             json=data,
                             auth=HTTPBasicAuth(issuer['account'],
                                                issuer['password']))
        self.assertEqual(resp.status_code, 200, resp.text)
        log = resp.json()
        self.assertTrue(log)
        print('------- LOG -----------')
        print(json.dumps(log, indent=2))
        print('------------------------')
        # Stop issuer state machine
        url = self.live_server_url + '/agent/admin/wallets/%s/messaging/stop_issue_credential/' % issuer[
            'wallet']
        data = dict(their_did=did_holder, pass_phrase=self.WALLET_PASS_PHRASE)
        resp = requests.post(url,
                             json=data,
                             auth=HTTPBasicAuth(issuer['account'],
                                                issuer['password']))
        self.assertTrue(400 >= resp.status_code < 500, resp.text)
        # Verify Proof Error
        print('------ Verify Proof Error ------')
        proof_request = {
            'nonce': '123432421212',
            'name': 'proof_req_2',
            'version': '0.1',
            'requested_attributes': {
                'attr1_referent': {
                    'name': 'name',
                    "restrictions": {
                        "issuer_did": did_issuer,
                        "schema_id": schema['id']
                    }
                },
                'attr2_referent': {
                    'name': 'name-invalid'
                }
            }
        }
        data = dict(their_did=did_holder,
                    pass_phrase=self.WALLET_PASS_PHRASE,
                    proof_request=proof_request)
        url = self.live_server_url + '/agent/admin/wallets/%s/messaging/verify_proof/' % issuer[
            'wallet']
        print('>')
        resp = requests.post(url,
                             json=data,
                             auth=HTTPBasicAuth(issuer['account'],
                                                issuer['password']))
        print('<')
        self.assertEqual(resp.status_code, 200, resp.text)
        stat = resp.json()
        self.assertFalse(stat.get('success'))
def remove_agent_databases(*names):
    with connection.cursor() as cursor:
        for name in names:
            db_name = WalletConnection.make_wallet_address(name)
            cursor.execute("DROP DATABASE  IF EXISTS %s" % db_name)
class Agent2AgentCommunicationTest(LiveServerTestCase):

    IDENTITY_AGENT1 = 'agent1_user'
    IDENTITY_AGENT2 = 'agent2_user'
    IDENTITY_PASS = '******'
    WALLET_AGENT1 = 'wallet_1'
    WALLET_AGENT2 = 'wallet_2'
    WALLET_PASS_PHRASE = 'pass'
    WALLET_AGENT1_DB_NAME = WalletConnection.make_wallet_address(WALLET_AGENT1)
    WALLET_AGENT2_DB_NAME = WalletConnection.make_wallet_address(WALLET_AGENT2)
    DEF_TIMEOUT = 5

    def setUp(self):
        for identity in [self.IDENTITY_AGENT1, self.IDENTITY_AGENT2]:
            account = AgentAccount.objects.create(username=identity,
                                                  is_active=True,
                                                  is_staff=True)
            account.set_password(self.IDENTITY_PASS)
            account.save()
        os.popen("pkill -f run_wallet_agent")
        sleep(0.1)
        psax = get_ps_ax()
        self.assertNotIn('run_wallet_agent', psax, psax)
        with connection.cursor() as cursor:
            for db_name in [
                    self.WALLET_AGENT1_DB_NAME, self.WALLET_AGENT2_DB_NAME
            ]:
                cursor.execute("DROP DATABASE  IF EXISTS %s" % db_name)
        self.agents = []
        self.agents_logs = dict()
        self.agents_logs[self.IDENTITY_AGENT1] = list()
        self.agents_logs[self.IDENTITY_AGENT2] = list()
        self.start_agents()

    def tearDown(self):
        self.stop_agents()
        sleep(1)
        os.popen("pkill -f run_wallet_agent")
        sleep(1)

    def start_agents(self):
        async def start_agent(agent_name, pass_phrase):
            conn = WalletConnection(agent_name, pass_phrase)
            await conn.create()
            try:
                print('Agent "%s" is started' % agent_name)
                await WalletAgent.process(agent_name)
            finally:
                await conn.delete()
                print('Wallet "%s" is deleted' % agent_name)

        for agent, identity in [(self.WALLET_AGENT1, self.IDENTITY_AGENT1),
                                (self.WALLET_AGENT2, self.IDENTITY_AGENT2)]:
            thread = ThreadScheduler()
            self.agents.append(thread)
            thread.start()
            asyncio.run_coroutine_threadsafe(start_agent(
                agent, self.WALLET_PASS_PHRASE),
                                             loop=thread.loop)
            account = AgentAccount.objects.get(username=identity)
            model_wallet = WalletModel.objects.create(uid=agent, owner=account)
            endpoint_uid = 'endpoint_for_' + agent
            EndpointModel.objects.create(uid=endpoint_uid,
                                         owner=account,
                                         wallet=model_wallet,
                                         url=reverse(
                                             'endpoint',
                                             kwargs=dict(uid=endpoint_uid)))

        sleep(10)

    pass

    def stop_agents(self):
        async def stop_agent(agent_name, pass_phrase):
            try:
                await WalletAgent.close(agent_name, pass_phrase)
            except AgentTimeOutError:
                pass

        for agent in [self.WALLET_AGENT1, self.WALLET_AGENT2]:
            run_async(stop_agent(agent, self.WALLET_PASS_PHRASE))
        sleep(5)
        for thread in self.agents:
            thread.stop()

    pass

    def create_did(self, wallet_uid: str, seed: str = None):
        run_async(WalletAgent.open(wallet_uid, self.WALLET_PASS_PHRASE))
        did, verkey = run_async(
            WalletAgent.create_and_store_my_did(wallet_uid,
                                                self.WALLET_PASS_PHRASE, seed))
        run_async(
            WalletAgent.add_wallet_record(wallet_uid, self.WALLET_PASS_PHRASE,
                                          WALLET_KEY_TO_DID_KEY, verkey, did))
        return did, verkey

    async def register_schema(self, wallet_uid: str, schema: dict, did: str):
        await WalletAgent.open(wallet_uid, self.WALLET_PASS_PHRASE)
        schema_request, schema_json = await WalletAgent.build_schema_request(
            wallet_uid, self.WALLET_PASS_PHRASE, did, schema['name'],
            schema['version'], schema['attributes'])
        schema_response = await WalletAgent.sign_and_submit_request(
            wallet_uid, self.WALLET_PASS_PHRASE, did, schema_request)
        assert schema_response['op'] == 'REPLY'

        cred_def_id, cred_def_json, cred_def_request, schema = await WalletAgent.issuer_create_credential_def(
            wallet_uid, self.WALLET_PASS_PHRASE, did, schema_json['id'], 'TAG',
            False)
        return cred_def_id, cred_def_json, cred_def_request, schema

    async def register_pairwise(self, wallet_uid: str, their_did: str,
                                my_did: str, their_vk: str, my_vk: str,
                                their_endpoint: str, label: str):
        metadata = {
            'label': label,
            'their_endpoint': their_endpoint,
            'their_vk': their_vk,
            'my_vk': my_vk,
        }
        await WalletAgent.create_pairwise_statically(wallet_uid,
                                                     self.WALLET_PASS_PHRASE,
                                                     their_did, their_vk,
                                                     my_did, metadata)

    @skip(True)
    def test_demo_issuer__feature_0037(self):
        """Тест на проблмы верификации credentials Android агента по feature 0037"""
        # Setup issuer
        endpoint_issuer = AgentAccount.objects.get(
            username=self.IDENTITY_AGENT1).endpoints.first()
        endpoint_issuer.url = self.live_server_url + reverse(
            'endpoint',
            kwargs=dict(uid=AgentAccount.objects.get(
                username=self.IDENTITY_AGENT1).endpoints.first().uid))
        endpoint_issuer.save()
        issuer = dict(account=self.IDENTITY_AGENT1,
                      wallet=AgentAccount.objects.get(
                          username=self.IDENTITY_AGENT1).wallets.first().uid,
                      password=self.IDENTITY_PASS,
                      endpoint_uid=AgentAccount.objects.get(
                          username=self.IDENTITY_AGENT1).endpoints.first().uid,
                      endpoint_url=endpoint_issuer.url)
        # Setup holder
        endpoint_holder = AgentAccount.objects.get(
            username=self.IDENTITY_AGENT2).endpoints.first()
        endpoint_holder.url = self.live_server_url + reverse(
            'endpoint',
            kwargs=dict(uid=AgentAccount.objects.get(
                username=self.IDENTITY_AGENT2).endpoints.first().uid))
        endpoint_holder.save()
        holder = dict(account=self.IDENTITY_AGENT2,
                      wallet=AgentAccount.objects.get(
                          username=self.IDENTITY_AGENT2).wallets.first().uid,
                      password=self.IDENTITY_PASS,
                      endpoint_uid=AgentAccount.objects.get(
                          username=self.IDENTITY_AGENT2).endpoints.first().uid,
                      endpoint_url=endpoint_holder.url)
        # Setup DID, VerKeys and schemas
        issuer_seed = '000000000000000000000000Steward1'
        holder_seed = '00000000000000000000000000Holder'
        did_issuer, verkey_issuer = self.create_did(issuer['wallet'],
                                                    issuer_seed)
        did_holder, verkey_holder = self.create_did(holder['wallet'],
                                                    holder_seed)

        # Exchange pairwise dids
        run_async(
            self.register_pairwise(wallet_uid=issuer['wallet'],
                                   their_did=did_holder,
                                   their_vk=verkey_holder,
                                   my_did=did_issuer,
                                   my_vk=verkey_issuer,
                                   their_endpoint=holder['endpoint_url'],
                                   label='Holder'))
        run_async(
            self.register_pairwise(wallet_uid=holder['wallet'],
                                   their_did=did_issuer,
                                   their_vk=verkey_issuer,
                                   my_did=did_holder,
                                   my_vk=verkey_holder,
                                   their_endpoint=issuer['endpoint_url'],
                                   label='Issuer'))
        # Load schema and cred-defs meta
        path = '/agent/admin/wallets/demo_issuer/did/%s/ledger/schemas/' % did_issuer
        resp = get_indy_agent(path)
        assert resp.status_code == 200
        print('=========== SCHEMAS ============')
        print(json.dumps(resp.json(), indent=2, sort_keys=True))
        print('================================')
        registered_schema = list(
            filter(
                lambda s: s['name'] == 'Transcript' and s['version'] == '1.2',
                resp.json()))[0]
        resp = get_indy_agent(
            '/agent/admin/wallets/demo_issuer/did/%s/cred_def/all/' %
            did_issuer)
        assert resp.status_code == 200
        print('=========== CRED-DEFs ============')
        print(json.dumps(resp.json(), indent=2, sort_keys=True))
        print('================================')
        registered_creddef = list(
            filter(lambda cd: cd['schema']['id'] == registered_schema['id'],
                   resp.json()))[0]
        credential = dict(birthday='Value for birthday',
                          ssn='Value for ssn',
                          first_name='Value for first_name',
                          last_name='Value for last_name')
        params = dict(cred_def_id=registered_creddef['id'],
                      cred_def=registered_creddef['cred_def'],
                      issuer_schema=registered_schema,
                      their_did=did_holder,
                      values=credential,
                      pass_phrase='pass')
        cred_req_meta = run_async(
            WalletAgent.issuer_create_credential_def(
                agent_name=issuer['wallet'],
                pass_phrase=self.WALLET_PASS_PHRASE,
                self_did=did_issuer,
                schema_id=registered_schema['id'],
                tag='DEMO',
                support_revocation=False))
        url = self.live_server_url + '/agent/admin/wallets/%s/messaging/issue_credential/' % issuer[
            'wallet']
        resp = requests.post(url,
                             json=params,
                             auth=HTTPBasicAuth(issuer['account'],
                                                issuer['password']))
        self.assertEqual(resp.status_code, 200, resp.text)
        log = resp.json()
        self.assertTrue(log)
        print('------- LOG -----------')
        print(json.dumps(log, indent=2))
        print('------------------------')
Exemple #16
0
class MessagingTest(LiveServerTestCase):

    IDENTITY1 = 'test1'
    IDENTITY2 = 'test2'
    IDENTITY3 = 'test3'
    PASS = '******'
    WALLET1_UID = 'test_wallet_uid_1'
    WALLET2_UID = 'test_wallet_uid_2'
    WALLET3_UID = 'test_wallet_uid_3'
    WALLET_PASS_PHRASE = 'pass'
    WALLET1_DB_NAME = WalletConnection.make_wallet_address(WALLET1_UID)
    WALLET2_DB_NAME = WalletConnection.make_wallet_address(WALLET2_UID)
    WALLET3_DB_NAME = WalletConnection.make_wallet_address(WALLET3_UID)
    DEF_TIMEOUT = 5

    def setUp(self):
        self.account1 = AgentAccount.objects.create(username=self.IDENTITY1,
                                                    is_active=True,
                                                    is_staff=True)
        self.account1.set_password(self.PASS)
        self.account1.save()
        self.account2 = AgentAccount.objects.create(username=self.IDENTITY2,
                                                    is_active=True,
                                                    is_staff=True)
        self.account2.set_password(self.PASS)
        self.account2.save()
        self.account3 = AgentAccount.objects.create(username=self.IDENTITY3,
                                                    is_active=True,
                                                    is_staff=True)
        self.account3.set_password(self.PASS)
        self.account3.save()
        os.popen("pkill -f run_wallet_agent")
        sleep(0.1)
        psax = get_ps_ax()
        self.assertNotIn('run_wallet_agent', psax, psax)
        with connection.cursor() as cursor:
            cursor.execute("DROP DATABASE  IF EXISTS %s" %
                           self.WALLET1_DB_NAME)
            cursor.execute("DROP DATABASE  IF EXISTS %s" %
                           self.WALLET2_DB_NAME)
            cursor.execute("DROP DATABASE  IF EXISTS %s" %
                           self.WALLET3_DB_NAME)

    def create_and_open_wallet(self, wallet_uid: str, account: str):
        # create
        cred = dict(uid=wallet_uid, pass_phrase=self.WALLET_PASS_PHRASE)
        url = self.live_server_url + reverse('admin-wallets-list')
        resp = requests.post(url,
                             json=cred,
                             auth=HTTPBasicAuth(account, self.PASS))
        self.assertEqual(201, resp.status_code)
        # open
        cred = dict(pass_phrase=self.WALLET_PASS_PHRASE)
        url = self.live_server_url + reverse('admin-wallets-open',
                                             kwargs=dict(uid=wallet_uid))
        resp = requests.post(url,
                             json=cred,
                             auth=HTTPBasicAuth(account, self.PASS))
        self.assertEqual(200, resp.status_code)
        url = self.live_server_url + reverse('admin-wallets-is-open',
                                             kwargs=dict(uid=wallet_uid))
        resp = requests.get(url, auth=HTTPBasicAuth(account, self.PASS))
        self.assertEqual(200, resp.status_code)

    def close_and_delete_wallet(self, wallet_uid: str, account: str):
        cred = dict(pass_phrase=self.WALLET_PASS_PHRASE)
        # close
        url = self.live_server_url + reverse('admin-wallets-close',
                                             kwargs=dict(uid=wallet_uid))
        resp = requests.post(url,
                             json=cred,
                             auth=HTTPBasicAuth(account, self.PASS))
        self.assertEqual(200, resp.status_code)
        # destroy
        url = self.live_server_url + reverse('admin-wallets-detail',
                                             kwargs=dict(uid=wallet_uid))
        resp = requests.delete(url,
                               json=cred,
                               auth=HTTPBasicAuth(account, self.PASS))
        self.assertEqual(204, resp.status_code)

    def ensure_did_exists(self, account: str, wallet_uid: str, seed: str):
        url = self.live_server_url + '/agent/admin/wallets/%s/did/create_and_store_my_did/' % wallet_uid
        cred = dict(pass_phrase=self.WALLET_PASS_PHRASE, seed=seed)
        resp = requests.post(url,
                             json=cred,
                             auth=HTTPBasicAuth(account, self.PASS))
        self.assertEqual(201, resp.status_code)
        info = resp.json()
        return info['did'], info['verkey']

    def create_did(self, account: str, wallet_uid: str):
        url = self.live_server_url + '/agent/admin/wallets/%s/did/create_and_store_my_did/' % wallet_uid
        cred = dict(pass_phrase=self.WALLET_PASS_PHRASE)
        resp = requests.post(url,
                             json=cred,
                             auth=HTTPBasicAuth(account, self.PASS))
        self.assertEqual(201, resp.status_code)
        info = resp.json()
        return info['did'], info['verkey']

    def test_create_pairwise_statically(self):
        headers = dict()
        headers[HEADER_PASS_PHRASE] = self.WALLET_PASS_PHRASE
        account_1 = self.IDENTITY1
        account_2 = self.IDENTITY2
        wallet_1 = self.WALLET1_UID
        wallet_2 = self.WALLET2_UID
        self.create_and_open_wallet(wallet_1, account_1)
        self.create_and_open_wallet(wallet_2, account_2)
        try:
            did_1, verkey_1 = self.create_did(account_1, wallet_1)
            did_2, verkey_2 = self.create_did(account_2, wallet_2)
            url = self.live_server_url + '/agent/admin/wallets/%s/pairwise/create_pairwise_statically/' % wallet_1
            #
            pairwise = dict(my_did=did_1,
                            their_did=did_2,
                            their_verkey=verkey_2,
                            metadata=dict(x=1, y=2, z='123'))
            resp = requests.post(url,
                                 json=pairwise,
                                 auth=HTTPBasicAuth(account_1, self.PASS),
                                 headers=headers)
            self.assertEqual(200, resp.status_code, resp.text)
            # check pairwise list
            url = self.live_server_url + '/agent/admin/wallets/%s/pairwise/all/' % wallet_1
            resp = requests.post(url,
                                 auth=HTTPBasicAuth(account_1, self.PASS),
                                 headers=headers)
            self.assertEqual(200, resp.status_code)
            ret = resp.json()
            self.assertEqual(1, len(ret))
            actual = ret[0]
            self.assertEqual(actual['my_did'], pairwise['my_did'])
            self.assertEqual(actual['their_did'], pairwise['their_did'])
            self.assertEqual(actual['metadata'], pairwise['metadata'])
            # check did for key
            url = self.live_server_url + '/agent/admin/wallets/%s/pairwise/did_for_key/' % wallet_1
            resp = requests.post(url,
                                 json=dict(their_verkey=verkey_2),
                                 auth=HTTPBasicAuth(account_1, self.PASS),
                                 headers=headers)
            self.assertEqual(200, resp.status_code)
            their_did = resp.json()
            self.assertEqual(their_did, did_2)
            # check metadata
            url = self.live_server_url + '/agent/admin/wallets/%s/pairwise/get_metadata/' % wallet_1
            resp = requests.post(url,
                                 json=dict(their_did=did_2),
                                 auth=HTTPBasicAuth(account_1, self.PASS),
                                 headers=headers)
            self.assertEqual(200, resp.status_code)
            their = resp.json()
            self.assertEqual(their['metadata'], pairwise['metadata'])
        finally:
            self.close_and_delete_wallet(wallet_1, account_1)
            self.close_and_delete_wallet(wallet_2, account_2)
    def test_invitation_ensure_exists(self):
        conn = WalletConnection(self.WALLET_UID, self.WALLET_PASS_PHRASE)
        wallet = Wallet.objects.create(uid=self.WALLET_UID, owner=self.account)
        endpoint = Endpoint.objects.create(uid='endpoint_uid',
                                           owner=self.account,
                                           wallet=wallet,
                                           url='http://example.com/endpoint')
        # first: create wallet
        run_async(conn.create())
        run_async(conn.open())
        my_did, my_verkey = run_async(conn.create_and_store_my_did())
        run_async(conn.close())
        try:
            seed = 'blablabla-seed-'
            expected_key = '3XvPjB4EDpmBBF4sRmqVbrQXQY5vk7zjiggSCGxSkPpV'
            cred = dict(pass_phrase=self.WALLET_PASS_PHRASE, seed=seed)
            url = self.live_server_url + '/agent/admin/wallets/%s/endpoints/%s/invitations/ensure_exists/' % (
                self.WALLET_UID, endpoint.uid)
            resp = requests.post(url,
                                 json=cred,
                                 auth=HTTPBasicAuth(self.IDENTITY, self.PASS))
            self.assertEqual(200, resp.status_code)
            i1 = resp.json()

            instance = Invitation.objects.get(endpoint=endpoint)
            self.assertEqual(seed, instance.seed)
            self.assertEqual(expected_key, instance.connection_key)
            self.assertIsNone(instance.my_did)
            resp = requests.post(url,
                                 json=cred,
                                 auth=HTTPBasicAuth(self.IDENTITY, self.PASS))
            self.assertEqual(200, resp.status_code)
            i2 = resp.json()

            self.assertEqual(
                1,
                Invitation.objects.filter(connection_key=expected_key).count())

            matches = re.match("(.+)?c_i=(.+)", i1['url'])
            invite_msg1 = Serializer.deserialize(
                base64.urlsafe_b64decode(
                    matches.group(2)).decode('utf-8')).to_dict()
            del invite_msg1['@id']
            matches = re.match("(.+)?c_i=(.+)", i2['url'])
            invite_msg2 = Serializer.deserialize(
                base64.urlsafe_b64decode(
                    matches.group(2)).decode('utf-8')).to_dict()
            del invite_msg2['@id']
            self.assertDictEqual(invite_msg1, invite_msg2)

            cred['my_did'] = my_did
            resp = requests.post(url,
                                 json=cred,
                                 auth=HTTPBasicAuth(self.IDENTITY, self.PASS))
            self.assertEqual(200, resp.status_code)
            instance = Invitation.objects.get(endpoint=endpoint)
            self.assertEqual(my_did, instance.my_did)

            self.assertEqual(1, Invitation.objects.count())
            cred = dict(pass_phrase=self.WALLET_PASS_PHRASE,
                        seed=seed + 'salt')
            resp = requests.post(url,
                                 json=cred,
                                 auth=HTTPBasicAuth(self.IDENTITY, self.PASS))
            self.assertEqual(200, resp.status_code)
            self.assertEqual(2, Invitation.objects.count())
        finally:
            os.popen("pkill -f run_wallet_agent")
            sleep(1)
            run_async(conn.delete())
class LedgerTest(LiveServerTestCase):

    IDENTITY1 = 'test1'
    IDENTITY2 = 'test2'
    IDENTITY3 = 'test3'
    PASS = '******'
    WALLET1_UID = 'test_wallet_uid_1'
    WALLET2_UID = 'test_wallet_uid_2'
    WALLET3_UID = 'test_wallet_uid_3'
    WALLET_PASS_PHRASE = 'pass'
    WALLET1_DB_NAME = WalletConnection.make_wallet_address(WALLET1_UID)
    WALLET2_DB_NAME = WalletConnection.make_wallet_address(WALLET2_UID)
    WALLET3_DB_NAME = WalletConnection.make_wallet_address(WALLET3_UID)
    DEF_TIMEOUT = 5

    def setUp(self):
        self.account1 = AgentAccount.objects.create(username=self.IDENTITY1,
                                                    is_active=True,
                                                    is_staff=True)
        self.account1.set_password(self.PASS)
        self.account1.save()
        self.account2 = AgentAccount.objects.create(username=self.IDENTITY2,
                                                    is_active=True,
                                                    is_staff=True)
        self.account2.set_password(self.PASS)
        self.account2.save()
        self.account3 = AgentAccount.objects.create(username=self.IDENTITY3,
                                                    is_active=True,
                                                    is_staff=True)
        self.account3.set_password(self.PASS)
        self.account3.save()
        os.popen("pkill -f run_wallet_agent")
        sleep(0.1)
        psax = get_ps_ax()
        self.assertNotIn('run_wallet_agent', psax, psax)
        with connection.cursor() as cursor:
            cursor.execute("DROP DATABASE  IF EXISTS %s" %
                           self.WALLET1_DB_NAME)
            cursor.execute("DROP DATABASE  IF EXISTS %s" %
                           self.WALLET2_DB_NAME)
            cursor.execute("DROP DATABASE  IF EXISTS %s" %
                           self.WALLET3_DB_NAME)

    def create_and_open_wallet(self, wallet_uid: str, account: str):
        # create
        cred = dict(uid=wallet_uid, pass_phrase=self.WALLET_PASS_PHRASE)
        url = self.live_server_url + reverse('admin-wallets-list')
        resp = requests.post(url,
                             json=cred,
                             auth=HTTPBasicAuth(account, self.PASS))
        self.assertEqual(201, resp.status_code)
        # open
        cred = dict(pass_phrase=self.WALLET_PASS_PHRASE)
        url = self.live_server_url + reverse('admin-wallets-open',
                                             kwargs=dict(uid=wallet_uid))
        resp = requests.post(url,
                             json=cred,
                             auth=HTTPBasicAuth(account, self.PASS))
        self.assertEqual(200, resp.status_code)
        url = self.live_server_url + reverse('admin-wallets-is-open',
                                             kwargs=dict(uid=wallet_uid))
        resp = requests.get(url, auth=HTTPBasicAuth(account, self.PASS))
        self.assertEqual(200, resp.status_code)

    def close_and_delete_wallet(self, wallet_uid: str, account: str):
        cred = dict(pass_phrase=self.WALLET_PASS_PHRASE)
        # close
        url = self.live_server_url + reverse('admin-wallets-close',
                                             kwargs=dict(uid=wallet_uid))
        resp = requests.post(url,
                             json=cred,
                             auth=HTTPBasicAuth(account, self.PASS))
        self.assertEqual(200, resp.status_code)
        # destroy
        url = self.live_server_url + reverse('admin-wallets-detail',
                                             kwargs=dict(uid=wallet_uid))
        resp = requests.delete(url,
                               json=cred,
                               auth=HTTPBasicAuth(account, self.PASS))
        self.assertEqual(204, resp.status_code)

    def ensure_did_exists(self, account: str, wallet_uid: str, seed: str):
        url = self.live_server_url + '/agent/admin/wallets/%s/did/create_and_store_my_did/' % wallet_uid
        cred = dict(pass_phrase=self.WALLET_PASS_PHRASE, seed=seed)
        resp = requests.post(url,
                             json=cred,
                             auth=HTTPBasicAuth(account, self.PASS))
        self.assertEqual(201, resp.status_code)
        info = resp.json()
        return info['did'], info['verkey']

    def create_did(self, account: str, wallet_uid: str):
        url = self.live_server_url + '/agent/admin/wallets/%s/did/create_and_store_my_did/' % wallet_uid
        cred = dict(pass_phrase=self.WALLET_PASS_PHRASE)
        resp = requests.post(url,
                             json=cred,
                             auth=HTTPBasicAuth(account, self.PASS))
        self.assertEqual(201, resp.status_code)
        info = resp.json()
        return info['did'], info['verkey']

    def test_send_nym_request(self):
        account_steward = self.IDENTITY1
        account_trustee = self.IDENTITY2
        wallet_steward = self.WALLET1_UID
        wallet_trustee = self.WALLET2_UID
        self.create_and_open_wallet(wallet_steward, account_steward)
        self.create_and_open_wallet(wallet_trustee, account_trustee)
        try:
            did_steward, verkey_steward = self.ensure_did_exists(
                account_steward, wallet_steward,
                '000000000000000000000000Steward1')
            did_trustee, verkey_trustee = self.create_did(
                account_trustee, wallet_trustee)

            url = self.live_server_url + '/agent/admin/wallets/%s/did/%s/ledger/nym_request/' % (
                wallet_steward, did_steward)
            entity = dict(target_did=did_trustee,
                          ver_key=verkey_trustee,
                          role='TRUST_ANCHOR',
                          pass_phrase=self.WALLET_PASS_PHRASE)
            resp = requests.post(url,
                                 json=entity,
                                 auth=HTTPBasicAuth(account_steward,
                                                    self.PASS))
            self.assertEqual(200, resp.status_code)
            self.assertTrue(resp.json())

            resp = requests.post(url,
                                 json=entity,
                                 auth=HTTPBasicAuth(account_steward,
                                                    self.PASS))
            self.assertEqual(400, resp.status_code)
            self.assertIn(
                'STEWARD can not touch role field since only the owner can modify',
                resp.text)

            # retrieve
            url = self.live_server_url + '/agent/admin/wallets/%s/did/%s/ledger/retrieve_did/' % (
                wallet_steward, did_steward)
            get_nym = dict(did=did_trustee,
                           pass_phrase=self.WALLET_PASS_PHRASE)
            resp = requests.post(url,
                                 json=get_nym,
                                 auth=HTTPBasicAuth(account_steward,
                                                    self.PASS))
            self.assertEqual(200, resp.status_code, resp.text)
            self.assertTrue(resp.json())
        finally:
            self.close_and_delete_wallet(wallet_steward, account_steward)
            self.close_and_delete_wallet(wallet_trustee, account_trustee)

    def test_set_get_attributes(self):
        account_steward = self.IDENTITY1
        wallet_steward = self.WALLET1_UID
        account_owner = self.IDENTITY2
        wallet_owner = self.WALLET2_UID
        account_reader = self.IDENTITY3
        wallet_reader = self.WALLET3_UID
        self.create_and_open_wallet(wallet_steward, account_steward)
        self.create_and_open_wallet(wallet_owner, account_owner)
        self.create_and_open_wallet(wallet_reader, account_reader)
        try:
            # initialize Steward
            did_steward, verkey_steward = self.ensure_did_exists(
                account_steward, wallet_steward,
                '000000000000000000000000Steward1')
            # Owner
            did_owner, verkey_owner = self.create_did(account_owner,
                                                      wallet_owner)
            url = self.live_server_url + '/agent/admin/wallets/%s/did/%s/ledger/nym_request/' % (
                wallet_steward, did_steward)
            entity = dict(target_did=did_owner,
                          ver_key=verkey_owner,
                          role=None,
                          pass_phrase=self.WALLET_PASS_PHRASE)
            resp = requests.post(url,
                                 json=entity,
                                 auth=HTTPBasicAuth(account_steward,
                                                    self.PASS))
            self.assertEqual(200, resp.status_code, resp.text)
            self.assertTrue(resp.json())
            # Owner set attribute
            url = self.live_server_url + '/agent/admin/wallets/%s/did/%s/ledger/set_attribute/' % (
                wallet_owner, did_owner)
            set_attrib_entity = dict(
                name='service',
                target_did=did_owner,
                pass_phrase=self.WALLET_PASS_PHRASE,
                value=[{
                    "id": "did:example:123456789abcdefghi#openid",
                    "type": "OpenIdConnectVersion1.0Service",
                    "serviceEndpoint": "https://openid.example.com/"
                }, {
                    "id": "did:example:123456789abcdefghi#agent",
                    "type": "AgentService",
                    "serviceEndpoint": "https://agent.example.com/8377464"
                }])
            resp = requests.post(url,
                                 json=set_attrib_entity,
                                 auth=HTTPBasicAuth(account_owner, self.PASS))
            self.assertEqual(200, resp.status_code, resp.text)
            self.assertTrue(resp.json())
            # Reader check
            did_reader, verkey_reader = self.create_did(
                account_reader, wallet_reader)
            url = self.live_server_url + '/agent/admin/wallets/%s/did/%s/ledger/get_attribute/' % (
                wallet_reader, did_reader)
            get_attrib_entity = dict(
                name='service',
                target_did=did_owner,
                pass_phrase=self.WALLET_PASS_PHRASE,
            )
            resp = requests.post(url,
                                 json=get_attrib_entity,
                                 auth=HTTPBasicAuth(account_reader, self.PASS))
            self.assertEqual(200, resp.status_code, resp.text)
            self.assertTrue(resp.json())
            raw = json.dumps(resp.json())
            for value in set_attrib_entity['value']:
                self.assertIn(value['id'], raw)
        finally:
            self.close_and_delete_wallet(wallet_steward, account_steward)
            self.close_and_delete_wallet(wallet_owner, account_owner)
            self.close_and_delete_wallet(wallet_reader, account_reader)

    def test_register_schema(self):
        account_steward = self.IDENTITY1
        wallet_steward = self.WALLET1_UID
        self.create_and_open_wallet(wallet_steward, account_steward)
        try:
            did_steward, verkey_steward = self.ensure_did_exists(
                account_steward, wallet_steward,
                '000000000000000000000000Steward1')
            schema = {
                'pass_phrase': self.WALLET_PASS_PHRASE,
                'name': 'test_schema_' + uuid.uuid4().hex,
                'version': '1.0',
                'attributes': ["age", "sex", "height", "name"]
            }
            url = self.live_server_url + '/agent/admin/wallets/%s/did/%s/ledger/register_schema/' % (
                wallet_steward, did_steward)
            resp = requests.post(url,
                                 json=schema,
                                 auth=HTTPBasicAuth(account_steward,
                                                    self.PASS))
            self.assertEqual(201, resp.status_code)
            self.assertTrue(resp.json())
            schema_id = resp.json()['schema']['id']

            resp = requests.post(url,
                                 json=schema,
                                 auth=HTTPBasicAuth(account_steward,
                                                    self.PASS))
            self.assertEqual(409, resp.status_code)

            # query schemas
            url = self.live_server_url + '/agent/admin/wallets/%s/did/%s/ledger/schemas/' % (
                wallet_steward, did_steward)
            resp = requests.get(url,
                                auth=HTTPBasicAuth(account_steward, self.PASS))
            raw = json.dumps(resp.json())
            self.assertIn(schema_id, raw)
        finally:
            self.close_and_delete_wallet(wallet_steward, account_steward)

    def test_create_and_send_credential_def(self):
        account_steward = self.IDENTITY1
        wallet_steward = self.WALLET1_UID
        account_issuer = self.IDENTITY2
        wallet_issuer = self.WALLET2_UID
        self.create_and_open_wallet(wallet_steward, account_steward)
        self.create_and_open_wallet(wallet_issuer, account_issuer)
        try:
            # initialize Steward
            did_steward, verkey_steward = self.ensure_did_exists(
                account_steward, wallet_steward,
                '000000000000000000000000Steward1')

            # Issuer
            did_issuer, verkey_issuer = self.create_did(
                account_issuer, wallet_issuer)

            # Nym request
            url = self.live_server_url + '/agent/admin/wallets/%s/did/%s/ledger/nym_request/' % (
                wallet_steward, did_steward)
            nym_request = dict(target_did=did_issuer,
                               ver_key=verkey_issuer,
                               role='TRUST_ANCHOR',
                               pass_phrase=self.WALLET_PASS_PHRASE)
            resp = requests.post(url,
                                 json=nym_request,
                                 auth=HTTPBasicAuth(account_steward,
                                                    self.PASS))
            self.assertEqual(200, resp.status_code)

            # Schema registration
            schema = {
                'pass_phrase': self.WALLET_PASS_PHRASE,
                'name': 'test_schema_' + uuid.uuid4().hex,
                'version': '1.0',
                'attributes': ["age", "sex", "height", "name"]
            }
            url = self.live_server_url + '/agent/admin/wallets/%s/did/%s/ledger/register_schema/' % (
                wallet_issuer, did_issuer)
            resp = requests.post(url,
                                 json=schema,
                                 auth=HTTPBasicAuth(account_issuer, self.PASS))
            self.assertEqual(201, resp.status_code)
            self.assertTrue(resp.json())
            schema_json = resp.json()['schema']

            # Cred Def
            url = self.live_server_url + '/agent/admin/wallets/%s/did/%s/cred_def/create_and_send/' % (
                wallet_issuer, did_issuer)
            cred_def = {
                'pass_phrase': self.WALLET_PASS_PHRASE,
                'schema_id': schema_json['id'],
                'tag': 'TAG1',
                'support_revocation': False
            }
            resp = requests.post(url,
                                 json=cred_def,
                                 auth=HTTPBasicAuth(account_issuer, self.PASS))
            self.assertEqual(201, resp.status_code)
            self.assertTrue(resp.json().get('id'))
            self.assertTrue(resp.json().get('cred_def'))

            resp = requests.post(url,
                                 json=cred_def,
                                 auth=HTTPBasicAuth(account_issuer, self.PASS))
            self.assertEqual(409, resp.status_code)

            # check cred_def_list
            url = self.live_server_url + '/agent/admin/wallets/%s/did/%s/cred_def/all/' % (
                wallet_issuer, did_issuer)
            resp = requests.get(url,
                                auth=HTTPBasicAuth(account_issuer, self.PASS))
            raw = json.dumps(resp.json())
            self.assertIn(schema['name'], raw)
        finally:
            self.close_and_delete_wallet(wallet_steward, account_steward)
            self.close_and_delete_wallet(wallet_issuer, account_issuer)

    def test_create_and_send_credential_def_diff_dags(self):
        account_steward = self.IDENTITY1
        wallet_steward = self.WALLET1_UID
        account_issuer = self.IDENTITY2
        wallet_issuer = self.WALLET2_UID
        self.create_and_open_wallet(wallet_steward, account_steward)
        self.create_and_open_wallet(wallet_issuer, account_issuer)
        try:
            # initialize Steward
            did_steward, verkey_steward = self.ensure_did_exists(
                account_steward, wallet_steward,
                '000000000000000000000000Steward1')

            # Issuer
            did_issuer, verkey_issuer = self.create_did(
                account_issuer, wallet_issuer)

            # Nym request
            url = self.live_server_url + '/agent/admin/wallets/%s/did/%s/ledger/nym_request/' % (
                wallet_steward, did_steward)
            nym_request = dict(target_did=did_issuer,
                               ver_key=verkey_issuer,
                               role='TRUST_ANCHOR',
                               pass_phrase=self.WALLET_PASS_PHRASE)
            resp = requests.post(url,
                                 json=nym_request,
                                 auth=HTTPBasicAuth(account_steward,
                                                    self.PASS))
            self.assertEqual(200, resp.status_code)

            # Schema registration
            schema = {
                'pass_phrase': self.WALLET_PASS_PHRASE,
                'name': 'test_schema_' + uuid.uuid4().hex,
                'version': '1.0',
                'attributes': ["age", "sex", "height", "name"]
            }
            url = self.live_server_url + '/agent/admin/wallets/%s/did/%s/ledger/register_schema/' % (
                wallet_issuer, did_issuer)
            resp = requests.post(url,
                                 json=schema,
                                 auth=HTTPBasicAuth(account_issuer, self.PASS))
            self.assertEqual(201, resp.status_code)
            self.assertTrue(resp.json())
            schema_json = resp.json()['schema']

            for tag in ['TAG1', 'TAG2', 'TAG3']:
                url = self.live_server_url + '/agent/admin/wallets/%s/did/%s/cred_def/create_and_send/' % (
                    wallet_issuer, did_issuer)
                cred_def = {
                    'pass_phrase': self.WALLET_PASS_PHRASE,
                    'schema_id': schema_json['id'],
                    'tag': tag,
                    'support_revocation': False
                }
                resp = requests.post(url,
                                     json=cred_def,
                                     auth=HTTPBasicAuth(
                                         account_issuer, self.PASS))
                self.assertEqual(201, resp.status_code)
                self.assertTrue(resp.json().get('id'))
                self.assertTrue(resp.json().get('cred_def'))

        finally:
            self.close_and_delete_wallet(wallet_steward, account_steward)
            self.close_and_delete_wallet(wallet_issuer, account_issuer)

    def test_credential(self):
        account_steward = self.IDENTITY1
        wallet_steward = self.WALLET1_UID
        account_issuer = self.IDENTITY2
        wallet_issuer = self.WALLET2_UID
        account_prover = self.IDENTITY3
        wallet_prover = self.WALLET3_UID
        self.create_and_open_wallet(wallet_steward, account_steward)
        self.create_and_open_wallet(wallet_issuer, account_issuer)
        self.create_and_open_wallet(wallet_prover, account_prover)
        try:
            # initialize Steward
            did_steward, verkey_steward = self.ensure_did_exists(
                account_steward, wallet_steward,
                '000000000000000000000000Steward1')
            # Issuer
            did_issuer, verkey_issuer = self.create_did(
                account_issuer, wallet_issuer)
            url = self.live_server_url + '/agent/admin/wallets/%s/did/%s/ledger/nym_request/' % (
                wallet_steward, did_steward)
            nym_request = dict(target_did=did_issuer,
                               ver_key=verkey_issuer,
                               role='TRUST_ANCHOR',
                               pass_phrase=self.WALLET_PASS_PHRASE)
            resp = requests.post(url,
                                 json=nym_request,
                                 auth=HTTPBasicAuth(account_steward,
                                                    self.PASS))
            self.assertEqual(200, resp.status_code)
            # Prover
            did_prover, verkey_prover = self.create_did(
                account_prover, wallet_prover)
            url = self.live_server_url + '/agent/admin/wallets/%s/did/%s/ledger/nym_request/' % (
                wallet_steward, did_steward)
            nym_request = dict(target_did=did_prover,
                               ver_key=verkey_prover,
                               role=None,
                               pass_phrase=self.WALLET_PASS_PHRASE)
            resp = requests.post(url,
                                 json=nym_request,
                                 auth=HTTPBasicAuth(account_steward,
                                                    self.PASS))
            self.assertEqual(200, resp.status_code)
            # Schema registration
            schema = {
                'pass_phrase': self.WALLET_PASS_PHRASE,
                'name': 'test_schema_' + uuid.uuid4().hex,
                'version': '1.0',
                'attributes': ["age", "sex", "height", "name"]
            }
            url = self.live_server_url + '/agent/admin/wallets/%s/did/%s/ledger/register_schema/' % (
                wallet_issuer, did_issuer)
            resp = requests.post(url,
                                 json=schema,
                                 auth=HTTPBasicAuth(account_issuer, self.PASS))
            self.assertEqual(201, resp.status_code)
            self.assertTrue(resp.json())
            schema_id = resp.json()['schema_id']
            # Cred Def
            url = self.live_server_url + '/agent/admin/wallets/%s/did/%s/cred_def/create_and_send/' % (
                wallet_issuer, did_issuer)
            cred_def = {
                'pass_phrase': self.WALLET_PASS_PHRASE,
                'schema_id': schema_id,
                'tag': 'TAG1',
                'support_revocation': False
            }
            resp = requests.post(url,
                                 json=cred_def,
                                 auth=HTTPBasicAuth(account_issuer, self.PASS))
            self.assertEqual(201, resp.status_code)
            cred_def_id = resp.json().get('id')
            cred_def = resp.json().get('cred_def')
            # Issuer: Create credential offer
            url = self.live_server_url + '/agent/admin/wallets/%s/proving/issuer_create_credential_offer/' % wallet_issuer
            params = dict(cred_def_id=cred_def_id,
                          pass_phrase=self.WALLET_PASS_PHRASE)
            resp = requests.post(url,
                                 json=params,
                                 auth=HTTPBasicAuth(account_issuer, self.PASS))
            self.assertEqual(200, resp.status_code)
            self.assertTrue(resp.json().get('cred_offer'))
            cred_offer = resp.json().get('cred_offer')
            # Prover: Create master key
            prover_link_secret_name = 'my_secret'
            url = self.live_server_url + '/agent/admin/wallets/%s/proving/prover_create_master_secret/' % wallet_prover
            params = dict(link_secret_name=prover_link_secret_name,
                          pass_phrase=self.WALLET_PASS_PHRASE)
            resp = requests.post(url,
                                 json=params,
                                 auth=HTTPBasicAuth(account_prover, self.PASS))
            self.assertEqual(200, resp.status_code)
            self.assertTrue(resp.json().get('link_secret_id'))
            link_secret_id = resp.json()['link_secret_id']
            # Prover: Credential request
            url = self.live_server_url + '/agent/admin/wallets/%s/proving/prover_create_credential_req/' % wallet_prover
            params = dict(pass_phrase=self.WALLET_PASS_PHRASE,
                          prover_did=did_prover,
                          cred_offer=cred_offer,
                          cred_def=cred_def,
                          link_secret_id=link_secret_id)
            resp = requests.post(url,
                                 json=params,
                                 auth=HTTPBasicAuth(account_prover, self.PASS))
            self.assertEqual(200, resp.status_code, resp.text)
            self.assertTrue(resp.json().get('cred_req'))
            self.assertTrue(resp.json().get('cred_req_metadata'))
            cred_req = resp.json().get('cred_req')
            cred_req_metadata = resp.json().get('cred_req_metadata')
            # Issuer: Create credential
            url = self.live_server_url + '/agent/admin/wallets/%s/proving/issuer_create_credential/' % wallet_issuer
            params = dict(pass_phrase=self.WALLET_PASS_PHRASE,
                          cred_offer=cred_offer,
                          cred_req=cred_req,
                          cred_values=dict(sex='male',
                                           name='Alex',
                                           height=175,
                                           age=28))
            resp = requests.post(url,
                                 json=params,
                                 auth=HTTPBasicAuth(account_issuer, self.PASS))
            self.assertEqual(200, resp.status_code, resp.text)
            self.assertTrue(resp.json().get('cred'))
            self.assertIn('cred_revoc_id', resp.json().keys())
            self.assertIn('revoc_reg_delta', resp.json().keys())
            cred = resp.json().get('cred')
            # Prover: store credentials
            url = self.live_server_url + '/agent/admin/wallets/%s/proving/prover_store_credential/' % wallet_prover
            params = dict(pass_phrase=self.WALLET_PASS_PHRASE,
                          cred_req_metadata=cred_req_metadata,
                          cred=cred,
                          cred_def=cred_def)
            resp = requests.post(url,
                                 json=params,
                                 auth=HTTPBasicAuth(account_prover, self.PASS))
            self.assertEqual(200, resp.status_code, resp.text)
            self.assertTrue(resp.json().get('cred_id'))
        finally:
            self.close_and_delete_wallet(wallet_steward, account_steward)
            self.close_and_delete_wallet(wallet_issuer, account_issuer)
            self.close_and_delete_wallet(wallet_prover, account_prover)

    def test_verify_credential(self):
        account_steward = self.IDENTITY1
        wallet_steward = self.WALLET1_UID
        account_issuer = self.IDENTITY2
        wallet_issuer = self.WALLET2_UID
        account_prover = self.IDENTITY3
        wallet_prover = self.WALLET3_UID
        self.create_and_open_wallet(wallet_steward, account_steward)
        self.create_and_open_wallet(wallet_issuer, account_issuer)
        self.create_and_open_wallet(wallet_prover, account_prover)
        try:
            # initialize Steward
            did_steward, verkey_steward = self.ensure_did_exists(
                account_steward, wallet_steward,
                '000000000000000000000000Steward1')
            # Issuer
            did_issuer, verkey_issuer = self.create_did(
                account_issuer, wallet_issuer)
            url = self.live_server_url + '/agent/admin/wallets/%s/did/%s/ledger/nym_request/' % (
                wallet_steward, did_steward)
            nym_request = dict(target_did=did_issuer,
                               ver_key=verkey_issuer,
                               role='TRUST_ANCHOR',
                               pass_phrase=self.WALLET_PASS_PHRASE)
            resp = requests.post(url,
                                 json=nym_request,
                                 auth=HTTPBasicAuth(account_steward,
                                                    self.PASS))
            self.assertEqual(200, resp.status_code)
            # Prover
            did_prover, verkey_prover = self.create_did(
                account_prover, wallet_prover)
            url = self.live_server_url + '/agent/admin/wallets/%s/did/%s/ledger/nym_request/' % (
                wallet_steward, did_steward)
            nym_request = dict(target_did=did_prover,
                               ver_key=verkey_prover,
                               role=None,
                               pass_phrase=self.WALLET_PASS_PHRASE)
            resp = requests.post(url,
                                 json=nym_request,
                                 auth=HTTPBasicAuth(account_steward,
                                                    self.PASS))
            self.assertEqual(200, resp.status_code)
            # Schema registration
            schema = {
                'pass_phrase': self.WALLET_PASS_PHRASE,
                'name': 'test_schema_' + uuid.uuid4().hex,
                'version': '1.0',
                'attributes': ["age", "sex", "height", "name"]
            }
            url = self.live_server_url + '/agent/admin/wallets/%s/did/%s/ledger/register_schema/' % (
                wallet_issuer, did_issuer)
            resp = requests.post(url,
                                 json=schema,
                                 auth=HTTPBasicAuth(account_issuer, self.PASS))
            self.assertEqual(201, resp.status_code)
            self.assertTrue(resp.json())
            schema_id = resp.json()['schema_id']
            # Cred Def
            url = self.live_server_url + '/agent/admin/wallets/%s/did/%s/cred_def/create_and_send/' % (
                wallet_issuer, did_issuer)
            cred_def = {
                'pass_phrase': self.WALLET_PASS_PHRASE,
                'schema_id': schema_id,
                'tag': 'TAG1',
                'support_revocation': False
            }
            resp = requests.post(url,
                                 json=cred_def,
                                 auth=HTTPBasicAuth(account_issuer, self.PASS))
            self.assertEqual(201, resp.status_code)
            cred_def_id = resp.json().get('id')
            cred_def = resp.json().get('cred_def')
            # Issuer: Create credential offer
            url = self.live_server_url + '/agent/admin/wallets/%s/proving/issuer_create_credential_offer/' % wallet_issuer
            params = dict(cred_def_id=cred_def_id,
                          pass_phrase=self.WALLET_PASS_PHRASE)
            resp = requests.post(url,
                                 json=params,
                                 auth=HTTPBasicAuth(account_issuer, self.PASS))
            self.assertEqual(200, resp.status_code)
            self.assertTrue(resp.json().get('cred_offer'))
            cred_offer = resp.json().get('cred_offer')
            # Prover: Create master key
            prover_link_secret_name = 'my_secret'
            url = self.live_server_url + '/agent/admin/wallets/%s/proving/prover_create_master_secret/' % wallet_prover
            params = dict(link_secret_name=prover_link_secret_name,
                          pass_phrase=self.WALLET_PASS_PHRASE)
            resp = requests.post(url,
                                 json=params,
                                 auth=HTTPBasicAuth(account_prover, self.PASS))
            self.assertEqual(200, resp.status_code)
            self.assertTrue(resp.json().get('link_secret_id'))
            link_secret_id = resp.json()['link_secret_id']
            # Prover: Credential request
            url = self.live_server_url + '/agent/admin/wallets/%s/proving/prover_create_credential_req/' % wallet_prover
            params = dict(pass_phrase=self.WALLET_PASS_PHRASE,
                          prover_did=did_prover,
                          cred_offer=cred_offer,
                          cred_def=cred_def,
                          link_secret_id=link_secret_id)
            resp = requests.post(url,
                                 json=params,
                                 auth=HTTPBasicAuth(account_prover, self.PASS))
            self.assertEqual(200, resp.status_code, resp.text)
            self.assertTrue(resp.json().get('cred_req'))
            self.assertTrue(resp.json().get('cred_req_metadata'))
            cred_req = resp.json().get('cred_req')
            cred_req_metadata = resp.json().get('cred_req_metadata')
            # Issuer: Create credential
            url = self.live_server_url + '/agent/admin/wallets/%s/proving/issuer_create_credential/' % wallet_issuer
            params = dict(pass_phrase=self.WALLET_PASS_PHRASE,
                          cred_offer=cred_offer,
                          cred_req=cred_req,
                          cred_values=dict(sex='male',
                                           name='Alex',
                                           height=175,
                                           age=28))
            resp = requests.post(url,
                                 json=params,
                                 auth=HTTPBasicAuth(account_issuer, self.PASS))
            self.assertEqual(200, resp.status_code, resp.text)
            self.assertTrue(resp.json().get('cred'))
            self.assertIn('cred_revoc_id', resp.json().keys())
            self.assertIn('revoc_reg_delta', resp.json().keys())
            cred = resp.json().get('cred')
            # Prover: store credentials
            url = self.live_server_url + '/agent/admin/wallets/%s/proving/prover_store_credential/' % wallet_prover
            params = dict(pass_phrase=self.WALLET_PASS_PHRASE,
                          cred_req_metadata=cred_req_metadata,
                          cred=cred,
                          cred_def=cred_def)
            resp = requests.post(url,
                                 json=params,
                                 auth=HTTPBasicAuth(account_prover, self.PASS))
            self.assertEqual(200, resp.status_code, resp.text)
            self.assertTrue(resp.json().get('cred_id'))
            # Prover gets Credentials for Proof Request
            proof_request = {
                'nonce': '123432421212',
                'name': 'proof_req_1',
                'version': '0.1',
                'requested_attributes': {
                    'attr1_referent': {
                        'name': 'name',
                        "restrictions": {
                            "issuer_did": did_issuer,
                            "schema_id": schema_id
                        }
                    }
                },
                'requested_predicates': {
                    'predicate1_referent': {
                        'name': 'age',
                        'p_type': '>=',
                        'p_value': 18,
                        "restrictions": {
                            "issuer_did": did_issuer
                        }
                    }
                }
            }
            # Prover gets Credentials for attr1_referent anf predicate1_referent
            url = self.live_server_url + '/agent/admin/wallets/%s/proving/prover_search_credentials_for_proof_req/' % wallet_prover
            params = dict(
                pass_phrase=self.WALLET_PASS_PHRASE,
                proof_req=proof_request,
            )
            resp = requests.post(url,
                                 json=params,
                                 auth=HTTPBasicAuth(account_prover, self.PASS))
            self.assertEqual(200, resp.status_code, resp.text)
            search_handle = resp.json()['search_handle']
            try:
                url = self.live_server_url + '/agent/admin/wallets/%s/proving/prover_fetch_credentials_for_proof_req/' % wallet_prover
                params = dict(pass_phrase=self.WALLET_PASS_PHRASE,
                              search_handle=search_handle)
                # attr1_referent
                params.update(dict(item_referent='attr1_referent', count=1))
                resp = requests.post(url,
                                     json=params,
                                     auth=HTTPBasicAuth(
                                         account_prover, self.PASS))
                self.assertEqual(200, resp.status_code, resp.text)
                prover_cred_for_attr1 = resp.json()[0]['cred_info']
                # predicate1_referent
                params.update(
                    dict(item_referent='predicate1_referent', count=1))
                resp = requests.post(url,
                                     json=params,
                                     auth=HTTPBasicAuth(
                                         account_prover, self.PASS))
                self.assertEqual(200, resp.status_code, resp.text)
                prover_cred_for_predicate1 = resp.json()[0]['cred_info']
            finally:
                url = self.live_server_url + '/agent/admin/wallets/%s/proving/prover_close_credentials_search_for_proof_req/' % wallet_prover
                params = dict(
                    pass_phrase=self.WALLET_PASS_PHRASE,
                    search_handle=search_handle,
                )
                resp = requests.post(url,
                                     json=params,
                                     auth=HTTPBasicAuth(
                                         account_prover, self.PASS))
                print('Close status: %d' % resp.status_code)
            # Prover declare requested creds
            prover_requested_creds = {
                'self_attested_attributes': {},
                'requested_attributes': {
                    'attr1_referent': {
                        'cred_id': prover_cred_for_attr1['referent'],
                        'revealed': True
                    }
                },
                'requested_predicates': {
                    'predicate1_referent': {
                        'cred_id': prover_cred_for_predicate1['referent']
                    }
                }
            }
            # Prover load entities from ledger
            url = self.live_server_url + '/agent/ledger/prover_get_entities/'
            identifiers = {
                prover_cred_for_attr1['referent']: prover_cred_for_attr1,
                prover_cred_for_predicate1['referent']:
                prover_cred_for_predicate1
            }
            params = dict(identifiers=identifiers)
            resp = requests.post(url,
                                 json=params,
                                 auth=HTTPBasicAuth(account_prover, self.PASS))
            self.assertEqual(200, resp.status_code, resp.text)
            schemas = resp.json()['schemas']
            cred_defs = resp.json()['cred_defs']
            rev_states = resp.json()['rev_states']
            # Prover creates Proof for Proof Request
            url = self.live_server_url + '/agent/admin/wallets/%s/proving/prover_create_proof/' % wallet_prover
            params = dict(pass_phrase=self.WALLET_PASS_PHRASE,
                          proof_req=proof_request,
                          requested_creds=prover_requested_creds,
                          link_secret_id=link_secret_id,
                          schemas=schemas,
                          cred_defs=cred_defs,
                          rev_states=rev_states)
            resp = requests.post(url,
                                 json=params,
                                 auth=HTTPBasicAuth(account_prover, self.PASS))
            self.assertEqual(200, resp.status_code)
            proof = resp.json()
            self.assertEqual(
                'Alex', proof['requested_proof']['revealed_attrs']
                ['attr1_referent']["raw"])
            # Verifier load entities from ledger
            url = self.live_server_url + '/agent/ledger/verifier_get_entities/'
            params = dict(identifiers=proof['identifiers'])
            resp = requests.post(url,
                                 json=params,
                                 auth=HTTPBasicAuth(account_steward,
                                                    self.PASS))
            self.assertEqual(200, resp.status_code, resp.text)
            schemas = resp.json()['schemas']
            cred_defs = resp.json()['cred_defs']
            rev_reg_defs = resp.json()['rev_reg_defs']
            rev_regs = resp.json()['rev_regs']
            # Verifier is verifying proof from Prover
            url = self.live_server_url + '/agent/verify/verify_proof/'
            params = dict(proof_req=proof_request,
                          proof=proof,
                          schemas=schemas,
                          cred_defs=cred_defs,
                          rev_reg_defs=rev_reg_defs,
                          rev_regs=rev_regs)
            resp = requests.post(url,
                                 json=params,
                                 auth=HTTPBasicAuth(account_steward,
                                                    self.PASS))
            self.assertEqual(200, resp.status_code, resp.text)
            self.assertTrue(resp.json()['success'])
        finally:
            self.close_and_delete_wallet(wallet_steward, account_steward)
            self.close_and_delete_wallet(wallet_issuer, account_issuer)
            self.close_and_delete_wallet(wallet_prover, account_prover)
class MessagingTest(LiveServerTestCase):

    IDENTITY1 = 'test1'
    IDENTITY2 = 'test2'
    IDENTITY3 = 'test3'
    PASS = '******'
    WALLET1_UID = 'test_wallet_uid_1'
    WALLET2_UID = 'test_wallet_uid_2'
    WALLET3_UID = 'test_wallet_uid_3'
    WALLET_PASS_PHRASE = 'pass'
    WALLET1_DB_NAME = WalletConnection.make_wallet_address(WALLET1_UID)
    WALLET2_DB_NAME = WalletConnection.make_wallet_address(WALLET2_UID)
    WALLET3_DB_NAME = WalletConnection.make_wallet_address(WALLET3_UID)
    DEF_TIMEOUT = 5

    def setUp(self):
        self.account1 = AgentAccount.objects.create(username=self.IDENTITY1,
                                                    is_active=True,
                                                    is_staff=True)
        self.account1.set_password(self.PASS)
        self.account1.save()
        self.account2 = AgentAccount.objects.create(username=self.IDENTITY2,
                                                    is_active=True,
                                                    is_staff=True)
        self.account2.set_password(self.PASS)
        self.account2.save()
        self.account3 = AgentAccount.objects.create(username=self.IDENTITY3,
                                                    is_active=True,
                                                    is_staff=True)
        self.account3.set_password(self.PASS)
        self.account3.save()
        os.popen("pkill -f run_wallet_agent")
        sleep(0.1)
        psax = get_ps_ax()
        self.assertNotIn('run_wallet_agent', psax, psax)
        with connection.cursor() as cursor:
            cursor.execute("DROP DATABASE  IF EXISTS %s" %
                           self.WALLET1_DB_NAME)
            cursor.execute("DROP DATABASE  IF EXISTS %s" %
                           self.WALLET2_DB_NAME)
            cursor.execute("DROP DATABASE  IF EXISTS %s" %
                           self.WALLET3_DB_NAME)

    def create_and_open_wallet(self, wallet_uid: str, account: str):
        # create
        cred = dict(uid=wallet_uid, pass_phrase=self.WALLET_PASS_PHRASE)
        url = self.live_server_url + reverse('admin-wallets-list')
        resp = requests.post(url,
                             json=cred,
                             auth=HTTPBasicAuth(account, self.PASS))
        self.assertEqual(201, resp.status_code)
        # open
        cred = dict(pass_phrase=self.WALLET_PASS_PHRASE)
        url = self.live_server_url + reverse('admin-wallets-open',
                                             kwargs=dict(uid=wallet_uid))
        resp = requests.post(url,
                             json=cred,
                             auth=HTTPBasicAuth(account, self.PASS))
        self.assertEqual(200, resp.status_code)
        url = self.live_server_url + reverse('admin-wallets-is-open',
                                             kwargs=dict(uid=wallet_uid))
        resp = requests.get(url, auth=HTTPBasicAuth(account, self.PASS))
        self.assertEqual(200, resp.status_code)
        # create endpoint
        endpoint_uid = 'endpoint_for_' + wallet_uid
        account_inst = AgentAccount.objects.get(username=account)
        endpoint = Endpoint.objects.create(uid=endpoint_uid,
                                           owner=account_inst,
                                           wallet=account_inst.wallets.first(),
                                           url=reverse(
                                               'endpoint',
                                               kwargs=dict(uid=endpoint_uid)))
        return self.live_server_url + endpoint.url

    def close_and_delete_wallet(self, wallet_uid: str, account: str):
        cred = dict(pass_phrase=self.WALLET_PASS_PHRASE)
        # close
        url = self.live_server_url + reverse('admin-wallets-close',
                                             kwargs=dict(uid=wallet_uid))
        resp = requests.post(url,
                             json=cred,
                             auth=HTTPBasicAuth(account, self.PASS))
        self.assertEqual(200, resp.status_code)
        # destroy
        url = self.live_server_url + reverse('admin-wallets-detail',
                                             kwargs=dict(uid=wallet_uid))
        resp = requests.delete(url,
                               json=cred,
                               auth=HTTPBasicAuth(account, self.PASS))
        self.assertEqual(204, resp.status_code)

    def ensure_did_exists(self, account: str, wallet_uid: str, seed: str):
        url = self.live_server_url + '/agent/admin/wallets/%s/did/create_and_store_my_did/' % wallet_uid
        cred = dict(pass_phrase=self.WALLET_PASS_PHRASE, seed=seed)
        resp = requests.post(url,
                             json=cred,
                             auth=HTTPBasicAuth(account, self.PASS))
        self.assertEqual(201, resp.status_code)
        info = resp.json()
        return info['did'], info['verkey']

    def create_did(self, account: str, wallet_uid: str):
        url = self.live_server_url + '/agent/admin/wallets/%s/did/create_and_store_my_did/' % wallet_uid
        cred = dict(pass_phrase=self.WALLET_PASS_PHRASE)
        resp = requests.post(url,
                             json=cred,
                             auth=HTTPBasicAuth(account, self.PASS))
        self.assertEqual(201, resp.status_code)
        info = resp.json()
        return info['did'], info['verkey']

    @staticmethod
    def ws_read_json(ws, timeout=5):

        ret = None
        ev = threading.Event()

        def routine(ws):
            nonlocal ret
            ret = json.loads(ws.recv())
            ev.set()

        th = threading.Thread(target=routine, args=(ws, ))
        th.daemon = True
        th.start()
        if ev.wait(timeout):
            return ret
        else:
            raise TimeoutError()

    def test_anon_crypt_message(self):
        account_sender = self.IDENTITY1
        account_receiver = self.IDENTITY2
        wallet_sender = self.WALLET1_UID
        wallet_receiver = self.WALLET2_UID
        self.create_and_open_wallet(wallet_sender, account_sender)
        self.create_and_open_wallet(wallet_receiver, account_receiver)
        try:
            did_sender, verkey_sender = self.create_did(
                account_sender, wallet_sender)
            did_receiver, verkey_receiver = self.create_did(
                account_receiver, wallet_receiver)
            url = self.live_server_url + '/agent/admin/wallets/%s/messaging/anon_crypt/' % wallet_sender
            # Message
            message = dict(content=uuid.uuid4().hex)
            # Encrypt
            entity = dict(message=message, their_verkey=verkey_receiver)
            resp = requests.post(url,
                                 json=entity,
                                 auth=HTTPBasicAuth(account_sender, self.PASS))
            self.assertEqual(200, resp.status_code)
            encrypted = resp.json()
            print('-------- Encrypted --------')
            print(json.dumps(encrypted, indent=2, sort_keys=True))
            self.assertNotIn(message['content'], str(encrypted))
            # Decrypt
            url = self.live_server_url + '/agent/admin/wallets/%s/messaging/unpack/' % wallet_receiver
            resp = requests.post(url,
                                 json=encrypted,
                                 auth=HTTPBasicAuth(account_receiver,
                                                    self.PASS))
            self.assertEqual(200, resp.status_code, resp.text)
            decrypted = resp.json()
            print('--------- Decrypted -------')
            print(json.dumps(decrypted, indent=2, sort_keys=True))
            self.assertIn(message['content'], str(decrypted))
        finally:
            self.close_and_delete_wallet(wallet_sender, account_sender)
            self.close_and_delete_wallet(wallet_receiver, account_receiver)

    def test_auth_crypt_message(self):
        account_sender = self.IDENTITY1
        account_receiver = self.IDENTITY2
        wallet_sender = self.WALLET1_UID
        wallet_receiver = self.WALLET2_UID
        self.create_and_open_wallet(wallet_sender, account_sender)
        self.create_and_open_wallet(wallet_receiver, account_receiver)
        try:
            did_sender, verkey_sender = self.create_did(
                account_sender, wallet_sender)
            did_receiver, verkey_receiver = self.create_did(
                account_receiver, wallet_receiver)
            url = self.live_server_url + '/agent/admin/wallets/%s/messaging/auth_crypt/' % wallet_sender
            # Message
            message = dict(content=uuid.uuid4().hex)
            # Encrypt
            entity = dict(message=message,
                          their_verkey=verkey_receiver,
                          my_verkey=verkey_sender)
            resp = requests.post(url,
                                 json=entity,
                                 auth=HTTPBasicAuth(account_sender, self.PASS))
            self.assertEqual(200, resp.status_code)
            encrypted = resp.json()
            print('-------- Encrypted --------')
            print(json.dumps(encrypted, indent=2, sort_keys=True))
            self.assertNotIn(message['content'], str(encrypted))
            # Decrypt
            url = self.live_server_url + '/agent/admin/wallets/%s/messaging/unpack/' % wallet_receiver
            resp = requests.post(url,
                                 json=encrypted,
                                 auth=HTTPBasicAuth(account_receiver,
                                                    self.PASS))
            self.assertEqual(200, resp.status_code, resp.text)
            decrypted = resp.json()
            print('--------- Decrypted -------')
            print(json.dumps(decrypted, indent=2, sort_keys=True))
            self.assertIn(message['content'], str(decrypted))
        finally:
            self.close_and_delete_wallet(wallet_sender, account_sender)
            self.close_and_delete_wallet(wallet_receiver, account_receiver)

    def test_receive_wired_message(self):
        headers = dict()
        headers[HEADER_PASS_PHRASE] = self.WALLET_PASS_PHRASE
        account_sender = self.IDENTITY1
        account_receiver = self.IDENTITY2
        wallet_sender = self.WALLET1_UID
        wallet_receiver = self.WALLET2_UID
        endpoint_sender = self.create_and_open_wallet(wallet_sender,
                                                      account_sender)
        endpoint_receiver = self.create_and_open_wallet(
            wallet_receiver, account_receiver)
        try:
            did_sender, verkey_sender = self.create_did(
                account_sender, wallet_sender)
            did_receiver, verkey_receiver = self.create_did(
                account_receiver, wallet_receiver)
            # create pairwise on receiver-side
            url = self.live_server_url + '/agent/admin/wallets/%s/pairwise/create_pairwise_statically/' % wallet_receiver
            pairwise = dict(my_did=did_receiver,
                            their_did=did_sender,
                            their_verkey=verkey_sender,
                            metadata={
                                'their_endpoint': endpoint_sender,
                                'their_vk': verkey_sender,
                                'my_vk': verkey_receiver,
                            })
            resp = requests.post(url,
                                 json=pairwise,
                                 auth=HTTPBasicAuth(account_receiver,
                                                    self.PASS),
                                 headers=headers)
            self.assertEqual(200, resp.status_code, resp.text)
            # create auth-crypt message
            url = self.live_server_url + '/agent/admin/wallets/%s/messaging/auth_crypt/' % wallet_sender
            message = dict(content=uuid.uuid4().hex)
            entity = dict(message=message,
                          their_verkey=verkey_receiver,
                          my_verkey=verkey_sender)
            resp = requests.post(url,
                                 json=entity,
                                 auth=HTTPBasicAuth(account_sender, self.PASS))
            self.assertEqual(200, resp.status_code)
            encrypted_message = resp.json()
            extra_field_value = uuid.uuid4().hex
            encrypted_message['extra_field'] = extra_field_value
            # send to receiver endpoint
            transport = EndpointTransport(address=endpoint_receiver)
            status = run_async(
                transport.send_wire_message(
                    json.dumps(encrypted_message).encode('utf-8')))
            self.assertEqual(410, status)

            # allocate channel
            ws = StubWalletStatusNotification(
                scope={},
                agent_name=wallet_receiver,
                pass_phrase=self.WALLET_PASS_PHRASE)

            async def run_websocket():
                chan_wired = await ReadOnlyChannel.create(
                    make_wallet_wired_messages_channel_name(wallet_receiver))
                await ws.listen_wired(chan_wired)

            async def run_send_wire_message(msg):
                await asyncio.sleep(3)
                t = EndpointTransport(address=endpoint_receiver)
                s = await t.send_wire_message(json.dumps(msg).encode('utf-8'))
                assert 202 == s

            async def run_tests():
                done, pending = await asyncio.wait([
                    run_websocket(),
                    run_send_wire_message(encrypted_message)
                ],
                                                   timeout=5)
                for f in pending:
                    f.cancel()
                for f in done:
                    if f.exception():
                        raise f.exception()
                await asyncio.sleep(1)
                assert ws.is_closed
                assert len(ws.send_queue) == 1
                # check structure
                recv = ws.send_queue[0]
                assert recv.get('topic') == UNPACKED_TRANSPORT
                data = recv.get('data')
                assert data['content_type'] == DEFAULT_WIRE_CONTENT_TYPE
                assert data['unpacked']['message']['content'] == message[
                    'content']
                assert data['unpacked']['recipient_verkey'] == verkey_receiver
                assert data['unpacked']['sender_verkey'] == verkey_sender
                assert data['their_did'] == did_sender
                assert data['extra']['extra_field'] == extra_field_value

            f = asyncio.ensure_future(run_tests())
            asyncio.get_event_loop().run_until_complete(f)
            if f.exception():
                raise f.exception()
        finally:
            self.close_and_delete_wallet(wallet_sender, account_sender)
            self.close_and_delete_wallet(wallet_receiver, account_receiver)

    def test_receive_json_message(self):
        headers = dict()
        headers[HEADER_PASS_PHRASE] = self.WALLET_PASS_PHRASE
        account_sender = self.IDENTITY1
        account_receiver = self.IDENTITY2
        wallet_sender = self.WALLET1_UID
        wallet_receiver = self.WALLET2_UID
        endpoint_sender = self.create_and_open_wallet(wallet_sender,
                                                      account_sender)
        endpoint_receiver = self.create_and_open_wallet(
            wallet_receiver, account_receiver)
        try:

            json_message = dict(content=uuid.uuid4().hex)

            ws = StubWalletStatusNotification(
                scope={},
                agent_name=wallet_receiver,
                pass_phrase=self.WALLET_PASS_PHRASE)

            async def run_websocket():
                chan_wired = await ReadOnlyChannel.create(
                    make_wallet_wired_messages_channel_name(wallet_receiver))
                await ws.listen_wired(chan_wired)

            async def run_send_wire_message(msg):
                await asyncio.sleep(3)
                t = EndpointTransport(address=endpoint_receiver)
                s = await t.send_wire_message(
                    json.dumps(msg).encode('utf-8'),
                    content_type=JSON_CONTENT_TYPES[0])
                assert 202 == s

            async def run_tests():
                done, pending = await asyncio.wait(
                    [run_websocket(),
                     run_send_wire_message(json_message)],
                    timeout=5)
                for f in pending:
                    f.cancel()
                for f in done:
                    if f.exception():
                        raise f.exception()
                await asyncio.sleep(1)
                assert ws.is_closed
                assert len(ws.send_queue) == 1
                # check structure
                recv = ws.send_queue[0]
                assert recv.get('topic') == UNPACKED_TRANSPORT
                data = recv.get('data')
                assert data['content_type'] == JSON_CONTENT_TYPES[0]
                assert data['unpacked']['message']['content'] == json_message[
                    'content']
                assert data['unpacked']['recipient_verkey'] is None
                assert data['unpacked']['sender_verkey'] is None
                assert data['their_did'] is None
                assert data['extra'] == {}

            f = asyncio.ensure_future(run_tests())
            asyncio.get_event_loop().run_until_complete(f)
            if f.exception():
                raise f.exception()
        finally:
            self.close_and_delete_wallet(wallet_sender, account_sender)
            self.close_and_delete_wallet(wallet_receiver, account_receiver)

    def test_post_to_peer(self):
        headers = dict()
        headers[HEADER_PASS_PHRASE] = self.WALLET_PASS_PHRASE
        account_sender = self.IDENTITY1
        account_receiver = self.IDENTITY2
        wallet_sender = self.WALLET1_UID
        wallet_receiver = self.WALLET2_UID
        endpoint_sender = self.create_and_open_wallet(wallet_sender,
                                                      account_sender)
        endpoint_receiver = self.create_and_open_wallet(
            wallet_receiver, account_receiver)
        try:
            did_sender, verkey_sender = self.create_did(
                account_sender, wallet_sender)
            did_receiver, verkey_receiver = self.create_did(
                account_receiver, wallet_receiver)
            # create pairwise on sender-side
            url = self.live_server_url + '/agent/admin/wallets/%s/pairwise/create_pairwise_statically/' % wallet_sender
            pairwise = dict(my_did=did_sender,
                            their_did=did_receiver,
                            their_verkey=verkey_receiver,
                            metadata={
                                'their_endpoint': endpoint_receiver,
                                'their_vk': verkey_receiver,
                                'my_vk': verkey_sender,
                                'label': 'Receiver'
                            })
            resp = requests.post(url,
                                 json=pairwise,
                                 auth=HTTPBasicAuth(account_sender, self.PASS),
                                 headers=headers)
            self.assertEqual(200, resp.status_code, resp.text)
            # create pairwise on receiver-side
            url = self.live_server_url + '/agent/admin/wallets/%s/pairwise/create_pairwise_statically/' % wallet_receiver
            pairwise = dict(my_did=did_receiver,
                            their_did=did_sender,
                            their_verkey=verkey_sender,
                            metadata={
                                'their_endpoint': endpoint_sender,
                                'their_vk': verkey_sender,
                                'my_vk': verkey_receiver,
                                'label': 'Sender'
                            })
            resp = requests.post(url,
                                 json=pairwise,
                                 auth=HTTPBasicAuth(account_receiver,
                                                    self.PASS),
                                 headers=headers)
            self.assertEqual(200, resp.status_code, resp.text)

            # generate message
            test_call = dict(message=dict(content=uuid.uuid4().hex),
                             extra=dict(extra_field=uuid.uuid4().hex),
                             their_did=did_receiver)

            # allocate channel
            ws = StubWalletStatusNotification(
                scope={},
                agent_name=wallet_receiver,
                pass_phrase=self.WALLET_PASS_PHRASE)

            async def run_websocket():
                chan_wired = await ReadOnlyChannel.create(
                    make_wallet_wired_messages_channel_name(wallet_receiver))
                await ws.listen_wired(chan_wired)

            async def run_post():
                await asyncio.sleep(3)
                url = self.live_server_url + '/agent/admin/wallets/%s/messaging/post_to_peer/' % wallet_sender
                async with aiohttp.ClientSession() as session:
                    headers_ = {'content-type': 'application/json'}
                    headers_.update(headers)
                    data = json.dumps(test_call).encode('utf-8')
                    async with session.post(url,
                                            data=data,
                                            headers=headers_,
                                            auth=aiohttp.BasicAuth(
                                                account_sender,
                                                self.PASS)) as resp:
                        assert resp.status == 202
                pass

            async def run_tests():
                done, pending = await asyncio.wait(
                    [run_websocket(), run_post()], timeout=15)
                for f in pending:
                    f.cancel()
                for f in done:
                    if f.exception():
                        raise f.exception()
                await asyncio.sleep(1)
                assert ws.is_closed
                assert len(ws.send_queue) == 1
                # check structure
                recv = ws.send_queue[0]
                assert recv.get('topic') == UNPACKED_TRANSPORT
                data = recv.get('data')
                assert data['content_type'] == DEFAULT_WIRE_CONTENT_TYPE
                assert 'Sender' in str(data['pairwise'])
                pass

            f = asyncio.ensure_future(run_tests())
            asyncio.get_event_loop().run_until_complete(f)
            if f.exception():
                raise f.exception()
        finally:
            self.close_and_delete_wallet(wallet_sender, account_sender)
            self.close_and_delete_wallet(wallet_receiver, account_receiver)
class AdminWalletsTest(LiveServerTestCase):

    IDENTITY = 'test'
    PASS = '******'
    WALLET_UID = 'test_wallet_uid'
    WALLET_PASS_PHRASE = 'pass'
    WALLET_DB_NAME = WalletConnection.make_wallet_address(WALLET_UID)
    DEF_TIMEOUT = 5

    def setUp(self):
        self.account = AgentAccount.objects.create(username=self.IDENTITY,
                                                   is_active=True,
                                                   is_staff=True)
        self.account.set_password(self.PASS)
        self.account.save()
        self.assertTrue(self.account.check_password(self.PASS))
        os.popen("pkill -f run_wallet_agent")
        sleep(0.1)
        psax = get_ps_ax()
        self.assertNotIn('run_wallet_agent', psax, psax)
        with connection.cursor() as cursor:
            cursor.execute("DROP DATABASE  IF EXISTS %s" % self.WALLET_DB_NAME)

    def test_list(self):
        url = self.live_server_url + reverse('admin-wallets-list')
        wallet1 = Wallet.objects.create(uid='wallet-1', owner=self.account)
        wallet2 = Wallet.objects.create(uid='wallet-2', owner=self.account)
        wallet3 = Wallet.objects.create(uid='wallet-3', owner=None)
        resp = requests.get(url, auth=HTTPBasicAuth(self.IDENTITY, self.PASS))
        self.assertEqual(200, resp.status_code)
        results = resp.json()
        self.assertIn(wallet1.uid, str(results))
        self.assertIn(wallet2.uid, str(results))
        self.assertNotIn(wallet3.uid, str(results))

    def test_retrieve(self):
        wallet = Wallet.objects.create(uid='wallet-uid', owner=self.account)
        url = self.live_server_url + reverse('admin-wallets-detail',
                                             kwargs=dict(uid=wallet.uid))
        resp = requests.get(url, auth=HTTPBasicAuth(self.IDENTITY, self.PASS))
        self.assertEqual(200, resp.status_code)
        results = resp.json()
        self.assertIn(wallet.uid, str(results))

    def test_create_destroy(self):
        url = self.live_server_url + reverse('admin-wallets-list')
        cred = dict(uid=self.WALLET_UID, pass_phrase=self.WALLET_PASS_PHRASE)
        resp = requests.post(url,
                             json=cred,
                             auth=HTTPBasicAuth(self.IDENTITY, self.PASS))
        self.assertEqual(201, resp.status_code)
        with connection.cursor() as cursor:
            cursor.execute("SELECT 1 FROM pg_database WHERE datname='%s'" %
                           self.WALLET_DB_NAME)
            res = cursor.fetchone()
            self.assertTrue(res)
            self.assertEqual(1, res[0])
        w = resp.json()
        self.assertTrue(w['uid'])
        url = self.live_server_url + reverse('admin-wallets-detail',
                                             kwargs=dict(uid=w['uid']))
        resp = requests.delete(url,
                               json=cred,
                               auth=HTTPBasicAuth(self.IDENTITY, self.PASS))
        self.assertEqual(204, resp.status_code)
        with connection.cursor() as cursor:
            cursor.execute("SELECT 1 FROM pg_database WHERE datname='%s'" %
                           self.WALLET_DB_NAME)
            res = cursor.fetchone()
            self.assertFalse(res)

    def test_open_close(self):
        conn = WalletConnection(self.WALLET_UID, self.WALLET_PASS_PHRASE)
        Wallet.objects.create(uid=self.WALLET_UID, owner=self.account)
        # first: create wallet
        run_async(conn.create())
        try:
            cred = dict(pass_phrase=self.WALLET_PASS_PHRASE)
            # open
            url = self.live_server_url + reverse(
                'admin-wallets-open', kwargs=dict(uid=self.WALLET_UID))
            resp = requests.post(url,
                                 json=cred,
                                 auth=HTTPBasicAuth(self.IDENTITY, self.PASS))
            self.assertEqual(200, resp.status_code)
            # is_open
            url = self.live_server_url + reverse(
                'admin-wallets-is-open', kwargs=dict(uid=self.WALLET_UID))
            resp = requests.get(url,
                                auth=HTTPBasicAuth(self.IDENTITY, self.PASS))
            self.assertEqual(200, resp.status_code)
            stat = resp.json()
            self.assertTrue(stat['is_open'])
            # close
            url = self.live_server_url + reverse(
                'admin-wallets-close', kwargs=dict(uid=self.WALLET_UID))
            resp = requests.post(url,
                                 json=cred,
                                 auth=HTTPBasicAuth(self.IDENTITY, self.PASS))
            self.assertEqual(200, resp.status_code)
            # is_open
            url = self.live_server_url + reverse(
                'admin-wallets-is-open', kwargs=dict(uid=self.WALLET_UID))
            resp = requests.get(url,
                                auth=HTTPBasicAuth(self.IDENTITY, self.PASS))
            self.assertEqual(200, resp.status_code)
            stat = resp.json()
            self.assertFalse(stat['is_open'])
        finally:
            os.popen("pkill -f run_wallet_agent")
            sleep(1)
            run_async(conn.delete())

    def test_open_close__via_http_header(self):
        conn = WalletConnection(self.WALLET_UID, self.WALLET_PASS_PHRASE)
        Wallet.objects.create(uid=self.WALLET_UID, owner=self.account)
        # first: create wallet
        run_async(conn.create())
        headers = dict()
        headers[HEADER_PASS_PHRASE] = self.WALLET_PASS_PHRASE
        try:
            # open
            url = self.live_server_url + reverse(
                'admin-wallets-open', kwargs=dict(uid=self.WALLET_UID))
            resp = requests.post(url,
                                 auth=HTTPBasicAuth(self.IDENTITY, self.PASS),
                                 headers=headers)
            self.assertEqual(200, resp.status_code)
            # is_open
            url = self.live_server_url + reverse(
                'admin-wallets-is-open', kwargs=dict(uid=self.WALLET_UID))
            resp = requests.get(url,
                                auth=HTTPBasicAuth(self.IDENTITY, self.PASS))
            self.assertEqual(200, resp.status_code)
            stat = resp.json()
            self.assertTrue(stat['is_open'])
            # close
            url = self.live_server_url + reverse(
                'admin-wallets-close', kwargs=dict(uid=self.WALLET_UID))
            resp = requests.post(url,
                                 auth=HTTPBasicAuth(self.IDENTITY, self.PASS),
                                 headers=headers)
            self.assertEqual(200, resp.status_code)
            # is_open
            url = self.live_server_url + reverse(
                'admin-wallets-is-open', kwargs=dict(uid=self.WALLET_UID))
            resp = requests.get(url,
                                auth=HTTPBasicAuth(self.IDENTITY, self.PASS))
            self.assertEqual(200, resp.status_code)
            stat = resp.json()
            self.assertFalse(stat['is_open'])
        finally:
            os.popen("pkill -f run_wallet_agent")
            sleep(1)
            run_async(conn.delete())

    def test_create_list_destroy_endpoints(self):
        wallet = Wallet.objects.create(uid='wallet_uid', owner=self.account)
        base_url = self.live_server_url + '/agent/admin/wallets/%s/endpoints/' % wallet.uid
        # step 1: create endpoint
        resp = requests.post(base_url,
                             auth=HTTPBasicAuth(self.IDENTITY, self.PASS))
        self.assertEqual(201, resp.status_code)
        self.assertTrue(resp.json()['url'])
        self.assertTrue(resp.json()['uid'])
        endpoint_uid = resp.json()['uid']
        endpoint_path = reverse('endpoint', kwargs=dict(uid=endpoint_uid))
        self.assertIn(endpoint_path, resp.json()['url'])
        # step 2: list endpoints
        resp = requests.get(base_url,
                            auth=HTTPBasicAuth(self.IDENTITY, self.PASS))
        self.assertEqual(200, resp.status_code)
        self.assertIn(endpoint_uid, str(resp.json()))
        # step 3: destroy
        self.assertTrue(Endpoint.objects.filter(uid=endpoint_uid).exists())
        resp = requests.delete(base_url + endpoint_uid + '/',
                               auth=HTTPBasicAuth(self.IDENTITY, self.PASS))
        self.assertEqual(204, resp.status_code)
        self.assertFalse(Endpoint.objects.filter(uid=endpoint_uid).exists())

    def test_create_endpoint_with_custom_host(self):
        wallet = Wallet.objects.create(uid='wallet_uid', owner=self.account)
        base_url = self.live_server_url + '/agent/admin/wallets/%s/endpoints/' % wallet.uid
        custom_host = 'http://example.com:8888/'
        resp = requests.post(base_url,
                             json=dict(host=custom_host),
                             auth=HTTPBasicAuth(self.IDENTITY, self.PASS))
        data = resp.json()
        self.assertIn(custom_host, data['url'])

    def test_create_invitation(self):
        conn = WalletConnection(self.WALLET_UID, self.WALLET_PASS_PHRASE)
        wallet = Wallet.objects.create(uid=self.WALLET_UID, owner=self.account)
        endpoint = Endpoint.objects.create(uid='endpoint_uid',
                                           owner=self.account,
                                           wallet=wallet,
                                           url='http://example.com/endpoint')
        # first: create wallet
        run_async(conn.create())
        try:
            cred = dict(pass_phrase=self.WALLET_PASS_PHRASE)
            url = self.live_server_url + '/agent/admin/wallets/%s/endpoints/%s/invitations/' % (
                self.WALLET_UID, endpoint.uid)
            resp = requests.post(url,
                                 json=cred,
                                 auth=HTTPBasicAuth(self.IDENTITY, self.PASS))
            self.assertEqual(201, resp.status_code)
            instance = Invitation.objects.get(endpoint=endpoint)
            entity = resp.json()
            self.assertTrue(entity['url'])
            invite_url = entity['url']
            self.assertTrue(resp.json()['connection_key'])
            connection_key = resp.json()['connection_key']
            self.assertIn(instance.invitation_string, invite_url)
            self.assertIn(settings.INDY['INVITATION_URL_BASE'], invite_url)
            self.assertEqual(1, invite_url.count('c_i='))
            # check list
            resp = requests.get(url,
                                auth=HTTPBasicAuth(self.IDENTITY, self.PASS))
            self.assertEqual(200, resp.status_code)
            raw = str(resp.json())
            self.assertIn(invite_url, raw)
            self.assertIn(connection_key, raw)
        finally:
            os.popen("pkill -f run_wallet_agent")
            sleep(1)
            run_async(conn.delete())

    def test_create_invitation__with_label(self):
        conn = WalletConnection(self.WALLET_UID, self.WALLET_PASS_PHRASE)
        wallet = Wallet.objects.create(uid=self.WALLET_UID, owner=self.account)
        endpoint = Endpoint.objects.create(uid='endpoint_uid',
                                           owner=self.account,
                                           wallet=wallet,
                                           url='http://example.com/endpoint')
        # first: create wallet
        run_async(conn.create())
        try:
            label = 'My Test Label'
            cred = dict(pass_phrase=self.WALLET_PASS_PHRASE, label=label)
            url = self.live_server_url + '/agent/admin/wallets/%s/endpoints/%s/invitations/' % (
                self.WALLET_UID, endpoint.uid)
            resp = requests.post(url,
                                 json=cred,
                                 auth=HTTPBasicAuth(self.IDENTITY, self.PASS))
            self.assertEqual(201, resp.status_code)
            entity = resp.json()
            self.assertTrue(entity['url'])
            invite_url = entity['url']
            matches = re.match("(.+)?c_i=(.+)", invite_url)
            self.assertTrue(matches)
            _ = base64.urlsafe_b64decode(matches.group(2)).decode('utf-8')
            invite_msg = json.loads(_)
            self.assertEqual(label, invite_msg.get('label'))
        finally:
            os.popen("pkill -f run_wallet_agent")
            sleep(1)
            run_async(conn.delete())

    def test_create_invitation_with_seed(self):
        conn = WalletConnection(self.WALLET_UID, self.WALLET_PASS_PHRASE)
        wallet = Wallet.objects.create(uid=self.WALLET_UID, owner=self.account)
        endpoint = Endpoint.objects.create(uid='endpoint_uid',
                                           owner=self.account,
                                           wallet=wallet,
                                           url='http://example.com/endpoint')
        # first: create wallet
        run_async(conn.create())
        try:
            seed = 'blablabla-seed-'
            expected_key = '3XvPjB4EDpmBBF4sRmqVbrQXQY5vk7zjiggSCGxSkPpV'
            cred = dict(pass_phrase=self.WALLET_PASS_PHRASE, seed=seed)
            url = self.live_server_url + '/agent/admin/wallets/%s/endpoints/%s/invitations/' % (
                self.WALLET_UID, endpoint.uid)
            resp = requests.post(url,
                                 json=cred,
                                 auth=HTTPBasicAuth(self.IDENTITY, self.PASS))
            self.assertEqual(201, resp.status_code)
            instance = Invitation.objects.get(endpoint=endpoint)
            connection_key = resp.json()['connection_key']
            self.assertEqual(expected_key, connection_key)
            self.assertEqual(instance.connection_key, connection_key)
            self.assertEqual(instance.seed, seed)
            resp = requests.post(url,
                                 json=cred,
                                 auth=HTTPBasicAuth(self.IDENTITY, self.PASS))
            self.assertEqual(409, resp.status_code)
        finally:
            os.popen("pkill -f run_wallet_agent")
            sleep(1)
            run_async(conn.delete())

    def test_create_invitation_with_did(self):
        conn = WalletConnection(self.WALLET_UID, self.WALLET_PASS_PHRASE)
        wallet = Wallet.objects.create(uid=self.WALLET_UID, owner=self.account)
        endpoint = Endpoint.objects.create(uid='endpoint_uid',
                                           owner=self.account,
                                           wallet=wallet,
                                           url='http://example.com/endpoint')
        # first: create wallet
        run_async(conn.create())
        run_async(conn.open())
        my_did, my_verkey = run_async(conn.create_and_store_my_did())
        run_async(conn.close())
        try:
            cred = dict(pass_phrase=self.WALLET_PASS_PHRASE, my_did=my_did)
            url = self.live_server_url + '/agent/admin/wallets/%s/endpoints/%s/invitations/' % (
                self.WALLET_UID, endpoint.uid)
            resp = requests.post(url,
                                 json=cred,
                                 auth=HTTPBasicAuth(self.IDENTITY, self.PASS))
            self.assertEqual(201, resp.status_code)
            instance = Invitation.objects.get(endpoint=endpoint)
            self.assertEqual(my_did, instance.my_did)
            resp = requests.post(url,
                                 json=cred,
                                 auth=HTTPBasicAuth(self.IDENTITY, self.PASS))
            self.assertEqual(201, resp.status_code)
        finally:
            os.popen("pkill -f run_wallet_agent")
            sleep(1)
            run_async(conn.delete())

    def test_invitation_ensure_exists(self):
        conn = WalletConnection(self.WALLET_UID, self.WALLET_PASS_PHRASE)
        wallet = Wallet.objects.create(uid=self.WALLET_UID, owner=self.account)
        endpoint = Endpoint.objects.create(uid='endpoint_uid',
                                           owner=self.account,
                                           wallet=wallet,
                                           url='http://example.com/endpoint')
        # first: create wallet
        run_async(conn.create())
        run_async(conn.open())
        my_did, my_verkey = run_async(conn.create_and_store_my_did())
        run_async(conn.close())
        try:
            seed = 'blablabla-seed-'
            expected_key = '3XvPjB4EDpmBBF4sRmqVbrQXQY5vk7zjiggSCGxSkPpV'
            cred = dict(pass_phrase=self.WALLET_PASS_PHRASE, seed=seed)
            url = self.live_server_url + '/agent/admin/wallets/%s/endpoints/%s/invitations/ensure_exists/' % (
                self.WALLET_UID, endpoint.uid)
            resp = requests.post(url,
                                 json=cred,
                                 auth=HTTPBasicAuth(self.IDENTITY, self.PASS))
            self.assertEqual(200, resp.status_code)
            i1 = resp.json()

            instance = Invitation.objects.get(endpoint=endpoint)
            self.assertEqual(seed, instance.seed)
            self.assertEqual(expected_key, instance.connection_key)
            self.assertIsNone(instance.my_did)
            resp = requests.post(url,
                                 json=cred,
                                 auth=HTTPBasicAuth(self.IDENTITY, self.PASS))
            self.assertEqual(200, resp.status_code)
            i2 = resp.json()

            self.assertEqual(
                1,
                Invitation.objects.filter(connection_key=expected_key).count())

            matches = re.match("(.+)?c_i=(.+)", i1['url'])
            invite_msg1 = Serializer.deserialize(
                base64.urlsafe_b64decode(
                    matches.group(2)).decode('utf-8')).to_dict()
            del invite_msg1['@id']
            matches = re.match("(.+)?c_i=(.+)", i2['url'])
            invite_msg2 = Serializer.deserialize(
                base64.urlsafe_b64decode(
                    matches.group(2)).decode('utf-8')).to_dict()
            del invite_msg2['@id']
            self.assertDictEqual(invite_msg1, invite_msg2)

            cred['my_did'] = my_did
            resp = requests.post(url,
                                 json=cred,
                                 auth=HTTPBasicAuth(self.IDENTITY, self.PASS))
            self.assertEqual(200, resp.status_code)
            instance = Invitation.objects.get(endpoint=endpoint)
            self.assertEqual(my_did, instance.my_did)

            self.assertEqual(1, Invitation.objects.count())
            cred = dict(pass_phrase=self.WALLET_PASS_PHRASE,
                        seed=seed + 'salt')
            resp = requests.post(url,
                                 json=cred,
                                 auth=HTTPBasicAuth(self.IDENTITY, self.PASS))
            self.assertEqual(200, resp.status_code)
            self.assertEqual(2, Invitation.objects.count())
        finally:
            os.popen("pkill -f run_wallet_agent")
            sleep(1)
            run_async(conn.delete())

    def test_invitation_search(self):
        wallet = Wallet.objects.create(uid=self.WALLET_UID, owner=self.account)
        endpoint = Endpoint.objects.create(uid='endpoint_uid',
                                           owner=self.account,
                                           wallet=wallet,
                                           url='http://example.com/endpoint')
        invitation1 = Invitation.objects.create(
            endpoint=endpoint,
            invitation_string='http://xxxxx.com',
            feature=InvitationSerializer.FEATURE_0160_ARIES_RFC,
            connection_key='connection_key1',
            seed='seed1',
            my_did='did1')
        invitation2 = Invitation.objects.create(
            endpoint=endpoint,
            invitation_string='http://xxxxx.com',
            feature=InvitationSerializer.FEATURE_0160_ARIES_RFC,
            connection_key='connection_key2',
            seed='seed2',
            my_did='did2')
        url = self.live_server_url + '/agent/admin/wallets/%s/endpoints/%s/invitations/search/' % (
            self.WALLET_UID, endpoint.uid)

        params1 = dict(connection_key='connection_key1')
        resp = requests.post(url,
                             json=params1,
                             auth=HTTPBasicAuth(self.IDENTITY, self.PASS))
        collection1 = resp.json()
        self.assertIn('connection_key1', str(collection1))

        params2 = dict(my_did='did2')
        resp = requests.post(url,
                             json=params2,
                             auth=HTTPBasicAuth(self.IDENTITY, self.PASS))
        collection2 = resp.json()
        self.assertIn('connection_key2', str(collection2))

        params3 = dict(my_did='did2', connection_key='connection_key1')
        resp = requests.post(url,
                             json=params3,
                             auth=HTTPBasicAuth(self.IDENTITY, self.PASS))
        collection3 = resp.json()
        self.assertEqual([], collection3)

    def test_ensure_exists(self):
        conn = WalletConnection(self.WALLET_UID, self.WALLET_PASS_PHRASE)
        try:
            url = self.live_server_url + '/agent/admin/wallets/ensure_exists/'
            cred = dict(pass_phrase=self.WALLET_PASS_PHRASE,
                        uid=self.WALLET_UID)
            resp = requests.post(url,
                                 json=cred,
                                 auth=HTTPBasicAuth(self.IDENTITY, self.PASS))
            self.assertIn(resp.status_code, [200, 201])
        finally:
            os.popen("pkill -f run_wallet_agent")
            sleep(1)
            run_async(conn.delete())

    def test_list_my_dids_with_meta(self):
        conn = WalletConnection(self.WALLET_UID, self.WALLET_PASS_PHRASE)
        wallet = Wallet.objects.create(uid=self.WALLET_UID, owner=self.account)
        url = self.live_server_url + '/agent/admin/wallets/%s/did/list_my_dids_with_meta/' % wallet.uid
        # first: create wallet
        run_async(conn.create())
        try:
            # create did from seed
            run_async(conn.open())
            did, verkey = run_async(
                conn.create_and_store_my_did(
                    seed='000000000000000000000000Steward1'))
            run_async(conn.close())
            cred = dict(pass_phrase=self.WALLET_PASS_PHRASE)
            # open
            url_open = self.live_server_url + reverse(
                'admin-wallets-open', kwargs=dict(uid=self.WALLET_UID))
            resp = requests.post(url_open,
                                 json=cred,
                                 auth=HTTPBasicAuth(self.IDENTITY, self.PASS))
            self.assertEqual(200, resp.status_code)
            # FIRE!!!
            resp = requests.post(url,
                                 json=cred,
                                 auth=HTTPBasicAuth(self.IDENTITY, self.PASS))
            self.assertEqual(200, resp.status_code)
            raw = json.dumps(resp.json())
            self.assertIn(did, raw)
            self.assertIn(verkey, raw)
        finally:
            os.popen("pkill -f run_wallet_agent")
            sleep(1)
            run_async(conn.delete())

    def test_create_and_store_my_did__with_seed(self):
        conn = WalletConnection(self.WALLET_UID, self.WALLET_PASS_PHRASE)
        wallet = Wallet.objects.create(uid=self.WALLET_UID, owner=self.account)
        url = self.live_server_url + '/agent/admin/wallets/%s/did/create_and_store_my_did/' % wallet.uid
        # first: create wallet
        run_async(conn.create())
        try:
            cred = dict(pass_phrase=self.WALLET_PASS_PHRASE,
                        seed='000000000000000000000000Steward1')
            # open
            url_open = self.live_server_url + reverse(
                'admin-wallets-open', kwargs=dict(uid=self.WALLET_UID))
            resp = requests.post(url_open,
                                 json=cred,
                                 auth=HTTPBasicAuth(self.IDENTITY, self.PASS))
            self.assertEqual(200, resp.status_code)
            # FIRE!!!
            resp = requests.post(url,
                                 json=cred,
                                 auth=HTTPBasicAuth(self.IDENTITY, self.PASS))
            self.assertEqual(201, resp.status_code)
            info = resp.json()
            self.assertTrue(info.get('did'))
            self.assertTrue(info.get('verkey'))
            # Fire second time
            resp = requests.post(url,
                                 json=cred,
                                 auth=HTTPBasicAuth(self.IDENTITY, self.PASS))
            self.assertIn(resp.status_code, [201, 409])
        finally:
            os.popen("pkill -f run_wallet_agent")
            sleep(1)
            run_async(conn.delete())

    def test_create_and_store_my_did__without_seed(self):
        conn = WalletConnection(self.WALLET_UID, self.WALLET_PASS_PHRASE)
        wallet = Wallet.objects.create(uid=self.WALLET_UID, owner=self.account)
        url = self.live_server_url + '/agent/admin/wallets/%s/did/create_and_store_my_did/' % wallet.uid
        # first: create wallet
        run_async(conn.create())
        try:
            cred = dict(pass_phrase=self.WALLET_PASS_PHRASE)
            # open
            url_open = self.live_server_url + reverse(
                'admin-wallets-open', kwargs=dict(uid=self.WALLET_UID))
            resp = requests.post(url_open,
                                 json=cred,
                                 auth=HTTPBasicAuth(self.IDENTITY, self.PASS))
            self.assertEqual(200, resp.status_code)
            # FIRE!!!
            resp = requests.post(url,
                                 json=cred,
                                 auth=HTTPBasicAuth(self.IDENTITY, self.PASS))
            self.assertEqual(201, resp.status_code)
            info1 = resp.json()
            self.assertTrue(info1.get('did'))
            self.assertTrue(info1.get('verkey'))
            # Fire second time
            resp = requests.post(url,
                                 json=cred,
                                 auth=HTTPBasicAuth(self.IDENTITY, self.PASS))
            self.assertEqual(201, resp.status_code)
            info2 = resp.json()
            self.assertTrue(info2.get('did'))
            self.assertTrue(info2.get('verkey'))
            # compare both answers
            self.assertNotEqual(info1['did'], info2['did'])
            self.assertNotEqual(info1['verkey'], info2['verkey'])
        finally:
            os.popen("pkill -f run_wallet_agent")
            sleep(1)
            run_async(conn.delete())
class VCXCompatibilityTest(LiveServerTestCase):

    IDENTITY_AGENT1 = 'agent1_user'
    IDENTITY_AGENT2 = 'agent2_user'
    IDENTITY_PASS = '******'
    WALLET_AGENT1 = 'wallet_1'
    WALLET_AGENT2 = 'wallet_2'
    WALLET_PASS_PHRASE = 'pass'
    WALLET_AGENT1_DB_NAME = WalletConnection.make_wallet_address(WALLET_AGENT1)
    WALLET_AGENT2_DB_NAME = WalletConnection.make_wallet_address(WALLET_AGENT2)
    DEF_TIMEOUT = 3

    def setUp(self):
        for identity in [self.IDENTITY_AGENT1, self.IDENTITY_AGENT2]:
            account = AgentAccount.objects.create(username=identity,
                                                  is_active=True,
                                                  is_staff=True)
            account.set_password(self.IDENTITY_PASS)
            account.save()
        os.popen("pkill -f run_wallet_agent")
        sleep(0.1)
        psax = get_ps_ax()
        self.assertNotIn('run_wallet_agent', psax, psax)
        self.assertNotIn('indy-dummy-agent', psax, psax)
        with connection.cursor() as cursor:
            for db_name in [
                    self.WALLET_AGENT1_DB_NAME, self.WALLET_AGENT2_DB_NAME
            ]:
                cursor.execute("DROP DATABASE  IF EXISTS %s" % db_name)
        self.agents = []
        self.agents_logs = dict()
        self.agents_logs[self.IDENTITY_AGENT1] = list()
        self.agents_logs[self.IDENTITY_AGENT2] = list()
        self.start_agents()
        self.start_dummy_cloud_agent()

    def tearDown(self):
        self.stop_agents()
        sleep(1)
        os.popen("pkill -f run_wallet_agent")
        os.popen("pkill -f indy-dummy-agent")
        sleep(1)

    def start_agents(self):
        async def start_agent(agent_name, pass_phrase):
            conn = WalletConnection(agent_name, pass_phrase)
            await conn.create()
            try:
                print('Agent "%s" is started' % agent_name)
                await WalletAgent.process(agent_name)
            finally:
                await conn.delete()
                print('Wallet "%s" is deleted' % agent_name)

        for agent, identity in [(self.WALLET_AGENT1, self.IDENTITY_AGENT1),
                                (self.WALLET_AGENT2, self.IDENTITY_AGENT2)]:
            thread = ThreadScheduler()
            self.agents.append(thread)
            thread.start()
            asyncio.run_coroutine_threadsafe(start_agent(
                agent, self.WALLET_PASS_PHRASE),
                                             loop=thread.loop)
            account = AgentAccount.objects.get(username=identity)
            model_wallet = WalletModel.objects.create(uid=agent, owner=account)
            endpoint_uid = 'endpoint_for_' + agent
            EndpointModel.objects.create(uid=endpoint_uid,
                                         owner=account,
                                         wallet=model_wallet,
                                         url=reverse(
                                             'endpoint',
                                             kwargs=dict(uid=endpoint_uid)))

        sleep(self.DEF_TIMEOUT)

    pass

    def start_dummy_cloud_agent(self):
        exe = "/dummy-cloud-agent/target/release/indy-dummy-agent"
        config = "/dummy-cloud-agent/config/sample-config.json"
        cmd_line = '%s %s' % (exe, config)
        args = cmd_line.split()
        process = subprocess.Popen(args)
        stat = process.poll()
        self.assertIsNone(stat)

    def stop_agents(self):
        async def stop_agent(agent_name, pass_phrase):
            try:
                await WalletAgent.close(agent_name, pass_phrase)
            except AgentTimeOutError:
                pass

        for agent in [self.WALLET_AGENT1, self.WALLET_AGENT2]:
            run_async(stop_agent(agent, self.WALLET_PASS_PHRASE))
        sleep(self.DEF_TIMEOUT)
        for thread in self.agents:
            thread.stop()

    pass

    def create_did(self, wallet_uid: str, seed: str = None):
        run_async(WalletAgent.open(wallet_uid, self.WALLET_PASS_PHRASE))
        did, verkey = run_async(
            WalletAgent.create_and_store_my_did(wallet_uid,
                                                self.WALLET_PASS_PHRASE, seed))
        run_async(
            WalletAgent.add_wallet_record(wallet_uid, self.WALLET_PASS_PHRASE,
                                          WALLET_KEY_TO_DID_KEY, verkey, did))
        return did, verkey

    def test_vcx_invitee(self):
        cred = dict(pass_phrase=self.WALLET_PASS_PHRASE)
        endpoint_inviter = AgentAccount.objects.get(
            username=self.IDENTITY_AGENT1).endpoints.first()
        endpoint_inviter.url = self.live_server_url + reverse(
            'endpoint',
            kwargs=dict(uid=AgentAccount.objects.get(
                username=self.IDENTITY_AGENT1).endpoints.first().uid))
        endpoint_inviter.save()
        inviter = dict(
            identity=self.IDENTITY_AGENT1,
            password=self.IDENTITY_PASS,
            wallet_uid=AgentAccount.objects.get(
                username=self.IDENTITY_AGENT1).wallets.first().uid,
            endpoint_uid=AgentAccount.objects.get(
                username=self.IDENTITY_AGENT1).endpoints.first().uid,
            endpoint_url=endpoint_inviter.url)
        # generate invitation link
        url = self.live_server_url + '/agent/admin/wallets/%s/endpoints/%s/invitations/' % \
              (inviter['wallet_uid'], inviter['endpoint_uid'])
        invitation_kwargs = dict(**cred)
        invitation_kwargs['feature'] = 'feature_0160'
        resp = requests.post(url,
                             json=invitation_kwargs,
                             auth=HTTPBasicAuth(inviter['identity'],
                                                inviter['password']))
        self.assertEqual(201, resp.status_code, resp.text)
        # Parse invitation message body
        link = resp.json()['url']
        matches = re.match("(.+)?c_i=(.+)", link)
        buffer = base64.urlsafe_b64decode(matches.group(2)).decode('utf-8')
        msg = json.loads(buffer)

        alice_vcx_config = ProvisionConfig(
            agency_url='http://localhost:8080',
            agency_did='VsKV7grR1BUE29mG2Fm2kX',
            agency_verkey='Hezce2UWMZ3wUhVkh2LfKSs8nDzWwzs2Win7EzNN3YaR',
            wallet_name='alice_wallet',
            enterprise_seed='000000000000000000000000Trustee1')
        alice_vcx_invitation = Invitation(
            label=msg['label'],
            recipient_keys=msg['recipientKeys'],
            service_endpoint=msg['serviceEndpoint'],
            routing_keys=[])
        connection_ok = run_async(alice_establish_connection(
            alice=alice_vcx_config, invitation=alice_vcx_invitation),
                                  timeout=60)
        self.assertTrue(connection_ok)

    def test_vcx_inviter(self):
        # 1 Prepare inviter
        faber_vcx_config = ProvisionConfig(
            agency_url='http://localhost:8080',
            agency_did='VsKV7grR1BUE29mG2Fm2kX',
            agency_verkey='Hezce2UWMZ3wUhVkh2LfKSs8nDzWwzs2Win7EzNN3YaR',
            wallet_name='faber_wallet',
            enterprise_seed='000000000000000000000000Trustee1')
        invite_msg, vcx_connection = run_async(
            faber_generate_invitation(faber_vcx_config, 'Faber'))
        b64_invite = base64.urlsafe_b64encode(
            json.dumps(invite_msg).encode('ascii')).decode('ascii')
        invitation_url = 'http://localhost:8080?c_i=' + b64_invite

        # Prepare Invitee
        endpoint_inviter = AgentAccount.objects.get(
            username=self.IDENTITY_AGENT1).endpoints.first()
        endpoint_inviter.url = self.live_server_url + reverse(
            'endpoint',
            kwargs=dict(uid=AgentAccount.objects.get(
                username=self.IDENTITY_AGENT1).endpoints.first().uid))
        endpoint_inviter.save()
        invitee = dict(
            identity=self.IDENTITY_AGENT1,
            password=self.IDENTITY_PASS,
            wallet_uid=AgentAccount.objects.get(
                username=self.IDENTITY_AGENT1).wallets.first().uid,
            endpoint_uid=AgentAccount.objects.get(
                username=self.IDENTITY_AGENT1).endpoints.first().uid,
            endpoint_url=endpoint_inviter.url)
        cred = dict(pass_phrase=self.WALLET_PASS_PHRASE)

        # 3 Run faber listener
        thread = ThreadScheduler()
        thread.start()
        try:
            asyncio.run_coroutine_threadsafe(
                faber_establish_connection(vcx_connection), loop=thread.loop)
            # 4 FIRE!!!
            url = self.live_server_url + '/agent/admin/wallets/%s/endpoints/%s/invite/' % (
                invitee['wallet_uid'], invitee['endpoint_uid'])
            invite = dict(**cred)
            invite['url'] = invitation_url
            resp = requests.post(url,
                                 json=invite,
                                 auth=HTTPBasicAuth(invitee['identity'],
                                                    invitee['password']))
            self.assertEqual(200, resp.status_code)
        finally:
            thread.stop()

    def test_vcx_issue_credential(self):
        # 1 Prepare Faber issuer
        faber_vcx_config = ProvisionConfig(
            agency_url='http://localhost:8080',
            agency_did='VsKV7grR1BUE29mG2Fm2kX',
            agency_verkey='Hezce2UWMZ3wUhVkh2LfKSs8nDzWwzs2Win7EzNN3YaR',
            wallet_name='faber_wallet',
            enterprise_seed='000000000000000000000000Trustee1')
        invite_msg, vcx_connection, schema_id, cred_def_handle = run_async(
            faber_setup_issuer(faber_vcx_config, 'Faber'), timeout=60)
        b64_invite = base64.urlsafe_b64encode(
            json.dumps(invite_msg).encode('ascii')).decode('ascii')
        invitation_url = 'http://localhost:8080?c_i=' + b64_invite
        # 2 Prepare Schemas and CredDef(s)
        # Prepare Invitee
        endpoint_inviter = AgentAccount.objects.get(
            username=self.IDENTITY_AGENT1).endpoints.first()
        endpoint_inviter.url = self.live_server_url + reverse(
            'endpoint',
            kwargs=dict(uid=AgentAccount.objects.get(
                username=self.IDENTITY_AGENT1).endpoints.first().uid))
        endpoint_inviter.save()
        invitee = dict(
            identity=self.IDENTITY_AGENT1,
            password=self.IDENTITY_PASS,
            wallet_uid=AgentAccount.objects.get(
                username=self.IDENTITY_AGENT1).wallets.first().uid,
            endpoint_uid=AgentAccount.objects.get(
                username=self.IDENTITY_AGENT1).endpoints.first().uid,
            endpoint_url=endpoint_inviter.url)
        cred = dict(pass_phrase=self.WALLET_PASS_PHRASE)

        # 3 Run faber listener
        thread = ThreadScheduler()
        thread.start()
        try:
            asyncio.run_coroutine_threadsafe(
                faber_establish_connection(vcx_connection), loop=thread.loop)
            # 4 FIRE!!!
            url = self.live_server_url + '/agent/admin/wallets/%s/endpoints/%s/invite/' % (
                invitee['wallet_uid'], invitee['endpoint_uid'])
            invite = dict(**cred)
            invite['url'] = invitation_url
            resp = requests.post(url,
                                 json=invite,
                                 auth=HTTPBasicAuth(invitee['identity'],
                                                    invitee['password']))
            self.assertEqual(200, resp.status_code)
            thread = ThreadScheduler()
            thread.start()
            try:
                asyncio.run_coroutine_threadsafe(faber_issue_credential(
                    vcx_connection, cred_def_handle),
                                                 loop=thread.loop)
                sleep(1000)
            finally:
                thread.stop()
        finally:
            thread.stop()