def _get_sorted_passwords(lock_id):
    type_ordinal = {
        PasswordType.UNLIMITED: 0,
        PasswordType.OTP: 1,
    }

    passwords = DB.child("Locks").child(lock_id).child(
        "passwords").get().val() or {}
    passwords_list = [(pw_id, password_dict)
                      for pw_id, password_dict in passwords.items()]
    passwords_list = sorted(
        passwords_list, key=lambda x: type_ordinal[PasswordType(x[1]['type'])])
    passwords_list = [
        Password.from_database(id, password_dict)
        for id, password_dict in passwords_list
    ]

    expired_passwords = []
    output = []
    for password in passwords_list:
        if password.expiration != -1 \
                and password.expiration < time_utils.get_current_time_ms():
            expired_passwords.append(password)
        elif _password_is_active(password):
            output.append(password)

    _prune_passwords(lock_id, expired_passwords)
    return output
Ejemplo n.º 2
0
def get_passwords(lock_id):
    passwords = get_lock(lock_id).get('passwords', {})

    result = {
        'otp': [],
        'permanent': [],
    }
    for pw_id, password in passwords.items():
        password_type = PasswordType(password['type'])
        if password_type == PasswordType.OTP:
            result['otp'].append(Password.from_database(pw_id, password))
        elif password_type == PasswordType.UNLIMITED:
            result['permanent'].append(Password.from_database(pw_id, password))
        else:
            raise AppException("Error: a password entry is malformed.")
    return result
Ejemplo n.º 3
0
def test_put_lock_status_open_requested_correct_password_otp(
        client,
        id_token,
        seeded_lock,
        seeded_password,  # A permanent password
        seed_password,
        get_mock_password,
        db,
        mocker):
    pw_str = "192168"
    otp_password = Password(type=PasswordType.OTP,
                            password=get_mock_password(pw_str, hashed=True))
    otp_password = seed_password(password=otp_password, lock=seeded_lock)

    lock_id = seeded_lock.id
    response = client.put('/api/v1/locks/{}/status'.format(lock_id),
                          headers={
                              'Authorization': id_token,
                          },
                          json={
                              'status': LockStatus.OPEN_REQUESTED.value,
                              'password': pw_str
                          })
    active_password_keys = db.child('Locks').child(lock_id).child(
        'passwords').get().val().keys()
    assert otp_password.id not in active_password_keys
    assert response.status_code == 200
    assert response.get_json() == {
        'status': LockStatus.OPEN_REQUESTED.value,
        'providedPasswordDisabled': True
    }
    def post(self, uid, user, **kwargs):
        lock_id = kwargs['lockId']
        security_utils.verify_lock_ownership(uid, lock_id)

        kwargs['password'] = security_utils.hash_password(kwargs['password'])

        password = Password.build(kwargs)
        return (password_manager.add_password(lock_id, password),
                LockPasswordResponse.code)
Ejemplo n.º 5
0
def test_put_lock_status_open_requested_password_not_active_day(
        client,
        id_token,
        seeded_lock,
        seeded_password,  # A permanent password
        seed_password,
        get_mock_password,
        db,
        mocker):
    # Feb 11 2019 is a Monday
    # NOTE: the lock is located in eastern time, GMT-5
    # (see document_templates.Lock.timezone)
    with freeze_time("Feb 11th, 2019 23:59:59", tz_offset=0):
        pw_str = "192168"
        expired_pw = Password(type=PasswordType.UNLIMITED,
                              active_days=[PasswordDays.MONDAY],
                              password=get_mock_password(pw_str, hashed=True))
        expired_pw = seed_password(password=expired_pw, lock=seeded_lock)

    # One second before Tuesday in eastern time
    with freeze_time("Feb 12th, 2019 04:59:59", tz_offset=0):
        lock_id = seeded_lock.id
        response = client.put('/api/v1/locks/{}/status'.format(lock_id),
                              headers={
                                  'Authorization': id_token,
                              },
                              json={
                                  'status': LockStatus.OPEN_REQUESTED.value,
                                  'password': pw_str
                              })
        assert response.status_code == 200

    # Exactly on Tuesday
    with freeze_time("Feb 12th, 2019 05:00:00", tz_offset=0):
        lock_id = seeded_lock.id
        response = client.put('/api/v1/locks/{}/status'.format(lock_id),
                              headers={
                                  'Authorization': id_token,
                              },
                              json={
                                  'status': LockStatus.OPEN_REQUESTED.value,
                                  'password': pw_str
                              })
        assert response.status_code == 401
        assert response.get_json() == {
            "error": "Invalid or inactive password supplied"
        }

        # Expired passwords should be removed from the database
        # after PUT request
        active_password_keys = db.child('Locks').child(lock_id).child(
            'passwords').get().val().keys()

        # Both passwords should be in the DB still
        assert expired_pw.id in active_password_keys
        assert seeded_password.id in active_password_keys
Ejemplo n.º 6
0
def add_password(lock_id, password: Password) -> PasswordMetadata:
    new_id = DB.child("Locks").child(lock_id).child("passwords").push(
        password.serialize())['name']
    # return a metadata object instead of a password to ensure that the
    # password is not shared with the outside world
    return PasswordMetadata(
        type=password.type,
        expiration=password.expiration,
        active_days=password.active_days,
        active_times=password.active_times,
        id=new_id,
    )
Ejemplo n.º 7
0
def test_put_lock_status_open_requested_expired_password(
        client,
        id_token,
        seeded_lock,
        seeded_password,  # A permanent password
        seed_password,
        get_mock_password,
        db,
        mocker):
    with freeze_time("Feb 2nd, 2019") as frozen_time:
        pw_str = "192168"
        expired_pw = Password(type=PasswordType.UNLIMITED,
                              expiration=time_utils.get_current_time_ms(),
                              password=get_mock_password(pw_str, hashed=True))
        expired_pw = seed_password(password=expired_pw, lock=seeded_lock)
        frozen_time.tick()

        lock_id = seeded_lock.id
        response = client.put('/api/v1/locks/{}/status'.format(lock_id),
                              headers={
                                  'Authorization': id_token,
                              },
                              json={
                                  'status': LockStatus.OPEN_REQUESTED.value,
                                  'password': pw_str
                              })

        assert response.status_code == 401
        assert response.get_json() == {
            "error": "Invalid or inactive password supplied"
        }

        # Expired passwords should be removed from the database
        # after PUT request
        active_password_keys = db.child('Locks').child(lock_id).child(
            'passwords').get().val().keys()
        assert expired_pw.id not in active_password_keys
        assert seeded_password.id in active_password_keys
Ejemplo n.º 8
0
def mock_password(get_mock_password, default_password) -> Password:
    return Password(
        type=PasswordType.UNLIMITED,
        password=get_mock_password(default_password, hashed=True),
    )
Ejemplo n.º 9
0
 def actual(password: Password, lock: Lock):
     new_id = db.child("Locks").child(lock.id).child("passwords").push(
         password.serialize())['name']
     password.id = new_id
     return password
Ejemplo n.º 10
0
def get_password(lock_id, password_id):
    found_password = _get_password_from_db(lock_id, password_id)
    if found_password:
        return Password.from_database(password_id, found_password)