1use crate::core::{Permission, PermissionContext};
8use async_trait::async_trait;
9use std::ops::{BitAnd, BitOr, Not};
10
11pub struct AndPermission<A, B> {
58 left: A,
59 right: B,
60}
61
62impl<A, B> AndPermission<A, B> {
63 pub fn new(left: A, right: B) -> Self {
74 Self { left, right }
75 }
76}
77
78#[async_trait]
79impl<A, B> Permission for AndPermission<A, B>
80where
81 A: Permission + Send + Sync,
82 B: Permission + Send + Sync,
83{
84 async fn has_permission(&self, context: &PermissionContext<'_>) -> bool {
85 self.left.has_permission(context).await && self.right.has_permission(context).await
86 }
87}
88
89pub struct OrPermission<A, B> {
126 left: A,
127 right: B,
128}
129
130impl<A, B> OrPermission<A, B> {
131 pub fn new(left: A, right: B) -> Self {
142 Self { left, right }
143 }
144}
145
146#[async_trait]
147impl<A, B> Permission for OrPermission<A, B>
148where
149 A: Permission + Send + Sync,
150 B: Permission + Send + Sync,
151{
152 async fn has_permission(&self, context: &PermissionContext<'_>) -> bool {
153 self.left.has_permission(context).await || self.right.has_permission(context).await
154 }
155}
156
157pub struct NotPermission<P> {
204 inner: P,
205}
206
207impl<P> NotPermission<P> {
208 pub fn new(inner: P) -> Self {
219 Self { inner }
220 }
221}
222
223#[async_trait]
224impl<P> Permission for NotPermission<P>
225where
226 P: Permission + Send + Sync,
227{
228 async fn has_permission(&self, context: &PermissionContext<'_>) -> bool {
229 !self.inner.has_permission(context).await
230 }
231}
232
233macro_rules! impl_permission_operators {
257 ($type:ty) => {
258 impl<B: Permission> BitAnd<B> for $type {
259 type Output = AndPermission<Self, B>;
260
261 fn bitand(self, rhs: B) -> Self::Output {
262 AndPermission::new(self, rhs)
263 }
264 }
265
266 impl<B: Permission> BitOr<B> for $type {
267 type Output = OrPermission<Self, B>;
268
269 fn bitor(self, rhs: B) -> Self::Output {
270 OrPermission::new(self, rhs)
271 }
272 }
273
274 impl Not for $type {
275 type Output = NotPermission<Self>;
276
277 fn not(self) -> Self::Output {
278 NotPermission::new(self)
279 }
280 }
281 };
282}
283
284impl_permission_operators!(crate::AllowAny);
286impl_permission_operators!(crate::IsAuthenticated);
287impl_permission_operators!(crate::IsAdminUser);
288impl_permission_operators!(crate::IsActiveUser);
289impl_permission_operators!(crate::IsAuthenticatedOrReadOnly);
290
291impl<A, B, C> BitAnd<C> for AndPermission<A, B>
293where
294 A: Permission,
295 B: Permission,
296 C: Permission,
297{
298 type Output = AndPermission<Self, C>;
299
300 fn bitand(self, rhs: C) -> Self::Output {
301 AndPermission::new(self, rhs)
302 }
303}
304
305impl<A, B, C> BitOr<C> for AndPermission<A, B>
306where
307 A: Permission,
308 B: Permission,
309 C: Permission,
310{
311 type Output = OrPermission<Self, C>;
312
313 fn bitor(self, rhs: C) -> Self::Output {
314 OrPermission::new(self, rhs)
315 }
316}
317
318impl<A, B> Not for AndPermission<A, B>
319where
320 A: Permission,
321 B: Permission,
322{
323 type Output = NotPermission<Self>;
324
325 fn not(self) -> Self::Output {
326 NotPermission::new(self)
327 }
328}
329
330impl<A, B, C> BitAnd<C> for OrPermission<A, B>
331where
332 A: Permission,
333 B: Permission,
334 C: Permission,
335{
336 type Output = AndPermission<Self, C>;
337
338 fn bitand(self, rhs: C) -> Self::Output {
339 AndPermission::new(self, rhs)
340 }
341}
342
343impl<A, B, C> BitOr<C> for OrPermission<A, B>
344where
345 A: Permission,
346 B: Permission,
347 C: Permission,
348{
349 type Output = OrPermission<Self, C>;
350
351 fn bitor(self, rhs: C) -> Self::Output {
352 OrPermission::new(self, rhs)
353 }
354}
355
356impl<A, B> Not for OrPermission<A, B>
357where
358 A: Permission,
359 B: Permission,
360{
361 type Output = NotPermission<Self>;
362
363 fn not(self) -> Self::Output {
364 NotPermission::new(self)
365 }
366}
367
368impl<P, B> BitAnd<B> for NotPermission<P>
369where
370 P: Permission,
371 B: Permission,
372{
373 type Output = AndPermission<Self, B>;
374
375 fn bitand(self, rhs: B) -> Self::Output {
376 AndPermission::new(self, rhs)
377 }
378}
379
380impl<P, B> BitOr<B> for NotPermission<P>
381where
382 P: Permission,
383 B: Permission,
384{
385 type Output = OrPermission<Self, B>;
386
387 fn bitor(self, rhs: B) -> Self::Output {
388 OrPermission::new(self, rhs)
389 }
390}
391
392impl<P> Not for NotPermission<P>
393where
394 P: Permission,
395{
396 type Output = NotPermission<Self>;
397
398 fn not(self) -> Self::Output {
399 NotPermission::new(self)
400 }
401}
402
403#[cfg(test)]
404mod tests {
405 use super::*;
406 use crate::core::{AllowAny, IsAdminUser, IsAuthenticated};
407 use bytes::Bytes;
408 use hyper::{HeaderMap, Method, Version};
409 use reinhardt_http::Request;
410
411 #[tokio::test]
412 async fn test_and_permission_both_true() {
413 let permission = AndPermission::new(IsAuthenticated, IsAdminUser);
414 let request = Request::builder()
415 .method(Method::GET)
416 .uri("/")
417 .version(Version::HTTP_11)
418 .headers(HeaderMap::new())
419 .body(Bytes::new())
420 .build()
421 .unwrap();
422
423 let context = PermissionContext {
424 request: &request,
425 is_authenticated: true,
426 is_admin: true,
427 is_active: true,
428 user: None,
429 };
430
431 assert!(permission.has_permission(&context).await);
432 }
433
434 #[tokio::test]
435 async fn test_and_permission_left_false() {
436 let permission = AndPermission::new(IsAuthenticated, IsAdminUser);
437 let request = Request::builder()
438 .method(Method::GET)
439 .uri("/")
440 .version(Version::HTTP_11)
441 .headers(HeaderMap::new())
442 .body(Bytes::new())
443 .build()
444 .unwrap();
445
446 let context = PermissionContext {
447 request: &request,
448 is_authenticated: false,
449 is_admin: true,
450 is_active: false,
451 user: None,
452 };
453
454 assert!(!permission.has_permission(&context).await);
455 }
456
457 #[tokio::test]
458 async fn test_and_permission_right_false() {
459 let permission = AndPermission::new(IsAuthenticated, IsAdminUser);
460 let request = Request::builder()
461 .method(Method::GET)
462 .uri("/")
463 .version(Version::HTTP_11)
464 .headers(HeaderMap::new())
465 .body(Bytes::new())
466 .build()
467 .unwrap();
468
469 let context = PermissionContext {
470 request: &request,
471 is_authenticated: true,
472 is_admin: false,
473 is_active: true,
474 user: None,
475 };
476
477 assert!(!permission.has_permission(&context).await);
478 }
479
480 #[tokio::test]
481 async fn test_or_permission_both_true() {
482 let permission = OrPermission::new(IsAuthenticated, AllowAny);
483 let request = Request::builder()
484 .method(Method::GET)
485 .uri("/")
486 .version(Version::HTTP_11)
487 .headers(HeaderMap::new())
488 .body(Bytes::new())
489 .build()
490 .unwrap();
491
492 let context = PermissionContext {
493 request: &request,
494 is_authenticated: true,
495 is_admin: false,
496 is_active: true,
497 user: None,
498 };
499
500 assert!(permission.has_permission(&context).await);
501 }
502
503 #[tokio::test]
504 async fn test_or_permission_left_true() {
505 let permission = OrPermission::new(IsAuthenticated, IsAdminUser);
506 let request = Request::builder()
507 .method(Method::GET)
508 .uri("/")
509 .version(Version::HTTP_11)
510 .headers(HeaderMap::new())
511 .body(Bytes::new())
512 .build()
513 .unwrap();
514
515 let context = PermissionContext {
516 request: &request,
517 is_authenticated: true,
518 is_admin: false,
519 is_active: true,
520 user: None,
521 };
522
523 assert!(permission.has_permission(&context).await);
524 }
525
526 #[tokio::test]
527 async fn test_or_permission_right_true() {
528 let permission = OrPermission::new(IsAuthenticated, AllowAny);
529 let request = Request::builder()
530 .method(Method::GET)
531 .uri("/")
532 .version(Version::HTTP_11)
533 .headers(HeaderMap::new())
534 .body(Bytes::new())
535 .build()
536 .unwrap();
537
538 let context = PermissionContext {
539 request: &request,
540 is_authenticated: false,
541 is_admin: false,
542 is_active: false,
543 user: None,
544 };
545
546 assert!(permission.has_permission(&context).await);
547 }
548
549 #[tokio::test]
550 async fn test_or_permission_both_false() {
551 let permission = OrPermission::new(IsAuthenticated, IsAdminUser);
552 let request = Request::builder()
553 .method(Method::GET)
554 .uri("/")
555 .version(Version::HTTP_11)
556 .headers(HeaderMap::new())
557 .body(Bytes::new())
558 .build()
559 .unwrap();
560
561 let context = PermissionContext {
562 request: &request,
563 is_authenticated: false,
564 is_admin: false,
565 is_active: false,
566 user: None,
567 };
568
569 assert!(!permission.has_permission(&context).await);
570 }
571
572 #[tokio::test]
573 async fn test_not_permission_true() {
574 let permission = NotPermission::new(IsAuthenticated);
575 let request = Request::builder()
576 .method(Method::GET)
577 .uri("/")
578 .version(Version::HTTP_11)
579 .headers(HeaderMap::new())
580 .body(Bytes::new())
581 .build()
582 .unwrap();
583
584 let context = PermissionContext {
585 request: &request,
586 is_authenticated: false,
587 is_admin: false,
588 is_active: false,
589 user: None,
590 };
591
592 assert!(permission.has_permission(&context).await);
593 }
594
595 #[tokio::test]
596 async fn test_not_permission_false() {
597 let permission = NotPermission::new(IsAuthenticated);
598 let request = Request::builder()
599 .method(Method::GET)
600 .uri("/")
601 .version(Version::HTTP_11)
602 .headers(HeaderMap::new())
603 .body(Bytes::new())
604 .build()
605 .unwrap();
606
607 let context = PermissionContext {
608 request: &request,
609 is_authenticated: true,
610 is_admin: false,
611 is_active: true,
612 user: None,
613 };
614
615 assert!(!permission.has_permission(&context).await);
616 }
617
618 #[tokio::test]
619 async fn test_complex_permission_combination() {
620 let permission =
621 OrPermission::new(AndPermission::new(IsAuthenticated, IsAdminUser), AllowAny);
622
623 let request = Request::builder()
624 .method(Method::GET)
625 .uri("/")
626 .version(Version::HTTP_11)
627 .headers(HeaderMap::new())
628 .body(Bytes::new())
629 .build()
630 .unwrap();
631
632 let context = PermissionContext {
633 request: &request,
634 is_authenticated: false,
635 is_admin: false,
636 is_active: false,
637 user: None,
638 };
639
640 assert!(permission.has_permission(&context).await);
641 }
642
643 #[tokio::test]
646 async fn test_bitand_operator() {
647 let permission = IsAuthenticated & IsAdminUser;
648
649 let request = Request::builder()
650 .method(Method::GET)
651 .uri("/")
652 .version(Version::HTTP_11)
653 .headers(HeaderMap::new())
654 .body(Bytes::new())
655 .build()
656 .unwrap();
657
658 let context = PermissionContext {
660 request: &request,
661 is_authenticated: true,
662 is_admin: true,
663 is_active: true,
664 user: None,
665 };
666 assert!(permission.has_permission(&context).await);
667
668 let context = PermissionContext {
670 request: &request,
671 is_authenticated: true,
672 is_admin: false,
673 is_active: true,
674 user: None,
675 };
676 assert!(!permission.has_permission(&context).await);
677 }
678
679 #[tokio::test]
680 async fn test_bitor_operator() {
681 let permission = IsAuthenticated | AllowAny;
682
683 let request = Request::builder()
684 .method(Method::GET)
685 .uri("/")
686 .version(Version::HTTP_11)
687 .headers(HeaderMap::new())
688 .body(Bytes::new())
689 .build()
690 .unwrap();
691
692 let context = PermissionContext {
694 request: &request,
695 is_authenticated: false,
696 is_admin: false,
697 is_active: false,
698 user: None,
699 };
700 assert!(permission.has_permission(&context).await);
701 }
702
703 #[tokio::test]
704 async fn test_not_operator() {
705 let permission = !IsAuthenticated;
706
707 let request = Request::builder()
708 .method(Method::GET)
709 .uri("/")
710 .version(Version::HTTP_11)
711 .headers(HeaderMap::new())
712 .body(Bytes::new())
713 .build()
714 .unwrap();
715
716 let context = PermissionContext {
718 request: &request,
719 is_authenticated: false,
720 is_admin: false,
721 is_active: false,
722 user: None,
723 };
724 assert!(permission.has_permission(&context).await);
725
726 let context = PermissionContext {
728 request: &request,
729 is_authenticated: true,
730 is_admin: false,
731 is_active: true,
732 user: None,
733 };
734 assert!(!permission.has_permission(&context).await);
735 }
736
737 #[tokio::test]
738 async fn test_complex_operator_combination() {
739 let permission = (IsAuthenticated & IsAdminUser) | AllowAny;
741
742 let request = Request::builder()
743 .method(Method::GET)
744 .uri("/")
745 .version(Version::HTTP_11)
746 .headers(HeaderMap::new())
747 .body(Bytes::new())
748 .build()
749 .unwrap();
750
751 let context = PermissionContext {
753 request: &request,
754 is_authenticated: false,
755 is_admin: false,
756 is_active: false,
757 user: None,
758 };
759 assert!(permission.has_permission(&context).await);
760 }
761}