Line data Source code
1 : /*
2 : * Copyright (c) 2024 Project CHIP Authors
3 : * All rights reserved.
4 : *
5 : * Licensed under the Apache License, Version 2.0 (the "License");
6 : * you may not use this file except in compliance with the License.
7 : * You may obtain a copy of the License at
8 : *
9 : * http://www.apache.org/licenses/LICENSE-2.0
10 : *
11 : * Unless required by applicable law or agreed to in writing, software
12 : * distributed under the License is distributed on an "AS IS" BASIS,
13 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 : * See the License for the specific language governing permissions and
15 : * limitations under the License.
16 : */
17 :
18 : #include "DefaultTermsAndConditionsProvider.h"
19 : #include "TermsAndConditionsProvider.h"
20 :
21 : #include <lib/core/CHIPError.h>
22 : #include <lib/core/TLV.h>
23 : #include <lib/core/TLVTypes.h>
24 : #include <lib/support/CodeUtils.h>
25 : #include <lib/support/DefaultStorageKeyAllocator.h>
26 : #include <lib/support/SafeInt.h>
27 : #include <protocols/Protocols.h>
28 : #include <protocols/interaction_model/StatusCode.h>
29 :
30 : namespace {
31 : constexpr chip::TLV::Tag kSerializationVersionTag = chip::TLV::ContextTag(1);
32 : constexpr chip::TLV::Tag kAcceptedAcknowledgementsTag = chip::TLV::ContextTag(2);
33 : constexpr chip::TLV::Tag kAcceptedAcknowledgementsVersionTag = chip::TLV::ContextTag(3);
34 : constexpr uint8_t kSerializationSchemaMinimumVersion = 1;
35 : constexpr uint8_t kSerializationSchemaCurrentVersion = 1;
36 :
37 : constexpr size_t kEstimatedTlvBufferSize = chip::TLV::EstimateStructOverhead(sizeof(uint8_t), // SerializationVersion
38 : sizeof(uint16_t), // AcceptedAcknowledgements
39 : sizeof(uint16_t) // AcceptedAcknowledgementsVersion
40 : ) *
41 : 4; // Extra space for rollback compatibility
42 : } // namespace
43 :
44 10 : CHIP_ERROR chip::app::DefaultTermsAndConditionsStorageDelegate::Init(PersistentStorageDelegate * inPersistentStorageDelegate)
45 : {
46 10 : VerifyOrReturnValue(nullptr != inPersistentStorageDelegate, CHIP_ERROR_INVALID_ARGUMENT);
47 :
48 10 : mStorageDelegate = inPersistentStorageDelegate;
49 :
50 10 : return CHIP_NO_ERROR;
51 : }
52 :
53 0 : CHIP_ERROR chip::app::DefaultTermsAndConditionsStorageDelegate::Delete()
54 : {
55 0 : VerifyOrReturnValue(nullptr != mStorageDelegate, CHIP_ERROR_UNINITIALIZED);
56 :
57 0 : const chip::StorageKeyName kStorageKey = chip::DefaultStorageKeyAllocator::TermsAndConditionsAcceptance();
58 0 : ReturnErrorOnFailure(mStorageDelegate->SyncDeleteKeyValue(kStorageKey.KeyName()));
59 :
60 0 : return CHIP_NO_ERROR;
61 0 : }
62 :
63 9 : CHIP_ERROR chip::app::DefaultTermsAndConditionsStorageDelegate::Get(Optional<TermsAndConditions> & outTermsAndConditions)
64 : {
65 9 : VerifyOrReturnValue(nullptr != mStorageDelegate, CHIP_ERROR_UNINITIALIZED);
66 :
67 9 : uint8_t serializationVersion = 0;
68 9 : uint16_t acknowledgements = 0;
69 9 : uint16_t acknowledgementsVersion = 0;
70 :
71 9 : chip::TLV::TLVReader tlvReader;
72 : chip::TLV::TLVType tlvContainer;
73 :
74 9 : uint8_t buffer[kEstimatedTlvBufferSize] = { 0 };
75 9 : uint16_t bufferSize = sizeof(buffer);
76 :
77 9 : const chip::StorageKeyName kStorageKey = chip::DefaultStorageKeyAllocator::TermsAndConditionsAcceptance();
78 :
79 9 : CHIP_ERROR err = mStorageDelegate->SyncGetKeyValue(kStorageKey.KeyName(), &buffer, bufferSize);
80 9 : VerifyOrReturnValue(CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND == err || CHIP_NO_ERROR == err, err);
81 :
82 9 : if (CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND == err)
83 : {
84 5 : outTermsAndConditions.ClearValue();
85 5 : return CHIP_NO_ERROR;
86 : }
87 :
88 4 : tlvReader.Init(buffer, bufferSize);
89 4 : ReturnErrorOnFailure(tlvReader.Next(chip::TLV::kTLVType_Structure, chip::TLV::AnonymousTag()));
90 4 : ReturnErrorOnFailure(tlvReader.EnterContainer(tlvContainer));
91 4 : ReturnErrorOnFailure(tlvReader.Next(kSerializationVersionTag));
92 4 : ReturnErrorOnFailure(tlvReader.Get(serializationVersion));
93 :
94 4 : if (serializationVersion < kSerializationSchemaMinimumVersion)
95 : {
96 0 : ChipLogError(AppServer, "The terms and conditions datastore schema (%hhu) is newer than oldest compatible schema (%hhu)",
97 : serializationVersion, kSerializationSchemaMinimumVersion);
98 0 : return CHIP_IM_GLOBAL_STATUS(ConstraintError);
99 : }
100 :
101 4 : if (serializationVersion != kSerializationSchemaCurrentVersion)
102 : {
103 0 : ChipLogDetail(AppServer, "The terms and conditions datastore schema (%hhu) differs from current schema (%hhu)",
104 : serializationVersion, kSerializationSchemaCurrentVersion);
105 : }
106 :
107 4 : ReturnErrorOnFailure(tlvReader.Next(kAcceptedAcknowledgementsTag));
108 4 : ReturnErrorOnFailure(tlvReader.Get(acknowledgements));
109 4 : ReturnErrorOnFailure(tlvReader.Next(kAcceptedAcknowledgementsVersionTag));
110 4 : ReturnErrorOnFailure(tlvReader.Get(acknowledgementsVersion));
111 4 : ReturnErrorOnFailure(tlvReader.ExitContainer(tlvContainer));
112 :
113 4 : outTermsAndConditions = Optional<TermsAndConditions>(TermsAndConditions(acknowledgements, acknowledgementsVersion));
114 :
115 4 : return CHIP_NO_ERROR;
116 9 : }
117 :
118 2 : CHIP_ERROR chip::app::DefaultTermsAndConditionsStorageDelegate::Set(const TermsAndConditions & inTermsAndConditions)
119 : {
120 2 : uint8_t buffer[kEstimatedTlvBufferSize] = { 0 };
121 2 : chip::TLV::TLVWriter tlvWriter;
122 : chip::TLV::TLVType tlvContainer;
123 :
124 2 : VerifyOrReturnValue(nullptr != mStorageDelegate, CHIP_ERROR_UNINITIALIZED);
125 :
126 2 : tlvWriter.Init(buffer);
127 2 : ReturnErrorOnFailure(tlvWriter.StartContainer(chip::TLV::AnonymousTag(), chip::TLV::kTLVType_Structure, tlvContainer));
128 2 : ReturnErrorOnFailure(tlvWriter.Put(kSerializationVersionTag, kSerializationSchemaCurrentVersion));
129 2 : ReturnErrorOnFailure(tlvWriter.Put(kAcceptedAcknowledgementsTag, inTermsAndConditions.GetValue()));
130 2 : ReturnErrorOnFailure(tlvWriter.Put(kAcceptedAcknowledgementsVersionTag, inTermsAndConditions.GetVersion()));
131 2 : ReturnErrorOnFailure(tlvWriter.EndContainer(tlvContainer));
132 2 : ReturnErrorOnFailure(tlvWriter.Finalize());
133 :
134 2 : const chip::StorageKeyName kStorageKey = chip::DefaultStorageKeyAllocator::TermsAndConditionsAcceptance();
135 2 : ReturnErrorOnFailure(
136 : mStorageDelegate->SyncSetKeyValue(kStorageKey.KeyName(), buffer, static_cast<uint16_t>(tlvWriter.GetLengthWritten())));
137 :
138 2 : return CHIP_NO_ERROR;
139 2 : }
140 :
141 13 : CHIP_ERROR chip::app::DefaultTermsAndConditionsProvider::Init(
142 : TermsAndConditionsStorageDelegate * inStorageDelegate,
143 : const chip::Optional<chip::app::TermsAndConditions> & inRequiredTermsAndConditions)
144 : {
145 13 : VerifyOrReturnValue(nullptr != inStorageDelegate, CHIP_ERROR_INVALID_ARGUMENT);
146 :
147 13 : mTermsAndConditionsStorageDelegate = inStorageDelegate;
148 13 : mRequiredAcknowledgements = inRequiredTermsAndConditions;
149 :
150 13 : return CHIP_NO_ERROR;
151 : }
152 :
153 2 : CHIP_ERROR chip::app::DefaultTermsAndConditionsProvider::CommitAcceptance()
154 : {
155 2 : VerifyOrReturnValue(nullptr != mTermsAndConditionsStorageDelegate, CHIP_ERROR_UNINITIALIZED);
156 :
157 : // No terms and conditions to commit
158 2 : VerifyOrReturnValue(mTemporalAcceptance.HasValue(), CHIP_NO_ERROR);
159 :
160 2 : ReturnErrorOnFailure(mTermsAndConditionsStorageDelegate->Set(mTemporalAcceptance.Value()));
161 2 : ChipLogProgress(AppServer, "Terms and conditions have been committed");
162 2 : mTemporalAcceptance.ClearValue();
163 :
164 2 : return CHIP_NO_ERROR;
165 : }
166 :
167 14 : CHIP_ERROR chip::app::DefaultTermsAndConditionsProvider::GetAcceptance(Optional<TermsAndConditions> & outTermsAndConditions) const
168 : {
169 14 : VerifyOrReturnValue(nullptr != mTermsAndConditionsStorageDelegate, CHIP_ERROR_UNINITIALIZED);
170 :
171 : // Return the in-memory acceptance state
172 14 : if (mTemporalAcceptance.HasValue())
173 : {
174 3 : outTermsAndConditions = mTemporalAcceptance;
175 3 : return CHIP_NO_ERROR;
176 : }
177 :
178 : // Otherwise, try to get the persisted acceptance state
179 11 : CHIP_ERROR err = mTermsAndConditionsStorageDelegate->Get(outTermsAndConditions);
180 11 : VerifyOrReturnValue(CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND == err || CHIP_NO_ERROR == err, err);
181 :
182 11 : if (CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND == err)
183 : {
184 0 : ChipLogError(AppServer, "No terms and conditions have been accepted");
185 0 : outTermsAndConditions.ClearValue();
186 0 : return CHIP_NO_ERROR;
187 : }
188 :
189 11 : return CHIP_NO_ERROR;
190 : }
191 :
192 0 : CHIP_ERROR chip::app::DefaultTermsAndConditionsProvider::GetAcknowledgementsRequired(bool & outAcknowledgementsRequired) const
193 : {
194 0 : Optional<TermsAndConditions> requiredTermsAndConditionsMaybe;
195 0 : ReturnErrorOnFailure(GetRequirements(requiredTermsAndConditionsMaybe));
196 :
197 0 : if (!requiredTermsAndConditionsMaybe.HasValue())
198 : {
199 0 : outAcknowledgementsRequired = false;
200 0 : return CHIP_NO_ERROR;
201 : }
202 :
203 0 : Optional<TermsAndConditions> acceptedTermsAndConditionsMaybe;
204 0 : ReturnErrorOnFailure(GetAcceptance(acceptedTermsAndConditionsMaybe));
205 :
206 0 : if (!acceptedTermsAndConditionsMaybe.HasValue())
207 : {
208 0 : outAcknowledgementsRequired = true;
209 0 : return CHIP_NO_ERROR;
210 : }
211 :
212 0 : TermsAndConditions requiredTermsAndConditions = requiredTermsAndConditionsMaybe.Value();
213 0 : TermsAndConditions acceptedTermsAndConditions = acceptedTermsAndConditionsMaybe.Value();
214 :
215 0 : bool requiredTermsAndConditionsAreAccepted = requiredTermsAndConditions.Validate(acceptedTermsAndConditions);
216 0 : outAcknowledgementsRequired = !requiredTermsAndConditionsAreAccepted;
217 0 : return CHIP_NO_ERROR;
218 : }
219 :
220 4 : CHIP_ERROR chip::app::DefaultTermsAndConditionsProvider::GetRequirements(Optional<TermsAndConditions> & outTermsAndConditions) const
221 : {
222 4 : outTermsAndConditions = mRequiredAcknowledgements;
223 4 : return CHIP_NO_ERROR;
224 : }
225 :
226 : CHIP_ERROR
227 0 : chip::app::DefaultTermsAndConditionsProvider::GetUpdateAcceptanceDeadline(Optional<uint32_t> & outUpdateAcceptanceDeadline) const
228 : {
229 : // No-op stub implementation. This feature is not implemented in this default implementation.
230 0 : outUpdateAcceptanceDeadline = Optional<uint32_t>();
231 0 : return CHIP_NO_ERROR;
232 : }
233 :
234 0 : CHIP_ERROR chip::app::DefaultTermsAndConditionsProvider::ResetAcceptance()
235 : {
236 0 : VerifyOrReturnValue(nullptr != mTermsAndConditionsStorageDelegate, CHIP_ERROR_UNINITIALIZED);
237 :
238 0 : (void) mTermsAndConditionsStorageDelegate->Delete();
239 0 : ReturnErrorOnFailure(RevertAcceptance());
240 0 : return CHIP_NO_ERROR;
241 : }
242 :
243 6 : CHIP_ERROR chip::app::DefaultTermsAndConditionsProvider::RevertAcceptance()
244 : {
245 6 : mTemporalAcceptance.ClearValue();
246 6 : return CHIP_NO_ERROR;
247 : }
248 :
249 7 : CHIP_ERROR chip::app::DefaultTermsAndConditionsProvider::SetAcceptance(const Optional<TermsAndConditions> & inTermsAndConditions)
250 : {
251 7 : mTemporalAcceptance = inTermsAndConditions;
252 7 : return CHIP_NO_ERROR;
253 : }
|