diff --git a/examples/chip-tool/commands/pairing/PairingCommand.cpp b/examples/chip-tool/commands/pairing/PairingCommand.cpp index 245c9ed57ff82c..b583aa5f202bd4 100644 --- a/examples/chip-tool/commands/pairing/PairingCommand.cpp +++ b/examples/chip-tool/commands/pairing/PairingCommand.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Project CHIP Authors + * Copyright (c) 2020-2024 Project CHIP Authors * All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -129,6 +129,17 @@ CommissioningParameters PairingCommand::GetCommissioningParameters() params.SetCountryCode(CharSpan::fromCharString(mCountryCode.Value())); } + // mTCAcknowledgements and mTCAcknowledgementVersion are optional, but related. When one is missing, default the value to 0, to + // increase the test tools ability to test the applications. + if (mTCAcknowledgements.HasValue() || mTCAcknowledgementVersion.HasValue()) + { + TermsAndConditionsAcknowledgement termsAndConditionsAcknowledgement = { + .acceptedTermsAndConditions = mTCAcknowledgements.ValueOr(0), + .acceptedTermsAndConditionsVersion = mTCAcknowledgementVersion.ValueOr(0), + }; + params.SetTermsAndConditionsAcknowledgement(termsAndConditionsAcknowledgement); + } + // mTimeZoneList is an optional argument managed by TypedComplexArgument mComplex_TimeZones. // Since optional Complex arguments are not currently supported via the class, // we will use mTimeZoneList.data() value to determine if the argument was provided. diff --git a/examples/chip-tool/commands/pairing/PairingCommand.h b/examples/chip-tool/commands/pairing/PairingCommand.h index 9965b663ec111c..1161c3b0950374 100644 --- a/examples/chip-tool/commands/pairing/PairingCommand.h +++ b/examples/chip-tool/commands/pairing/PairingCommand.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Project CHIP Authors + * Copyright (c) 2020-2024 Project CHIP Authors * All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -202,6 +202,14 @@ class PairingCommand : public CHIPCommand, AddArgument("dst-offset", &mComplex_DSTOffsets, "DSTOffset list to use when setting Time Synchronization cluster's DSTOffset attribute", Argument::kOptional); + + AddArgument("tc-acknowledgements", 0, UINT16_MAX, &mTCAcknowledgements, + "Terms and Conditions acknowledgements to use to set the General Commissioning cluster's TC " + "Acknowledgements bit-field"); + + AddArgument("tc-acknowledgements-version", 0, UINT16_MAX, &mTCAcknowledgementVersion, + "Terms and Conditions acknowledgement version to use to set the General Commissioning cluster's TC " + "Acknowledgement version"); } AddArgument("timeout", 0, UINT16_MAX, &mTimeout); @@ -259,6 +267,8 @@ class PairingCommand : public CHIPCommand, chip::Optional mICDMonitoredSubject; chip::Optional mICDClientType; chip::Optional mICDStayActiveDurationMsec; + chip::Optional mTCAcknowledgements; + chip::Optional mTCAcknowledgementVersion; chip::app::DataModel::List mTimeZoneList; TypedComplexArgument> mComplex_TimeZones; diff --git a/src/app/clusters/general-commissioning-server/general-commissioning-server.cpp b/src/app/clusters/general-commissioning-server/general-commissioning-server.cpp index 776441ffc9ae75..fd7bbc6421525d 100644 --- a/src/app/clusters/general-commissioning-server/general-commissioning-server.cpp +++ b/src/app/clusters/general-commissioning-server/general-commissioning-server.cpp @@ -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. @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -57,6 +58,45 @@ using Transport::Session; namespace { +template +static CHIP_ERROR ReadInternal(Provider* const provider, CHIP_ERROR (Provider::*const getter)(T&), AttributeValueEncoder& aEncoder) +{ + T data; + + if (nullptr == provider) + { + return CHIP_ERROR_PERSISTED_STORAGE_FAILED; + } + + CHIP_ERROR err = (provider->*getter)(data); + if (err == CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE) + { + data = 0; + } + else if (err != CHIP_NO_ERROR) + { + return err; + } + + return aEncoder.Encode(data); +} + +template +static CHIP_ERROR ReadInternal(Provider* const provider, CHIP_ERROR (Provider::*const getter)(T&) const, AttributeValueEncoder& aEncoder) +{ + // Removing the const qualifier from the getter function pointer because there are a handful of getter functions that are not correctly marked as const. + using NonConstGetter = CHIP_ERROR (Provider::*)(T&); + NonConstGetter nonConstGetter = reinterpret_cast(getter); + + return ReadInternal(provider, nonConstGetter, aEncoder); +} + +template +static CHIP_ERROR ReadIfSupported(Args &&... args) +{ + return ReadInternal(std::forward(args)...); +} + class GeneralCommissioningAttrAccess : public AttributeAccessInterface { public: @@ -66,7 +106,6 @@ class GeneralCommissioningAttrAccess : public AttributeAccessInterface CHIP_ERROR Read(const ConcreteReadAttributePath & aPath, AttributeValueEncoder & aEncoder) override; private: - CHIP_ERROR ReadIfSupported(CHIP_ERROR (ConfigurationManager::*getter)(uint8_t &), AttributeValueEncoder & aEncoder); CHIP_ERROR ReadBasicCommissioningInfo(AttributeValueEncoder & aEncoder); CHIP_ERROR ReadSupportsConcurrentConnection(AttributeValueEncoder & aEncoder); }; @@ -84,10 +123,10 @@ CHIP_ERROR GeneralCommissioningAttrAccess::Read(const ConcreteReadAttributePath switch (aPath.mAttributeId) { case RegulatoryConfig::Id: { - return ReadIfSupported(&ConfigurationManager::GetRegulatoryLocation, aEncoder); + return ReadIfSupported(&DeviceLayer::ConfigurationMgr(), &ConfigurationManager::GetRegulatoryLocation, aEncoder); } case LocationCapability::Id: { - return ReadIfSupported(&ConfigurationManager::GetLocationCapability, aEncoder); + return ReadIfSupported(&DeviceLayer::ConfigurationMgr(), &ConfigurationManager::GetLocationCapability, aEncoder); } case BasicCommissioningInfo::Id: { return ReadBasicCommissioningInfo(aEncoder); @@ -95,28 +134,32 @@ CHIP_ERROR GeneralCommissioningAttrAccess::Read(const ConcreteReadAttributePath case SupportsConcurrentConnection::Id: { return ReadSupportsConcurrentConnection(aEncoder); } - default: { - break; +#if defined (CHIP_CONFIG_TC_REQUIRED_ACKNOWLEDGEMENTS) && defined (CHIP_CONFIG_TC_REQUIRED_ACKNOWLEDGEMENTS_VERSION) + case TCAcceptedVersion::Id: { + app::EnhancedSetupFlowProvider * provider = Server::GetInstance().GetEnhancedSetupFlowProvider(); + auto getter = &EnhancedSetupFlowProvider::GetTermsAndConditionsAcceptedAcknowledgementsVersion; + return ReadIfSupported(provider, getter, aEncoder); } + case TCMinRequiredVersion::Id: { + auto provider = Server::GetInstance().GetEnhancedSetupFlowProvider(); + auto getter = &EnhancedSetupFlowProvider::GetTermsAndConditionsRequiredAcknowledgementsVersion; + return ReadIfSupported(provider, getter, aEncoder); } - return CHIP_NO_ERROR; -} - -CHIP_ERROR GeneralCommissioningAttrAccess::ReadIfSupported(CHIP_ERROR (ConfigurationManager::*getter)(uint8_t &), - AttributeValueEncoder & aEncoder) -{ - uint8_t data; - CHIP_ERROR err = (DeviceLayer::ConfigurationMgr().*getter)(data); - if (err == CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE) - { - data = 0; + case TCAcknowledgements::Id: { + auto provider = Server::GetInstance().GetEnhancedSetupFlowProvider(); + auto getter = &EnhancedSetupFlowProvider::GetTermsAndConditionsAcceptedAcknowledgements; + return ReadIfSupported(provider, getter, aEncoder); } - else if (err != CHIP_NO_ERROR) - { - return err; + case TCAcknowledgementsRequired::Id: { + auto provider = Server::GetInstance().GetEnhancedSetupFlowProvider(); + auto getter = &EnhancedSetupFlowProvider::GetTermsAndConditionsRequiredAcknowledgements; + return ReadIfSupported(provider, getter, aEncoder); } - - return aEncoder.Encode(data); +#endif + default: + break; + } + return CHIP_NO_ERROR; } CHIP_ERROR GeneralCommissioningAttrAccess::ReadBasicCommissioningInfo(AttributeValueEncoder & aEncoder) @@ -214,9 +257,12 @@ bool emberAfGeneralCommissioningClusterCommissioningCompleteCallback( { MATTER_TRACE_SCOPE("CommissioningComplete", "GeneralCommissioning"); - DeviceControlServer * devCtrl = &DeviceLayer::DeviceControlServer::DeviceControlSvr(); - auto & failSafe = Server::GetInstance().GetFailSafeContext(); - auto & fabricTable = Server::GetInstance().GetFabricTable(); +#if defined (CHIP_CONFIG_TC_REQUIRED_ACKNOWLEDGEMENTS) && defined (CHIP_CONFIG_TC_REQUIRED_ACKNOWLEDGEMENTS_VERSION) + EnhancedSetupFlowProvider * enhancedSetupFlowProvider = Server::GetInstance().GetEnhancedSetupFlowProvider(); +#endif + DeviceControlServer * const devCtrl = &DeviceLayer::DeviceControlServer::DeviceControlSvr(); + auto & failSafe = Server::GetInstance().GetFailSafeContext(); + auto & fabricTable = Server::GetInstance().GetFabricTable(); ChipLogProgress(FailSafe, "GeneralCommissioning: Received CommissioningComplete"); @@ -239,34 +285,64 @@ bool emberAfGeneralCommissioningClusterCommissioningCompleteCallback( } else { - if (failSafe.NocCommandHasBeenInvoked()) + CHIP_ERROR err; + +#if defined (CHIP_CONFIG_TC_REQUIRED_ACKNOWLEDGEMENTS) && defined (CHIP_CONFIG_TC_REQUIRED_ACKNOWLEDGEMENTS_VERSION) + + uint16_t termsAndConditionsAcceptedAcknowledgements; + bool hasRequiredTermAccepted; + bool hasRequiredTermVersionAccepted; + + err = enhancedSetupFlowProvider->GetTermsAndConditionsAcceptedAcknowledgements( + termsAndConditionsAcceptedAcknowledgements); + CheckSuccess(err, Failure); + + err = enhancedSetupFlowProvider->HasTermsAndConditionsRequiredAcknowledgementsBeenAccepted( + hasRequiredTermAccepted); + CheckSuccess(err, Failure); + + err = enhancedSetupFlowProvider->HasTermsAndConditionsRequiredAcknowledgementsVersionBeenAccepted( + hasRequiredTermVersionAccepted); + CheckSuccess(err, Failure); + + if (!hasRequiredTermAccepted) { - CHIP_ERROR err = fabricTable.CommitPendingFabricData(); - if (err != CHIP_NO_ERROR) - { - // No need to revert on error: CommitPendingFabricData always reverts if not fully successful. - ChipLogError(FailSafe, "GeneralCommissioning: Failed to commit pending fabric data: %" CHIP_ERROR_FORMAT, - err.Format()); - } - else + ChipLogProgress(AppServer, "Required terms and conditions have not been accepted"); + Breadcrumb::Set(commandPath.mEndpointId, 0); + response.errorCode = (0 == termsAndConditionsAcceptedAcknowledgements) + ? CommissioningErrorEnum::kTCAcknowledgementsNotReceived + : CommissioningErrorEnum::kRequiredTCNotAccepted; + } + + else if (!hasRequiredTermVersionAccepted) + { + ChipLogProgress(AppServer, "Minimum terms and conditions version has not been accepted"); + Breadcrumb::Set(commandPath.mEndpointId, 0); + response.errorCode = CommissioningErrorEnum::kTCMinVersionNotMet; + } + + else +#endif + { + if (failSafe.NocCommandHasBeenInvoked()) { + err = fabricTable.CommitPendingFabricData(); + CheckSuccess(err, Failure); ChipLogProgress(FailSafe, "GeneralCommissioning: Successfully commited pending fabric data"); } - CheckSuccess(err, Failure); - } - /* - * Pass fabric of commissioner to DeviceControlSvr. - * This allows device to send messages back to commissioner. - * Once bindings are implemented, this may no longer be needed. - */ - failSafe.DisarmFailSafe(); - CheckSuccess( - devCtrl->PostCommissioningCompleteEvent(handle->AsSecureSession()->GetPeerNodeId(), handle->GetFabricIndex()), - Failure); + /* + * Pass fabric of commissioner to DeviceControlSvr. + * This allows device to send messages back to commissioner. + * Once bindings are implemented, this may no longer be needed. + */ + failSafe.DisarmFailSafe(); + err = devCtrl->PostCommissioningCompleteEvent(handle->AsSecureSession()->GetPeerNodeId(), handle->GetFabricIndex()); + CheckSuccess(err, Failure); - Breadcrumb::Set(commandPath.mEndpointId, 0); - response.errorCode = CommissioningErrorEnum::kOk; + Breadcrumb::Set(commandPath.mEndpointId, 0); + response.errorCode = CommissioningErrorEnum::kOk; + } } } @@ -328,6 +404,24 @@ 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 defined (CHIP_CONFIG_TC_REQUIRED_ACKNOWLEDGEMENTS) && defined (CHIP_CONFIG_TC_REQUIRED_ACKNOWLEDGEMENTS_VERSION) + 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); + response.errorCode = CommissioningErrorEnum::kOk; + + commandObj->AddResponse(commandPath, response); +#endif + return true; +} + namespace { void OnPlatformEventHandler(const DeviceLayer::ChipDeviceEvent * event, intptr_t arg) { diff --git a/src/app/server/BUILD.gn b/src/app/server/BUILD.gn index 401356d7b753a4..10627a8c2d2b36 100644 --- a/src/app/server/BUILD.gn +++ b/src/app/server/BUILD.gn @@ -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. @@ -36,14 +36,20 @@ static_library("server") { "CommissioningWindowManager.h", "DefaultAclStorage.cpp", "DefaultAclStorage.h", + "DefaultEnhancedSetupFlowProvider.cpp", + "DefaultEnhancedSetupFlowProvider.h", + "DefaultTermsAndConditionsProvider.cpp", + "DefaultTermsAndConditionsProvider.h", "Dnssd.cpp", "Dnssd.h", "EchoHandler.cpp", "EchoHandler.h", + "EnhancedSetupFlowProvider.h", "OnboardingCodesUtil.cpp", "OnboardingCodesUtil.h", "Server.cpp", "Server.h", + "TermsAndConditionsProvider.h", ] public_configs = [ ":server_config" ] diff --git a/src/app/server/DefaultEnhancedSetupFlowProvider.cpp b/src/app/server/DefaultEnhancedSetupFlowProvider.cpp new file mode 100644 index 00000000000000..d9f9b31fa84a76 --- /dev/null +++ b/src/app/server/DefaultEnhancedSetupFlowProvider.cpp @@ -0,0 +1,157 @@ +/* + * + * Copyright (c) 2024 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#if defined (CHIP_CONFIG_TC_REQUIRED_ACKNOWLEDGEMENTS) && defined (CHIP_CONFIG_TC_REQUIRED_ACKNOWLEDGEMENTS_VERSION) + +#include "DefaultEnhancedSetupFlowProvider.h" + +#include +#include +#include + +CHIP_ERROR chip::app::DefaultEnhancedSetupFlowProvider::Init(TermsAndConditionsProvider * const inTermsAndConditionsProvider) +{ + VerifyOrReturnError(nullptr != inTermsAndConditionsProvider, CHIP_ERROR_INVALID_ARGUMENT); + + mTermsAndConditionsProvider = inTermsAndConditionsProvider; + + return CHIP_NO_ERROR; +} + +CHIP_ERROR +chip::app::DefaultEnhancedSetupFlowProvider::HasTermsAndConditionsRequiredAcknowledgementsBeenAccepted(bool & outAccepted) const +{ + uint16_t requiredAcknowledgements; + uint16_t requiredAcknowledgementsVersion; + uint16_t acceptedAcknowledgements; + uint16_t acceptedAcknowledgementsVersion; + + VerifyOrReturnError(nullptr != mTermsAndConditionsProvider, CHIP_ERROR_UNINITIALIZED); + ReturnErrorOnFailure(mTermsAndConditionsProvider->GetRequirements(requiredAcknowledgements, requiredAcknowledgementsVersion)); + + if (0 == requiredAcknowledgements) + { + outAccepted = true; + return CHIP_NO_ERROR; + } + + ReturnErrorOnFailure(mTermsAndConditionsProvider->GetAcceptance(acceptedAcknowledgements, acceptedAcknowledgementsVersion)); + + outAccepted = ((requiredAcknowledgements & acceptedAcknowledgements) == requiredAcknowledgements); + + return CHIP_NO_ERROR; +} + +CHIP_ERROR chip::app::DefaultEnhancedSetupFlowProvider::HasTermsAndConditionsRequiredAcknowledgementsVersionBeenAccepted( + bool & outAccepted) const +{ + uint16_t requiredAcknowledgements; + uint16_t requiredAcknowledgementsVersion; + uint16_t acceptedAcknowledgements; + uint16_t acceptedAcknowledgementsVersion; + + VerifyOrReturnError(nullptr != mTermsAndConditionsProvider, CHIP_ERROR_UNINITIALIZED); + ReturnErrorOnFailure(mTermsAndConditionsProvider->GetRequirements(requiredAcknowledgements, requiredAcknowledgementsVersion)); + + if (0 == requiredAcknowledgementsVersion) + { + outAccepted = true; + return CHIP_NO_ERROR; + } + + ReturnErrorOnFailure(mTermsAndConditionsProvider->GetAcceptance(acceptedAcknowledgements, acceptedAcknowledgementsVersion)); + + outAccepted = (acceptedAcknowledgementsVersion >= requiredAcknowledgementsVersion); + + return CHIP_NO_ERROR; +} + +CHIP_ERROR chip::app::DefaultEnhancedSetupFlowProvider::GetTermsAndConditionsRequiredAcknowledgements(uint16_t & outValue) const +{ + uint16_t requiredAcknowledgements; + uint16_t requiredAcknowledgementsVersion; + + VerifyOrReturnError(nullptr != mTermsAndConditionsProvider, CHIP_ERROR_UNINITIALIZED); + ReturnErrorOnFailure(mTermsAndConditionsProvider->GetRequirements(requiredAcknowledgements, requiredAcknowledgementsVersion)); + + outValue = requiredAcknowledgements; + + return CHIP_NO_ERROR; +} + +CHIP_ERROR +chip::app::DefaultEnhancedSetupFlowProvider::GetTermsAndConditionsRequiredAcknowledgementsVersion(uint16_t & outValue) const +{ + uint16_t requiredAcknowledgements; + uint16_t requiredAcknowledgementsVersion; + + VerifyOrReturnError(nullptr != mTermsAndConditionsProvider, CHIP_ERROR_UNINITIALIZED); + ReturnErrorOnFailure(mTermsAndConditionsProvider->GetRequirements(requiredAcknowledgements, requiredAcknowledgementsVersion)); + + outValue = requiredAcknowledgementsVersion; + + return CHIP_NO_ERROR; +} + +CHIP_ERROR chip::app::DefaultEnhancedSetupFlowProvider::GetTermsAndConditionsAcceptedAcknowledgements(uint16_t & outValue) const +{ + uint16_t acceptedAcknowledgements; + uint16_t acceptedAcknowledgementsVersion; + + VerifyOrReturnError(nullptr != mTermsAndConditionsProvider, CHIP_ERROR_UNINITIALIZED); + ReturnErrorOnFailure(mTermsAndConditionsProvider->GetAcceptance(acceptedAcknowledgements, acceptedAcknowledgementsVersion)); + + outValue = acceptedAcknowledgements; + + return CHIP_NO_ERROR; +} + +CHIP_ERROR +chip::app::DefaultEnhancedSetupFlowProvider::GetTermsAndConditionsAcceptedAcknowledgementsVersion(uint16_t & outValue) const +{ + uint16_t acceptedAcknowledgements; + uint16_t acceptedAcknowledgementsVersion; + + VerifyOrReturnError(nullptr != mTermsAndConditionsProvider, CHIP_ERROR_UNINITIALIZED); + ReturnErrorOnFailure(mTermsAndConditionsProvider->GetAcceptance(acceptedAcknowledgements, acceptedAcknowledgementsVersion)); + + outValue = acceptedAcknowledgementsVersion; + + return CHIP_NO_ERROR; +} + +CHIP_ERROR chip::app::DefaultEnhancedSetupFlowProvider::SetTermsAndConditionsAcceptance(uint16_t inTCAcknowledgementsValue, + uint16_t inTCAcknowledgementsVersionValue) +{ + VerifyOrReturnError(nullptr != mTermsAndConditionsProvider, CHIP_ERROR_UNINITIALIZED); + ReturnErrorOnFailure(mTermsAndConditionsProvider->SetAcceptance(inTCAcknowledgementsValue, inTCAcknowledgementsVersionValue)); + + return CHIP_NO_ERROR; +} + +CHIP_ERROR chip::app::DefaultEnhancedSetupFlowProvider::ClearTermsAndConditionsAcceptance() +{ + VerifyOrReturnError(nullptr != mTermsAndConditionsProvider, CHIP_ERROR_UNINITIALIZED); + ReturnErrorOnFailure(mTermsAndConditionsProvider->ClearAcceptance()); + + return CHIP_NO_ERROR; +} + +#endif // defined (CHIP_CONFIG_TC_REQUIRED_ACKNOWLEDGEMENTS) && defined (CHIP_CONFIG_TC_REQUIRED_ACKNOWLEDGEMENTS_VERSION) diff --git a/src/app/server/DefaultEnhancedSetupFlowProvider.h b/src/app/server/DefaultEnhancedSetupFlowProvider.h new file mode 100644 index 00000000000000..e1bce574cbd2be --- /dev/null +++ b/src/app/server/DefaultEnhancedSetupFlowProvider.h @@ -0,0 +1,93 @@ +/* + * + * Copyright (c) 2024 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +#if defined (CHIP_CONFIG_TC_REQUIRED_ACKNOWLEDGEMENTS) && defined (CHIP_CONFIG_TC_REQUIRED_ACKNOWLEDGEMENTS_VERSION) + +#include "EnhancedSetupFlowProvider.h" + +#include + +#include + +#include "TermsAndConditionsProvider.h" + +namespace chip { +namespace app { +class DefaultEnhancedSetupFlowProvider : public EnhancedSetupFlowProvider +{ +public: + /** + * @brief Initializes the EnhancedSetupFlowProvider. + * + * @param[in] inTermsAndConditionsProvider The terms and conditions provide dependency. + * @return CHIP_ERROR On success returns CHIP_NO_ERROR, otherwise returns an error code. + */ + CHIP_ERROR Init(TermsAndConditionsProvider * const inTermsAndConditionsProvider); + + /** + * @copydoc EnhancedSetupFlowProvider::HasTermsAndConditionsRequiredAcknowledgementsBeenAccepted + */ + CHIP_ERROR HasTermsAndConditionsRequiredAcknowledgementsBeenAccepted(bool & outAccepted) const override; + + /** + * @copydoc EnhancedSetupFlowProvider::HasTermsAndConditionsRequiredAcknowledgementsVersionBeenAccepted + */ + CHIP_ERROR HasTermsAndConditionsRequiredAcknowledgementsVersionBeenAccepted(bool & outAccepted) const override; + + /** + * @copydoc EnhancedSetupFlowProvider::GetTermsAndConditionsRequiredAcknowledgements + */ + CHIP_ERROR GetTermsAndConditionsRequiredAcknowledgements(uint16_t & outValue) const override; + + /** + * @copydoc EnhancedSetupFlowProvider::GetTermsAndConditionsRequiredAcknowledgementsVersion + */ + CHIP_ERROR GetTermsAndConditionsRequiredAcknowledgementsVersion(uint16_t & outValue) const override; + + /** + * @copydoc EnhancedSetupFlowProvider::GetTermsAndConditionsAcceptedAcknowledgements + */ + CHIP_ERROR GetTermsAndConditionsAcceptedAcknowledgements(uint16_t & outValue) const override; + + /** + * @copydoc EnhancedSetupFlowProvider::GetTermsAndConditionsAcceptedAcknowledgementsVersion + */ + CHIP_ERROR GetTermsAndConditionsAcceptedAcknowledgementsVersion(uint16_t & outValue) const override; + + /** + * @copydoc EnhancedSetupFlowProvider::SetTermsAndConditionsAcceptance + */ + CHIP_ERROR SetTermsAndConditionsAcceptance(uint16_t aTCAcknowledgements, uint16_t aTCAcknowledgementsVersion) override; + + /** + * @copydoc EnhancedSetupFlowProvider::ClearTermsAndConditionsAcceptance + */ + CHIP_ERROR ClearTermsAndConditionsAcceptance() override; + +private: + TermsAndConditionsProvider * mTermsAndConditionsProvider; /**< TermsAndConditionsProvider instance. */ +}; + +}; // namespace app +}; // namespace chip + +#endif // defined (CHIP_CONFIG_TC_REQUIRED_ACKNOWLEDGEMENTS) && defined (CHIP_CONFIG_TC_REQUIRED_ACKNOWLEDGEMENTS_VERSION) diff --git a/src/app/server/DefaultTermsAndConditionsProvider.cpp b/src/app/server/DefaultTermsAndConditionsProvider.cpp new file mode 100644 index 00000000000000..7e0aa23f631867 --- /dev/null +++ b/src/app/server/DefaultTermsAndConditionsProvider.cpp @@ -0,0 +1,135 @@ +/* + * + * Copyright (c) 2024 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#if defined (CHIP_CONFIG_TC_REQUIRED_ACKNOWLEDGEMENTS) && defined (CHIP_CONFIG_TC_REQUIRED_ACKNOWLEDGEMENTS_VERSION) + +#include "DefaultTermsAndConditionsProvider.h" + +#include +#include +#include +#include +#include +#include + +namespace { +static constexpr chip::TLV::Tag kAcceptedAcknowledgementsTag = chip::TLV::ContextTag(1); +static constexpr chip::TLV::Tag kAcceptedAcknowledgementsVersionTag = chip::TLV::ContextTag(2); +static constexpr size_t kEstimatedTlvBufferSize = chip::TLV::EstimateStructOverhead(sizeof(uint16_t), sizeof(uint16_t)); +}; // namespace + +CHIP_ERROR chip::app::DefaultTermsAndConditionsProvider::Init(chip::PersistentStorageDelegate * const inPersistentStorageDelegate, + uint16_t inRequiredAcknowledgementsValue, + uint16_t inRequiredAcknowledgementsVersionValue) +{ + VerifyOrReturnError(nullptr != inPersistentStorageDelegate, CHIP_ERROR_INVALID_ARGUMENT); + + mPersistentStorageDelegate = inPersistentStorageDelegate; + mRequiredAcknowledgementsValue = inRequiredAcknowledgementsValue; + mRequiredAcknowledgementsVersionValue = inRequiredAcknowledgementsVersionValue; + + return CHIP_NO_ERROR; +} + +CHIP_ERROR chip::app::DefaultTermsAndConditionsProvider::ClearAcceptance() +{ + VerifyOrReturnError(nullptr != mPersistentStorageDelegate, CHIP_ERROR_UNINITIALIZED); + + const chip::StorageKeyName storageKey = DefaultStorageKeyAllocator::TermsAndConditionsAcceptance(); + ReturnErrorOnFailure(mPersistentStorageDelegate->SyncDeleteKeyValue(storageKey.KeyName())); + + return CHIP_NO_ERROR; +} + +CHIP_ERROR chip::app::DefaultTermsAndConditionsProvider::GetAcceptance(uint16_t & outAcknowledgementsValue, + uint16_t & outAcknowledgementsVersionValue) const +{ + uint16_t acknowledgements = 0; + uint16_t acknowledgementsVersion = 0; + + chip::TLV::TLVReader tlvReader; + chip::TLV::TLVType tlvContainer; + + uint8_t buffer[kEstimatedTlvBufferSize] = { 0 }; + uint16_t bufferSize = sizeof(buffer); + + VerifyOrReturnError(nullptr != mPersistentStorageDelegate, CHIP_ERROR_UNINITIALIZED); + + const chip::StorageKeyName storageKey = DefaultStorageKeyAllocator::TermsAndConditionsAcceptance(); + CHIP_ERROR err = mPersistentStorageDelegate->SyncGetKeyValue(storageKey.KeyName(), &buffer, bufferSize); + if (CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND == err) + { + outAcknowledgementsValue = acknowledgements; + outAcknowledgementsVersionValue = acknowledgementsVersion; + + return CHIP_NO_ERROR; + } + + VerifyOrReturnError(CHIP_NO_ERROR == err, err); + + tlvReader.Init(buffer); + ReturnErrorOnFailure(tlvReader.Next(chip::TLV::kTLVType_Structure, chip::TLV::AnonymousTag())); + ReturnErrorOnFailure(tlvReader.EnterContainer(tlvContainer)); + ReturnErrorOnFailure(tlvReader.Next()); + ReturnErrorOnFailure(tlvReader.Expect(kAcceptedAcknowledgementsTag)); + ReturnErrorOnFailure(tlvReader.Get(acknowledgements)); + ReturnErrorOnFailure(tlvReader.Next()); + ReturnErrorOnFailure(tlvReader.Expect(kAcceptedAcknowledgementsVersionTag)); + ReturnErrorOnFailure(tlvReader.Get(acknowledgementsVersion)); + ReturnErrorOnFailure(tlvReader.ExitContainer(tlvContainer)); + + outAcknowledgementsValue = acknowledgements; + outAcknowledgementsVersionValue = acknowledgementsVersion; + + return CHIP_NO_ERROR; +} + +CHIP_ERROR chip::app::DefaultTermsAndConditionsProvider::GetRequirements(uint16_t & outAcknowledgementsValue, + uint16_t & outAcknowledgementsVersionValue) const +{ + outAcknowledgementsValue = mRequiredAcknowledgementsValue; + outAcknowledgementsVersionValue = mRequiredAcknowledgementsVersionValue; + + return CHIP_NO_ERROR; +} + +CHIP_ERROR chip::app::DefaultTermsAndConditionsProvider::SetAcceptance(uint16_t inAcceptedAcknowledgementsValue, + uint16_t inAcceptedAcknowledgementsVersionValue) +{ + uint8_t buffer[kEstimatedTlvBufferSize] = { 0 }; + chip::TLV::TLVWriter tlvWriter; + chip::TLV::TLVType tlvContainer; + + VerifyOrReturnError(nullptr != mPersistentStorageDelegate, CHIP_ERROR_UNINITIALIZED); + + tlvWriter.Init(buffer, sizeof(buffer)); + ReturnErrorOnFailure(tlvWriter.StartContainer(chip::TLV::AnonymousTag(), chip::TLV::kTLVType_Structure, tlvContainer)); + ReturnErrorOnFailure(tlvWriter.Put(kAcceptedAcknowledgementsTag, inAcceptedAcknowledgementsValue)); + ReturnErrorOnFailure(tlvWriter.Put(kAcceptedAcknowledgementsVersionTag, inAcceptedAcknowledgementsVersionValue)); + ReturnErrorOnFailure(tlvWriter.EndContainer(tlvContainer)); + ReturnErrorOnFailure(tlvWriter.Finalize()); + + const chip::StorageKeyName storageKey = DefaultStorageKeyAllocator::TermsAndConditionsAcceptance(); + ReturnErrorOnFailure(mPersistentStorageDelegate->SyncSetKeyValue(storageKey.KeyName(), buffer, sizeof(buffer))); + + return CHIP_NO_ERROR; +} + +#endif // defined (CHIP_CONFIG_TC_REQUIRED_ACKNOWLEDGEMENTS) && defined (CHIP_CONFIG_TC_REQUIRED_ACKNOWLEDGEMENTS_VERSION) diff --git a/src/app/server/DefaultTermsAndConditionsProvider.h b/src/app/server/DefaultTermsAndConditionsProvider.h new file mode 100644 index 00000000000000..8549e05d0323eb --- /dev/null +++ b/src/app/server/DefaultTermsAndConditionsProvider.h @@ -0,0 +1,77 @@ +/* + * + * Copyright (c) 2024 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +#if defined (CHIP_CONFIG_TC_REQUIRED_ACKNOWLEDGEMENTS) && defined (CHIP_CONFIG_TC_REQUIRED_ACKNOWLEDGEMENTS_VERSION) + +#include "TermsAndConditionsProvider.h" + +#include + +#include +#include + +namespace chip { +namespace app { +class DefaultTermsAndConditionsProvider : public TermsAndConditionsProvider +{ +public: + /** + * @brief Initializes the TermsAndConditionsProvider. + * + * @param[in] inPersistentStorageDelegate Persistent storage delegate dependency. + * @param[in] inRequiredAcknowledgementsValue The bitmask of required acknowledgements. + * @param[in] inRequiredAcknowledgementsVersionValue The version of the required acknowledgements. + * @return CHIP_ERROR On success returns CHIP_NO_ERROR, otherwise returns an error code. + */ + CHIP_ERROR Init(chip::PersistentStorageDelegate * const inPersistentStorageDelegate, uint16_t inRequiredAcknowledgementsValue, + uint16_t inRequiredAcknowledgementsVersionValue); + + /** + * @copydoc TermsAndConditionsProvider::ClearAcceptance + */ + CHIP_ERROR ClearAcceptance() override; + + /** + * @copydoc TermsAndConditionsProvider::GetAcceptance + */ + CHIP_ERROR GetAcceptance(uint16_t & outAcknowledgementsValue, uint16_t & outAcknowledgementsVersionValue) const override; + + /** + * @copydoc TermsAndConditionsProvider::GetRequirements + */ + CHIP_ERROR GetRequirements(uint16_t & outAcknowledgementsValue, uint16_t & outAcknowledgementsVersionValue) const override; + + /** + * @copydoc TermsAndConditionsProvider::SetAcceptance + */ + CHIP_ERROR SetAcceptance(uint16_t inAcknowledgementsValue, uint16_t inAcknowledgementsVersionValue) override; + +private: + chip::PersistentStorageDelegate * mPersistentStorageDelegate; + uint16_t mRequiredAcknowledgementsValue; + uint16_t mRequiredAcknowledgementsVersionValue; +}; + +}; // namespace app +}; // namespace chip + +#endif // defined (CHIP_CONFIG_TC_REQUIRED_ACKNOWLEDGEMENTS) && defined (CHIP_CONFIG_TC_REQUIRED_ACKNOWLEDGEMENTS_VERSION) diff --git a/src/app/server/EnhancedSetupFlowProvider.h b/src/app/server/EnhancedSetupFlowProvider.h new file mode 100644 index 00000000000000..015226b4c85afb --- /dev/null +++ b/src/app/server/EnhancedSetupFlowProvider.h @@ -0,0 +1,114 @@ +/* + * + * Copyright (c) 2024 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +#if defined (CHIP_CONFIG_TC_REQUIRED_ACKNOWLEDGEMENTS) && defined (CHIP_CONFIG_TC_REQUIRED_ACKNOWLEDGEMENTS_VERSION) + +#include + +#include + +namespace chip { +namespace app { + +/** + * @brief Feature state access layer for the EnhancedSetupFlowProvider. + * + * This class provides access to the state of the feature through the TermsAndConditionsProvider. + */ +class EnhancedSetupFlowProvider +{ +public: + /** + * @brief Destructor. + */ + virtual ~EnhancedSetupFlowProvider() = default; + + /** + * @brief Checks if the required terms and conditions acknowledgements have been accepted. + * + * @param[out] outAccepted true if the required acknowledgements have been accepted, false otherwise. + * @return CHIP_ERROR On success returns CHIP_NO_ERROR, otherwise returns an error code. + */ + virtual CHIP_ERROR HasTermsAndConditionsRequiredAcknowledgementsBeenAccepted(bool & outAccepted) const = 0; + + /** + * @brief Checks if the required terms and conditions acknowledgements version has been accepted. + * + * @param[out] outAccepted true if the required acknowledgements version has been accepted, false otherwise. + * @return CHIP_ERROR On success returns CHIP_NO_ERROR, otherwise returns an error code. + */ + virtual CHIP_ERROR HasTermsAndConditionsRequiredAcknowledgementsVersionBeenAccepted(bool & outAccepted) const = 0; + + /** + * @brief Retrieves the required terms and conditions acknowledgements. + * + * @param[out] outValue The version of the required acknowledgements. + * @return CHIP_ERROR On success returns CHIP_NO_ERROR, otherwise returns an error code. + */ + virtual CHIP_ERROR GetTermsAndConditionsRequiredAcknowledgements(uint16_t & outValue) const = 0; + + /** + * @brief Retrieves the required terms and conditions acknowledgements version. + * + * @param[out] outValue The outValue of the required acknowledgements version. + * @return CHIP_ERROR On success returns CHIP_NO_ERROR, otherwise returns an error code. + */ + virtual CHIP_ERROR GetTermsAndConditionsRequiredAcknowledgementsVersion(uint16_t & outValue) const = 0; + + /** + * @brief Retrieves the accepted terms and conditions acknowledgements. + * + * @param[out] outValue The outValue of the accepted acknowledgements. + * @return CHIP_ERROR On success returns CHIP_NO_ERROR, otherwise returns an error code. + */ + virtual CHIP_ERROR GetTermsAndConditionsAcceptedAcknowledgements(uint16_t & outValue) const = 0; + + /** + * @brief Retrieves the accepted terms and conditions acknowledgements version. + * + * @param[out] outValue The outValue of the accepted acknowledgements version. + * @return CHIP_ERROR On success returns CHIP_NO_ERROR, otherwise returns an error code. + */ + virtual CHIP_ERROR GetTermsAndConditionsAcceptedAcknowledgementsVersion(uint16_t & outValue) const = 0; + + /** + * @brief Sets the acceptance status of the terms and conditions. + * + * @param[in] inTCAcknowledgements The acknowledgements to accept. + * @param[in] inTCAcknowledgementsoutValue The version of the acknowledgements to accept. + * @return CHIP_ERROR On success returns CHIP_NO_ERROR, otherwise returns an error code. + */ + virtual CHIP_ERROR SetTermsAndConditionsAcceptance(uint16_t inTCAcknowledgementsValue, + uint16_t inTCAcknowledgementsoutValue) = 0; + + /** + * @brief Clears the acceptance status of the terms and conditions. + * + * @return CHIP_ERROR On success returns CHIP_NO_ERROR, otherwise returns an error code. + */ + virtual CHIP_ERROR ClearTermsAndConditionsAcceptance() = 0; +}; + +}; // namespace app +}; // namespace chip + +#endif // defined (CHIP_CONFIG_TC_REQUIRED_ACKNOWLEDGEMENTS) && defined (CHIP_CONFIG_TC_REQUIRED_ACKNOWLEDGEMENTS_VERSION) diff --git a/src/app/server/Server.cpp b/src/app/server/Server.cpp index 22cd274ba87e39..94915381275e23 100644 --- a/src/app/server/Server.cpp +++ b/src/app/server/Server.cpp @@ -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. @@ -21,6 +21,8 @@ #include #include +#include +#include #include #include #include @@ -105,6 +107,110 @@ static ::chip::PersistedCounter sGlobalEventIdCounter; static ::chip::app::CircularEventBuffer sLoggingBuffer[CHIP_NUM_EVENT_LOGGING_BUFFERS]; #endif // CHIP_CONFIG_ENABLE_SERVER_IM_EVENT +#if defined (CHIP_CONFIG_TC_REQUIRED_ACKNOWLEDGEMENTS) && defined (CHIP_CONFIG_TC_REQUIRED_ACKNOWLEDGEMENTS_VERSION) +app::DefaultEnhancedSetupFlowProvider sDefaultEnhancedSetupFlowProviderInstance; +app::EnhancedSetupFlowProvider * CommonCaseDeviceServerInitParams::sDefaultEnhancedSetupFlowProvider = + &sDefaultEnhancedSetupFlowProviderInstance; + +app::DefaultTermsAndConditionsProvider sDefaultTermsAndConditionsProviderInstance; +app::TermsAndConditionsProvider * CommonCaseDeviceServerInitParams::sDefaultTermsAndConditionsProvider = + &sDefaultTermsAndConditionsProviderInstance; +#endif + +CHIP_ERROR CommonCaseDeviceServerInitParams::InitializeStaticResourcesBeforeServerInit() +{ + chip::DeviceLayer::PersistedStorage::KeyValueStoreManager & kvsManager = DeviceLayer::PersistedStorage::KeyValueStoreMgr(); + + // KVS-based persistent storage delegate injection + if (persistentStorageDelegate == nullptr) + { + ReturnErrorOnFailure(sKvsPersistenStorageDelegate.Init(&kvsManager)); + this->persistentStorageDelegate = &sKvsPersistenStorageDelegate; + } + + // PersistentStorageDelegate "software-based" operational key access injection + if (this->operationalKeystore == nullptr) + { + // WARNING: PersistentStorageOperationalKeystore::Finish() is never called. It's fine for + // for examples and for now. + ReturnErrorOnFailure(sPersistentStorageOperationalKeystore.Init(this->persistentStorageDelegate)); + this->operationalKeystore = &sPersistentStorageOperationalKeystore; + } + + // OpCertStore can be injected but default to persistent storage default + // for simplicity of the examples. + if (this->opCertStore == nullptr) + { + // WARNING: PersistentStorageOpCertStore::Finish() is never called. It's fine for + // for examples and for now, since all storage is immediate for that impl. + ReturnErrorOnFailure(sPersistentStorageOpCertStore.Init(this->persistentStorageDelegate)); + this->opCertStore = &sPersistentStorageOpCertStore; + } + + // Injection of report scheduler WILL lead to two schedulers being allocated. As recommended above, this should only be used + // for IN-TREE examples. If a default scheduler is desired, the basic ServerInitParams should be used by the application and + // CommonCaseDeviceServerInitParams should not be allocated. + if (this->reportScheduler == nullptr) + { + reportScheduler = &sReportScheduler; + } + +#if defined (CHIP_CONFIG_TC_REQUIRED_ACKNOWLEDGEMENTS) && defined (CHIP_CONFIG_TC_REQUIRED_ACKNOWLEDGEMENTS_VERSION) + if (this->termsAndConditionsProvider == nullptr) + { + ReturnErrorOnFailure(sDefaultTermsAndConditionsProviderInstance.Init(this->persistentStorageDelegate, + CHIP_CONFIG_TC_REQUIRED_ACKNOWLEDGEMENTS, + CHIP_CONFIG_TC_REQUIRED_ACKNOWLEDGEMENTS_VERSION)); + this->termsAndConditionsProvider = sDefaultTermsAndConditionsProvider; + } + + if (this->enhancedSetupFlowProvider == nullptr) + { + ReturnErrorOnFailure(sDefaultEnhancedSetupFlowProviderInstance.Init(this->termsAndConditionsProvider)); + this->enhancedSetupFlowProvider = sDefaultEnhancedSetupFlowProvider; + } +#endif + + // Session Keystore injection + this->sessionKeystore = &sSessionKeystore; + + // Group Data provider injection + sGroupDataProvider.SetStorageDelegate(this->persistentStorageDelegate); + sGroupDataProvider.SetSessionKeystore(this->sessionKeystore); + ReturnErrorOnFailure(sGroupDataProvider.Init()); + this->groupDataProvider = &sGroupDataProvider; + +#if CHIP_CONFIG_ENABLE_SESSION_RESUMPTION + ReturnErrorOnFailure(sSessionResumptionStorage.Init(this->persistentStorageDelegate)); + this->sessionResumptionStorage = &sSessionResumptionStorage; +#else + this->sessionResumptionStorage = nullptr; +#endif + + // Inject access control delegate + this->accessDelegate = Access::Examples::GetAccessControlDelegate(); + + // Inject ACL storage. (Don't initialize it.) + this->aclStorage = &sAclStorage; + +#if CHIP_CONFIG_PERSIST_SUBSCRIPTIONS + ChipLogProgress(AppServer, "Initializing subscription resumption storage..."); + ReturnErrorOnFailure(sSubscriptionResumptionStorage.Init(this->persistentStorageDelegate)); + this->subscriptionResumptionStorage = &sSubscriptionResumptionStorage; +#else + ChipLogProgress(AppServer, "Subscription persistence not supported"); +#endif + +#if CHIP_CONFIG_ENABLE_ICD_CIP + if (this->icdCheckInBackOffStrategy == nullptr) + { + this->icdCheckInBackOffStrategy = &sDefaultICDCheckInBackOffStrategy; + } +#endif + + return CHIP_NO_ERROR; +} + CHIP_ERROR Server::Init(const ServerInitParams & initParams) { ChipLogProgress(AppServer, "Server initializing..."); @@ -129,6 +235,10 @@ CHIP_ERROR Server::Init(const ServerInitParams & initParams) VerifyOrExit(initParams.operationalKeystore != nullptr, err = CHIP_ERROR_INVALID_ARGUMENT); VerifyOrExit(initParams.opCertStore != nullptr, err = CHIP_ERROR_INVALID_ARGUMENT); VerifyOrExit(initParams.reportScheduler != nullptr, err = CHIP_ERROR_INVALID_ARGUMENT); +#if defined (CHIP_CONFIG_TC_REQUIRED_ACKNOWLEDGEMENTS) && defined (CHIP_CONFIG_TC_REQUIRED_ACKNOWLEDGEMENTS_VERSION) + VerifyOrExit(initParams.enhancedSetupFlowProvider != nullptr, err = CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrExit(initParams.termsAndConditionsProvider != nullptr, err = CHIP_ERROR_INVALID_ARGUMENT); +#endif // TODO(16969): Remove chip::Platform::MemoryInit() call from Server class, it belongs to outer code chip::Platform::MemoryInit(); @@ -185,6 +295,11 @@ CHIP_ERROR Server::Init(const ServerInitParams & initParams) mReportScheduler = initParams.reportScheduler; +#if defined (CHIP_CONFIG_TC_REQUIRED_ACKNOWLEDGEMENTS) && defined (CHIP_CONFIG_TC_REQUIRED_ACKNOWLEDGEMENTS_VERSION) + mTermsAndConditionsProvider = initParams.termsAndConditionsProvider; + mEnhancedSetupFlowProvider = initParams.enhancedSetupFlowProvider; +#endif + mTestEventTriggerDelegate = initParams.testEventTriggerDelegate; if (mTestEventTriggerDelegate == nullptr) { diff --git a/src/app/server/Server.h b/src/app/server/Server.h index 2f6126a4ace635..f9ef037df96c08 100644 --- a/src/app/server/Server.h +++ b/src/app/server/Server.h @@ -1,6 +1,6 @@ /* * - * 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. @@ -33,6 +33,8 @@ #include #include #include +#include +#include #include #include #include @@ -179,6 +181,12 @@ struct ServerInitParams // Optional. Support for the ICD Check-In BackOff strategy. Must be initialized before being provided. // If the ICD Check-In protocol use-case is supported and no strategy is provided, server will use the default strategy. app::ICDCheckInBackOffStrategy * icdCheckInBackOffStrategy = nullptr; +#if defined (CHIP_CONFIG_TC_REQUIRED_ACKNOWLEDGEMENTS) && defined (CHIP_CONFIG_TC_REQUIRED_ACKNOWLEDGEMENTS_VERSION) + // Optional. Enhanced setup flow provider to support terms and conditions acceptance check. + app::EnhancedSetupFlowProvider * enhancedSetupFlowProvider = nullptr; + // Optional. Terms and conditions provider to support enhanced setup flow feature. + app::TermsAndConditionsProvider * termsAndConditionsProvider = nullptr; +#endif }; /** @@ -225,83 +233,7 @@ struct CommonCaseDeviceServerInitParams : public ServerInitParams * @return CHIP_NO_ERROR on success or a CHIP_ERROR value from APIs called to initialize * resources on failure. */ - CHIP_ERROR InitializeStaticResourcesBeforeServerInit() - { - // KVS-based persistent storage delegate injection - if (persistentStorageDelegate == nullptr) - { - chip::DeviceLayer::PersistedStorage::KeyValueStoreManager & kvsManager = - DeviceLayer::PersistedStorage::KeyValueStoreMgr(); - ReturnErrorOnFailure(sKvsPersistenStorageDelegate.Init(&kvsManager)); - this->persistentStorageDelegate = &sKvsPersistenStorageDelegate; - } - - // PersistentStorageDelegate "software-based" operational key access injection - if (this->operationalKeystore == nullptr) - { - // WARNING: PersistentStorageOperationalKeystore::Finish() is never called. It's fine for - // for examples and for now. - ReturnErrorOnFailure(sPersistentStorageOperationalKeystore.Init(this->persistentStorageDelegate)); - this->operationalKeystore = &sPersistentStorageOperationalKeystore; - } - - // OpCertStore can be injected but default to persistent storage default - // for simplicity of the examples. - if (this->opCertStore == nullptr) - { - // WARNING: PersistentStorageOpCertStore::Finish() is never called. It's fine for - // for examples and for now, since all storage is immediate for that impl. - ReturnErrorOnFailure(sPersistentStorageOpCertStore.Init(this->persistentStorageDelegate)); - this->opCertStore = &sPersistentStorageOpCertStore; - } - - // Injection of report scheduler WILL lead to two schedulers being allocated. As recommended above, this should only be used - // for IN-TREE examples. If a default scheduler is desired, the basic ServerInitParams should be used by the application and - // CommonCaseDeviceServerInitParams should not be allocated. - if (this->reportScheduler == nullptr) - { - reportScheduler = &sReportScheduler; - } - - // Session Keystore injection - this->sessionKeystore = &sSessionKeystore; - - // Group Data provider injection - sGroupDataProvider.SetStorageDelegate(this->persistentStorageDelegate); - sGroupDataProvider.SetSessionKeystore(this->sessionKeystore); - ReturnErrorOnFailure(sGroupDataProvider.Init()); - this->groupDataProvider = &sGroupDataProvider; - -#if CHIP_CONFIG_ENABLE_SESSION_RESUMPTION - ReturnErrorOnFailure(sSessionResumptionStorage.Init(this->persistentStorageDelegate)); - this->sessionResumptionStorage = &sSessionResumptionStorage; -#else - this->sessionResumptionStorage = nullptr; -#endif - - // Inject access control delegate - this->accessDelegate = Access::Examples::GetAccessControlDelegate(); - - // Inject ACL storage. (Don't initialize it.) - this->aclStorage = &sAclStorage; - -#if CHIP_CONFIG_PERSIST_SUBSCRIPTIONS - ChipLogProgress(AppServer, "Initializing subscription resumption storage..."); - ReturnErrorOnFailure(sSubscriptionResumptionStorage.Init(this->persistentStorageDelegate)); - this->subscriptionResumptionStorage = &sSubscriptionResumptionStorage; -#else - ChipLogProgress(AppServer, "Subscription persistence not supported"); -#endif - -#if CHIP_CONFIG_ENABLE_ICD_CIP - if (this->icdCheckInBackOffStrategy == nullptr) - { - this->icdCheckInBackOffStrategy = &sDefaultICDCheckInBackOffStrategy; - } -#endif - - return CHIP_NO_ERROR; - } + CHIP_ERROR InitializeStaticResourcesBeforeServerInit(); private: static KvsPersistentStorageDelegate sKvsPersistenStorageDelegate; @@ -322,6 +254,10 @@ struct CommonCaseDeviceServerInitParams : public ServerInitParams #if CHIP_CONFIG_ENABLE_ICD_CIP static app::DefaultICDCheckInBackOffStrategy sDefaultICDCheckInBackOffStrategy; #endif +#if defined (CHIP_CONFIG_TC_REQUIRED_ACKNOWLEDGEMENTS) && defined (CHIP_CONFIG_TC_REQUIRED_ACKNOWLEDGEMENTS_VERSION) + static app::EnhancedSetupFlowProvider * sDefaultEnhancedSetupFlowProvider; + static app::TermsAndConditionsProvider * sDefaultTermsAndConditionsProvider; +#endif }; /** @@ -402,6 +338,10 @@ class Server app::reporting::ReportScheduler * GetReportScheduler() { return mReportScheduler; } +#if defined (CHIP_CONFIG_TC_REQUIRED_ACKNOWLEDGEMENTS) && defined (CHIP_CONFIG_TC_REQUIRED_ACKNOWLEDGEMENTS_VERSION) + app::EnhancedSetupFlowProvider * GetEnhancedSetupFlowProvider() { return mEnhancedSetupFlowProvider; } +#endif + #if CHIP_CONFIG_ENABLE_ICD_SERVER app::ICDManager & GetICDManager() { return mICDManager; } @@ -675,6 +615,10 @@ class Server GroupDataProviderListener mListener; ServerFabricDelegate mFabricDelegate; app::reporting::ReportScheduler * mReportScheduler; +#if defined (CHIP_CONFIG_TC_REQUIRED_ACKNOWLEDGEMENTS) && defined (CHIP_CONFIG_TC_REQUIRED_ACKNOWLEDGEMENTS_VERSION) + app::EnhancedSetupFlowProvider * mEnhancedSetupFlowProvider; + app::TermsAndConditionsProvider * mTermsAndConditionsProvider; +#endif Access::AccessControl mAccessControl; app::AclStorage * mAclStorage; diff --git a/src/app/server/TermsAndConditionsProvider.h b/src/app/server/TermsAndConditionsProvider.h new file mode 100644 index 00000000000000..79b6da751acbb7 --- /dev/null +++ b/src/app/server/TermsAndConditionsProvider.h @@ -0,0 +1,75 @@ +/* + * + * Copyright (c) 2024 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +#include + +namespace chip { +namespace app { + +/** + * @brief Data access layer for the required terms and conditions and the store for the user acceptance. + */ +class TermsAndConditionsProvider +{ +public: + /** + * @brief Destructor. + */ + virtual ~TermsAndConditionsProvider() = default; + + /** + * @brief Sets the acceptance status of the required terms and conditions. + * + * @return CHIP_ERROR On success returns CHIP_NO_ERROR, otherwise returns an error code. + */ + virtual CHIP_ERROR ClearAcceptance() = 0; + + /** + * @brief Retrieves the acceptance status of the required terms and conditions. + * + * @param[out] outAcknowledgementsValue The bitmask of acknowledgements accepted. + * @param[out] outAcknowledgementsVersionValue The version of the accepted acknowledgements. + * @return CHIP_ERROR On success returns CHIP_NO_ERROR, otherwise returns an error code. + */ + virtual CHIP_ERROR GetAcceptance(uint16_t & outAcknowledgementsValue, uint16_t & outAcknowledgementsVersionValue) const = 0; + + /** + * @brief Retrieves the requirements of the terms and conditions. + * + * @param[out] outAcknowledgementsValue The bitmask of required acknowledgements. + * @param[out] outAcknowledgementsVersionValue The version of the required acknowledgements. + * @return CHIP_ERROR On success returns CHIP_NO_ERROR, otherwise returns an error code. + */ + virtual CHIP_ERROR GetRequirements(uint16_t & outAcknowledgementsValue, uint16_t & outAcknowledgementsVersionValue) const = 0; + + /** + * @brief Sets the acceptance status of the required terms and conditions. + * + * @param[in] inAcknowledgementsValue The bitmask of acknowledgements that was accepted. + * @param[in] inAcknowledgementsVersionValue The version of the acknowledgements that was accepted. + * @return CHIP_ERROR On success returns CHIP_NO_ERROR, otherwise returns an error code. + */ + virtual CHIP_ERROR SetAcceptance(uint16_t inAcknowledgementsValue, uint16_t inAcknowledgementsVersionValue) = 0; +}; + +}; // namespace app +}; // namespace chip diff --git a/src/app/tests/BUILD.gn b/src/app/tests/BUILD.gn index e600fbeb3f1987..ae6dbd7f6b4fe2 100644 --- a/src/app/tests/BUILD.gn +++ b/src/app/tests/BUILD.gn @@ -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. @@ -194,7 +194,9 @@ chip_test_suite("tests") { "TestCommandPathParams.cpp", "TestConcreteAttributePath.cpp", "TestDataModelSerialization.cpp", + "TestDefaultEnhancedSetupFlowProvider.cpp", "TestDefaultOTARequestorStorage.cpp", + "TestDefaultTermsAndConditionsProvider.cpp", "TestDefaultThreadNetworkDirectoryStorage.cpp", "TestEventLoggingNoUTCTime.cpp", "TestEventOverflow.cpp", @@ -232,6 +234,7 @@ chip_test_suite("tests") { "${chip_root}/src/app/codegen-data-model:instance-header", "${chip_root}/src/app/common:cluster-objects", "${chip_root}/src/app/icd/client:manager", + "${chip_root}/src/app/server:server", "${chip_root}/src/app/tests:helpers", "${chip_root}/src/app/util/mock:mock_codegen_data_model", "${chip_root}/src/app/util/mock:mock_ember", diff --git a/src/app/tests/TestDefaultEnhancedSetupFlowProvider.cpp b/src/app/tests/TestDefaultEnhancedSetupFlowProvider.cpp new file mode 100644 index 00000000000000..e75418c9b59c32 --- /dev/null +++ b/src/app/tests/TestDefaultEnhancedSetupFlowProvider.cpp @@ -0,0 +1,305 @@ +/* + * Copyright (c) 2024 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "app/server/DefaultEnhancedSetupFlowProvider.h" + +#include +#include + +class FakeTermsAndConditionsProvider : public chip::app::TermsAndConditionsProvider +{ +public: + FakeTermsAndConditionsProvider(uint16_t inAcceptedAcknowledgements, uint16_t inAcceptedAcknowledgementsVersion, + uint16_t inRequiredAcknowledgements, uint16_t inRequiredAcknowledgementsVersion) : + mAcceptedAcknowledgements(inAcceptedAcknowledgements), + mAcceptedAcknowledgementsVersion(inAcceptedAcknowledgementsVersion), mRequiredAcknowledgements(inRequiredAcknowledgements), + mRequiredAcknowledgementsVersion(inRequiredAcknowledgementsVersion) + {} + + CHIP_ERROR GetAcceptance(uint16_t & outAcknowledgements, uint16_t & outAcknowledgementsVersion) const override + { + outAcknowledgements = mAcceptedAcknowledgements; + outAcknowledgementsVersion = mAcceptedAcknowledgementsVersion; + return CHIP_NO_ERROR; + } + + CHIP_ERROR GetRequirements(uint16_t & outAcknowledgements, uint16_t & outAcknowledgementsVersion) const override + { + outAcknowledgements = mRequiredAcknowledgements; + outAcknowledgementsVersion = mRequiredAcknowledgementsVersion; + return CHIP_NO_ERROR; + } + + CHIP_ERROR SetAcceptance(uint16_t inAcknowledgements, uint16_t inAcknowledgementsVersion) override + { + mAcceptedAcknowledgements = inAcknowledgements; + mAcceptedAcknowledgementsVersion = inAcknowledgementsVersion; + return CHIP_NO_ERROR; + } + + CHIP_ERROR ClearAcceptance() override + { + mAcceptedAcknowledgements = 0; + mAcceptedAcknowledgementsVersion = 0; + return CHIP_NO_ERROR; + } + +private: + uint16_t mAcceptedAcknowledgements; + uint16_t mAcceptedAcknowledgementsVersion; + uint16_t mRequiredAcknowledgements; + uint16_t mRequiredAcknowledgementsVersion; +}; + +TEST(DefaultEnhancedSetupFlowProvider, TestNoAcceptanceRequiredCheckAcknowledgementsAcceptedSuccess) +{ + CHIP_ERROR err; + bool hasTermsBeenAccepted; + + FakeTermsAndConditionsProvider tncProvider(0, 0, 0, 0); + chip::app::DefaultEnhancedSetupFlowProvider esfProvider; + + err = esfProvider.Init(&tncProvider); + EXPECT_TRUE(CHIP_NO_ERROR == err); + + err = esfProvider.HasTermsAndConditionsRequiredAcknowledgementsBeenAccepted(hasTermsBeenAccepted); + EXPECT_TRUE(CHIP_NO_ERROR == err); + EXPECT_TRUE(hasTermsBeenAccepted); +} + +TEST(DefaultEnhancedSetupFlowProvider, TestNoAcceptanceRequiredCheckAcknowledgementsVersionAcceptedSuccess) +{ + CHIP_ERROR err; + bool hasTermsVersionBeenAccepted; + + FakeTermsAndConditionsProvider tncProvider(0, 0, 0, 0); + chip::app::DefaultEnhancedSetupFlowProvider esfProvider; + + err = esfProvider.Init(&tncProvider); + EXPECT_TRUE(CHIP_NO_ERROR == err); + + err = esfProvider.HasTermsAndConditionsRequiredAcknowledgementsVersionBeenAccepted(hasTermsVersionBeenAccepted); + EXPECT_TRUE(CHIP_NO_ERROR == err); + EXPECT_TRUE(hasTermsVersionBeenAccepted); +} + +TEST(DefaultEnhancedSetupFlowProvider, TestAcceptanceRequiredNoTermsAcceptedCheckAcknowledgementsAcceptedFailure) +{ + CHIP_ERROR err; + bool hasTermsBeenAccepted; + + FakeTermsAndConditionsProvider tncProvider(0, 0, 1, 1); + chip::app::DefaultEnhancedSetupFlowProvider esfProvider; + + err = esfProvider.Init(&tncProvider); + EXPECT_TRUE(CHIP_NO_ERROR == err); + + err = esfProvider.HasTermsAndConditionsRequiredAcknowledgementsBeenAccepted(hasTermsBeenAccepted); + EXPECT_TRUE(CHIP_NO_ERROR == err); + EXPECT_TRUE(!hasTermsBeenAccepted); +} + +TEST(DefaultEnhancedSetupFlowProvider, + TestAcceptanceRequiredTermsAcceptedTermsVersionOutdatedCheckAcknowledgementsVersionAcceptedFailure) +{ + CHIP_ERROR err; + bool hasTermsBeenAccepted; + bool hasTermsVersionBeenAccepted; + + FakeTermsAndConditionsProvider tncProvider(0, 0, 1, 1); + chip::app::DefaultEnhancedSetupFlowProvider esfProvider; + + err = esfProvider.Init(&tncProvider); + EXPECT_TRUE(CHIP_NO_ERROR == err); + + err = esfProvider.SetTermsAndConditionsAcceptance(1, 0); + EXPECT_TRUE(CHIP_NO_ERROR == err); + + err = esfProvider.HasTermsAndConditionsRequiredAcknowledgementsBeenAccepted(hasTermsBeenAccepted); + EXPECT_TRUE(CHIP_NO_ERROR == err); + EXPECT_TRUE(hasTermsBeenAccepted); + + err = esfProvider.HasTermsAndConditionsRequiredAcknowledgementsVersionBeenAccepted(hasTermsVersionBeenAccepted); + EXPECT_TRUE(CHIP_NO_ERROR == err); + EXPECT_TRUE(!hasTermsVersionBeenAccepted); +} + +TEST(DefaultEnhancedSetupFlowProvider, TestAcceptanceRequiredTermsAcceptedFutureVersionCheckAcknowledgementsAcceptedSuccess) +{ + CHIP_ERROR err; + bool hasTermsBeenAccepted; + bool hasTermsVersionBeenAccepted; + + uint16_t acceptedTerms = 1; + uint16_t requiredTerms = 1; + uint16_t acceptedTermsVersion = 2; + uint16_t requiredTermsVersion = 1; + + FakeTermsAndConditionsProvider tncProvider(acceptedTerms, acceptedTermsVersion, requiredTerms, requiredTermsVersion); + chip::app::DefaultEnhancedSetupFlowProvider esfProvider; + + err = esfProvider.Init(&tncProvider); + EXPECT_TRUE(CHIP_NO_ERROR == err); + + err = esfProvider.HasTermsAndConditionsRequiredAcknowledgementsBeenAccepted(hasTermsBeenAccepted); + EXPECT_TRUE(CHIP_NO_ERROR == err); + EXPECT_TRUE(hasTermsBeenAccepted); + + err = esfProvider.HasTermsAndConditionsRequiredAcknowledgementsVersionBeenAccepted(hasTermsVersionBeenAccepted); + EXPECT_TRUE(CHIP_NO_ERROR == err); + EXPECT_TRUE(hasTermsVersionBeenAccepted); +} + +TEST(DefaultEnhancedSetupFlowProvider, TestAcceptanceRequiredTermsAcceptedSuccess) +{ + CHIP_ERROR err; + bool hasTermsBeenAccepted; + bool hasTermsVersionBeenAccepted; + + FakeTermsAndConditionsProvider tncProvider(0, 0, 1, 1); + chip::app::DefaultEnhancedSetupFlowProvider esfProvider; + + err = esfProvider.Init(&tncProvider); + EXPECT_TRUE(CHIP_NO_ERROR == err); + + err = esfProvider.SetTermsAndConditionsAcceptance(1, 1); + EXPECT_TRUE(CHIP_NO_ERROR == err); + + err = esfProvider.HasTermsAndConditionsRequiredAcknowledgementsBeenAccepted(hasTermsBeenAccepted); + EXPECT_TRUE(CHIP_NO_ERROR == err); + EXPECT_TRUE(hasTermsBeenAccepted); + + err = esfProvider.HasTermsAndConditionsRequiredAcknowledgementsVersionBeenAccepted(hasTermsVersionBeenAccepted); + EXPECT_TRUE(CHIP_NO_ERROR == err); + EXPECT_TRUE(hasTermsVersionBeenAccepted); +} + +TEST(DefaultEnhancedSetupFlowProvider, TestAcceptanceRequiredTermsMissingFailure) +{ + CHIP_ERROR err; + bool hasTermsBeenAccepted; + bool hasTermsVersionBeenAccepted; + + uint16_t acceptedTerms = 0b0111'1111'1111'1111; + uint16_t requiredTerms = 0b1111'1111'1111'1111; + uint16_t acceptedTermsVersion = 1; + uint16_t requiredTermsVersion = 1; + + FakeTermsAndConditionsProvider tncProvider(acceptedTerms, acceptedTermsVersion, requiredTerms, requiredTermsVersion); + chip::app::DefaultEnhancedSetupFlowProvider esfProvider; + + err = esfProvider.Init(&tncProvider); + EXPECT_TRUE(CHIP_NO_ERROR == err); + + err = esfProvider.HasTermsAndConditionsRequiredAcknowledgementsBeenAccepted(hasTermsBeenAccepted); + EXPECT_TRUE(CHIP_NO_ERROR == err); + EXPECT_TRUE(!hasTermsBeenAccepted); + + err = esfProvider.HasTermsAndConditionsRequiredAcknowledgementsVersionBeenAccepted(hasTermsVersionBeenAccepted); + EXPECT_TRUE(CHIP_NO_ERROR == err); + EXPECT_TRUE(hasTermsVersionBeenAccepted); +} + +TEST(DefaultEnhancedSetupFlowProvider, TestAcceptanceRequiredAllTermsAcceptedCheckAcknowledgementsAcceptedSuccess) +{ + CHIP_ERROR err; + bool hasTermsBeenAccepted; + bool hasTermsVersionBeenAccepted; + + uint16_t acceptedTerms = 0b1111'1111'1111'1111; + uint16_t requiredTerms = 0b1111'1111'1111'1111; + uint16_t acceptedTermsVersion = 1; + uint16_t requiredTermsVersion = 1; + + FakeTermsAndConditionsProvider tncProvider(acceptedTerms, acceptedTermsVersion, requiredTerms, requiredTermsVersion); + chip::app::DefaultEnhancedSetupFlowProvider esfProvider; + + err = esfProvider.Init(&tncProvider); + EXPECT_TRUE(CHIP_NO_ERROR == err); + + err = esfProvider.HasTermsAndConditionsRequiredAcknowledgementsBeenAccepted(hasTermsBeenAccepted); + EXPECT_TRUE(CHIP_NO_ERROR == err); + EXPECT_TRUE(hasTermsBeenAccepted); + + err = esfProvider.HasTermsAndConditionsRequiredAcknowledgementsVersionBeenAccepted(hasTermsVersionBeenAccepted); + EXPECT_TRUE(CHIP_NO_ERROR == err); + EXPECT_TRUE(hasTermsVersionBeenAccepted); +} + +TEST(DefaultEnhancedSetupFlowProvider, TestClearAcceptanceRetainsRequirements) +{ + CHIP_ERROR err; + + uint16_t initialAcceptedTermsAndConditions = 0; + uint16_t initialRequiredTermsAndConditions = 0b1111'1111'1111'1111; + uint16_t initialAcceptedTermsAndConditionsVersion = 0; + uint16_t initialRequiredTermsAndConditionsVersion = 1; + + uint16_t outAcceptedTermsAndConditions; + uint16_t outRequiredTermsAndConditions; + uint16_t outAcceptedTermsAndConditionsVersion; + uint16_t outRequiredTermsAndConditionsVersion; + + uint16_t updatedAcceptedTermsAndConditions = 0b1111'1111'1111'1111; + uint16_t updatedAcceptedTermsAndConditionsVersion = 1; + + FakeTermsAndConditionsProvider tncProvider(initialAcceptedTermsAndConditions, initialAcceptedTermsAndConditionsVersion, + initialRequiredTermsAndConditions, initialRequiredTermsAndConditionsVersion); + + chip::app::DefaultEnhancedSetupFlowProvider esfProvider; + + err = esfProvider.Init(&tncProvider); + EXPECT_TRUE(CHIP_NO_ERROR == err); + + err = esfProvider.SetTermsAndConditionsAcceptance(updatedAcceptedTermsAndConditions, updatedAcceptedTermsAndConditionsVersion); + EXPECT_TRUE(CHIP_NO_ERROR == err); + + err = esfProvider.GetTermsAndConditionsRequiredAcknowledgements(outRequiredTermsAndConditions); + EXPECT_TRUE(CHIP_NO_ERROR == err); + EXPECT_TRUE(outRequiredTermsAndConditions == initialRequiredTermsAndConditions); + + err = esfProvider.GetTermsAndConditionsRequiredAcknowledgementsVersion(outRequiredTermsAndConditionsVersion); + EXPECT_TRUE(CHIP_NO_ERROR == err); + EXPECT_TRUE(outRequiredTermsAndConditionsVersion == initialRequiredTermsAndConditionsVersion); + + err = esfProvider.GetTermsAndConditionsAcceptedAcknowledgements(outAcceptedTermsAndConditions); + EXPECT_TRUE(CHIP_NO_ERROR == err); + EXPECT_TRUE(outAcceptedTermsAndConditions == updatedAcceptedTermsAndConditions); + + err = esfProvider.GetTermsAndConditionsAcceptedAcknowledgementsVersion(outAcceptedTermsAndConditionsVersion); + EXPECT_TRUE(CHIP_NO_ERROR == err); + EXPECT_TRUE(outAcceptedTermsAndConditionsVersion == updatedAcceptedTermsAndConditionsVersion); + + err = esfProvider.ClearTermsAndConditionsAcceptance(); + EXPECT_TRUE(CHIP_NO_ERROR == err); + + err = esfProvider.GetTermsAndConditionsRequiredAcknowledgements(outRequiredTermsAndConditions); + EXPECT_TRUE(CHIP_NO_ERROR == err); + EXPECT_TRUE(outRequiredTermsAndConditions == initialRequiredTermsAndConditions); + + err = esfProvider.GetTermsAndConditionsRequiredAcknowledgementsVersion(outRequiredTermsAndConditionsVersion); + EXPECT_TRUE(CHIP_NO_ERROR == err); + EXPECT_TRUE(outRequiredTermsAndConditionsVersion == initialRequiredTermsAndConditionsVersion); + + err = esfProvider.GetTermsAndConditionsAcceptedAcknowledgements(outAcceptedTermsAndConditions); + EXPECT_TRUE(CHIP_NO_ERROR == err); + EXPECT_TRUE(outAcceptedTermsAndConditions == 0); + + err = esfProvider.GetTermsAndConditionsAcceptedAcknowledgementsVersion(outAcceptedTermsAndConditionsVersion); + EXPECT_TRUE(CHIP_NO_ERROR == err); + EXPECT_TRUE(outAcceptedTermsAndConditionsVersion == 0); +} diff --git a/src/app/tests/TestDefaultTermsAndConditionsProvider.cpp b/src/app/tests/TestDefaultTermsAndConditionsProvider.cpp new file mode 100644 index 00000000000000..5b496998d895ea --- /dev/null +++ b/src/app/tests/TestDefaultTermsAndConditionsProvider.cpp @@ -0,0 +1,225 @@ +/* + * + * Copyright (c) 2024 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "app/server/DefaultTermsAndConditionsProvider.h" + +#include +#include +#include + +TEST(DefaultTermsAndConditionsProvider, TestInitSuccess) +{ + CHIP_ERROR err; + + chip::TestPersistentStorageDelegate storageDelegate; + chip::app::DefaultTermsAndConditionsProvider tncProvider; + + uint16_t requiredAcknowledgements = 1; + uint16_t requiredAcknowledgementsVersion = 1; + err = tncProvider.Init(&storageDelegate, requiredAcknowledgements, requiredAcknowledgementsVersion); + EXPECT_TRUE(CHIP_NO_ERROR == err); +} + +TEST(DefaultTermsAndConditionsProvider, TestNoRequirementsGetRequirementsSuccess) +{ + CHIP_ERROR err; + + chip::TestPersistentStorageDelegate storageDelegate; + chip::app::DefaultTermsAndConditionsProvider tncProvider; + + uint16_t requiredAcknowledgements = 0; + uint16_t requiredAcknowledgementsVersion = 0; + err = tncProvider.Init(&storageDelegate, requiredAcknowledgements, requiredAcknowledgementsVersion); + EXPECT_TRUE(CHIP_NO_ERROR == err); + + uint16_t outAcceptance; + uint16_t outAcknowledgementsVersion; + err = tncProvider.GetAcceptance(outAcceptance, outAcknowledgementsVersion); + EXPECT_TRUE(CHIP_NO_ERROR == err); + EXPECT_TRUE(0 == outAcceptance); + EXPECT_TRUE(0 == outAcknowledgementsVersion); +} + +TEST(DefaultTermsAndConditionsProvider, TestNeverAcceptanceGetAcceptanceSuccess) +{ + CHIP_ERROR err; + + chip::TestPersistentStorageDelegate storageDelegate; + chip::app::DefaultTermsAndConditionsProvider tncProvider; + + uint16_t requiredAcknowledgements = 0b1111'1111'1111'1111; + uint16_t requiredAcknowledgementsVersion = 1; + err = tncProvider.Init(&storageDelegate, requiredAcknowledgements, requiredAcknowledgementsVersion); + EXPECT_TRUE(CHIP_NO_ERROR == err); + + uint16_t outAcceptance; + uint16_t outAcknowledgementsVersion; + err = tncProvider.GetAcceptance(outAcceptance, outAcknowledgementsVersion); + EXPECT_TRUE(CHIP_NO_ERROR == err); + EXPECT_TRUE(0 == outAcceptance); + EXPECT_TRUE(0 == outAcknowledgementsVersion); +} + +TEST(DefaultTermsAndConditionsProvider, TestTermsAcceptedPersistsSuccess) +{ + CHIP_ERROR err; + + chip::TestPersistentStorageDelegate storageDelegate; + chip::app::DefaultTermsAndConditionsProvider tncProvider; + chip::app::DefaultTermsAndConditionsProvider anotherTncProvider; + + uint16_t requiredAcknowledgements = 1; + uint16_t requiredAcknowledgementsVersion = 1; + err = tncProvider.Init(&storageDelegate, requiredAcknowledgements, requiredAcknowledgementsVersion); + EXPECT_TRUE(CHIP_NO_ERROR == err); + + uint16_t acceptedTermsAndConditions = 1; + uint16_t acceptedTermsAndConditionsVersion = 1; + err = tncProvider.SetAcceptance(acceptedTermsAndConditions, acceptedTermsAndConditionsVersion); + EXPECT_TRUE(CHIP_NO_ERROR == err); + + uint16_t outAcceptance; + uint16_t outAcknowledgementsVersion; + err = tncProvider.GetAcceptance(outAcceptance, outAcknowledgementsVersion); + EXPECT_TRUE(CHIP_NO_ERROR == err); + EXPECT_TRUE(1 == outAcceptance); + EXPECT_TRUE(1 == outAcknowledgementsVersion); + + err = anotherTncProvider.Init(&storageDelegate, requiredAcknowledgements, requiredAcknowledgementsVersion); + EXPECT_TRUE(CHIP_NO_ERROR == err); + + err = anotherTncProvider.GetAcceptance(outAcceptance, outAcknowledgementsVersion); + EXPECT_TRUE(CHIP_NO_ERROR == err); + EXPECT_TRUE(1 == outAcceptance); + EXPECT_TRUE(1 == outAcknowledgementsVersion); +} + +TEST(DefaultTermsAndConditionsProvider, TestTermsRequiredGetRequirementsSuccess) +{ + CHIP_ERROR err; + + chip::TestPersistentStorageDelegate storageDelegate; + chip::app::DefaultTermsAndConditionsProvider tncProvider; + + uint16_t initialRequiredAcknowledgements = 1; + uint16_t initialRequiredAcknowledgementsVersion = 1; + err = tncProvider.Init(&storageDelegate, initialRequiredAcknowledgements, initialRequiredAcknowledgementsVersion); + EXPECT_TRUE(CHIP_NO_ERROR == err); + + uint16_t outRequiredAcknowledgements; + uint16_t outRequiredAcknowledgementsVersion; + err = tncProvider.GetRequirements(outRequiredAcknowledgements, outRequiredAcknowledgementsVersion); + EXPECT_TRUE(CHIP_NO_ERROR == err); + EXPECT_TRUE(1 == outRequiredAcknowledgements); + EXPECT_TRUE(1 == outRequiredAcknowledgementsVersion); +} + +TEST(DefaultTermsAndConditionsProvider, TestSetAcceptanceGetAcceptanceSuccess) +{ + CHIP_ERROR err; + + chip::TestPersistentStorageDelegate storageDelegate; + chip::app::DefaultTermsAndConditionsProvider tncProvider; + + uint16_t requiredAcknowledgements = 1; + uint16_t requiredAcknowledgementsVersion = 1; + err = tncProvider.Init(&storageDelegate, requiredAcknowledgements, requiredAcknowledgementsVersion); + EXPECT_TRUE(CHIP_NO_ERROR == err); + + uint16_t acceptedTermsAndConditions = 1; + uint16_t acceptedTermsAndConditionsVersion = 1; + err = tncProvider.SetAcceptance(acceptedTermsAndConditions, acceptedTermsAndConditionsVersion); + EXPECT_TRUE(CHIP_NO_ERROR == err); + + uint16_t outAcceptance; + uint16_t outAcknowledgementsVersion; + err = tncProvider.GetAcceptance(outAcceptance, outAcknowledgementsVersion); + EXPECT_TRUE(CHIP_NO_ERROR == err); + EXPECT_TRUE(1 == outAcceptance); + EXPECT_TRUE(1 == outAcknowledgementsVersion); +} + +TEST(DefaultTermsAndConditionsProvider, TestClearAcceptanceGetAcceptanceSuccess) +{ + CHIP_ERROR err; + + chip::TestPersistentStorageDelegate storageDelegate; + chip::app::DefaultTermsAndConditionsProvider tncProvider; + + uint16_t requiredAcknowledgements = 1; + uint16_t requiredAcknowledgementsVersion = 1; + err = tncProvider.Init(&storageDelegate, requiredAcknowledgements, requiredAcknowledgementsVersion); + EXPECT_TRUE(CHIP_NO_ERROR == err); + + uint16_t acceptedTermsAndConditions = 1; + uint16_t acceptedTermsAndConditionsVersion = 1; + err = tncProvider.SetAcceptance(acceptedTermsAndConditions, acceptedTermsAndConditionsVersion); + EXPECT_TRUE(CHIP_NO_ERROR == err); + + uint16_t outAcceptance; + uint16_t outAcknowledgementsVersion; + err = tncProvider.GetAcceptance(outAcceptance, outAcknowledgementsVersion); + EXPECT_TRUE(CHIP_NO_ERROR == err); + EXPECT_TRUE(1 == outAcceptance); + EXPECT_TRUE(1 == outAcknowledgementsVersion); + + err = tncProvider.ClearAcceptance(); + EXPECT_TRUE(CHIP_NO_ERROR == err); + + uint16_t outAcceptance2; + uint16_t outAcknowledgementsVersion2; + err = tncProvider.GetAcceptance(outAcceptance2, outAcknowledgementsVersion2); + EXPECT_TRUE(CHIP_NO_ERROR == err); + EXPECT_TRUE(0 == outAcceptance2); + EXPECT_TRUE(0 == outAcknowledgementsVersion2); +} + +TEST(DefaultTermsAndConditionsProvider, TestAcceptanceRequiredTermsMissingFailure) +{ + CHIP_ERROR err; + + chip::TestPersistentStorageDelegate storageDelegate; + chip::app::DefaultTermsAndConditionsProvider tncProvider; + + uint16_t requiredAcknowledgements = 1; + uint16_t requiredAcknowledgementsVersion = 1; + err = tncProvider.Init(&storageDelegate, requiredAcknowledgements, requiredAcknowledgementsVersion); + EXPECT_TRUE(CHIP_NO_ERROR == err); + + uint16_t acceptedTermsAndConditions = 1; + uint16_t acceptedTermsAndConditionsVersion = 1; + err = tncProvider.SetAcceptance(acceptedTermsAndConditions, acceptedTermsAndConditionsVersion); + EXPECT_TRUE(CHIP_NO_ERROR == err); + + uint16_t outAcceptance; + uint16_t outAcknowledgementsVersion; + err = tncProvider.GetAcceptance(outAcceptance, outAcknowledgementsVersion); + EXPECT_TRUE(CHIP_NO_ERROR == err); + EXPECT_TRUE(1 == outAcceptance); + EXPECT_TRUE(1 == outAcknowledgementsVersion); + + err = tncProvider.ClearAcceptance(); + EXPECT_TRUE(CHIP_NO_ERROR == err); + + uint16_t outRequiredAcknowledgements; + uint16_t outRequiredAcknowledgementsVersion; + err = tncProvider.GetRequirements(outRequiredAcknowledgements, outRequiredAcknowledgementsVersion); + EXPECT_TRUE(CHIP_NO_ERROR == err); + EXPECT_TRUE(1 == outRequiredAcknowledgements); + EXPECT_TRUE(1 == outRequiredAcknowledgementsVersion); +} diff --git a/src/controller/AutoCommissioner.cpp b/src/controller/AutoCommissioner.cpp index 0e83d7125cf175..30911228298599 100644 --- a/src/controller/AutoCommissioner.cpp +++ b/src/controller/AutoCommissioner.cpp @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2021 Project CHIP Authors + * Copyright (c) 2021-2024 Project CHIP Authors * All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -365,6 +365,8 @@ CommissioningStage AutoCommissioner::GetNextCommissioningStageInternal(Commissio case CommissioningStage::kArmFailsafe: return CommissioningStage::kConfigRegulatory; case CommissioningStage::kConfigRegulatory: + return CommissioningStage::kConfigureTCAcknowledgments; + case CommissioningStage::kConfigureTCAcknowledgments: if (mDeviceCommissioningInfo.requiresUTC) { return CommissioningStage::kConfigureUTCTime; diff --git a/src/controller/CHIPDeviceController.cpp b/src/controller/CHIPDeviceController.cpp index 955e36bfb0d8a2..eb0755eeed769b 100644 --- a/src/controller/CHIPDeviceController.cpp +++ b/src/controller/CHIPDeviceController.cpp @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2020-2022 Project CHIP Authors + * Copyright (c) 2020-2024 Project CHIP Authors * Copyright (c) 2013-2017 Nest Labs, Inc. * All rights reserved. * @@ -2691,6 +2691,22 @@ void DeviceCommissioner::OnSetRegulatoryConfigResponse( commissioner->CommissioningStageComplete(err, report); } +void DeviceCommissioner::OnSetTCAcknowledgementsResponse( + void * context, const GeneralCommissioning::Commands::SetTCAcknowledgementsResponse::DecodableType & data) +{ + CommissioningDelegate::CommissioningReport report; + CHIP_ERROR err = CHIP_NO_ERROR; + + ChipLogProgress(Controller, "Received SetTCAcknowledgements response errorCode=%u", to_underlying(data.errorCode)); + if (data.errorCode != GeneralCommissioning::CommissioningErrorEnum::kOk) + { + err = CHIP_ERROR_INTERNAL; + report.Set(data.errorCode); + } + DeviceCommissioner * commissioner = static_cast(context); + commissioner->CommissioningStageComplete(err, report); +} + void DeviceCommissioner::OnSetTimeZoneResponse(void * context, const TimeSynchronization::Commands::SetTimeZoneResponse::DecodableType & data) { @@ -2766,6 +2782,16 @@ CHIP_ERROR DeviceCommissioner::ICDRegistrationInfoReady() return CHIP_NO_ERROR; } +CHIP_ERROR DeviceCommissioner::TermsAndConditionsAcknowledgementsReady() +{ + ReturnErrorCodeIf(mCommissioningStage != CommissioningStage::kConfigureTCAcknowledgments, CHIP_ERROR_INCORRECT_STATE); + + // need to advance to next step + CommissioningStageComplete(CHIP_NO_ERROR); + + return CHIP_NO_ERROR; +} + void DeviceCommissioner::OnNetworkConfigResponse(void * context, const NetworkCommissioning::Commands::NetworkConfigResponse::DecodableType & data) { @@ -3163,6 +3189,29 @@ void DeviceCommissioner::PerformCommissioningStep(DeviceProxy * proxy, Commissio } } break; + case CommissioningStage::kConfigureTCAcknowledgments: { + ChipLogProgress(Controller, "Setting Terms and Conditions"); + + if (!params.GetTermsAndConditionsAcknowledgement().HasValue()) + { + CommissioningStageComplete(CHIP_NO_ERROR); + return; + } + + GeneralCommissioning::Commands::SetTCAcknowledgements::Type request; + TermsAndConditionsAcknowledgement termsAndConditionsAcknowledgement = params.GetTermsAndConditionsAcknowledgement().Value(); + request.TCUserResponse = termsAndConditionsAcknowledgement.acceptedTermsAndConditions; + request.TCVersion = termsAndConditionsAcknowledgement.acceptedTermsAndConditionsVersion; + CHIP_ERROR err = + SendCommissioningCommand(proxy, request, OnSetTCAcknowledgementsResponse, OnBasicFailure, endpoint, timeout); + if (err != CHIP_NO_ERROR) + { + ChipLogError(Controller, "Failed to send SetTCAcknowledgements command: %" CHIP_ERROR_FORMAT, err.Format()); + CommissioningStageComplete(err); + return; + } + break; + } case CommissioningStage::kSendPAICertificateRequest: { ChipLogProgress(Controller, "Sending request for PAI certificate"); CHIP_ERROR err = SendCertificateChainRequestCommand(proxy, CertificateType::kPAI, timeout); diff --git a/src/controller/CHIPDeviceController.h b/src/controller/CHIPDeviceController.h index 4b876156199735..397fcdbe5508d5 100644 --- a/src/controller/CHIPDeviceController.h +++ b/src/controller/CHIPDeviceController.h @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2020-2022 Project CHIP Authors + * Copyright (c) 2020-2024 Project CHIP Authors * Copyright (c) 2013-2017 Nest Labs, Inc. * All rights reserved. * @@ -696,6 +696,8 @@ class DLL_EXPORT DeviceCommissioner : public DeviceController, */ CHIP_ERROR ICDRegistrationInfoReady(); + CHIP_ERROR TermsAndConditionsAcknowledgementsReady(); + /** * @brief * This function returns the current CommissioningStage for this commissioner. @@ -947,6 +949,9 @@ class DLL_EXPORT DeviceCommissioner : public DeviceController, static void OnSetRegulatoryConfigResponse( void * context, const chip::app::Clusters::GeneralCommissioning::Commands::SetRegulatoryConfigResponse::DecodableType & data); + static void OnSetTCAcknowledgementsResponse( + void * context, + const chip::app::Clusters::GeneralCommissioning::Commands::SetTCAcknowledgementsResponse::DecodableType & data); static void OnSetUTCError(void * context, CHIP_ERROR error); static void OnSetTimeZoneResponse(void * context, diff --git a/src/controller/CommissioningDelegate.cpp b/src/controller/CommissioningDelegate.cpp index 85ea5e86c5e3a6..800a54f81df87c 100644 --- a/src/controller/CommissioningDelegate.cpp +++ b/src/controller/CommissioningDelegate.cpp @@ -46,6 +46,9 @@ const char * StageToString(CommissioningStage stage) case kConfigRegulatory: return "ConfigRegulatory"; + case kConfigureTCAcknowledgments: + return "ConfigureTCAcknowledgments"; + case kConfigureUTCTime: return "ConfigureUTCTime"; diff --git a/src/controller/CommissioningDelegate.h b/src/controller/CommissioningDelegate.h index 7a96939cf49434..5d2688e776787e 100644 --- a/src/controller/CommissioningDelegate.h +++ b/src/controller/CommissioningDelegate.h @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2021 Project CHIP Authors + * Copyright (c) 2021-2024 Project CHIP Authors * All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -40,6 +40,7 @@ enum CommissioningStage : uint8_t kReadCommissioningInfo2, ///< Query SupportsConcurrentConnection, ICD state, check for matching fabric kArmFailsafe, ///< Send ArmFailSafe (0x30:0) command to the device kConfigRegulatory, ///< Send SetRegulatoryConfig (0x30:2) command to the device + kConfigureTCAcknowledgments, ///< Send SetTCAcknowledgements (0x30:6) command to the device kConfigureUTCTime, ///< SetUTCTime if the DUT has a time cluster kConfigureTimeZone, ///< Configure a time zone if one is required and available kConfigureDSTOffset, ///< Configure DST offset if one is required and available @@ -104,6 +105,12 @@ struct WiFiCredentials WiFiCredentials(ByteSpan newSsid, ByteSpan newCreds) : ssid(newSsid), credentials(newCreds) {} }; +struct TermsAndConditionsAcknowledgement +{ + uint16_t acceptedTermsAndConditions; + uint16_t acceptedTermsAndConditionsVersion; +}; + struct NOCChainGenerationParameters { ByteSpan nocsrElements; @@ -168,6 +175,11 @@ class CommissioningParameters // The country code to be used for the node, if set. Optional GetCountryCode() const { return mCountryCode; } + Optional GetTermsAndConditionsAcknowledgement() const + { + return mTermsAndConditionsAcknowledgement; + } + // Time zone to set for the node // If required, this will be truncated to fit the max size allowable on the node Optional> GetTimeZone() const @@ -340,6 +352,13 @@ class CommissioningParameters return *this; } + CommissioningParameters & + SetTermsAndConditionsAcknowledgement(TermsAndConditionsAcknowledgement termsAndConditionsAcknowledgement) + { + mTermsAndConditionsAcknowledgement.SetValue(termsAndConditionsAcknowledgement); + return *this; + } + // The lifetime of the list buffer needs to exceed the lifetime of the CommissioningParameters object. CommissioningParameters & SetTimeZone(app::DataModel::List timeZone) @@ -611,6 +630,7 @@ class CommissioningParameters Optional mAttestationNonce; Optional mWiFiCreds; Optional mCountryCode; + Optional mTermsAndConditionsAcknowledgement; Optional mThreadOperationalDataset; Optional mNOCChainGenerationParameters; Optional mRootCert; diff --git a/src/lib/support/DefaultStorageKeyAllocator.h b/src/lib/support/DefaultStorageKeyAllocator.h index 9ed8a2f56cfd77..b0de78d085e48d 100644 --- a/src/lib/support/DefaultStorageKeyAllocator.h +++ b/src/lib/support/DefaultStorageKeyAllocator.h @@ -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. @@ -256,6 +256,10 @@ class DefaultStorageKeyAllocator // when new fabric is created, this list needs to be updated, // when client init DefaultICDClientStorage, this table needs to be loaded. static StorageKeyName ICDFabricList() { return StorageKeyName::FromConst("g/icdfl"); } + + // Terms and Conditions Acceptance Key + // Stores the terms and conditions acceptance including terms and conditions revision, TLV encoded + static StorageKeyName TermsAndConditionsAcceptance() { return StorageKeyName::FromConst("g/tc"); } }; } // namespace chip