Exemple #1
0
    def _submit_attempt(self, user, face_image, photo_id_image=None, initial_verification=None):
        """
        Submit a verification attempt.

        Arguments:
            user (User): The user making the attempt.
            face_image (str): Decoded face image data.

        Keyword Arguments:
            photo_id_image (str or None): Decoded photo ID image data.
            initial_verification (SoftwareSecurePhotoVerification): The initial verification attempt.
        """
        attempt = SoftwareSecurePhotoVerification(user=user)

        # We will always have face image data, so upload the face image
        attempt.upload_face_image(face_image)

        # If an ID photo wasn't submitted, re-use the ID photo from the initial attempt.
        # Earlier validation rules ensure that at least one of these is available.
        if photo_id_image is not None:
            attempt.upload_photo_id_image(photo_id_image)
        elif initial_verification is None:
            # Earlier validation should ensure that we never get here.
            log.error(
                "Neither a photo ID image or initial verification attempt provided. "
                "Parameter validation in the view should prevent this from happening!"
            )

        # Submit the attempt
        attempt.mark_ready()
        attempt.submit(copy_id_photo_from=initial_verification)

        return attempt
Exemple #2
0
    def test_retire_user(self):
        """
        Retire user with record(s) in table
        """
        user = UserFactory.create()
        user.profile.name = u"Enrique"
        attempt = SoftwareSecurePhotoVerification(user=user)

        # Populate Record
        attempt.mark_ready()
        attempt.status = "submitted"
        attempt.photo_id_image_url = "https://example.com/test/image/img.jpg"
        attempt.face_image_url = "https://example.com/test/face/img.jpg"
        attempt.photo_id_key = 'there_was_an_attempt'
        attempt.approve()

        # Validate data before retirement
        self.assertEqual(attempt.name, user.profile.name)
        self.assertEqual(attempt.photo_id_image_url, 'https://example.com/test/image/img.jpg')
        self.assertEqual(attempt.face_image_url, 'https://example.com/test/face/img.jpg')
        self.assertEqual(attempt.photo_id_key, 'there_was_an_attempt')

        # Retire User
        attempt_again = SoftwareSecurePhotoVerification(user=user)
        self.assertTrue(attempt_again.retire_user(user_id=user.id))

        # Validate data after retirement
        self.assertEqual(attempt_again.name, '')
        self.assertEqual(attempt_again.face_image_url, '')
        self.assertEqual(attempt_again.photo_id_image_url, '')
        self.assertEqual(attempt_again.photo_id_key, '')
 def create_and_submit(self, user):
     """ Helper method that lets us create new SoftwareSecurePhotoVerifications """
     attempt = SoftwareSecurePhotoVerification(user=user)
     attempt.upload_face_image("Fake Data")
     attempt.upload_photo_id_image("More Fake Data")
     attempt.mark_ready()
     attempt.submit()
     return attempt
Exemple #4
0
    def test_state_transitions(self):
        """
        Make sure we can't make unexpected status transitions.

        The status transitions we expect are::

                        → → → must_retry
                        ↑        ↑ ↓
            created → ready → submitted → approved
                                    ↓        ↑ ↓
                                    ↓ → →  denied
        """
        user = UserFactory.create()
        attempt = SoftwareSecurePhotoVerification(user=user)
        self.assertEqual(attempt.status, "created")

        # These should all fail because we're in the wrong starting state.
        self.assertRaises(VerificationException, attempt.submit)
        self.assertRaises(VerificationException, attempt.approve)
        self.assertRaises(VerificationException, attempt.deny)

        # Now let's fill in some values so that we can pass the mark_ready() call
        attempt.mark_ready()
        self.assertEqual(attempt.status, "ready")

        # ready (can't approve or deny unless it's "submitted")
        self.assertRaises(VerificationException, attempt.approve)
        self.assertRaises(VerificationException, attempt.deny)

        DENY_ERROR_MSG = '[{"photoIdReasons": ["Not provided"]}]'

        # must_retry
        attempt.status = "must_retry"
        attempt.system_error("System error")
        attempt.approve()
        attempt.status = "must_retry"
        attempt.deny(DENY_ERROR_MSG)

        # submitted
        attempt.status = "submitted"
        attempt.deny(DENY_ERROR_MSG)
        attempt.status = "submitted"
        attempt.approve()

        # approved
        self.assertRaises(VerificationException, attempt.submit)
        attempt.approve()  # no-op
        attempt.system_error("System error")  # no-op, something processed it without error
        attempt.deny(DENY_ERROR_MSG)

        # denied
        self.assertRaises(VerificationException, attempt.submit)
        attempt.deny(DENY_ERROR_MSG)  # no-op
        attempt.system_error("System error")  # no-op, something processed it without error
        attempt.approve()
Exemple #5
0
    def create_and_submit(self):
        """Helper method to create a generic submission and send it."""
        user = UserFactory.create()
        attempt = SoftwareSecurePhotoVerification(user=user)
        user.profile.name = u"Rust\u01B4"

        attempt.upload_face_image("Just pretend this is image data")
        attempt.upload_photo_id_image("Hey, we're a photo ID")
        attempt.mark_ready()
        attempt.submit()

        return attempt
