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, 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 
24 use crate::operations::common::{CRITICAL_LABEL_ATTRS, NORMAL_LABEL_ATTRS, NORMAL_LOCAL_LABEL_ATTRS};
25 
26 const MIN_NUMBER_VALUE: u32 = 0;
27 const MAX_RETURN_LIMIT: u32 = 0x10000; // 65536
28 const MAX_AUTH_VALID_PERIOD: u32 = 600; // 10min
29 
30 const MIN_ARRAY_SIZE: usize = 0;
31 const MAX_SECRET_SIZE: usize = 1024;
32 const MAX_TIME_SIZE: usize = 1024;
33 
34 const MAX_ALIAS_SIZE: usize = 256;
35 pub const MAX_LABEL_SIZE: usize = 2048;
36 
37 const AUTH_TOKEN_SIZE: usize = 280;
38 const CHALLENGE_SIZE: usize = 32;
39 const SYNC_TYPE_MIN_BITS: u32 = 0;
40 const SYNC_TYPE_MAX_BITS: u32 = 3;
41 
check_data_type(tag: &Tag, value: &Value) -> Result<()>42 fn check_data_type(tag: &Tag, value: &Value) -> Result<()> {
43     if tag.data_type() != value.data_type() {
44         return log_throw_error!(
45             ErrCode::InvalidArgument,
46             "[FATAL]The data type[{}] of the tag[{}] does not match that of the value.",
47             value.data_type(),
48             tag
49         );
50     }
51     Ok(())
52 }
53 
check_array_size(tag: &Tag, value: &Value, min: usize, max: usize) -> Result<()>54 fn check_array_size(tag: &Tag, value: &Value, min: usize, max: usize) -> Result<()> {
55     let Value::Bytes(v) = value else {
56         return log_throw_error!(ErrCode::InvalidArgument, "[FATAL][{}] is not a bytes.", tag);
57     };
58     if v.len() > max || v.len() <= min {
59         return log_throw_error!(
60             ErrCode::InvalidArgument,
61             "[FATAL]The array length[{}] of Tag[{}], exceeds the valid range.",
62             v.len(),
63             tag
64         );
65     }
66     Ok(())
67 }
68 
check_enum_variant<T: TryFrom<u32>>(tag: &Tag, value: &Value) -> Result<()>69 fn check_enum_variant<T: TryFrom<u32>>(tag: &Tag, value: &Value) -> Result<()> {
70     let Value::Number(n) = value else {
71         return log_throw_error!(ErrCode::InvalidArgument, "[FATAL][{}] is not a number.", tag);
72     };
73     if T::try_from(*n).is_err() {
74         return log_throw_error!(
75             ErrCode::InvalidArgument,
76             "[FATAL]The value[{}] of Tag[{}] is not a legal enumeration variant",
77             *n,
78             tag
79         );
80     }
81     Ok(())
82 }
83 
check_valid_bits(tag: &Tag, value: &Value, min_bits: u32, max_bits: u32) -> Result<()>84 fn check_valid_bits(tag: &Tag, value: &Value, min_bits: u32, max_bits: u32) -> Result<()> {
85     let Value::Number(n) = value else {
86         return log_throw_error!(ErrCode::InvalidArgument, "[FATAL][{}] is not a number.", tag);
87     };
88     if *n >= 2_u32.pow(max_bits) || *n < (2_u32.pow(min_bits) - 1) {
89         // 2: binary system
90         return log_throw_error!(
91             ErrCode::InvalidArgument,
92             "[FATAL]The value[{}] of Tag[{}] is not in the valid bit number.",
93             *n,
94             tag
95         );
96     }
97     Ok(())
98 }
99 
check_number_range(tag: &Tag, value: &Value, min: u32, max: u32) -> Result<()>100 fn check_number_range(tag: &Tag, value: &Value, min: u32, max: u32) -> Result<()> {
101     let Value::Number(n) = value else {
102         return log_throw_error!(ErrCode::InvalidArgument, "[FATAL][{}] is not a number.", tag);
103     };
104     if *n <= min || *n > max {
105         return log_throw_error!(
106             ErrCode::InvalidArgument,
107             "[FATAL]The value[{}] of Tag[{}] is not in the valid number range.",
108             *n,
109             tag
110         );
111     }
112     Ok(())
113 }
114 
check_tag_range(tag: &Tag, value: &Value, tags: &[Tag]) -> Result<()>115 fn check_tag_range(tag: &Tag, value: &Value, tags: &[Tag]) -> Result<()> {
116     let Value::Number(n) = value else {
117         return log_throw_error!(ErrCode::InvalidArgument, "[FATAL][{}] is not a number.", tag);
118     };
119     match Tag::try_from(*n) {
120         Ok(value) if tags.contains(&value) => Ok(()),
121         _ => {
122             log_throw_error!(
123                 ErrCode::InvalidArgument,
124                 "[FATAL]The value[{}] of Tag[{}] is not in the valid tag range.",
125                 *n,
126                 tag
127             )
128         },
129     }
130 }
131 
check_user_id(tag: &Tag, value: &Value) -> Result<()>132 fn check_user_id(tag: &Tag, value: &Value) -> Result<()> {
133     check_number_range(tag, value, ROOT_USER_UPPERBOUND, i32::MAX as u32)?;
134     let Value::Number(n) = value else {
135         return log_throw_error!(ErrCode::InvalidArgument, "[FATAL][{}] is not a number.", tag);
136     };
137     match is_user_id_exist(*n as i32) {
138         Ok(res) if res => Ok(()),
139         Ok(_) => log_throw_error!(ErrCode::InvalidArgument, "[FATAL]The user id [{}] is not exist.", *n),
140         Err(e) => Err(e),
141     }
142 }
143 
check_data_value(tag: &Tag, value: &Value) -> Result<()>144 fn check_data_value(tag: &Tag, value: &Value) -> Result<()> {
145     match tag {
146         Tag::Secret => check_array_size(tag, value, MIN_ARRAY_SIZE, MAX_SECRET_SIZE),
147         Tag::Alias => check_array_size(tag, value, MIN_ARRAY_SIZE, MAX_ALIAS_SIZE),
148         Tag::Accessibility => check_enum_variant::<Accessibility>(tag, value),
149         Tag::RequirePasswordSet | Tag::IsPersistent | Tag::RequireAttrEncrypted => Ok(()),
150         Tag::AuthType => check_enum_variant::<AuthType>(tag, value),
151         Tag::AuthValidityPeriod => check_number_range(tag, value, MIN_NUMBER_VALUE, MAX_AUTH_VALID_PERIOD),
152         Tag::AuthChallenge => check_array_size(tag, value, CHALLENGE_SIZE - 1, CHALLENGE_SIZE),
153         Tag::AuthToken => check_array_size(tag, value, AUTH_TOKEN_SIZE - 1, AUTH_TOKEN_SIZE),
154         Tag::SyncType => check_valid_bits(tag, value, SYNC_TYPE_MIN_BITS, SYNC_TYPE_MAX_BITS),
155         Tag::ConflictResolution => check_enum_variant::<ConflictResolution>(tag, value),
156         Tag::DataLabelCritical1 | Tag::DataLabelCritical2 | Tag::DataLabelCritical3 | Tag::DataLabelCritical4 => {
157             check_array_size(tag, value, MIN_ARRAY_SIZE, MAX_LABEL_SIZE)
158         },
159         Tag::DataLabelNormal1 | Tag::DataLabelNormal2 | Tag::DataLabelNormal3 | Tag::DataLabelNormal4 => {
160             check_array_size(tag, value, MIN_ARRAY_SIZE, MAX_LABEL_SIZE)
161         },
162         Tag::DataLabelNormalLocal1
163         | Tag::DataLabelNormalLocal2
164         | Tag::DataLabelNormalLocal3
165         | Tag::DataLabelNormalLocal4 => check_array_size(tag, value, MIN_ARRAY_SIZE, MAX_LABEL_SIZE),
166         Tag::ReturnType => check_enum_variant::<ReturnType>(tag, value),
167         Tag::ReturnLimit => check_number_range(tag, value, MIN_NUMBER_VALUE, MAX_RETURN_LIMIT),
168         Tag::ReturnOffset => Ok(()),
169         Tag::ReturnOrderedBy => {
170             check_tag_range(tag, value, &[CRITICAL_LABEL_ATTRS, NORMAL_LABEL_ATTRS, NORMAL_LOCAL_LABEL_ATTRS].concat())
171         },
172         Tag::UserId => check_user_id(tag, value),
173         Tag::UpdateTime => check_array_size(tag, value, MIN_ARRAY_SIZE, MAX_TIME_SIZE),
174         Tag::OperationType => check_enum_variant::<OperationType>(tag, value),
175     }
176 }
177 
check_value_validity(attrs: &AssetMap) -> Result<()>178 pub(crate) fn check_value_validity(attrs: &AssetMap) -> Result<()> {
179     for (tag, value) in attrs {
180         check_data_type(tag, value)?;
181         check_data_value(tag, value)?;
182     }
183     Ok(())
184 }
185 
check_required_tags(attrs: &AssetMap, required_tags: &[Tag]) -> Result<()>186 pub(crate) fn check_required_tags(attrs: &AssetMap, required_tags: &[Tag]) -> Result<()> {
187     for tag in required_tags {
188         if !attrs.contains_key(tag) {
189             return log_throw_error!(ErrCode::InvalidArgument, "[FATAL]The required tag [{}] is missing.", tag);
190         }
191     }
192     Ok(())
193 }
194 
check_tag_validity(attrs: &AssetMap, valid_tags: &[Tag]) -> Result<()>195 pub(crate) fn check_tag_validity(attrs: &AssetMap, valid_tags: &[Tag]) -> Result<()> {
196     for tag in attrs.keys() {
197         if !valid_tags.contains(tag) {
198             return log_throw_error!(ErrCode::InvalidArgument, "[FATAL]The tag [{}] is illegal.", tag);
199         }
200     }
201     Ok(())
202 }
203