From 233d7756d952d4748e58778bae114f6945bac063 Mon Sep 17 00:00:00 2001
From: James Swan <122404367+swan-amazon@users.noreply.github.com>
Date: Mon, 29 Jul 2024 21:47:20 +0000
Subject: [PATCH] Implemented support for T&C
---
.../all-clusters-app.matter | 8 +-
.../all-clusters-common/all-clusters-app.zap | 83 ++++-
.../linux/include/CHIPProjectAppConfig.h | 23 +-
.../google/chip/chiptool/CHIPToolActivity.kt | 5 +
.../chiptool/GenericChipDeviceListener.kt | 8 +
.../chip/chiptool/SelectActionFragment.kt | 2 +-
.../DeviceProvisioningFragment.kt | 8 +
.../CHIPDeviceDetailsFragment.kt | 4 +-
.../CHIPLedgerDetailsFragment.kt | 113 ++++---
.../res/layout/chip_device_info_fragment.xml | 4 +-
.../res/layout/chip_ledger_info_fragment.xml | 13 +-
.../res/layout/select_action_fragment.xml | 2 +-
.../main/res/raw/mock_dcl_responses_json.json | 38 +++
.../app/src/main/res/values/strings.xml | 5 +-
.../commands/pairing/PairingCommand.cpp | 13 +-
.../commands/pairing/PairingCommand.h | 12 +-
.../general-commissioning-server.cpp | 189 ++++++++---
src/app/server/BUILD.gn | 8 +-
.../DefaultEnhancedSetupFlowProvider.cpp | 151 +++++++++
.../server/DefaultEnhancedSetupFlowProvider.h | 87 +++++
.../DefaultTermsAndConditionsProvider.cpp | 129 ++++++++
.../DefaultTermsAndConditionsProvider.h | 71 ++++
src/app/server/EnhancedSetupFlowProvider.h | 108 +++++++
src/app/server/Server.cpp | 120 ++++++-
src/app/server/Server.h | 101 ++----
src/app/server/TermsAndConditionsProvider.h | 75 +++++
src/app/tests/BUILD.gn | 5 +-
.../TestDefaultEnhancedSetupFlowProvider.cpp | 305 ++++++++++++++++++
.../TestDefaultTermsAndConditionsProvider.cpp | 225 +++++++++++++
src/controller/AutoCommissioner.cpp | 4 +-
src/controller/CHIPDeviceController.cpp | 51 ++-
src/controller/CHIPDeviceController.h | 7 +-
src/controller/CommissioningDelegate.cpp | 3 +
src/controller/CommissioningDelegate.h | 22 +-
.../java/CHIPDeviceController-JNI.cpp | 36 +++
.../ChipDeviceController.java | 13 +
.../src/matter/controller/MatterController.kt | 4 +
src/lib/support/DefaultStorageKeyAllocator.h | 6 +-
38 files changed, 1864 insertions(+), 197 deletions(-)
create mode 100644 examples/android/CHIPTool/app/src/main/res/raw/mock_dcl_responses_json.json
create mode 100644 src/app/server/DefaultEnhancedSetupFlowProvider.cpp
create mode 100644 src/app/server/DefaultEnhancedSetupFlowProvider.h
create mode 100644 src/app/server/DefaultTermsAndConditionsProvider.cpp
create mode 100644 src/app/server/DefaultTermsAndConditionsProvider.h
create mode 100644 src/app/server/EnhancedSetupFlowProvider.h
create mode 100644 src/app/server/TermsAndConditionsProvider.h
create mode 100644 src/app/tests/TestDefaultEnhancedSetupFlowProvider.cpp
create mode 100644 src/app/tests/TestDefaultTermsAndConditionsProvider.cpp
diff --git a/examples/all-clusters-app/all-clusters-common/all-clusters-app.matter b/examples/all-clusters-app/all-clusters-common/all-clusters-app.matter
index f243ce415d23fc..255b5946195980 100644
--- a/examples/all-clusters-app/all-clusters-common/all-clusters-app.matter
+++ b/examples/all-clusters-app/all-clusters-common/all-clusters-app.matter
@@ -7508,11 +7508,15 @@ endpoint 0 {
callback attribute regulatoryConfig;
callback attribute locationCapability;
callback attribute supportsConcurrentConnection;
+ ram attribute TCAcceptedVersion;
+ ram attribute TCMinRequiredVersion default = 1;
+ ram attribute TCAcknowledgements default = 0x0000;
+ ram attribute TCAcknowledgementsRequired default = true;
callback attribute generatedCommandList;
callback attribute acceptedCommandList;
callback attribute eventList;
callback attribute attributeList;
- ram attribute featureMap default = 0;
+ ram attribute featureMap default = 1;
ram attribute clusterRevision default = 1;
handle command ArmFailSafe;
@@ -7521,6 +7525,8 @@ endpoint 0 {
handle command SetRegulatoryConfigResponse;
handle command CommissioningComplete;
handle command CommissioningCompleteResponse;
+ handle command SetTCAcknowledgements;
+ handle command SetTCAcknowledgementsResponse;
}
server cluster NetworkCommissioning {
diff --git a/examples/all-clusters-app/all-clusters-common/all-clusters-app.zap b/examples/all-clusters-app/all-clusters-common/all-clusters-app.zap
index 9e0452b0c423fc..28d3d174be2b0d 100644
--- a/examples/all-clusters-app/all-clusters-common/all-clusters-app.zap
+++ b/examples/all-clusters-app/all-clusters-common/all-clusters-app.zap
@@ -2124,6 +2124,7 @@
"define": "GENERAL_COMMISSIONING_CLUSTER",
"side": "server",
"enabled": 1,
+ "apiMaturity": "provisional",
"commands": [
{
"name": "ArmFailSafe",
@@ -2172,6 +2173,22 @@
"source": "server",
"isIncoming": 0,
"isEnabled": 1
+ },
+ {
+ "name": "SetTCAcknowledgements",
+ "code": 6,
+ "mfgCode": null,
+ "source": "client",
+ "isIncoming": 1,
+ "isEnabled": 1
+ },
+ {
+ "name": "SetTCAcknowledgementsResponse",
+ "code": 7,
+ "mfgCode": null,
+ "source": "server",
+ "isIncoming": 0,
+ "isEnabled": 1
}
],
"attributes": [
@@ -2255,6 +2272,70 @@
"maxInterval": 65534,
"reportableChange": 0
},
+ {
+ "name": "TCAcceptedVersion",
+ "code": 5,
+ "mfgCode": null,
+ "side": "server",
+ "type": "int16u",
+ "included": 1,
+ "storageOption": "RAM",
+ "singleton": 0,
+ "bounded": 0,
+ "defaultValue": "",
+ "reportable": 1,
+ "minInterval": 1,
+ "maxInterval": 65534,
+ "reportableChange": 0
+ },
+ {
+ "name": "TCMinRequiredVersion",
+ "code": 6,
+ "mfgCode": null,
+ "side": "server",
+ "type": "int16u",
+ "included": 1,
+ "storageOption": "RAM",
+ "singleton": 0,
+ "bounded": 0,
+ "defaultValue": "1",
+ "reportable": 1,
+ "minInterval": 1,
+ "maxInterval": 65534,
+ "reportableChange": 0
+ },
+ {
+ "name": "TCAcknowledgements",
+ "code": 7,
+ "mfgCode": null,
+ "side": "server",
+ "type": "bitmap16",
+ "included": 1,
+ "storageOption": "RAM",
+ "singleton": 0,
+ "bounded": 0,
+ "defaultValue": "0x0000",
+ "reportable": 1,
+ "minInterval": 1,
+ "maxInterval": 65534,
+ "reportableChange": 0
+ },
+ {
+ "name": "TCAcknowledgementsRequired",
+ "code": 8,
+ "mfgCode": null,
+ "side": "server",
+ "type": "boolean",
+ "included": 1,
+ "storageOption": "RAM",
+ "singleton": 0,
+ "bounded": 0,
+ "defaultValue": "true",
+ "reportable": 1,
+ "minInterval": 1,
+ "maxInterval": 65534,
+ "reportableChange": 0
+ },
{
"name": "GeneratedCommandList",
"code": 65528,
@@ -2329,7 +2410,7 @@
"storageOption": "RAM",
"singleton": 0,
"bounded": 0,
- "defaultValue": "0",
+ "defaultValue": "1",
"reportable": 1,
"minInterval": 1,
"maxInterval": 65534,
diff --git a/examples/all-clusters-app/linux/include/CHIPProjectAppConfig.h b/examples/all-clusters-app/linux/include/CHIPProjectAppConfig.h
index 0285563216e706..24658d46ca1c8c 100644
--- a/examples/all-clusters-app/linux/include/CHIPProjectAppConfig.h
+++ b/examples/all-clusters-app/linux/include/CHIPProjectAppConfig.h
@@ -1,6 +1,6 @@
/*
*
- * Copyright (c) 2022 Project CHIP Authors
+ * Copyright (c) 2022-2024 Project CHIP Authors
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -51,3 +51,24 @@
// Claim a device type while advertising that matches the device type on our
// endpoint 1. 0x0101 is the "Dimmable Light" device type.
#define CHIP_DEVICE_CONFIG_DEVICE_TYPE 0x0101
+
+/**
+ * @brief Configures the required terms and conditions acknowledgements.
+ *
+ * This macro defines the required terms and conditions acknowledgements bitmask. The bit-field is 16 bits long, so the possible
+ * value range is [0, 65535). This setting can be used to require that terms and conditions are presented to the user during
+ * commissioning.
+ */
+#define CHIP_CONFIG_TC_REQUIRED_ACKNOWLEDGEMENTS 1 // Require that terms and conditions ordinal 1 must be accepted.
+
+/**
+ * @brief Configures the latest known version of the terms and conditions.
+ *
+ * This macro defines the version number of the latest terms and conditions. It allows the application to iterate on revisions of
+ * the terms and conditions. A value of 0 indicates that no specific version is required. This setting can be used to enforce
+ * version-specific terms and conditions acknowledgements in the application. When the set of terms and conditions needs to be
+ * changes, the version number should be monotomically increased. If the lateast terms and conditions version is updated (most
+ * likely during an OTA) then this may signal to the Administrator that updated terms and conditions should be presented to the
+ * user.
+ */
+#define CHIP_CONFIG_TC_REQUIRED_ACKNOWLEDGEMENTS_VERSION 1 // The current terms and conditions revision is 1.
diff --git a/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/CHIPToolActivity.kt b/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/CHIPToolActivity.kt
index 2b2078dde5e688..75353ffa5ea355 100644
--- a/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/CHIPToolActivity.kt
+++ b/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/CHIPToolActivity.kt
@@ -122,6 +122,11 @@ class CHIPToolActivity :
startActivity(redirectIntent)
}
+ override fun handleEnhancedSetupFlowClicked() {
+ Toast.makeText(this, "Enhanced Setup Flow", Toast.LENGTH_SHORT).show()
+ showFragment(DeviceProvisioningFragment.newInstance(deviceInfo!!, null))
+ }
+
override fun setNetworkType(type: ProvisionNetworkType?) {
networkType = type
}
diff --git a/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/GenericChipDeviceListener.kt b/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/GenericChipDeviceListener.kt
index 2eb2a1c77fa042..bc333f3153ee0b 100644
--- a/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/GenericChipDeviceListener.kt
+++ b/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/GenericChipDeviceListener.kt
@@ -60,4 +60,12 @@ open class GenericChipDeviceListener : ChipDeviceController.CompletionListener {
override fun onICDRegistrationComplete(errorCode: Long, icdDeviceInfo: ICDDeviceInfo) {
// No op
}
+
+ override fun onTermsAndConditionsRequired() {
+ // No op
+ }
+
+ override fun onTermsAndConditionsRequiredComplete(termsAndConditionsAcknowledgements: Int, termsAndConditionsVersion: Int) {
+ // No op
+ }
}
diff --git a/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/SelectActionFragment.kt b/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/SelectActionFragment.kt
index 69bfdc109912c9..9f23e67db4f559 100644
--- a/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/SelectActionFragment.kt
+++ b/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/SelectActionFragment.kt
@@ -69,7 +69,7 @@ class SelectActionFragment : Fragment() {
binding.basicClusterBtn.setOnClickListener { handleBasicClicked() }
binding.attestationTestBtn.setOnClickListener { handleAttestationTestClicked() }
binding.clusterInteractionBtn.setOnClickListener { handleClusterInteractionClicked() }
- binding.provisionCustomFlowBtn.setOnClickListener { handleProvisionCustomFlowClicked() }
+ binding.provisionCustomFlowReadFromLedgerBtn.setOnClickListener { handleProvisionCustomFlowClicked() }
binding.wildcardBtn.setOnClickListener { handleWildcardClicked() }
binding.unpairDeviceBtn.setOnClickListener { handleUnpairDeviceClicked() }
binding.groupSettingBtn.setOnClickListener { handleGroupSettingClicked() }
diff --git a/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/provisioning/DeviceProvisioningFragment.kt b/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/provisioning/DeviceProvisioningFragment.kt
index 97b2576827079a..3466fe4e746c13 100644
--- a/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/provisioning/DeviceProvisioningFragment.kt
+++ b/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/provisioning/DeviceProvisioningFragment.kt
@@ -314,6 +314,14 @@ class DeviceProvisioningFragment : Fragment() {
.show()
}
}
+
+ override fun onTermsAndConditionsRequired() {
+ }
+
+ override fun onTermsAndConditionsRequiredComplete(termsAndConditionsAcknowledgements: Int, termsAndConditionsVersion: Int) {
+ Log.d(TAG, "onTermsAndConditionsRequiredComplete: $termsAndConditionsAcknowledgements, $termsAndConditionsVersion")
+ deviceController.updateTermsAndConditionsAcknowledgements(termsAndConditionsAcknowledgements, termsAndConditionsVersion)
+ }
}
private fun ByteArray.toHex(): String =
diff --git a/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/setuppayloadscanner/CHIPDeviceDetailsFragment.kt b/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/setuppayloadscanner/CHIPDeviceDetailsFragment.kt
index 411f51eae3de73..d8200b22c7ef2a 100644
--- a/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/setuppayloadscanner/CHIPDeviceDetailsFragment.kt
+++ b/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/setuppayloadscanner/CHIPDeviceDetailsFragment.kt
@@ -80,8 +80,8 @@ class CHIPDeviceDetailsFragment : Fragment() {
// commissioningFlow = 2 (Custom), read device info from Ledger
if (deviceInfo.commissioningFlow == 2) {
- binding.customFlowBtn.visibility = View.VISIBLE
- binding.customFlowBtn.setOnClickListener {
+ binding.customFlowReadFromLedgerBtn.visibility = View.VISIBLE
+ binding.customFlowReadFromLedgerBtn.setOnClickListener {
FragmentUtil.getHost(this@CHIPDeviceDetailsFragment, Callback::class.java)
?.handleReadFromLedgerClicked(deviceInfo)
}
diff --git a/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/setuppayloadscanner/CHIPLedgerDetailsFragment.kt b/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/setuppayloadscanner/CHIPLedgerDetailsFragment.kt
index 92edce9da1331b..0f6fce6e95d85f 100644
--- a/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/setuppayloadscanner/CHIPLedgerDetailsFragment.kt
+++ b/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/setuppayloadscanner/CHIPLedgerDetailsFragment.kt
@@ -25,14 +25,19 @@ import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
+import android.widget.Toast
import androidx.fragment.app.Fragment
import com.android.volley.Request
+import com.android.volley.Response.Listener
import com.android.volley.toolbox.JsonObjectRequest
import com.android.volley.toolbox.Volley
import com.google.chip.chiptool.R
import com.google.chip.chiptool.databinding.ChipLedgerInfoFragmentBinding
import com.google.chip.chiptool.util.FragmentUtil
import com.google.gson.Gson
+import java.io.BufferedReader
+import java.io.InputStreamReader
+import org.json.JSONObject
/** Show the [CHIPDeviceInfo] from Ledger */
class CHIPLedgerDetailsFragment : Fragment() {
@@ -55,7 +60,7 @@ class CHIPLedgerDetailsFragment : Fragment() {
// Ledger api url
val url =
- Uri.parse(context!!.getString(R.string.dcl_api_root_url))
+ Uri.parse(DCL_API_ROOT_URL)
.buildUpon()
.appendPath("${deviceInfo.vendorId}")
.appendPath("${deviceInfo.productId}")
@@ -63,53 +68,42 @@ class CHIPLedgerDetailsFragment : Fragment() {
.toString()
Log.d(TAG, "Dcl request Url: $url")
- // Ledger API call
- val jsonObjectRequest =
- JsonObjectRequest(
- Request.Method.GET,
- url,
- null,
- { response ->
- Log.d(TAG, "Response from dcl $response")
-
- // parse redirect Url
- val responseJson = response.getJSONObject(context!!.getString(R.string.dcl_response_key))
- val redirectUrl =
- responseJson.getString(context!!.getString(R.string.dcl_custom_flow_url_key))
- Log.d(TAG, "Redirect Url from Ledger: $redirectUrl")
- binding.commissioningFlowUrlTv.text = redirectUrl
-
- // generate redirect payload
- val gson = Gson()
- val payloadJson = gson.toJson(deviceInfo)
- val payloadBase64 = Base64.encodeToString(payloadJson.toByteArray(), Base64.DEFAULT)
- val redirectUrlWithPayload =
- Uri.parse(redirectUrl)
- .buildUpon()
- .appendQueryParameter("payload", payloadBase64)
- .appendQueryParameter(
- "returnUrl",
- context!!.getString(R.string.custom_flow_return_url)
- )
- .build()
- .toString()
-
- Log.d(TAG, "Redirect Url with Payload: $redirectUrlWithPayload")
- binding.redirectBtn.setOnClickListener {
- FragmentUtil.getHost(this@CHIPLedgerDetailsFragment, Callback::class.java)
- ?.handleCustomFlowRedirectClicked(redirectUrlWithPayload)
- }
+ val context = getContext()!!
+ val mockDclRequestsResponsesRaw = readRawResourceFile(R.raw.mock_dcl_responses_json)
+ val mockDclRequestsResponses: org.json.JSONArray = org.json.JSONArray(mockDclRequestsResponsesRaw)
+
+ val mockDclRequestsResponseMap = HashMap()
+ for (i in 0 until mockDclRequestsResponses.length()) {
+ val mockDclRequestsResponse = mockDclRequestsResponses.getJSONObject(i)
+
+ val mockDclRequest: org.json.JSONObject = mockDclRequestsResponse.getJSONObject("request")
+ val mockDclResponse: org.json.JSONObject = mockDclRequestsResponse.getJSONObject("response")
- // enable redirect button
- binding.redirectBtn.visibility = View.VISIBLE
- },
- { error ->
- Log.e(TAG, "Dcl request failed: $error")
- binding.commissioningFlowUrlTv.text =
- context!!.getString(R.string.chip_ledger_info_commissioning_flow_url_not_available)
- }
- )
- queue.add(jsonObjectRequest)
+ val mockDclRequestURL = mockDclRequest.getString("url")
+ val mockDclResponseBody = mockDclResponse.getJSONObject("body")
+
+ mockDclRequestsResponseMap.put(mockDclRequestURL, mockDclResponseBody)
+ Log.d(TAG, "mockDclRequestURL= $mockDclRequestURL")
+ Log.d(TAG, "mockDclResponseBody= $mockDclResponseBody")
+ }
+
+ Log.d(TAG, "Request url= $url")
+ val response: org.json.JSONObject = mockDclRequestsResponseMap.get(url.toString())!!
+ Log.d(TAG, "Response from dcl $response")
+ Toast.makeText(context, "Enhanced Setup Flow: $response", Toast.LENGTH_LONG).show()
+
+ val enhancedSetupFlowOptions = response.optInt("enhancedSetupFlowOptions", 0)
+
+ if (0 != (enhancedSetupFlowOptions and 0b00000001)) {
+ Toast.makeText(context, "Enhanced Setup Flow supported!", Toast.LENGTH_SHORT).show()
+
+ binding.commissionBtn.setOnClickListener {
+ FragmentUtil.getHost(this@CHIPLedgerDetailsFragment, Callback::class.java)
+ ?.handleEnhancedSetupFlowClicked()
+ }
+
+ binding.commissionBtn.visibility = View.VISIBLE
+ }
return binding.root
}
@@ -119,15 +113,40 @@ class CHIPLedgerDetailsFragment : Fragment() {
_binding = null
}
+ private fun readRawResourceFile(resourceId: Int): String? {
+ return try {
+ val inputStream = resources.openRawResource(resourceId)
+ val bufferedReader = BufferedReader(InputStreamReader(inputStream))
+ val stringBuilder = StringBuilder()
+ var line: String? = bufferedReader.readLine()
+ while (line != null) {
+ stringBuilder.append(line)
+ line = bufferedReader.readLine()
+ }
+ bufferedReader.close()
+ inputStream.close()
+ stringBuilder.toString()
+ } catch (e: Exception) {
+ Log.e("MainActivity", "Error reading raw resource file", e)
+ null
+ }
+ }
+
/** Interface for notifying the host. */
interface Callback {
/** Notifies listener of Custom flow redirect button click. */
fun handleCustomFlowRedirectClicked(redirectUrl: String)
+
+ /** Notifies listener of Enhanced Setup flow button click. */
+ fun handleEnhancedSetupFlowClicked()
}
companion object {
private const val TAG = "CUSTOM_FLOW"
private const val ARG_DEVICE_INFO = "device_info"
+ private const val DCL_CUSTOM_FLOW_URL_KEY = "commissioningCustomFlowUrl";
+ private const val DCL_API_ROOT_URL = "https://on.dcl.csa-iot.org/dcl/model/models";
+ private const val CUSTOM_FLOW_RETURN_URL = "mt://modelinfo";
@JvmStatic
fun newInstance(deviceInfo: CHIPDeviceInfo): CHIPLedgerDetailsFragment {
diff --git a/examples/android/CHIPTool/app/src/main/res/layout/chip_device_info_fragment.xml b/examples/android/CHIPTool/app/src/main/res/layout/chip_device_info_fragment.xml
index a1deab648adc9f..04df24030f35cd 100644
--- a/examples/android/CHIPTool/app/src/main/res/layout/chip_device_info_fragment.xml
+++ b/examples/android/CHIPTool/app/src/main/res/layout/chip_device_info_fragment.xml
@@ -220,7 +220,7 @@
tools:ignore="LabelFor" />
+
diff --git a/examples/android/CHIPTool/app/src/main/res/layout/select_action_fragment.xml b/examples/android/CHIPTool/app/src/main/res/layout/select_action_fragment.xml
index 5824e8061a4e03..45af60768eb0d0 100644
--- a/examples/android/CHIPTool/app/src/main/res/layout/select_action_fragment.xml
+++ b/examples/android/CHIPTool/app/src/main/res/layout/select_action_fragment.xml
@@ -32,7 +32,7 @@
android:text="@string/provision_thread_credentials_btn_text" />
Loading...
Redirect
+ Commission
Not available
Commissioning flow Completed.
- https://dcl.dev.dsr-corporation.com/api/modelinfo/models
- result
- custom
- mt://modelinfo
Retrieve Endpoint List
Invoke
Select a command
diff --git a/examples/chip-tool/commands/pairing/PairingCommand.cpp b/examples/chip-tool/commands/pairing/PairingCommand.cpp
index 35ce2ba1cc7aaa..aba44341ae3da7 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");
@@ -124,6 +124,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 0cf4e1de2de713..ff58eee2a0e561 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");
@@ -192,6 +192,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);
@@ -249,6 +257,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..305f12dfae9801 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
@@ -34,6 +35,7 @@
#include
#include
#include
+#include
#include
using namespace chip;
@@ -57,6 +59,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 +107,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 +124,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 +135,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 +258,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 +286,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 +405,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..750e21fafc31c2
--- /dev/null
+++ b/src/app/server/DefaultEnhancedSetupFlowProvider.cpp
@@ -0,0 +1,151 @@
+/*
+ *
+ * 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 "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;
+}
diff --git a/src/app/server/DefaultEnhancedSetupFlowProvider.h b/src/app/server/DefaultEnhancedSetupFlowProvider.h
new file mode 100644
index 00000000000000..eb9d145d6221d4
--- /dev/null
+++ b/src/app/server/DefaultEnhancedSetupFlowProvider.h
@@ -0,0 +1,87 @@
+/*
+ *
+ * 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 "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
diff --git a/src/app/server/DefaultTermsAndConditionsProvider.cpp b/src/app/server/DefaultTermsAndConditionsProvider.cpp
new file mode 100644
index 00000000000000..564c80b16e783d
--- /dev/null
+++ b/src/app/server/DefaultTermsAndConditionsProvider.cpp
@@ -0,0 +1,129 @@
+/*
+ *
+ * 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 "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;
+}
diff --git a/src/app/server/DefaultTermsAndConditionsProvider.h b/src/app/server/DefaultTermsAndConditionsProvider.h
new file mode 100644
index 00000000000000..a6a47f22f4a5dd
--- /dev/null
+++ b/src/app/server/DefaultTermsAndConditionsProvider.h
@@ -0,0 +1,71 @@
+/*
+ *
+ * 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 "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
diff --git a/src/app/server/EnhancedSetupFlowProvider.h b/src/app/server/EnhancedSetupFlowProvider.h
new file mode 100644
index 00000000000000..6db950b87e7fa5
--- /dev/null
+++ b/src/app/server/EnhancedSetupFlowProvider.h
@@ -0,0 +1,108 @@
+/*
+ *
+ * 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 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
diff --git a/src/app/server/Server.cpp b/src/app/server/Server.cpp
index 33f657f7ec1030..97ddc183446814 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,11 @@
#include
#include
+#include
+#if defined (CHIP_CONFIG_TC_REQUIRED_ACKNOWLEDGEMENTS) && defined (CHIP_CONFIG_TC_REQUIRED_ACKNOWLEDGEMENTS_VERSION)
+#include
+#include
+#endif
#include
#include
#include
@@ -101,6 +106,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...");
@@ -125,6 +234,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();
@@ -181,6 +294,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 9e0216877fea61..23231278133377 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
@@ -67,6 +69,7 @@
#endif
#include
#include
+#include
#include
#include
@@ -172,6 +175,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
};
/**
@@ -218,83 +227,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;
@@ -315,6 +248,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
};
/**
@@ -395,6 +332,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; }
@@ -668,6 +609,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 59d8f2c325fd8c..94f5e9f82dc1c0 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.
@@ -183,7 +183,9 @@ chip_test_suite("tests") {
"TestCommandPathParams.cpp",
"TestConcreteAttributePath.cpp",
"TestDataModelSerialization.cpp",
+ "TestDefaultEnhancedSetupFlowProvider.cpp",
"TestDefaultOTARequestorStorage.cpp",
+ "TestDefaultTermsAndConditionsProvider.cpp",
"TestDefaultThreadNetworkDirectoryStorage.cpp",
"TestEventLoggingNoUTCTime.cpp",
"TestEventOverflow.cpp",
@@ -221,6 +223,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 8232292479ff3f..fb8f148a5e9306 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 5212350c913696..330a6d913835a9 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.
*
@@ -2620,6 +2620,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)
{
@@ -2695,6 +2711,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)
{
@@ -3092,6 +3118,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 1c4b490faa891a..ecba10d2d33710 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.
@@ -942,6 +944,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/controller/java/CHIPDeviceController-JNI.cpp b/src/controller/java/CHIPDeviceController-JNI.cpp
index 93ab5ccd0a1012..bd0a44a2463f09 100644
--- a/src/controller/java/CHIPDeviceController-JNI.cpp
+++ b/src/controller/java/CHIPDeviceController-JNI.cpp
@@ -733,6 +733,9 @@ JNI_METHOD(void, pairDeviceWithAddress)
{
commissioningParams.SetDeviceAttestationDelegate(wrapper->GetDeviceAttestationDelegateBridge());
}
+
+ commissioningParams.SetTermsAndConditionsAcknowledgement((const TermsAndConditionsAcknowledgement){ 1, 1 });
+
err = wrapper->Controller()->PairDevice(static_cast(deviceId), rendezvousParams, commissioningParams);
if (err != CHIP_NO_ERROR)
@@ -933,6 +936,39 @@ JNI_METHOD(void, updateCommissioningNetworkCredentials)
}
}
+JNI_METHOD(void, updateTermsAndConditionsAcknowledgements)
+(JNIEnv * env, jobject self, jlong handle, jint acceptedTermsAndConditions, jint acceptedTermsAndConditionsVersion)
+{
+ ChipLogProgress(Controller, "updateTermsAndConditionsAcknowledgements() called");
+
+ // Check if the input values are within the range of uint16_t
+ if (acceptedTermsAndConditions < 0 || acceptedTermsAndConditions > 65535 || acceptedTermsAndConditionsVersion < 0 ||
+ acceptedTermsAndConditionsVersion > 65535)
+ {
+ jclass illegalArgumentExceptionClass = env->FindClass("java/lang/IllegalArgumentException");
+ if (illegalArgumentExceptionClass != nullptr)
+ {
+ env->ThrowNew(illegalArgumentExceptionClass, "Input values must be in the range 0 to 65535.");
+ }
+ return;
+ }
+
+ AndroidDeviceControllerWrapper * wrapper = AndroidDeviceControllerWrapper::FromJNIHandle(handle);
+
+ // Retrieve the commissioning parameters
+ CommissioningParameters commissioningParams = wrapper->GetAutoCommissioner()->GetCommissioningParameters();
+
+ TermsAndConditionsAcknowledgement termsAndConditionsAcknowledgement;
+ termsAndConditionsAcknowledgement.acceptedTermsAndConditions = static_cast(acceptedTermsAndConditions);
+ termsAndConditionsAcknowledgement.acceptedTermsAndConditionsVersion = static_cast(acceptedTermsAndConditionsVersion);
+
+ // Update the commissioning parameters with the new terms and conditions
+ commissioningParams.SetTermsAndConditionsAcknowledgement(termsAndConditionsAcknowledgement);
+
+ // Set the updated commissioning parameters back to the wrapper
+ wrapper->GetAutoCommissioner()->SetCommissioningParameters(commissioningParams);
+}
+
JNI_METHOD(void, updateCommissioningICDRegistrationInfo)
(JNIEnv * env, jobject self, jlong handle, jobject icdRegistrationInfo)
{
diff --git a/src/controller/java/src/chip/devicecontroller/ChipDeviceController.java b/src/controller/java/src/chip/devicecontroller/ChipDeviceController.java
index 37e9e7093a1afc..034679eabe2032 100644
--- a/src/controller/java/src/chip/devicecontroller/ChipDeviceController.java
+++ b/src/controller/java/src/chip/devicecontroller/ChipDeviceController.java
@@ -580,6 +580,10 @@ public void updateCommissioningICDRegistrationInfo(ICDRegistrationInfo icdRegist
updateCommissioningICDRegistrationInfo(deviceControllerPtr, icdRegistrationInfo);
}
+ public void updateTermsAndConditionsAcknowledgements(int acceptedTermsAndConditions, int acceptedTermsAndConditionsVersion) throws java.lang.IllegalArgumentException {
+ updateTermsAndConditionsAcknowledgements(deviceControllerPtr, acceptedTermsAndConditions, acceptedTermsAndConditionsVersion);
+ }
+
public void unpairDevice(long deviceId) {
unpairDevice(deviceControllerPtr, deviceId);
}
@@ -1717,6 +1721,8 @@ private native void setUseJavaCallbackForNOCRequest(
private native void updateCommissioningNetworkCredentials(
long deviceControllerPtr, NetworkCredentials networkCredentials);
+ private native void updateTermsAndConditionsAcknowledgements(long deviceControllerPtr, int acceptedTermsAndConditions, int acceptedTermsAndConditionsVersion) throws java.lang.IllegalArgumentException;
+
private native void updateCommissioningICDRegistrationInfo(
long deviceControllerPtr, ICDRegistrationInfo icdRegistrationInfo);
@@ -1793,6 +1799,10 @@ void onScanNetworksSuccess(
Optional> threadScanResults);
}
+ public interface TermsAndConditionsListener {
+ void onTermsAndConditionsAcknowlegementRequired();
+ }
+
/** Interface to listen for callbacks from CHIPDeviceController. */
public interface CompletionListener {
@@ -1838,5 +1848,8 @@ void onReadCommissioningInfo(
/** Notifies when the registration flow for the ICD completes. */
void onICDRegistrationComplete(long errorCode, ICDDeviceInfo icdDeviceInfo);
+
+ void onTermsAndConditionsRequired();
+ void onTermsAndConditionsRequiredComplete(int termsAndConditionsAcknowledgements, int termsAndConditionsVersion);
}
}
diff --git a/src/controller/java/src/matter/controller/MatterController.kt b/src/controller/java/src/matter/controller/MatterController.kt
index 2e4ecb54da1fb9..d474b52fbdd494 100644
--- a/src/controller/java/src/matter/controller/MatterController.kt
+++ b/src/controller/java/src/matter/controller/MatterController.kt
@@ -59,6 +59,10 @@ interface MatterController : Closeable, InteractionClient {
/** Notifies the Commissioner when the OpCSR for the Comissionee is generated. */
fun onOpCSRGenerationComplete(csr: ByteArray)
+ fun onTermsAndConditionsRequired()
+
+ fun onTermsAndConditionsComplete()
+
/**
* Notifies when the ICD registration information (ICD symmetric key, check-in node ID and
* monitored subject) is required.
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