Exemplo n.º 1
0
    def test_get_devices_for_safe_and_owners(self):
        safe_contract = SafeContractFactory()
        self.assertEqual(
            FirebaseDeviceOwner.objects.get_devices_for_safe_and_owners(
                safe_contract.address, []), [])
        self.assertEqual(
            FirebaseDeviceOwner.objects.get_devices_for_safe_and_owners(
                safe_contract.address, [Account.create().address]), [])

        firebase_device_owner = FirebaseDeviceOwnerFactory.create(
            firebase_device__safes=(safe_contract, ))
        firebase_device_owner_2 = FirebaseDeviceOwnerFactory(
            firebase_device=firebase_device_owner.firebase_device)

        self.assertEqual(
            FirebaseDeviceOwner.objects.get_devices_for_safe_and_owners(
                Account.create().address, []), [])
        self.assertEqual(
            FirebaseDeviceOwner.objects.get_devices_for_safe_and_owners(
                safe_contract.address,
                [firebase_device_owner.owner, firebase_device_owner_2.owner]),
            [firebase_device_owner.firebase_device.cloud_messaging_token])

        safe_contract_2 = SafeContractFactory()
        firebase_device_owner_3 = FirebaseDeviceOwnerFactory.create(
            firebase_device__safes=(safe_contract_2, ))
        self.assertEqual(
            FirebaseDeviceOwner.objects.get_devices_for_safe_and_owners(
                safe_contract.address, [
                    firebase_device_owner.owner, firebase_device_owner_2.owner,
                    firebase_device_owner_3.owner
                ]),
            [firebase_device_owner.firebase_device.cloud_messaging_token])
        self.assertEqual(
            FirebaseDeviceOwner.objects.get_devices_for_safe_and_owners(
                safe_contract_2.address, [
                    firebase_device_owner.owner, firebase_device_owner_2.owner,
                    firebase_device_owner_3.owner
                ]),
            [firebase_device_owner_3.firebase_device.cloud_messaging_token])

        firebase_device_owner_3.firebase_device.safes.add(safe_contract)
        self.assertCountEqual(
            FirebaseDeviceOwner.objects.get_devices_for_safe_and_owners(
                safe_contract.address, [
                    firebase_device_owner.owner, firebase_device_owner_2.owner,
                    firebase_device_owner_3.owner
                ]),
            [
                firebase_device_owner.firebase_device.cloud_messaging_token,
                firebase_device_owner_3.firebase_device.cloud_messaging_token
            ])
