1use crate::tlv;
7use anyhow;
8use serde_json;
9
10
11#[derive(Debug, serde::Serialize)]
14pub struct AccessControlEntry {
15 pub privilege: Option<u8>,
16 pub auth_mode: Option<u8>,
17 pub subjects: Option<Vec<u64>>,
18 pub targets: Option<Vec<AccessControlTarget>>,
19}
20
21#[derive(Debug, serde::Serialize)]
22pub struct AccessControlExtension {
23 pub data: Option<Vec<u8>>,
24}
25
26#[derive(Debug, serde::Serialize)]
27pub struct AccessControlTarget {
28 pub cluster: Option<u32>,
29 pub endpoint: Option<u16>,
30 pub device_type: Option<u32>,
31}
32
33#[derive(Debug, serde::Serialize)]
34pub struct AccessRestrictionEntry {
35 pub endpoint: Option<u16>,
36 pub cluster: Option<u32>,
37 pub restrictions: Option<Vec<AccessRestriction>>,
38}
39
40#[derive(Debug, serde::Serialize)]
41pub struct AccessRestriction {
42 pub type_: Option<u8>,
43 pub id: Option<u32>,
44}
45
46#[derive(Debug, serde::Serialize)]
47pub struct CommissioningAccessRestrictionEntry {
48 pub endpoint: Option<u16>,
49 pub cluster: Option<u32>,
50 pub restrictions: Option<Vec<AccessRestriction>>,
51}
52
53pub fn encode_review_fabric_restrictions(arl: Vec<u8>) -> anyhow::Result<Vec<u8>> {
57 let tlv = tlv::TlvItemEnc {
58 tag: 0,
59 value: tlv::TlvItemValueEnc::StructInvisible(vec![
60 (0, tlv::TlvItemValueEnc::StructAnon(arl.into_iter().map(|v| (0, tlv::TlvItemValueEnc::UInt8(v)).into()).collect())).into(),
61 ]),
62 };
63 Ok(tlv.encode()?)
64}
65
66pub fn decode_acl(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<AccessControlEntry>> {
70 let mut res = Vec::new();
71 if let tlv::TlvItemValue::List(v) = inp {
72 for item in v {
73 res.push(AccessControlEntry {
74 privilege: item.get_int(&[1]).map(|v| v as u8),
75 auth_mode: item.get_int(&[2]).map(|v| v as u8),
76 subjects: {
77 if let Some(tlv::TlvItemValue::List(l)) = item.get(&[3]) {
78 let items: Vec<u64> = l.iter().filter_map(|e| { if let tlv::TlvItemValue::Int(v) = &e.value { Some(*v) } else { None } }).collect();
79 Some(items)
80 } else {
81 None
82 }
83 },
84 targets: {
85 if let Some(tlv::TlvItemValue::List(l)) = item.get(&[4]) {
86 let mut items = Vec::new();
87 for list_item in l {
88 items.push(AccessControlTarget {
89 cluster: list_item.get_int(&[0]).map(|v| v as u32),
90 endpoint: list_item.get_int(&[1]).map(|v| v as u16),
91 device_type: list_item.get_int(&[2]).map(|v| v as u32),
92 });
93 }
94 Some(items)
95 } else {
96 None
97 }
98 },
99 });
100 }
101 }
102 Ok(res)
103}
104
105pub fn decode_extension(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<AccessControlExtension>> {
107 let mut res = Vec::new();
108 if let tlv::TlvItemValue::List(v) = inp {
109 for item in v {
110 res.push(AccessControlExtension {
111 data: item.get_octet_string_owned(&[1]),
112 });
113 }
114 }
115 Ok(res)
116}
117
118pub fn decode_subjects_per_access_control_entry(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
120 if let tlv::TlvItemValue::Int(v) = inp {
121 Ok(*v as u16)
122 } else {
123 Err(anyhow::anyhow!("Expected Integer"))
124 }
125}
126
127pub fn decode_targets_per_access_control_entry(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
129 if let tlv::TlvItemValue::Int(v) = inp {
130 Ok(*v as u16)
131 } else {
132 Err(anyhow::anyhow!("Expected Integer"))
133 }
134}
135
136pub fn decode_access_control_entries_per_fabric(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
138 if let tlv::TlvItemValue::Int(v) = inp {
139 Ok(*v as u16)
140 } else {
141 Err(anyhow::anyhow!("Expected Integer"))
142 }
143}
144
145pub fn decode_commissioning_arl(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<CommissioningAccessRestrictionEntry>> {
147 let mut res = Vec::new();
148 if let tlv::TlvItemValue::List(v) = inp {
149 for item in v {
150 res.push(CommissioningAccessRestrictionEntry {
151 endpoint: item.get_int(&[0]).map(|v| v as u16),
152 cluster: item.get_int(&[1]).map(|v| v as u32),
153 restrictions: {
154 if let Some(tlv::TlvItemValue::List(l)) = item.get(&[2]) {
155 let mut items = Vec::new();
156 for list_item in l {
157 items.push(AccessRestriction {
158 type_: list_item.get_int(&[0]).map(|v| v as u8),
159 id: list_item.get_int(&[1]).map(|v| v as u32),
160 });
161 }
162 Some(items)
163 } else {
164 None
165 }
166 },
167 });
168 }
169 }
170 Ok(res)
171}
172
173pub fn decode_arl(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<AccessRestrictionEntry>> {
175 let mut res = Vec::new();
176 if let tlv::TlvItemValue::List(v) = inp {
177 for item in v {
178 res.push(AccessRestrictionEntry {
179 endpoint: item.get_int(&[0]).map(|v| v as u16),
180 cluster: item.get_int(&[1]).map(|v| v as u32),
181 restrictions: {
182 if let Some(tlv::TlvItemValue::List(l)) = item.get(&[2]) {
183 let mut items = Vec::new();
184 for list_item in l {
185 items.push(AccessRestriction {
186 type_: list_item.get_int(&[0]).map(|v| v as u8),
187 id: list_item.get_int(&[1]).map(|v| v as u32),
188 });
189 }
190 Some(items)
191 } else {
192 None
193 }
194 },
195 });
196 }
197 }
198 Ok(res)
199}
200
201
202pub fn decode_attribute_json(cluster_id: u32, attribute_id: u32, tlv_value: &crate::tlv::TlvItemValue) -> String {
214 if cluster_id != 0x001F {
216 return format!("{{\"error\": \"Invalid cluster ID. Expected 0x001F, got {}\"}}", cluster_id);
217 }
218
219 match attribute_id {
220 0x0000 => {
221 match decode_acl(tlv_value) {
222 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
223 Err(e) => format!("{{\"error\": \"{}\"}}", e),
224 }
225 }
226 0x0001 => {
227 match decode_extension(tlv_value) {
228 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
229 Err(e) => format!("{{\"error\": \"{}\"}}", e),
230 }
231 }
232 0x0002 => {
233 match decode_subjects_per_access_control_entry(tlv_value) {
234 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
235 Err(e) => format!("{{\"error\": \"{}\"}}", e),
236 }
237 }
238 0x0003 => {
239 match decode_targets_per_access_control_entry(tlv_value) {
240 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
241 Err(e) => format!("{{\"error\": \"{}\"}}", e),
242 }
243 }
244 0x0004 => {
245 match decode_access_control_entries_per_fabric(tlv_value) {
246 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
247 Err(e) => format!("{{\"error\": \"{}\"}}", e),
248 }
249 }
250 0x0005 => {
251 match decode_commissioning_arl(tlv_value) {
252 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
253 Err(e) => format!("{{\"error\": \"{}\"}}", e),
254 }
255 }
256 0x0006 => {
257 match decode_arl(tlv_value) {
258 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
259 Err(e) => format!("{{\"error\": \"{}\"}}", e),
260 }
261 }
262 _ => format!("{{\"error\": \"Unknown attribute ID: {}\"}}", attribute_id),
263 }
264}
265
266pub fn get_attribute_list() -> Vec<(u32, &'static str)> {
271 vec![
272 (0x0000, "ACL"),
273 (0x0001, "Extension"),
274 (0x0002, "SubjectsPerAccessControlEntry"),
275 (0x0003, "TargetsPerAccessControlEntry"),
276 (0x0004, "AccessControlEntriesPerFabric"),
277 (0x0005, "CommissioningARL"),
278 (0x0006, "ARL"),
279 ]
280}
281