cyfs_lib/base/
source.rs

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    // bdt层的chunk数据传输
18    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// source device's zone info
87#[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// The identy info of a request
212#[derive(Clone)]
213pub struct RequestSourceInfo {
214    pub protocol: RequestProtocol,
215    pub zone: DeviceZoneInfo,
216    pub dec: ObjectId,
217
218    // is passed the acl verified for target-dec-id
219    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    // dec-id = anonymous-dec-id if None
263    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    // dec-id = system-dec-id if None
273    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    // dec-id = anonymous-dec-id if None
283    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    // dec-id = anonymous-dec-id if None
293    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    // dec-id = anonymous-dec-id if None
303    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    // return none if is anonymous dec
335    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                    // target_dec_id is none then equal as current dec
384                    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        /*
421        A and B two dec
422        A creates objX, the permission is the default permission, that is, B in the same zone can access
423        B After obtaining the ID of objX, configure the rpath permission so that objX can be accessed outside the zone
424
425        The key point here is that this behavior is inevitable. As long as B can access the obj, 
426        it is theoretically impossible to prevent B from spreading the obj out of the zone? 
427        So if other dec is allowed to access in the same zone at the object level access(Only true at the object access layer), 
428        it can be allowed
429        */
430        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            // remove other dec access
625            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            // remove other dec access
641            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}