Exemplo n.º 2
0
    def test_send_notification_owner_task(self):
        from ..tasks import logger as task_logger
        safe_contract = SafeContractFactory()
        safe_address = safe_contract.address
        threshold = 2
        owners = [Account.create().address for _ in range(2)]
        safe_tx_hash = Web3.keccak(text='hola').hex()
        with self.assertLogs(logger=task_logger) as cm:
            self.assertEqual(send_notification_owner_task(safe_address, safe_tx_hash), (0, 0))
            self.assertIn('Cannot find threshold information', cm.output[0])

        safe_status = SafeStatusFactory(address=safe_address, threshold=1, owners=owners)
        with self.assertLogs(logger=task_logger) as cm:
            self.assertEqual(send_notification_owner_task(safe_address, safe_tx_hash), (0, 0))
            self.assertIn('No need to send confirmation notification for ', cm.output[0])

        safe_status.threshold = threshold
        safe_status.save(update_fields=['threshold'])
        with self.assertLogs(logger=task_logger) as cm:
            self.assertEqual(send_notification_owner_task(safe_address, safe_tx_hash), (0, 0))
            self.assertIn('No cloud messaging tokens found', cm.output[0])

        firebase_device_owner_factories = [FirebaseDeviceOwnerFactory(owner=owner) for owner in owners]
        # Notification is not sent to both owners as they are not related to the safe address
        self.assertEqual(send_notification_owner_task(safe_address, safe_tx_hash), (0, 0))

        for firebase_device_owner in firebase_device_owner_factories:
            firebase_device_owner.firebase_device.safes.add(safe_contract)
        self.assertEqual(send_notification_owner_task(safe_address, safe_tx_hash), (2, 0))

        # Duplicated notifications are not sent
        with self.assertLogs(logger=task_logger) as cm:
            self.assertEqual(send_notification_owner_task(safe_address, safe_tx_hash), (0, 0))
            self.assertIn('Duplicated notification', cm.output[0])

        # Disable duplicated detection
        with mock.patch.object(DuplicateNotification, 'is_duplicated', autospec=True, return_value=False):
            self.assertEqual(send_notification_owner_task(safe_address, safe_tx_hash), (2, 0))

            # Add one confirmation for that transaction and other random confirmation for other transaction
            # to check that they don't influence each other
            multisig_confirmation = MultisigConfirmationFactory(owner=owners[0],
                                                                multisig_transaction__safe_tx_hash=safe_tx_hash)
            MultisigConfirmationFactory(owner=owners[1])  # Not related multisig transaction

            # Just one transaction sent, as owners[0] already confirmed
            self.assertEqual(send_notification_owner_task(safe_address, safe_tx_hash), (1, 0))

            # Reach the threshold with an unrelated owner
            MultisigConfirmationFactory(multisig_transaction=multisig_confirmation.multisig_transaction)
            with self.assertLogs(logger=task_logger) as cm:
                self.assertEqual(send_notification_owner_task(safe_address, safe_tx_hash), (0, 0))
                self.assertIn('does not require more confirmations', cm.output[0])
    def test_notifications_devices_safe_delete_view(self):
        safe_contract = SafeContractFactory()
        firebase_device = FirebaseDeviceFactory()
        firebase_device_owner = FirebaseDeviceOwnerFactory(
            firebase_device=firebase_device)
        not_related_firebase_device_owner = FirebaseDeviceOwnerFactory()
        firebase_device.safes.add(safe_contract)
        device_id = firebase_device.uuid

        # Test not existing `safe_contract`, even if `device_id` is correct
        random_safe_address = Account.create().address
        self.assertEqual(firebase_device.safes.count(), 1)
        self.assertEqual(FirebaseDeviceOwner.objects.count(), 2)
        response = self.client.delete(reverse(
            'v1:notifications-devices-safes-delete',
            args=(device_id, random_safe_address)),
                                      format='json')
        self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
        self.assertEqual(firebase_device.safes.count(), 1)
        self.assertEqual(FirebaseDeviceOwner.objects.count(), 2)

        # Happy path
        response = self.client.delete(reverse(
            'v1:notifications-devices-safes-delete',
            args=(device_id, safe_contract.address)),
                                      format='json')
        self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
        self.assertEqual(firebase_device.safes.count(), 0)
        self.assertEqual(FirebaseDeviceOwner.objects.count(), 1)
        self.assertEqual(FirebaseDeviceOwner.objects.get(),
                         not_related_firebase_device_owner)

        # Try to delete again and get the same result even if the Safe is not linked
        response = self.client.delete(reverse(
            'v1:notifications-devices-safes-delete',
            args=(device_id, safe_contract.address)),
                                      format='json')
        self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
        self.assertEqual(firebase_device.safes.count(), 0)
        self.assertEqual(FirebaseDeviceOwner.objects.count(), 1)

        # Remove not existing Safe should not trigger an error
        response = self.client.delete(reverse(
            'v1:notifications-devices-safes-delete',
            args=(device_id, Account.create().address)),
                                      format='json')
        self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
        self.assertEqual(firebase_device.safes.count(), 0)
        self.assertEqual(FirebaseDeviceOwner.objects.count(), 1)
