Exemplo n.º 1
0
    def test_perfect_match(self):
        KnockServerTestCase.env_setup()

        stored_pattern = models.AccessPattern()
        stored_pattern.active = True
        stored_pattern.name = "Test Pattern 1"
        stored_pattern.pending = False
        stored_pattern.used_count = 0

        # Make this access pattern expire in the future by a significant amount of seconds
        stored_pattern.expiration = time.time() + 10000

        for i in range(3):
            piece = models.PatternPiece()
            piece.length = 123
            piece.order = i
            # First int is pressed time so all even indexed values are pressed
            piece.pressed = i % 2 == 0

            stored_pattern.pattern_pieces.append(piece)

        db_session.add(stored_pattern)
        db_session.commit()

        resp = self.app.post('/knock/',
                             data=json.dumps({"pattern": [123, 123, 123]}),
                             content_type='application/json',
                             follow_redirects=True)

        data = json.loads(resp.data.decode())
        self.assertEqual(data['success'], True)
Exemplo n.º 2
0
def patterns_post():
    """Handles the creation of new knock patterns for a user."""
    data = request.get_json(
        force=True)  # Converts request body json into python dict

    pattern = AccessPattern()

    # Fields from form
    try:
        pattern.name = data['name']
    except KeyError as e:
        return Response('Name is required', 400)

    if 'expiration' in data:
        pattern.expiration = data['expiration']
    else:
        pattern.expiration = 0

    if 'max_uses' in data:
        pattern.max_uses = data['max_uses']
    else:
        pattern.max_uses = -1
    if 'device_id' in data:
        device_id = data['device_id']
        device = Device.get_device()
        device.identifier = device_id

    if 'door_name' in data:
        door_name = data['door_name']
        profile = ProfileJoin.get_profile()
        profile.door_name = door_name
        db_session.add(profile)

    # Fields that always are initialized to the same value
    pattern.active = True
    pattern.used_count = 0
    pattern.pending = True

    db_session.add(pattern)
    db_session.commit()

    return jsonify(success=True)
Exemplo n.º 3
0
def on_board_user():
    """Onboard a user."""
    form = UserProfileForm()
    if form.validate_on_submit():
        user = User()
        user.username = form.username.data
        user.ifttt_secret = form.ifttt_secret.data

        device = Device()
        device.identifier = form.device_id.data
        device.failure_count = 0

        preferences = NotificationPreferences()
        preferences.expire_threshold = form.expire_threshold.data
        preferences.failed_attempts_threshold = form.failed_attempts_threshold.data
        preferences.remaining_use_threshold = form.remaining_use_threshold.data
        preferences.send_no_earlier = form.send_no_earlier.data
        preferences.send_no_later = form.send_no_later.data
        preferences.success_threshold = form.success_threshold.data
        preferences.name = form.name.data
        preferences.failure_endpoint = form.failure_endpoint.data

        db_session.add(user)
        db_session.add(device)
        db_session.add(preferences)
        db_session.commit()

        profile_join = ProfileJoin()
        profile_join.device_id = device.id
        profile_join.user_id = user.id
        profile_join.preference_id = preferences.id
        profile_join.door_name = "Door 1"

        db_session.add(profile_join)
        db_session.commit()
        flash(user.username + ' successfully onboarded!', 'success')

    return render_template('onboarding.html', form=form)
Exemplo n.º 4
0
    def env_setup():
        """
        Utilize this helper function to initialize all the user profile stuff for testing
        """
        stored_device = models.Device()
        stored_device.failure_count = 1
        stored_device.name = "TestDevice1"
        stored_device.identifier = "TestDevice1"

        stored_user = models.User()
        stored_user.hashed_pass = "******"
        stored_user.ifttt_secret = "cMq6JSJtMAzXa9BFq_EjX6"
        stored_user.salt = "fake the salt"
        stored_user.username = "******"

        stored_profile = models.ProfileJoin()
        stored_profile.device_id = 1
        stored_profile.pattern_id = 1
        stored_profile.preference_id = 1
        stored_profile.user_id = 1
        stored_profile.door_name = "TestDoor1"

        stored_preferences = models.NotificationPreferences()
        stored_preferences.expire_threshold = 10000
        stored_preferences.failed_attempts_threshold = 1
        stored_preferences.name = "knock_knock"
        stored_preferences.remaining_use_threshold = 10
        stored_preferences.send_no_earlier = None
        stored_preferences.send_no_later = None
        stored_preferences.success_threshold = 1
        stored_preferences.failure_endpoint = "knock_failed"

        db_session.add(stored_device)
        db_session.add(stored_user)
        db_session.add(stored_profile)
        db_session.add(stored_preferences)
        db_session.commit()