Exemple #6
0
    def test_submission_while_testing_flag_is_true(self):
        """ Test that a fake value is set for field 'photo_id_key' of user's
        initial verification when the feature flag 'AUTOMATIC_VERIFY_STUDENT_IDENTITY_FOR_TESTING'
        is enabled.
        """
        user = UserFactory.create()
        attempt = SoftwareSecurePhotoVerification(user=user)
        user.profile.name = "test-user"

        attempt.upload_photo_id_image("Image data")
        attempt.mark_ready()
        attempt.submit()

        self.assertEqual(attempt.photo_id_key, "fake-photo-id-key")
Exemple #7
0
    def test_name_freezing(self):
        """
        You can change your name prior to marking a verification attempt ready,
        but changing your name afterwards should not affect the value in the
        in the attempt record. Basically, we want to always know what your name
        was when you submitted it.
        """
        user = UserFactory.create()
        user.profile.name = u"Jack \u01B4"  # gratuious non-ASCII char to test encodings

        attempt = SoftwareSecurePhotoVerification(user=user)
        user.profile.name = u"Clyde \u01B4"
        attempt.mark_ready()

        user.profile.name = u"Rusty \u01B4"

        self.assertEqual(u"Clyde \u01B4", attempt.name)
    def test_active_for_user(self):
        """
        Make sure we can retrive a user's active (in progress) verification
        attempt.
        """
        user = UserFactory.create()

        # This user has no active at the moment...
        assert_is_none(SoftwareSecurePhotoVerification.active_for_user(user))

        # Create an attempt and mark it ready...
        attempt = SoftwareSecurePhotoVerification(user=user)
        attempt.mark_ready()
        assert_equals(attempt, SoftwareSecurePhotoVerification.active_for_user(user))

        # A new user won't see this...
        user2 = UserFactory.create()
        user2.save()
        assert_is_none(SoftwareSecurePhotoVerification.active_for_user(user2))

        # If it's got a different status, it doesn't count
        for status in ["submitted", "must_retry", "approved", "denied"]:
            attempt.status = status
            attempt.save()
            assert_is_none(SoftwareSecurePhotoVerification.active_for_user(user))

        # But if we create yet another one and mark it ready, it passes again.
        attempt_2 = SoftwareSecurePhotoVerification(user=user)
        attempt_2.mark_ready()
        assert_equals(attempt_2, SoftwareSecurePhotoVerification.active_for_user(user))

        # And if we add yet another one with a later created time, we get that
        # one instead. We always want the most recent attempt marked ready()
        attempt_3 = SoftwareSecurePhotoVerification(
            user=user,
            created_at=attempt_2.created_at + timedelta(days=1)
        )
        attempt_3.save()

        # We haven't marked attempt_3 ready yet, so attempt_2 still wins
        assert_equals(attempt_2, SoftwareSecurePhotoVerification.active_for_user(user))

        # Now we mark attempt_3 ready and expect it to come back
        attempt_3.mark_ready()
        assert_equals(attempt_3, SoftwareSecurePhotoVerification.active_for_user(user))
Exemple #9
0
    def test_state_transitions(self):
        """
        Make sure we can't make unexpected status transitions.

        The status transitions we expect are::

                        → → → must_retry
                        ↑        ↑ ↓
            created → ready → submitted → approved
                                    ↓        ↑ ↓
                                    ↓ → →  denied
        """
        user = UserFactory.create()
        attempt = SoftwareSecurePhotoVerification(user=user)
        self.assertEqual(attempt.status, PhotoVerification.STATUS.created)

        # These should all fail because we're in the wrong starting state.
        self.assertRaises(VerificationException, attempt.submit)
        self.assertRaises(VerificationException, attempt.approve)
        self.assertRaises(VerificationException, attempt.deny)
        self.assertRaises(VerificationException, attempt.mark_must_retry)
        self.assertRaises(VerificationException, attempt.mark_submit)

        # Now let's fill in some values so that we can pass the mark_ready() call
        attempt.mark_ready()
        self.assertEqual(attempt.status, PhotoVerification.STATUS.ready)

        # ready (can't approve or deny unless it's "submitted")
        self.assertRaises(VerificationException, attempt.approve)
        self.assertRaises(VerificationException, attempt.deny)
        attempt.mark_must_retry()
        attempt.mark_submit()

        DENY_ERROR_MSG = '[{"photoIdReasons": ["Not provided"]}]'

        # must_retry
        attempt.status = PhotoVerification.STATUS.must_retry
        attempt.system_error("System error")
        attempt.mark_must_retry()  # no-op
        attempt.mark_submit()
        attempt.approve()

        attempt.status = PhotoVerification.STATUS.must_retry
        attempt.deny(DENY_ERROR_MSG)

        # submitted
        attempt.status = PhotoVerification.STATUS.submitted
        attempt.deny(DENY_ERROR_MSG)

        attempt.status = PhotoVerification.STATUS.submitted
        attempt.mark_must_retry()

        attempt.status = PhotoVerification.STATUS.submitted
        attempt.approve()

        # approved
        self.assertRaises(VerificationException, attempt.submit)
        self.assertRaises(VerificationException, attempt.mark_must_retry)
        self.assertRaises(VerificationException, attempt.mark_submit)
        attempt.approve()  # no-op
        attempt.system_error(
            "System error")  # no-op, something processed it without error
        attempt.deny(DENY_ERROR_MSG)

        # denied
        self.assertRaises(VerificationException, attempt.submit)
        self.assertRaises(VerificationException, attempt.mark_must_retry)
        self.assertRaises(VerificationException, attempt.mark_submit)
        attempt.deny(DENY_ERROR_MSG)  # no-op
        attempt.system_error(
            "System error")  # no-op, something processed it without error
        attempt.approve()