Exemplo n.º 4
0
    def test_notifications_devices_delete_view(self):
        safe_contract = SafeContractFactory()
        firebase_device = FirebaseDeviceFactory()
        firebase_device.safes.add(safe_contract)
        device_id = firebase_device.uuid

        self.assertEqual(FirebaseDevice.objects.count(), 1)
        response = self.client.delete(reverse(
            'v1:notifications-devices-delete', args=(device_id, )),
                                      format='json')
        self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
        self.assertEqual(FirebaseDevice.objects.count(), 0)

        # Try to delete again if not exists
        response = self.client.delete(reverse(
            'v1:notifications-devices-delete', args=(device_id, )),
                                      format='json')
        self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
    def test_notifications_devices_create_view(self):
        response = self.client.post(reverse('v1:notifications-devices'))
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

        safe_address = Account.create().address
        safe_contract = SafeContractFactory(address=safe_address)

        self.assertEqual(FirebaseDevice.objects.count(), 0)
        data = {
            'safes': [safe_address],
            'cloudMessagingToken': 'A' * 163,
            'buildNumber': 0,
            'bundle': 'company.package.app',
            'deviceType': 'WEB',
            'version': '2.0.1',
        }
        response = self.client.post(reverse('v1:notifications-devices'),
                                    format='json',
                                    data=data)
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        self.assertEqual(FirebaseDevice.objects.count(), 1)
        device_uuid = response.data['uuid']
        self.assertTrue(uuid.UUID(device_uuid))

        # Same request should return a 400 because a new device with same push token cannot be created
        response = self.client.post(reverse('v1:notifications-devices'),
                                    format='json',
                                    data=data)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

        # Request with `uuid` should not create a new object
        data['uuid'] = device_uuid
        response = self.client.post(reverse('v1:notifications-devices'),
                                    format='json',
                                    data=data)
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        self.assertEqual(FirebaseDevice.objects.count(), 1)

        # Changing the token and using the uuid will change the cloud messaging token
        data['cloudMessagingToken'] = 'B' * 163
        response = self.client.post(reverse('v1:notifications-devices'),
                                    format='json',
                                    data=data)
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        self.assertEqual(FirebaseDevice.objects.count(), 1)
        self.assertEqual(FirebaseDevice.objects.first().cloud_messaging_token,
                         data['cloudMessagingToken'])

        # Add the same FirebaseDevice to another Safe
        safe_contract_2 = SafeContractFactory()
        data['safes'].append(safe_contract_2.address)
        response = self.client.post(reverse('v1:notifications-devices'),
                                    format='json',
                                    data=data)
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        self.assertEqual(safe_contract.firebase_devices.count(), 1)
        self.assertEqual(safe_contract_2.firebase_devices.count(), 1)
        self.assertEqual(FirebaseDevice.objects.count(), 1)
        self.assertEqual(FirebaseDevice.objects.first().safes.count(), 2)

        # Use not valid deviceType
        previous_device_type = data['deviceType']
        data['deviceType'] = 'RANGER-MORPHER'
        response = self.client.post(reverse('v1:notifications-devices'),
                                    format='json',
                                    data=data)
        self.assertIn('is not a valid choice', response.content.decode())
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
        self.assertEqual(safe_contract.firebase_devices.count(), 1)
        data['deviceType'] = previous_device_type

        # Use not valid version
        previous_version = data['version']
        data['version'] = 'Megazord'
        response = self.client.post(reverse('v1:notifications-devices'),
                                    format='json',
                                    data=data)
        self.assertIn('Semantic version was expected',
                      response.content.decode())
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
        self.assertEqual(safe_contract.firebase_devices.count(), 1)
        data['version'] = previous_version

        # Remove one of the Safes
        data['safes'] = [safe_contract_2.address]
        response = self.client.post(reverse('v1:notifications-devices'),
                                    format='json',
                                    data=data)
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        self.assertEqual(safe_contract.firebase_devices.count(), 0)
        self.assertEqual(safe_contract_2.firebase_devices.count(), 1)
    def test_notifications_devices_create_with_signatures_view(self):
        safe_address = Account.create().address
        safe_contract = SafeContractFactory(address=safe_address)
        owner_account = Account.create()
        owner_account_2 = Account.create()

        self.assertEqual(FirebaseDevice.objects.count(), 0)
        unique_id = uuid.uuid4()
        timestamp = int(time.time())
        cloud_messaging_token = 'A' * 163
        safes = [safe_address]
        hash_to_sign = calculate_device_registration_hash(
            timestamp, unique_id, cloud_messaging_token, safes)
        signatures = [owner_account.signHash(hash_to_sign)['signature'].hex()]
        data = {
            'uuid': unique_id,
            'safes': [safe_address],
            'cloudMessagingToken': cloud_messaging_token,
            'buildNumber': 0,
            'bundle': 'company.package.app',
            'deviceType': 'WEB',
            'version': '2.0.1',
            'timestamp': timestamp,
            'signatures': signatures,
        }
        response = self.client.post(reverse('v1:notifications-devices'),
                                    format='json',
                                    data=data)
        # self.assertIn('is not an owner of any of the safes', str(response.data['non_field_errors']))
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        self.assertEqual(response.data['owners_registered'], [])
        self.assertEqual(response.data['owners_not_registered'],
                         [owner_account.address])

        with mock.patch(
                'safe_transaction_service.notifications.serializers.get_safe_owners',
                return_value=[owner_account.address]):
            response = self.client.post(reverse('v1:notifications-devices'),
                                        format='json',
                                        data=data)
            self.assertEqual(response.status_code, status.HTTP_201_CREATED)
            self.assertEqual(response.data['uuid'], str(unique_id))
            self.assertEqual(FirebaseDevice.objects.count(), 1)
            self.assertEqual(FirebaseDeviceOwner.objects.count(), 1)
            self.assertEqual(FirebaseDeviceOwner.objects.first().owner,
                             owner_account.address)

            # Add another signature
            signatures.append(
                owner_account_2.signHash(hash_to_sign)['signature'].hex())
            response = self.client.post(reverse('v1:notifications-devices'),
                                        format='json',
                                        data=data)
            # self.assertIn('is not an owner of any of the safes', str(response.data['non_field_errors']))
            self.assertEqual(response.status_code, status.HTTP_201_CREATED)
            self.assertEqual(response.data['owners_registered'],
                             [owner_account.address])
            self.assertEqual(response.data['owners_not_registered'],
                             [owner_account_2.address])

        with mock.patch(
                'safe_transaction_service.notifications.serializers.get_safe_owners',
                return_value=[owner_account.address, owner_account_2.address]):
            response = self.client.post(reverse('v1:notifications-devices'),
                                        format='json',
                                        data=data)
            self.assertEqual(response.status_code, status.HTTP_201_CREATED)
            self.assertEqual(response.data['owners_registered'],
                             [owner_account.address, owner_account_2.address])
            self.assertEqual(response.data['owners_not_registered'], [])
            self.assertEqual(FirebaseDevice.objects.count(), 1)
            self.assertCountEqual(
                FirebaseDeviceOwner.objects.values_list('owner', flat=True),
                [owner_account.address, owner_account_2.address])