Exemplo n.º 5
0
    def test_expired_knock_not_matched(self):

        stored_device = models.Device()
        stored_device.failure_count = 1
        stored_device.name = "TestDevice1"
        stored_device.identifier = "TestDevice1"

        stored_user = models.User()
        stored_user.hashed_pass = "******"
        stored_user.ifttt_secret = "cMq6JSJtMAzXa9BFq_EjX6"
        stored_user.salt = "fake the salt"
        stored_user.username = "******"

        stored_profile = models.ProfileJoin()
        stored_profile.device_id = 1
        stored_profile.pattern_id = 1
        stored_profile.preference_id = 1
        stored_profile.user_id = 1
        stored_profile.door_name = "TestDoor1"

        stored_preferences = models.NotificationPreferences()
        stored_preferences.expire_threshold = 10000
        stored_preferences.failed_attempts_threshold = 1
        stored_preferences.name = "knock_knock"
        stored_preferences.remaining_use_threshold = 10
        stored_preferences.send_no_earlier = None
        stored_preferences.send_no_later = None
        stored_preferences.success_threshold = 1
        stored_preferences.failure_endpoint = "knock_failed"

        stored_pattern = models.AccessPattern()
        stored_pattern.active = True
        stored_pattern.name = "Test Pattern 1"
        stored_pattern.pending = False
        stored_pattern.used_count = 0

        # Set the pattern in the past
        stored_pattern.expiration = 1491230220

        for i in range(3):
            piece = models.PatternPiece()
            piece.length = 123
            piece.order = i
            # First int is pressed time so all even indexed values are pressed
            piece.pressed = i % 2 == 0

            stored_pattern.pattern_pieces.append(piece)

        db_session.add(stored_device)
        db_session.add(stored_user)
        db_session.add(stored_profile)
        db_session.add(stored_preferences)
        db_session.add(stored_pattern)
        db_session.commit()

        # Add a pattern that should match, and try to match it
        resp = self.app.post('/knock/',
                             data=json.dumps({"pattern": [123, 123, 123]}),
                             content_type='application/json',
                             follow_redirects=True)

        data = json.loads(resp.data.decode())

        # The pattern should not be in the database
        self.assertEqual(data['success'], False)
Exemplo n.º 6
0
def knock():
    """
    Receives knock information from the Android app
    If a knock is pending, this will set the pattern for the knock
    If no knocks are pending, this will attempt to match the pattern
    """
    pattern = ast.literal_eval(request.form["pattern"])
    device_id = request.form["deviceId"]

    # Check for pending knock
    pending_pattern = AccessPattern.query.filter(
        AccessPattern.pending == True).first()

    if pending_pattern is not None:

        # Convert int values from json array and store them as pattern_pieces
        for i, json_val in enumerate(pattern):
            piece = PatternPiece()
            piece.length = pattern[i]
            piece.order = i
            # First int is pressed time so all even indexed values are pressed
            piece.pressed = i % 2 == 0

            pending_pattern.pattern_pieces.append(piece)

        # Don't keep adding knocks to this pattern
        pending_pattern.pending = False

        db_session.add(pending_pattern)
        db_session.commit()

        return jsonify(success=True)

    else:
        # Grab the current pattern pieces
        received_pattern_pieces = pattern

        # Get the Profile
        profile = ProfileJoin.get_profile()

        # Filter out all expired knocks
        match_patterns = AccessPattern.query.filter(
            AccessPattern.expiration > time.time())

        # # Filter for all match patterns with the current device id
        # filtered_match_patterns = []
        # for pattern in match_patterns:
        #     if pattern.id == profile.pattern_id:
        #         filtered_match_patterns.append(pattern)

        for pattern in match_patterns:

            # Check to make sure number of pieces match
            if (len(received_pattern_pieces) != len(pattern.pattern_pieces)
                ) or (len(pattern.pattern_pieces) <= 0):
                continue

            # We know that new_pattern is already ordered because we just created it.
            # but we don't know if pattern is so order it here before comparing.
            ordered_pattern_pieces = sorted(pattern.pattern_pieces,
                                            key=lambda p: p.order)

            piece_failed = False
            for received_pattern_piece, stored_pattern_piece in zip(
                    received_pattern_pieces, ordered_pattern_pieces):
                if not abs(received_pattern_piece - stored_pattern_piece.length
                           ) <= RECOGNITION_TOLERANCE:
                    piece_failed = True
                    break

            if piece_failed:
                # Move onto checking the next pattern.
                continue
            else:

                # Correct pattern detected!!! :D
                # Unlock the door
                pattern.used_count += 1
                db_session.commit()
                pattern_success(pattern,
                                device_id)  # temp device id until implemented
                return jsonify(success=True)

        send_failure_notification(
            device_id)  # temp device id until implemented
        return jsonify(success=False)