1use cyfs_base::*;
2use cyfs_core::*;
3
4use serde::{Deserialize, Deserializer, Serialize, Serializer};
5use serde_json::{Map, Value};
6use std::str::FromStr;
7
8#[derive(Clone, Copy, Eq, Debug, PartialEq)]
9pub enum RequestProtocol {
10 Native,
11 Meta,
12 Sync,
13 HttpBdt,
14 HttpLocal,
15 HttpLocalAuth,
16 DatagramBdt,
17 DataBdt,
19}
20
21impl RequestProtocol {
22 pub fn is_local(&self) -> bool {
23 match *self {
24 Self::Native | Self::HttpLocal | Self::HttpLocalAuth => true,
25 Self::HttpBdt | Self::DatagramBdt | Self::DataBdt => false,
26 Self::Meta | Self::Sync => false,
27 }
28 }
29
30 pub fn is_remote(&self) -> bool {
31 !self.is_local()
32 }
33
34 pub fn is_require_acl(&self) -> bool {
35 match *self {
36 Self::HttpBdt | Self::DatagramBdt | Self::DataBdt => true,
37 Self::Native | Self::HttpLocal | Self::Meta | Self::Sync | Self::HttpLocalAuth => false,
38 }
39 }
40
41 pub fn as_str(&self) -> &str {
42 match *self {
43 Self::Native => "native",
44 Self::Meta => "meta",
45 Self::Sync => "sync",
46 Self::HttpBdt => "http-bdt",
47 Self::HttpLocal => "http-local",
48 Self::HttpLocalAuth => "http-local-auth",
49 Self::DatagramBdt => "datagram-bdt",
50 Self::DataBdt => "data-bdt",
51 }
52 }
53}
54
55impl ToString for RequestProtocol {
56 fn to_string(&self) -> String {
57 self.as_str().to_owned()
58 }
59}
60
61impl FromStr for RequestProtocol {
62 type Err = BuckyError;
63
64 fn from_str(value: &str) -> Result<Self, Self::Err> {
65 let ret = match value {
66 "native" => Self::Native,
67 "meta" => Self::Meta,
68 "sync" => Self::Sync,
69 "http-bdt" => Self::HttpBdt,
70 "http-local" => Self::HttpLocal,
71 "http-local-auth" => Self::HttpLocalAuth,
72 "datagram-bdt" => Self::DatagramBdt,
73 "data-bdt" => Self::DataBdt,
74 v @ _ => {
75 let msg = format!("unknown request input protocol: {}", v);
76 error!("{}", msg);
77
78 return Err(BuckyError::new(BuckyErrorCode::InvalidParam, msg));
79 }
80 };
81
82 Ok(ret)
83 }
84}
85
86#[repr(u8)]
88#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)]
89pub enum DeviceZoneCategory {
90 CurrentDevice = 0,
91 CurrentZone = 1,
92 FriendZone = 2,
93 OtherZone = 3,
94}
95
96impl DeviceZoneCategory {
97 pub fn as_str(&self) -> &str {
98 match self {
99 Self::CurrentDevice => "current-device",
100 Self::CurrentZone => "current-zone",
101 Self::FriendZone => "friend-zone",
102 Self::OtherZone => "other-zone",
103 }
104 }
105
106 pub fn is_included(&self, target: Self) -> bool {
107 *self as u8 <= target as u8
108 }
109}
110
111impl ToString for DeviceZoneCategory {
112 fn to_string(&self) -> String {
113 self.as_str().to_owned()
114 }
115}
116
117impl FromStr for DeviceZoneCategory {
118 type Err = BuckyError;
119 fn from_str(s: &str) -> Result<Self, Self::Err> {
120 let ret = match s {
121 "current-device" => Self::CurrentDevice,
122 "current-zone" => Self::CurrentZone,
123 "friend-zone" => Self::FriendZone,
124 "other-zone" => Self::OtherZone,
125 _ => {
126 let msg = format!("unknown device zone category: {}", s);
127 error!("{}", msg);
128
129 return Err(BuckyError::new(BuckyErrorCode::InvalidParam, msg));
130 }
131 };
132
133 Ok(ret)
134 }
135}
136impl Into<AccessGroup> for DeviceZoneCategory {
137 fn into(self) -> AccessGroup {
138 match self {
139 DeviceZoneCategory::CurrentDevice => AccessGroup::CurrentDevice,
140 DeviceZoneCategory::CurrentZone => AccessGroup::CurrentZone,
141 DeviceZoneCategory::FriendZone => AccessGroup::FriendZone,
142 DeviceZoneCategory::OtherZone => AccessGroup::OthersZone,
143 }
144 }
145}
146
147#[derive(Clone, Debug)]
148pub struct DeviceZoneInfo {
149 pub device: Option<DeviceId>,
150 pub zone: Option<ObjectId>,
151 pub zone_category: DeviceZoneCategory,
152}
153
154impl DeviceZoneInfo {
155 pub fn new_local() -> Self {
156 Self {
157 device: None,
158 zone: None,
159 zone_category: DeviceZoneCategory::CurrentDevice,
160 }
161 }
162
163 pub fn new_current_zone() -> Self {
164 Self {
165 device: None,
166 zone: None,
167 zone_category: DeviceZoneCategory::CurrentZone,
168 }
169 }
170
171 pub fn new_friend_zone() -> Self {
172 Self {
173 device: None,
174 zone: None,
175 zone_category: DeviceZoneCategory::FriendZone,
176 }
177 }
178
179 pub fn new_other_zone() -> Self {
180 Self {
181 device: None,
182 zone: None,
183 zone_category: DeviceZoneCategory::OtherZone,
184 }
185 }
186
187 pub fn is_current_device(&self) -> bool {
188 match self.zone_category {
189 DeviceZoneCategory::CurrentDevice => true,
190 _ => false,
191 }
192 }
193
194 pub fn is_current_zone(&self) -> bool {
195 match self.zone_category {
196 DeviceZoneCategory::CurrentDevice | DeviceZoneCategory::CurrentZone => true,
197 _ => false,
198 }
199 }
200
201 pub fn is_friend_zone(&self) -> bool {
202 match self.zone_category {
203 DeviceZoneCategory::CurrentDevice
204 | DeviceZoneCategory::CurrentZone
205 | DeviceZoneCategory::FriendZone => true,
206 _ => false,
207 }
208 }
209}
210
211#[derive(Clone)]
213pub struct RequestSourceInfo {
214 pub protocol: RequestProtocol,
215 pub zone: DeviceZoneInfo,
216 pub dec: ObjectId,
217
218 pub verified: Option<ObjectId>,
220}
221
222impl std::fmt::Debug for RequestSourceInfo {
223 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
224 std::fmt::Display::fmt(&self, f)
225 }
226}
227
228impl std::fmt::Display for RequestSourceInfo {
229 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
230 write!(
231 f,
232 "protocol={}, zone=({:?}-{:?}-{:?}), dec={}, verified={:?}",
233 self.protocol.as_str(),
234 self.zone.zone_category,
235 self.zone.device,
236 self.zone.zone,
237 cyfs_core::dec_id_to_string(&self.dec),
238 self.verified,
239 )
240 }
241}
242
243impl RequestSourceInfo {
244 pub fn new_local_system() -> Self {
245 Self {
246 protocol: RequestProtocol::Native,
247 zone: DeviceZoneInfo::new_local(),
248 dec: get_system_dec_app().to_owned(),
249 verified: None,
250 }
251 }
252
253 pub fn new_local_anonymouse() -> Self {
254 Self {
255 protocol: RequestProtocol::Native,
256 zone: DeviceZoneInfo::new_local(),
257 dec: get_anonymous_dec_app().to_owned(),
258 verified: None,
259 }
260 }
261
262 pub fn new_local_dec(dec: Option<ObjectId>) -> Self {
264 Self {
265 protocol: RequestProtocol::Native,
266 zone: DeviceZoneInfo::new_local(),
267 dec: dec.unwrap_or(get_anonymous_dec_app().to_owned()),
268 verified: None,
269 }
270 }
271
272 pub fn new_local_dec_or_system(dec: Option<ObjectId>) -> Self {
274 Self {
275 protocol: RequestProtocol::Native,
276 zone: DeviceZoneInfo::new_local(),
277 dec: dec.unwrap_or(get_system_dec_app().to_owned()),
278 verified: None,
279 }
280 }
281
282 pub fn new_zone_dec(dec: Option<ObjectId>) -> Self {
284 Self {
285 protocol: RequestProtocol::Native,
286 zone: DeviceZoneInfo::new_current_zone(),
287 dec: dec.unwrap_or(get_anonymous_dec_app().to_owned()),
288 verified: None,
289 }
290 }
291
292 pub fn new_friend_zone_dec(dec: Option<ObjectId>) -> Self {
294 Self {
295 protocol: RequestProtocol::Native,
296 zone: DeviceZoneInfo::new_friend_zone(),
297 dec: dec.unwrap_or(get_anonymous_dec_app().to_owned()),
298 verified: None,
299 }
300 }
301
302 pub fn new_other_zone_dec(dec: Option<ObjectId>) -> Self {
304 Self {
305 protocol: RequestProtocol::Native,
306 zone: DeviceZoneInfo::new_other_zone(),
307 dec: dec.unwrap_or(get_anonymous_dec_app().to_owned()),
308 verified: None,
309 }
310 }
311
312 pub fn protocol(mut self, protocol: RequestProtocol) -> Self {
313 self.protocol = protocol;
314 self
315 }
316
317 pub fn set_dec(&mut self, dec_id: ObjectId) {
318 self.dec = dec_id;
319 }
320
321 pub fn dec(mut self, dec_id: ObjectId) -> Self {
322 self.set_dec(dec_id);
323 self
324 }
325
326 pub fn is_system_dec(&self) -> bool {
327 self.dec == *get_system_dec_app()
328 }
329
330 pub fn is_anonymous_dec_app(&self) -> bool {
331 self.dec == *get_anonymous_dec_app()
332 }
333
334 pub fn get_opt_dec(&self) -> Option<&ObjectId> {
336 if self.is_anonymous_dec_app() {
337 None
338 } else {
339 Some(&self.dec)
340 }
341 }
342
343 pub fn set_verified(&mut self, target_dec_id: ObjectId) {
344 assert!(self.verified.is_none());
345 self.verified = Some(target_dec_id);
346 }
347
348 pub fn is_verified(&self, target_dec_id: &ObjectId) -> bool {
349 match &self.verified {
350 Some(id) => {
351 if id == target_dec_id {
352 true
353 } else {
354 if self.is_system_dec() {
355 true
356 } else {
357 warn!("request source pass verify but target_dec_id not match! pass={}, required={}",
358 cyfs_core::dec_id_to_string(&id), cyfs_core::dec_id_to_string(&target_dec_id));
359
360 false
361 }
362 }
363 }
364 None => false,
365 }
366 }
367
368 pub fn is_fuzzy_verified(&self) -> bool {
369 self.verified.is_some()
370 }
371
372 pub fn check_target_dec_permission(&self, op_target_dec: &Option<ObjectId>) -> bool {
373 self.check_target_dec_permission2(op_target_dec.as_ref())
374 }
375
376 pub fn check_target_dec_permission2(&self, op_target_dec: Option<&ObjectId>) -> bool {
377 if self.is_system_dec() {
378 true
379 } else {
380 match op_target_dec {
381 Some(target) => self.compare_dec(target),
382 None => {
383 true
385 }
386 }
387 }
388 }
389
390 pub fn is_current_device(&self) -> bool {
391 self.zone.is_current_device()
392 }
393
394 pub fn is_current_zone(&self) -> bool {
395 self.zone.is_current_zone()
396 }
397
398 pub fn compare_zone_category(&self, zone_category: DeviceZoneCategory) -> bool {
399 self.zone.zone_category.is_included(zone_category)
400 }
401
402 pub fn compare_zone(&self, zone: &ObjectId) -> bool {
403 self.zone.device.as_ref().map(|v| v.object_id()) == Some(zone)
404 || self.zone.zone.as_ref() == Some(zone)
405 }
406
407 pub fn compare_dec(&self, dec: &ObjectId) -> bool {
408 self.dec == *dec
409 }
410
411 pub fn mask(&self, own_dec_id: &ObjectId, permissions: impl Into<AccessPermissions>) -> u32 {
412 let permissions = permissions.into();
413 let mut access = AccessString::new(0);
414 if self.dec == *own_dec_id {
415 access.set_group_permissions(AccessGroup::OwnerDec, permissions);
416 } else {
417 access.set_group_permissions(AccessGroup::OthersDec, permissions);
418 }
419
420 if self.is_fuzzy_verified() {
431 access.set_group_permissions(AccessGroup::CurrentDevice, permissions);
432 access.set_group_permissions(AccessGroup::CurrentZone, permissions);
433 } else {
434 let group = self.zone.zone_category.into();
435 access.set_group_permissions(group, permissions);
436 }
437
438 access.value()
439 }
440
441 pub fn owner_dec_mask(&self, permissions: impl Into<AccessPermissions>) -> u32 {
442 let permissions = permissions.into();
443
444 let mut access = AccessString::new(0);
445 access.set_group_permissions(AccessGroup::OwnerDec, permissions);
446
447 let group = self.zone.zone_category.into();
448 access.set_group_permissions(group, permissions);
449
450 access.value()
451 }
452
453 pub fn other_dec_mask(&self, permissions: impl Into<AccessPermissions>) -> u32 {
454 let permissions = permissions.into();
455
456 let mut access = AccessString::new(0);
457 access.set_group_permissions(AccessGroup::OthersDec, permissions);
458
459 let group = self.zone.zone_category.into();
460 access.set_group_permissions(group, permissions);
461
462 access.value()
463 }
464
465 pub fn check_current_zone(&self, service: &str) -> BuckyResult<()> {
466 if !self.is_current_zone() {
467 let msg = format!(
468 "{} service valid only in current zone! source device={:?}, category={}",
469 service,
470 self.zone.device,
471 self.zone.zone_category.as_str(),
472 );
473 error!("{}", msg);
474
475 return Err(BuckyError::new(BuckyErrorCode::PermissionDenied, msg));
476 }
477
478 Ok(())
479 }
480
481 pub fn check_current_device(&self, service: &str) -> BuckyResult<()> {
482 if !self.is_current_device() {
483 let msg = format!(
484 "{} service valid only on current device! source device={:?}, category={}",
485 service,
486 self.zone.device,
487 self.zone.zone_category.as_str(),
488 );
489 error!("{}", msg);
490
491 return Err(BuckyError::new(BuckyErrorCode::PermissionDenied, msg));
492 }
493
494 Ok(())
495 }
496}
497
498impl JsonCodec<Self> for DeviceZoneInfo {
499 fn encode_json(&self) -> Map<String, Value> {
500 let mut obj = Map::new();
501 JsonCodecHelper::encode_option_string_field(&mut obj, "device", self.device.as_ref());
502 JsonCodecHelper::encode_option_string_field(&mut obj, "zone", self.zone.as_ref());
503 JsonCodecHelper::encode_string_field(
504 &mut obj,
505 "zone_category",
506 self.zone_category.as_str(),
507 );
508
509 obj
510 }
511
512 fn decode_json(obj: &Map<String, Value>) -> BuckyResult<Self> {
513 Ok(Self {
514 device: JsonCodecHelper::decode_option_string_field(obj, "device")?,
515 zone: JsonCodecHelper::decode_option_string_field(obj, "zone")?,
516 zone_category: JsonCodecHelper::decode_string_field(obj, "zone_category")?,
517 })
518 }
519}
520
521impl JsonCodec<Self> for RequestSourceInfo {
522 fn encode_json(&self) -> Map<String, Value> {
523 let mut obj = Map::new();
524 JsonCodecHelper::encode_field(&mut obj, "zone", &self.zone);
525 JsonCodecHelper::encode_string_field(&mut obj, "dec", &self.dec);
526 JsonCodecHelper::encode_string_field(&mut obj, "protocol", &self.protocol);
527 JsonCodecHelper::encode_option_string_field(&mut obj, "verified", self.verified.as_ref());
528
529 obj
530 }
531
532 fn decode_json(obj: &Map<String, Value>) -> BuckyResult<Self> {
533 Ok(Self {
534 zone: JsonCodecHelper::decode_field(obj, "zone")?,
535 dec: JsonCodecHelper::decode_string_field(obj, "dec")?,
536 protocol: JsonCodecHelper::decode_string_field(obj, "protocol")?,
537 verified: JsonCodecHelper::decode_option_string_field(obj, "verified")?,
538 })
539 }
540}
541
542impl Serialize for DeviceZoneCategory {
543 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
544 where
545 S: Serializer,
546 {
547 serializer.serialize_str(&self.to_string())
548 }
549}
550
551impl<'de> Deserialize<'de> for DeviceZoneCategory {
552 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
553 where
554 D: Deserializer<'de>,
555 {
556 deserializer.deserialize_str(TStringVisitor::<Self>::new())
557 }
558}
559
560impl Into<OpEnvSourceInfo> for RequestSourceInfo {
561 fn into(self) -> OpEnvSourceInfo {
562 OpEnvSourceInfo {
563 dec: self.dec,
564 device: self.zone.device,
565 }
566 }
567}
568#[cfg(test)]
569mod test {
570 use super::*;
571
572 fn other_dec_read() {
573 let dec = ObjectId::default();
574 let source = RequestSourceInfo {
575 zone: DeviceZoneInfo {
576 device: None,
577 zone: None,
578 zone_category: DeviceZoneCategory::CurrentDevice,
579 },
580 dec,
581 protocol: RequestProtocol::Native,
582 verified: None,
583 };
584
585 let system = ObjectId::default();
586 let mask = source.mask(&system, RequestOpType::Read);
587
588 let default = AccessString::default().value();
589 assert_ne!(default & mask, mask)
590 }
591
592 #[test]
593 fn test_verified() {
594 let owner = ObjectId::default();
595 let dec_a = cyfs_core::DecApp::generate_id(owner.clone(), "dec-a");
596 let dec_b = cyfs_core::DecApp::generate_id(owner.clone(), "dec-b");
597
598 let source = RequestSourceInfo {
599 zone: DeviceZoneInfo {
600 device: None,
601 zone: None,
602 zone_category: DeviceZoneCategory::OtherZone,
603 },
604 dec: dec_a.clone(),
605 protocol: RequestProtocol::HttpBdt,
606 verified: None,
607 };
608
609 {
610 let mut source = source.clone();
611 let object_access = AccessString::default().value();
612
613 let mask = source.mask(&dec_b, RequestOpType::Read);
614 assert_ne!(object_access & mask, mask);
615
616 source.set_verified(dec_a);
617 let mask = source.mask(&dec_b, RequestOpType::Read);
618 assert_eq!(object_access & mask, mask);
619 }
620
621 {
622 let mut source = source.clone();
623
624 let mut access = AccessString::default();
626 access.clear_group_permissions(AccessGroup::OthersDec);
627 let object_access = access.value();
628
629 let mask = source.mask(&dec_b, RequestOpType::Read);
630 assert_ne!(object_access & mask, mask);
631
632 source.set_verified(dec_a);
633 let mask = source.mask(&dec_b, RequestOpType::Read);
634 assert_ne!(object_access & mask, mask);
635 }
636
637 {
638 let mut source = source.clone();
639
640 let mut access = AccessString::default();
642 access.clear_group_permissions(AccessGroup::CurrentZone);
643 let object_access = access.value();
644
645 let mask = source.mask(&dec_b, RequestOpType::Read);
646 assert_ne!(object_access & mask, mask);
647
648 source.set_verified(dec_a);
649 let mask = source.mask(&dec_b, RequestOpType::Read);
650 assert_ne!(object_access & mask, mask);
651 }
652 }
653}