Exemplo n.º 7
0
    def test_notifications_devices_create_view(self):
        response = self.client.post(reverse("v1:notifications:devices"))
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

        safe_address = Account.create().address
        safe_contract = SafeContractFactory(address=safe_address)

        self.assertEqual(FirebaseDevice.objects.count(), 0)
        data = {
            "safes": [safe_address],
            "cloudMessagingToken": "A" * 163,
            "buildNumber": 0,
            "bundle": "company.package.app",
            "deviceType": "WEB",
            "version": "2.0.1",
        }
        response = self.client.post(reverse("v1:notifications:devices"),
                                    format="json",
                                    data=data)
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        self.assertEqual(FirebaseDevice.objects.count(), 1)
        device_uuid = response.data["uuid"]
        self.assertTrue(uuid.UUID(device_uuid))

        # Same request should return a 400 because a new device with same push token cannot be created
        response = self.client.post(reverse("v1:notifications:devices"),
                                    format="json",
                                    data=data)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

        # Request with `uuid` should not create a new object
        data["uuid"] = device_uuid
        response = self.client.post(reverse("v1:notifications:devices"),
                                    format="json",
                                    data=data)
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        self.assertEqual(FirebaseDevice.objects.count(), 1)

        # Changing the token and using the uuid will change the cloud messaging token
        data["cloudMessagingToken"] = "B" * 163
        response = self.client.post(reverse("v1:notifications:devices"),
                                    format="json",
                                    data=data)
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        self.assertEqual(FirebaseDevice.objects.count(), 1)
        self.assertEqual(
            FirebaseDevice.objects.first().cloud_messaging_token,
            data["cloudMessagingToken"],
        )

        # Add the same FirebaseDevice to another Safe
        safe_contract_2 = SafeContractFactory()
        data["safes"].append(safe_contract_2.address)
        response = self.client.post(reverse("v1:notifications:devices"),
                                    format="json",
                                    data=data)
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        self.assertEqual(safe_contract.firebase_devices.count(), 1)
        self.assertEqual(safe_contract_2.firebase_devices.count(), 1)
        self.assertEqual(FirebaseDevice.objects.count(), 1)
        self.assertEqual(FirebaseDevice.objects.first().safes.count(), 2)

        # Use not valid deviceType
        previous_device_type = data["deviceType"]
        data["deviceType"] = "RANGER-MORPHER"
        response = self.client.post(reverse("v1:notifications:devices"),
                                    format="json",
                                    data=data)
        self.assertIn("is not a valid choice", response.content.decode())
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
        self.assertEqual(safe_contract.firebase_devices.count(), 1)
        data["deviceType"] = previous_device_type

        # Use not valid version
        previous_version = data["version"]
        data["version"] = "Megazord"
        response = self.client.post(reverse("v1:notifications:devices"),
                                    format="json",
                                    data=data)
        self.assertIn("Semantic version was expected",
                      response.content.decode())
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
        self.assertEqual(safe_contract.firebase_devices.count(), 1)
        data["version"] = previous_version

        # Remove one of the Safes
        data["safes"] = [safe_contract_2.address]
        response = self.client.post(reverse("v1:notifications:devices"),
                                    format="json",
                                    data=data)
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        self.assertEqual(safe_contract.firebase_devices.count(), 0)
        self.assertEqual(safe_contract_2.firebase_devices.count(), 1)
