Skip to content

Commit

Permalink
Reset the wrong code retry attempts if a valid credential is presented (
Browse files Browse the repository at this point in the history
#25536)

* Reset the wrong code retry attempts if a valid credential is presented

- Provide a ResetWrongCodeEntryAttempts for apps to use to reset the wrong entry attempts

- Update DL_LockUnlock.yaml to test resetting the wrong code retry attempts

* Update src/app/clusters/door-lock-server/door-lock-server.cpp

Co-authored-by: Boris Zbarsky <bzbarsky@apple.com>

* Update src/app/clusters/door-lock-server/door-lock-server.cpp

Co-authored-by: Boris Zbarsky <bzbarsky@apple.com>

* Update src/app/clusters/door-lock-server/door-lock-server.h

Co-authored-by: Boris Zbarsky <bzbarsky@apple.com>

* Update src/app/clusters/door-lock-server/door-lock-server.h

Co-authored-by: Boris Zbarsky <bzbarsky@apple.com>

* Update src/app/clusters/door-lock-server/door-lock-server.cpp

Co-authored-by: Boris Zbarsky <bzbarsky@apple.com>

* Address review comment - fix YAML to lock door before unlocking again. Restyle changes

---------

Co-authored-by: Boris Zbarsky <bzbarsky@apple.com>
  • Loading branch information
2 people authored and pull[bot] committed Sep 1, 2023
1 parent 6d745d7 commit 6023221
Show file tree
Hide file tree
Showing 4 changed files with 381 additions and 70 deletions.
28 changes: 26 additions & 2 deletions src/app/clusters/door-lock-server/door-lock-server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,13 @@ bool DoorLockServer::SetLockState(chip::EndpointId endpointId, DlLockState newLo
SendLockOperationEvent(endpointId, opType, opSource, OperationErrorEnum::kUnspecified, userIndex, Nullable<chip::FabricIndex>(),
Nullable<chip::NodeId>(), credentials, success);

// Reset wrong entry attempts (in case there were any incorrect credentials presented before) if lock/unlock was a success
// and a valid credential was presented.
if (success && !credentials.IsNull() && !(credentials.Value().empty()))
{
ResetWrongCodeEntryAttempts(endpointId);
}

// Schedule auto-relocking
if (success && LockOperationTypeEnum::kUnlock == opType)
{
Expand Down Expand Up @@ -181,7 +188,7 @@ bool DoorLockServer::SetPrivacyModeButton(chip::EndpointId endpointId, bool isEn
return SetAttribute(endpointId, Attributes::EnablePrivacyModeButton::Id, Attributes::EnablePrivacyModeButton::Set, isEnabled);
}

bool DoorLockServer::TrackWrongCodeEntry(chip::EndpointId endpointId)
bool DoorLockServer::HandleWrongCodeEntry(chip::EndpointId endpointId)
{
auto endpointContext = getContext(endpointId);
if (nullptr == endpointContext)
Expand Down Expand Up @@ -209,6 +216,17 @@ bool DoorLockServer::TrackWrongCodeEntry(chip::EndpointId endpointId)
return true;
}

void DoorLockServer::ResetWrongCodeEntryAttempts(chip::EndpointId endpointId)
{
auto endpointContext = getContext(endpointId);
if (nullptr == endpointContext)
{
ChipLogError(Zcl, "Failed to reset wrong code entry attempts. No context for endpoint %d", endpointId);
return;
}
endpointContext->wrongCodeEntryAttempts = 0;
}

bool DoorLockServer::engageLockout(chip::EndpointId endpointId)
{
uint8_t lockoutTimeout;
Expand Down Expand Up @@ -3352,7 +3370,13 @@ bool DoorLockServer::HandleRemoteLockOperation(chip::app::CommandHandler * comma
exit:
if (!success && reason == OperationErrorEnum::kInvalidCredential)
{
TrackWrongCodeEntry(endpoint);
HandleWrongCodeEntry(endpoint);
}

// Reset the wrong code retry attempts if a valid credential is presented during lock/unlock
if (success && pinCode.HasValue())
{
ResetWrongCodeEntryAttempts(endpoint);
}

// Send command response
Expand Down
19 changes: 18 additions & 1 deletion src/app/clusters/door-lock-server/door-lock-server.h
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,15 @@ class DoorLockServer
bool SetOneTouchLocking(chip::EndpointId endpointId, bool isEnabled);
bool SetPrivacyModeButton(chip::EndpointId endpointId, bool isEnabled);

bool TrackWrongCodeEntry(chip::EndpointId endpointId);
/**
* @brief Handles a wrong code entry attempt for the endpoint. If the number of wrong entry attempts exceeds the max limit,
* engage lockout. Otherwise increment the number of incorrect attempts by 1. This is handled automatically for
* remote operations - lock and unlock. Applications are responsible for calling it for non-remote incorrect credential
* presentation attempts.
*
* @param endpointId
*/
bool HandleWrongCodeEntry(chip::EndpointId endpointId);

bool GetAutoRelockTime(chip::EndpointId endpointId, uint32_t & autoRelockTime);
bool GetNumberOfUserSupported(chip::EndpointId endpointId, uint16_t & numberOfUsersSupported);
Expand Down Expand Up @@ -183,6 +191,15 @@ class DoorLockServer
bool OnFabricRemoved(chip::EndpointId endpointId, chip::FabricIndex fabricIndex);

static void DoorLockOnAutoRelockCallback(chip::System::Layer *, void * callbackContext);
/**
* @brief Resets the wrong code entry attempts to 0 for the endpoint. This is done automatically when a
* remote lock operation with credentials succeeds, or when SetLockState is called with a non-empty credentials list.
* Applications that call the two-argument version of SetLockState and handle sending the relevant operation events
* themselves or via SendLockOperationEvent are responsible for calling this API when a valid credential is presented.
*
* @param endpointId
*/
void ResetWrongCodeEntryAttempts(chip::EndpointId endpointId);

private:
chip::FabricIndex getFabricIndex(const chip::app::CommandHandler * commandObj);
Expand Down
112 changes: 107 additions & 5 deletions src/app/tests/suites/DL_LockUnlock.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -238,11 +238,11 @@ tests:
arguments:
value: 0

- label: "Read the lockout timeout"
command: "readAttribute"
attribute: "UserCodeTemporaryDisableTime"
response:
value: 10
# Test resetting wrong code entry retry attempts
# Set the retry limit to 3. Try to unlock with incorrect PIN 2 times followed by a third time
# with correct PIN code. The retry attempts should be reset to 0. Try to unock with incorrect
# PIN 2 times followed by a third time with correct PIN code. We should be able to unlock since
# the count has been reset and we are not in lockout.

- label: "Set the WrongCodeEntryLimit to small value so we can test lockout"
command: "writeAttribute"
Expand Down Expand Up @@ -270,6 +270,108 @@ tests:
response:
error: FAILURE

- label: "Try to unlock the door with valid PIN for the third time"
command: "UnlockDoor"
timedInteractionTimeoutMs: 10000
arguments:
values:
- name: "PINCode"
value: "123456"

- label: "Verify that lock state attribute value is set to Unlocked"
command: "readAttribute"
attribute: "LockState"
response:
value: 2

- label: "Lock the door back prior to next tests"
command: "LockDoor"
timedInteractionTimeoutMs: 10000
arguments:
values:
- name: "PINCode"
value: "123456"

- label: "Verify that lock state attribute value is set to Locked"
command: "readAttribute"
attribute: "LockState"
response:
value: 1

- label: "Try to unlock the door with invalid PIN for the first time"
command: "UnlockDoor"
timedInteractionTimeoutMs: 10000
arguments:
values:
- name: "PINCode"
value: "000000"
response:
error: FAILURE

- label: "Try to unlock the door with invalid PIN for the second time"
command: "UnlockDoor"
timedInteractionTimeoutMs: 10000
arguments:
values:
- name: "PINCode"
value: "000000"
response:
error: FAILURE

- label: "Try to unlock the door with valid PIN for the third time"
command: "UnlockDoor"
timedInteractionTimeoutMs: 10000
arguments:
values:
- name: "PINCode"
value: "123456"

- label: "Verify that lock state attribute value is set to Unlocked"
command: "readAttribute"
attribute: "LockState"
response:
value: 2

- label: "Lock the door back prior to next tests"
command: "LockDoor"
timedInteractionTimeoutMs: 10000
arguments:
values:
- name: "PINCode"
value: "123456"

- label: "Verify that lock state attribute value is set to Locked"
command: "readAttribute"
attribute: "LockState"
response:
value: 1

- label: "Read the lockout timeout"
command: "readAttribute"
attribute: "UserCodeTemporaryDisableTime"
response:
value: 10

- label: "Try to unlock the door with invalid PIN for the first time"
command: "UnlockDoor"
timedInteractionTimeoutMs: 10000
arguments:
values:
- name: "PINCode"
value: "000000"
response:
error: FAILURE

- label: "Try to unlock the door with invalid PIN for the second time"
command: "UnlockDoor"
timedInteractionTimeoutMs: 10000
arguments:
values:
- name: "PINCode"
value: "000000"
response:
error: FAILURE

- label: "Try to unlock the door with invalid PIN for the third time"
command: "UnlockDoor"
timedInteractionTimeoutMs: 10000
Expand Down
Loading

0 comments on commit 6023221

Please sign in to comment.