Skip to content

Commit

Permalink
Add initial feature logic for Terms and Conditions (TC) acknowledgements
Browse files Browse the repository at this point in the history
This commit introduces the initial logic for handling Terms and
Conditions (TC) acknowledgements in the General Commissioning cluster.
The logic includes support for setting and checking TC acknowledgements
and versions during the commissioning process.

Changes include:
- Handling TC acknowledgements and TC acknowledgement version in the
  pairing command.
- Logic to read TC attributes and check TC acceptance in the General
  Commissioning server.
- Introduction of classes to manage TC acceptance logic.
- Initialization and use of TC providers in the server setup.
- Addition of a new commissioning stage for TC acknowledgements in the
  commissioning flow.

The feature logic is currently disabled and will be enabled in an
example in a subsequent commit.
  • Loading branch information
swan-amazon committed Aug 21, 2024
1 parent 150aad3 commit fd2baed
Show file tree
Hide file tree
Showing 20 changed files with 1,607 additions and 12 deletions.
18 changes: 17 additions & 1 deletion src/app/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,19 @@ declare_args() {
current_os != "android"
}

config("enhanced_setup_flow_config") {
defines = []
if (chip_config_tc_required) {
defines += [
"CHIP_CONFIG_TC_REQUIRED=1",
"CHIP_CONFIG_TC_REQUIRED_ACKNOWLEDGEMENTS=${chip_config_tc_required_acknowledgements}",
"CHIP_CONFIG_TC_REQUIRED_ACKNOWLEDGEMENTS_VERSION=${chip_config_tc_required_acknowledgements_version}",
]
} else {
defines += [ "CHIP_CONFIG_TC_REQUIRED=0" ]
}
}