Exemplo n.º 8
0
    def test_notifications_devices_create_with_signatures_view(self):
        safe_address = Account.create().address
        safe_contract = SafeContractFactory(address=safe_address)
        owner_account = Account.create()
        owner_account_2 = Account.create()

        self.assertEqual(FirebaseDevice.objects.count(), 0)
        unique_id = uuid.uuid4()
        timestamp = int(time.time())
        cloud_messaging_token = "A" * 163
        safes = [safe_address]
        hash_to_sign = calculate_device_registration_hash(
            timestamp, unique_id, cloud_messaging_token, safes)
        signatures = [owner_account.signHash(hash_to_sign)["signature"].hex()]
        data = {
            "uuid": unique_id,
            "safes": [safe_address],
            "cloudMessagingToken": cloud_messaging_token,
            "buildNumber": 0,
            "bundle": "company.package.app",
            "deviceType": "WEB",
            "version": "2.0.1",
            "timestamp": timestamp,
            "signatures": signatures,
        }
        response = self.client.post(reverse("v1:notifications:devices"),
                                    format="json",
                                    data=data)
        # self.assertIn('is not an owner of any of the safes', str(response.data['non_field_errors']))
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        self.assertEqual(response.data["owners_registered"], [])
        self.assertEqual(response.data["owners_not_registered"],
                         [owner_account.address])

        with mock.patch(
                "safe_transaction_service.notifications.serializers.get_safe_owners",
                return_value=[owner_account.address],
        ):
            response = self.client.post(reverse("v1:notifications:devices"),
                                        format="json",
                                        data=data)
            self.assertEqual(response.status_code, status.HTTP_201_CREATED)
            self.assertEqual(response.data["uuid"], str(unique_id))
            self.assertEqual(FirebaseDevice.objects.count(), 1)
            self.assertEqual(FirebaseDeviceOwner.objects.count(), 1)
            self.assertEqual(FirebaseDeviceOwner.objects.first().owner,
                             owner_account.address)

            # Add another signature
            signatures.append(
                owner_account_2.signHash(hash_to_sign)["signature"].hex())
            response = self.client.post(reverse("v1:notifications:devices"),
                                        format="json",
                                        data=data)
            # self.assertIn('is not an owner of any of the safes', str(response.data['non_field_errors']))
            self.assertEqual(response.status_code, status.HTTP_201_CREATED)
            self.assertEqual(response.data["owners_registered"],
                             [owner_account.address])
            self.assertEqual(response.data["owners_not_registered"],
                             [owner_account_2.address])

        with mock.patch(
                "safe_transaction_service.notifications.serializers.get_safe_owners",
                return_value=[owner_account.address, owner_account_2.address],
        ):
            response = self.client.post(reverse("v1:notifications:devices"),
                                        format="json",
                                        data=data)
            self.assertEqual(response.status_code, status.HTTP_201_CREATED)
            self.assertEqual(
                response.data["owners_registered"],
                [owner_account.address, owner_account_2.address],
            )
            self.assertEqual(response.data["owners_not_registered"], [])
            self.assertEqual(FirebaseDevice.objects.count(), 1)
            self.assertCountEqual(
                FirebaseDeviceOwner.objects.values_list("owner", flat=True),
                [owner_account.address, owner_account_2.address],
            )