1 /*
2 * Copyright (c) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 //! This module is used to verify the validity of asset attributes.
17
18 use asset_common::{is_user_id_exist, CallingInfo, OwnerType, ROOT_USER_UPPERBOUND};
19 use asset_definition::{
20 log_throw_error, Accessibility, AssetMap, AuthType, ConflictResolution, Conversion, ErrCode, OperationType, Result,
21 ReturnType, Tag, Value,
22 };
23 use asset_sdk::WrapType;
24
25 use crate::operations::common::{CRITICAL_LABEL_ATTRS, NORMAL_LABEL_ATTRS, NORMAL_LOCAL_LABEL_ATTRS};
26
27 const MIN_NUMBER_VALUE: u32 = 0;
28 const MAX_RETURN_LIMIT: u32 = 0x10000; // 65536
29 const MAX_AUTH_VALID_PERIOD: u32 = 600; // 10min
30
31 const MIN_ARRAY_SIZE: usize = 0;
32 const MAX_SECRET_SIZE: usize = 1024;
33 const MAX_TIME_SIZE: usize = 1024;
34
35 const MAX_ALIAS_SIZE: usize = 256;
36 pub const MAX_LABEL_SIZE: usize = 2048;
37
38 const MAX_GROUP_ID_LEN: usize = 127;
39 const MIN_GROUP_ID_LEN: usize = 7;
40
41 const MAX_AUTH_TOKEN_SIZE: usize = 1024;
42 const CHALLENGE_SIZE: usize = 32;
43 const SYNC_TYPE_MIN_BITS: u32 = 0;
44 const SYNC_TYPE_MAX_BITS: u32 = 3;
45
check_data_type(tag: &Tag, value: &Value) -> Result<()>46 fn check_data_type(tag: &Tag, value: &Value) -> Result<()> {
47 if tag.data_type() != value.data_type() {
48 return log_throw_error!(
49 ErrCode::InvalidArgument,
50 "[FATAL]The data type[{}] of the tag[{}] does not match that of the value.",
51 value.data_type(),
52 tag
53 );
54 }
55 Ok(())
56 }
57
check_array_size(tag: &Tag, value: &Value, min: usize, max: usize) -> Result<()>58 fn check_array_size(tag: &Tag, value: &Value, min: usize, max: usize) -> Result<()> {
59 let Value::Bytes(v) = value else {
60 return log_throw_error!(ErrCode::InvalidArgument, "[FATAL][{}] is not a bytes.", tag);
61 };
62 if v.len() > max || v.len() <= min {
63 return log_throw_error!(
64 ErrCode::InvalidArgument,
65 "[FATAL]The array length[{}] of Tag[{}], exceeds the valid range.",
66 v.len(),
67 tag
68 );
69 }
70 Ok(())
71 }
72
check_enum_variant<T: TryFrom<u32>>(tag: &Tag, value: &Value) -> Result<()>73 fn check_enum_variant<T: TryFrom<u32>>(tag: &Tag, value: &Value) -> Result<()> {
74 let Value::Number(n) = value else {
75 return log_throw_error!(ErrCode::InvalidArgument, "[FATAL][{}] is not a number.", tag);
76 };
77 if T::try_from(*n).is_err() {
78 return log_throw_error!(
79 ErrCode::InvalidArgument,
80 "[FATAL]The value[{}] of Tag[{}] is not a legal enumeration variant",
81 *n,
82 tag
83 );
84 }
85 Ok(())
86 }
87
check_valid_bits(tag: &Tag, value: &Value, min_bits: u32, max_bits: u32) -> Result<()>88 fn check_valid_bits(tag: &Tag, value: &Value, min_bits: u32, max_bits: u32) -> Result<()> {
89 let Value::Number(n) = value else {
90 return log_throw_error!(ErrCode::InvalidArgument, "[FATAL][{}] is not a number.", tag);
91 };
92 if *n >= 2_u32.pow(max_bits) || *n < (2_u32.pow(min_bits) - 1) {
93 // 2: binary system
94 return log_throw_error!(
95 ErrCode::InvalidArgument,
96 "[FATAL]The value[{}] of Tag[{}] is not in the valid bit number.",
97 *n,
98 tag
99 );
100 }
101 Ok(())
102 }
103
check_number_range(tag: &Tag, value: &Value, min: u32, max: u32) -> Result<()>104 fn check_number_range(tag: &Tag, value: &Value, min: u32, max: u32) -> Result<()> {
105 let Value::Number(n) = value else {
106 return log_throw_error!(ErrCode::InvalidArgument, "[FATAL][{}] is not a number.", tag);
107 };
108 if *n <= min || *n > max {
109 return log_throw_error!(
110 ErrCode::InvalidArgument,
111 "[FATAL]The value[{}] of Tag[{}] is not in the valid number range.",
112 *n,
113 tag
114 );
115 }
116 Ok(())
117 }
118
check_tag_range(tag: &Tag, value: &Value, tags: &[Tag]) -> Result<()>119 fn check_tag_range(tag: &Tag, value: &Value, tags: &[Tag]) -> Result<()> {
120 let Value::Number(n) = value else {
121 return log_throw_error!(ErrCode::InvalidArgument, "[FATAL][{}] is not a number.", tag);
122 };
123 match Tag::try_from(*n) {
124 Ok(value) if tags.contains(&value) => Ok(()),
125 _ => {
126 log_throw_error!(
127 ErrCode::InvalidArgument,
128 "[FATAL]The value[{}] of Tag[{}] is not in the valid tag range.",
129 *n,
130 tag
131 )
132 },
133 }
134 }
135
check_user_id(tag: &Tag, value: &Value) -> Result<()>136 fn check_user_id(tag: &Tag, value: &Value) -> Result<()> {
137 check_number_range(tag, value, ROOT_USER_UPPERBOUND, i32::MAX as u32)?;
138 let Value::Number(n) = value else {
139 return log_throw_error!(ErrCode::InvalidArgument, "[FATAL][{}] is not a number.", tag);
140 };
141 match is_user_id_exist(*n as i32) {
142 Ok(res) if res => Ok(()),
143 Ok(_) => log_throw_error!(ErrCode::InvalidArgument, "[FATAL]The user id [{}] is not exist.", *n),
144 Err(e) => Err(e),
145 }
146 }
147
check_data_value(tag: &Tag, value: &Value) -> Result<()>148 fn check_data_value(tag: &Tag, value: &Value) -> Result<()> {
149 match tag {
150 Tag::Secret => check_array_size(tag, value, MIN_ARRAY_SIZE, MAX_SECRET_SIZE),
151 Tag::Alias => check_array_size(tag, value, MIN_ARRAY_SIZE, MAX_ALIAS_SIZE),
152 Tag::Accessibility => check_enum_variant::<Accessibility>(tag, value),
153 Tag::RequirePasswordSet | Tag::IsPersistent | Tag::RequireAttrEncrypted => Ok(()),
154 Tag::AuthType => check_enum_variant::<AuthType>(tag, value),
155 Tag::AuthValidityPeriod => check_number_range(tag, value, MIN_NUMBER_VALUE, MAX_AUTH_VALID_PERIOD),
156 Tag::AuthChallenge => check_array_size(tag, value, CHALLENGE_SIZE - 1, CHALLENGE_SIZE),
157 Tag::AuthToken => check_array_size(tag, value, MIN_ARRAY_SIZE, MAX_AUTH_TOKEN_SIZE),
158 Tag::SyncType => check_valid_bits(tag, value, SYNC_TYPE_MIN_BITS, SYNC_TYPE_MAX_BITS),
159 Tag::ConflictResolution => check_enum_variant::<ConflictResolution>(tag, value),
160 Tag::DataLabelCritical1 | Tag::DataLabelCritical2 | Tag::DataLabelCritical3 | Tag::DataLabelCritical4 => {
161 check_array_size(tag, value, MIN_ARRAY_SIZE, MAX_LABEL_SIZE)
162 },
163 Tag::DataLabelNormal1 | Tag::DataLabelNormal2 | Tag::DataLabelNormal3 | Tag::DataLabelNormal4 => {
164 check_array_size(tag, value, MIN_ARRAY_SIZE, MAX_LABEL_SIZE)
165 },
166 Tag::DataLabelNormalLocal1
167 | Tag::DataLabelNormalLocal2
168 | Tag::DataLabelNormalLocal3
169 | Tag::DataLabelNormalLocal4 => check_array_size(tag, value, MIN_ARRAY_SIZE, MAX_LABEL_SIZE),
170 Tag::ReturnType => check_enum_variant::<ReturnType>(tag, value),
171 Tag::ReturnLimit => check_number_range(tag, value, MIN_NUMBER_VALUE, MAX_RETURN_LIMIT),
172 Tag::ReturnOffset => Ok(()),
173 Tag::ReturnOrderedBy => {
174 check_tag_range(tag, value, &[CRITICAL_LABEL_ATTRS, NORMAL_LABEL_ATTRS, NORMAL_LOCAL_LABEL_ATTRS].concat())
175 },
176 Tag::UserId => check_user_id(tag, value),
177 Tag::UpdateTime => check_array_size(tag, value, MIN_ARRAY_SIZE, MAX_TIME_SIZE),
178 Tag::OperationType => check_enum_variant::<OperationType>(tag, value),
179 Tag::GroupId => check_array_size(tag, value, MIN_GROUP_ID_LEN, MAX_GROUP_ID_LEN),
180 Tag::WrapType => check_enum_variant::<WrapType>(tag, value),
181 }
182 }
183
check_value_validity(attrs: &AssetMap) -> Result<()>184 pub(crate) fn check_value_validity(attrs: &AssetMap) -> Result<()> {
185 for (tag, value) in attrs {
186 check_data_type(tag, value)?;
187 check_data_value(tag, value)?;
188 }
189 Ok(())
190 }
191
check_required_tags(attrs: &AssetMap, required_tags: &[Tag]) -> Result<()>192 pub(crate) fn check_required_tags(attrs: &AssetMap, required_tags: &[Tag]) -> Result<()> {
193 for tag in required_tags {
194 if !attrs.contains_key(tag) {
195 return log_throw_error!(ErrCode::InvalidArgument, "[FATAL]The required tag [{}] is missing.", tag);
196 }
197 }
198 Ok(())
199 }
200
check_tag_validity(attrs: &AssetMap, valid_tags: &[Tag]) -> Result<()>201 pub(crate) fn check_tag_validity(attrs: &AssetMap, valid_tags: &[Tag]) -> Result<()> {
202 for tag in attrs.keys() {
203 if !valid_tags.contains(tag) {
204 return log_throw_error!(ErrCode::InvalidArgument, "[FATAL]The tag [{}] is illegal.", tag);
205 }
206 }
207 Ok(())
208 }
209
check_group_validity(attrs: &AssetMap, calling_info: &CallingInfo) -> Result<()>210 pub(crate) fn check_group_validity(attrs: &AssetMap, calling_info: &CallingInfo) -> Result<()> {
211 if attrs.get(&Tag::GroupId).is_some() {
212 if let Some(Value::Bool(true)) = attrs.get(&Tag::IsPersistent) {
213 return log_throw_error!(
214 ErrCode::InvalidArgument,
215 "[FATAL]The value of the tag [{}] cannot be set to true when the tag [{}] is specified.",
216 &Tag::IsPersistent,
217 &Tag::GroupId
218 );
219 }
220 if calling_info.owner_type_enum() == OwnerType::Native {
221 return log_throw_error!(
222 ErrCode::Unsupported,
223 "[FATAL]The tag [{}] is not yet supported for [{}] owner.",
224 &Tag::GroupId,
225 OwnerType::Native
226 );
227 }
228 if calling_info.app_index() > 0 {
229 return log_throw_error!(
230 ErrCode::Unsupported,
231 "[FATAL]The tag [{}] is not yet supported for clone or sandbox app.",
232 &Tag::GroupId
233 );
234 }
235 }
236 Ok(())
237 }
238