buildconfig_header("app_buildconfig") {
header = "AppBuildConfig.h"
header_dir = "app"
Expand Down Expand Up @@ -519,5 +532,8 @@ static_library("app") {

cflags = [ "-Wconversion" ]

public_configs = [ "${chip_root}/src:includes" ]
public_configs = [
":enhanced_setup_flow_config",
"${chip_root}/src:includes",
]
}
11 changes: 8 additions & 3 deletions src/app/FailSafeContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,9 +86,14 @@ void FailSafeContext::ScheduleFailSafeCleanup(FabricIndex fabricIndex, bool addN
SetFailSafeArmed(false);

ChipDeviceEvent event{ .Type = DeviceEventType::kFailSafeTimerExpired,
.FailSafeTimerExpired = { .fabricIndex = fabricIndex,
.addNocCommandHasBeenInvoked = addNocCommandInvoked,
.updateNocCommandHasBeenInvoked = updateNocCommandInvoked } };
.FailSafeTimerExpired = {
.fabricIndex = fabricIndex,
.addNocCommandHasBeenInvoked = addNocCommandInvoked,
.updateNocCommandHasBeenInvoked = updateNocCommandInvoked,
#if CHIP_CONFIG_TC_REQUIRED
.updateTermsAndConditionsHasBeenInvoked = mUpdateTermsAndConditionsHasBeenInvoked,
#endif
} };
CHIP_ERROR status = PlatformMgr().PostEvent(&event);

if (status != CHIP_NO_ERROR)
Expand Down
15 changes: 13 additions & 2 deletions src/app/FailSafeContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,9 @@ class FailSafeContext
void SetUpdateNocCommandInvoked() { mUpdateNocCommandHasBeenInvoked = true; }
void SetAddTrustedRootCertInvoked() { mAddTrustedRootCertHasBeenInvoked = true; }
void SetCsrRequestForUpdateNoc(bool isForUpdateNoc) { mIsCsrRequestForUpdateNoc = isForUpdateNoc; }

#if CHIP_CONFIG_TC_REQUIRED
void SetUpdateTermsAndConditionsHasBeenInvoked() { mUpdateTermsAndConditionsHasBeenInvoked = true; }
#endif
/**
* @brief
* Schedules a work to cleanup the FailSafe Context asynchronously after various cleanup work
Expand Down Expand Up @@ -91,6 +93,9 @@ class FailSafeContext
bool UpdateNocCommandHasBeenInvoked() const { return mUpdateNocCommandHasBeenInvoked; }
bool AddTrustedRootCertHasBeenInvoked() const { return mAddTrustedRootCertHasBeenInvoked; }
bool IsCsrRequestForUpdateNoc() const { return mIsCsrRequestForUpdateNoc; }
#if CHIP_CONFIG_TC_REQUIRED
bool UpdateTermsAndConditionsHasBeenInvoked() { return mUpdateTermsAndConditionsHasBeenInvoked; }
#endif

FabricIndex GetFabricIndex() const
{
Expand All @@ -110,7 +115,10 @@ class FailSafeContext
bool mAddTrustedRootCertHasBeenInvoked = false;
// The fact of whether a CSR occurred at all is stored elsewhere.
bool mIsCsrRequestForUpdateNoc = false;
FabricIndex mFabricIndex = kUndefinedFabricIndex;
#if CHIP_CONFIG_TC_REQUIRED
bool mUpdateTermsAndConditionsHasBeenInvoked = false;
#endif
FabricIndex mFabricIndex = kUndefinedFabricIndex;

/**
* @brief
Expand Down Expand Up @@ -145,6 +153,9 @@ class FailSafeContext
mAddTrustedRootCertHasBeenInvoked = false;
mFailSafeBusy = false;
mIsCsrRequestForUpdateNoc = false;
#if CHIP_CONFIG_TC_REQUIRED
mUpdateTermsAndConditionsHasBeenInvoked = false;
#endif
}

void FailSafeTimerExpired();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/**
*
* Copyright (c) 2021 Project CHIP Authors
* Copyright (c) 2021-2024 Project CHIP Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -27,6 +27,9 @@
#include <app/CommandHandler.h>
#include <app/ConcreteCommandPath.h>
#include <app/server/CommissioningWindowManager.h>
#if CHIP_CONFIG_TC_REQUIRED
#include <app/server/EnhancedSetupFlowProvider.h>
#endif
#include <app/server/Server.h>
#include <app/util/attribute-storage.h>
#include <lib/support/Span.h>
Expand Down Expand Up @@ -69,6 +72,9 @@ class GeneralCommissioningAttrAccess : public AttributeAccessInterface
CHIP_ERROR ReadIfSupported(CHIP_ERROR (ConfigurationManager::*getter)(uint8_t &), AttributeValueEncoder & aEncoder);
CHIP_ERROR ReadBasicCommissioningInfo(AttributeValueEncoder & aEncoder);
CHIP_ERROR ReadSupportsConcurrentConnection(AttributeValueEncoder & aEncoder);
template <typename Provider, typename T>
CHIP_ERROR ReadFromProvider(Provider * const aProvider, CHIP_ERROR (Provider::*const aConstGetter)(T &) const,
AttributeValueEncoder & aEncoder);
};

GeneralCommissioningAttrAccess gAttrAccess;
Expand All @@ -95,6 +101,28 @@ CHIP_ERROR GeneralCommissioningAttrAccess::Read(const ConcreteReadAttributePath
case SupportsConcurrentConnection::Id: {
return ReadSupportsConcurrentConnection(aEncoder);
}
#if CHIP_CONFIG_TC_REQUIRED
case TCAcceptedVersion::Id: {
auto provider = Server::GetInstance().GetEnhancedSetupFlowProvider();
auto getter = &EnhancedSetupFlowProvider::GetTermsAndConditionsAcceptedAcknowledgementsVersion;
return ReadFromProvider(provider, getter, aEncoder);
}
case TCMinRequiredVersion::Id: {
auto provider = Server::GetInstance().GetEnhancedSetupFlowProvider();
auto getter = &EnhancedSetupFlowProvider::GetTermsAndConditionsRequiredAcknowledgementsVersion;
return ReadFromProvider(provider, getter, aEncoder);
}
case TCAcknowledgements::Id: {
auto provider = Server::GetInstance().GetEnhancedSetupFlowProvider();
auto getter = &EnhancedSetupFlowProvider::GetTermsAndConditionsAcceptedAcknowledgements;
return ReadFromProvider(provider, getter, aEncoder);
}
case TCAcknowledgementsRequired::Id: {
auto provider = Server::GetInstance().GetEnhancedSetupFlowProvider();
auto getter = &EnhancedSetupFlowProvider::IsTermsAndConditionsAcceptanceRequired;
return ReadFromProvider(provider, getter, aEncoder);
}
#endif
default: {
break;
}
Expand Down Expand Up @@ -144,6 +172,94 @@ CHIP_ERROR GeneralCommissioningAttrAccess::ReadSupportsConcurrentConnection(Attr
return aEncoder.Encode(supportsConcurrentConnection);
}

template <typename Provider, typename T>
CHIP_ERROR GeneralCommissioningAttrAccess::ReadFromProvider(Provider * const aProvider,
CHIP_ERROR (Provider::*const aConstGetter)(T &) const,
AttributeValueEncoder & aEncoder)
{
if (nullptr == aProvider)
{
return CHIP_ERROR_PERSISTED_STORAGE_FAILED;
}

T value;
CHIP_ERROR err = (aProvider->*aConstGetter)(value);
if (err != CHIP_NO_ERROR)
{
return err;
}

return aEncoder.Encode(value);
}

#if CHIP_CONFIG_TC_REQUIRED
CHIP_ERROR checkTermsAndConditionsAcknowledgementsState(CommissioningErrorEnum & errorCode)
{
EnhancedSetupFlowProvider * enhancedSetupFlowProvider = Server::GetInstance().GetEnhancedSetupFlowProvider();

CHIP_ERROR err;

uint16_t termsAndConditionsAcceptedAcknowledgements;
bool hasAnyAcknowledgements;
bool hasRequiredTermAccepted;
bool hasRequiredTermVersionAccepted;

err = enhancedSetupFlowProvider->HasReceivedTermsAndConditionscknowledgements(hasAnyAcknowledgements);
if (!::chip::ChipError::IsSuccess(err))
{
ChipLogError(AppServer, "Failed to HasReceivedTermsAndConditionscknowledgements");
errorCode = CommissioningErrorEnum::kTCAcknowledgementsNotReceived;
return err;
}

err = enhancedSetupFlowProvider->GetTermsAndConditionsAcceptedAcknowledgements(termsAndConditionsAcceptedAcknowledgements);
if (!::chip::ChipError::IsSuccess(err))
{
ChipLogError(AppServer, "Failed to GetTermsAndConditionsAcceptedAcknowledgements");
return err;
}

err = enhancedSetupFlowProvider->HasTermsAndConditionsRequiredAcknowledgementsBeenAccepted(hasRequiredTermAccepted);
if (!::chip::ChipError::IsSuccess(err))
{
ChipLogError(AppServer, "Failed to HasTermsAndConditionsRequiredAcknowledgementsBeenAccepted");
return err;
}

err =
enhancedSetupFlowProvider->HasTermsAndConditionsRequiredAcknowledgementsVersionBeenAccepted(hasRequiredTermVersionAccepted);
if (!::chip::ChipError::IsSuccess(err))
{
ChipLogError(AppServer, "Failed to HasTermsAndConditionsRequiredAcknowledgementsVersionBeenAccepted");
return err;
}

if (!hasRequiredTermVersionAccepted)
{
uint16_t requiredAcknowledgementsVersion = 0;
(void) enhancedSetupFlowProvider->GetTermsAndConditionsRequiredAcknowledgementsVersion(requiredAcknowledgementsVersion);
ChipLogProgress(AppServer, "Minimum terms and conditions version, 0x%04x, has not been accepted",
requiredAcknowledgementsVersion);
errorCode = CommissioningErrorEnum::kTCMinVersionNotMet;
return CHIP_NO_ERROR;
}

if (!hasRequiredTermAccepted)
{
uint16_t requiredAcknowledgements = 0;
(void) enhancedSetupFlowProvider->GetTermsAndConditionsRequiredAcknowledgements(requiredAcknowledgements);

ChipLogProgress(AppServer, "Required terms and conditions, 0x%04x,have not been accepted", requiredAcknowledgements);
errorCode = (0 == termsAndConditionsAcceptedAcknowledgements) ? CommissioningErrorEnum::kTCAcknowledgementsNotReceived
: CommissioningErrorEnum::kRequiredTCNotAccepted;
return CHIP_NO_ERROR;
}

errorCode = CommissioningErrorEnum::kOk;
return CHIP_NO_ERROR;
}
#endif

} // anonymous namespace

bool emberAfGeneralCommissioningClusterArmFailSafeCallback(app::CommandHandler * commandObj,
Expand Down Expand Up @@ -239,6 +355,10 @@ bool emberAfGeneralCommissioningClusterCommissioningCompleteCallback(
}
else
{
#if CHIP_CONFIG_TC_REQUIRED
CheckSuccess(checkTermsAndConditionsAcknowledgementsState(response.errorCode), Failure);
#endif

if (failSafe.NocCommandHasBeenInvoked())
{
CHIP_ERROR err = fabricTable.CommitPendingFabricData();
Expand Down Expand Up @@ -328,13 +448,57 @@ bool emberAfGeneralCommissioningClusterSetRegulatoryConfigCallback(app::CommandH
return true;
}

bool emberAfGeneralCommissioningClusterSetTCAcknowledgementsCallback(
chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath,
const chip::app::Clusters::GeneralCommissioning::Commands::SetTCAcknowledgements::DecodableType & commandData)
{
#if !CHIP_CONFIG_TC_REQUIRED
return false;

#else
auto & failSafeContext = Server::GetInstance().GetFailSafeContext();

MATTER_TRACE_SCOPE("SetTCAcknowledgements", "GeneralCommissioning");
Commands::SetTCAcknowledgementsResponse::Type response;
EnhancedSetupFlowProvider * const enhancedSetupFlowProvider = Server::GetInstance().GetEnhancedSetupFlowProvider();
uint16_t acknowledgements = commandData.TCUserResponse;
uint16_t acknowledgementsVersion = commandData.TCVersion;
CheckSuccess(enhancedSetupFlowProvider->SetTermsAndConditionsAcceptance(acknowledgements, acknowledgementsVersion), Failure);
CheckSuccess(checkTermsAndConditionsAcknowledgementsState(response.errorCode), Failure);
failSafeContext.SetUpdateTermsAndConditionsHasBeenInvoked();
commandObj->AddResponse(commandPath, response);
return true;

#endif
}

namespace {
void OnPlatformEventHandler(const DeviceLayer::ChipDeviceEvent * event, intptr_t arg)
{
if (event->Type == DeviceLayer::DeviceEventType::kFailSafeTimerExpired)
{
// Spec says to reset Breadcrumb attribute to 0.
Breadcrumb::Set(0, 0);

#if CHIP_CONFIG_TC_REQUIRED
if (event->FailSafeTimerExpired.updateTermsAndConditionsHasBeenInvoked)
{
// Clear terms and conditions acceptance on failsafe timer expiration
Server::GetInstance().GetEnhancedSetupFlowProvider()->RevertTermsAndConditionsAcceptance();
}
#endif
}

if (event->Type == DeviceLayer::DeviceEventType::kCommissioningComplete)
{
#if CHIP_CONFIG_TC_REQUIRED
auto & failSafeContext = Server::GetInstance().GetFailSafeContext();
if (failSafeContext.UpdateTermsAndConditionsHasBeenInvoked())
{
// Commit terms and conditions acceptance on commissioning complete
Server::GetInstance().GetEnhancedSetupFlowProvider()->CommitTermsAndConditionsAcceptance();
}
#endif
}
}

Expand Down
4 changes: 4 additions & 0 deletions src/app/common_flags.gni
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ declare_args() {
chip_enable_read_client = true
chip_build_controller_dynamic_server = false

chip_config_tc_required = false
chip_config_tc_required_acknowledgements = 0
chip_config_tc_required_acknowledgements_version = 0

# Flag that controls whether the time-to-wait from BUSY responses is
# communicated to OperationalSessionSetup API consumers.
chip_enable_busy_handling_for_operational_session_setup = true
Expand Down
29 changes: 28 additions & 1 deletion src/app/server/BUILD.gn
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright (c) 2020 Project CHIP Authors
# Copyright (c) 2020-2024 Project CHIP Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
Expand All @@ -24,6 +24,28 @@ config("server_config") {
}
}

source_set("enhanced_setup_flow_interface") {
sources = [
"DefaultEnhancedSetupFlowProvider.h",
"DefaultTermsAndConditionsProvider.h",
"EnhancedSetupFlowProvider.h",
"TermsAndConditionsProvider.h",
]

public_configs = [ "${chip_root}/src/app:enhanced_setup_flow_config" ]

public_deps = [ "${chip_root}/src/lib/core" ]
}

source_set("enhanced_setup_flow") {
sources = [
"DefaultEnhancedSetupFlowProvider.cpp",
"DefaultTermsAndConditionsProvider.cpp",
]

deps = [ ":enhanced_setup_flow_interface" ]
}

static_library("server") {
output_name = "libCHIPAppServer"

Expand Down Expand Up @@ -51,6 +73,7 @@ static_library("server") {
cflags = [ "-Wconversion" ]

public_deps = [
":enhanced_setup_flow_interface",
"${chip_root}/src/app",
"${chip_root}/src/app:test-event-trigger",
"${chip_root}/src/app/icd/server:check-in-back-off",
Expand Down Expand Up @@ -79,4 +102,8 @@ static_library("server") {
[ "${chip_root}/src/app/icd/server:default-check-in-back-off" ]
}
}

if (chip_config_tc_required) {
public_deps += [ ":enhanced_setup_flow" ]
}
}
Loading

0 comments on commit fd2baed

Please sign in to comment.