@@ -5,7 +5,6 @@ use darling::FromMeta;
5
5
use proc_macro:: TokenStream ;
6
6
use proc_macro2:: Span ;
7
7
use quote:: quote;
8
- use syn:: parse:: Parser ;
9
8
use syn:: { parse_macro_input, AttributeArgs , ItemFn , ItemStruct } ;
10
9
11
10
/// Defines attributes for the `access_controllable` macro.
@@ -17,7 +16,6 @@ pub struct MacroArgs {
17
16
}
18
17
19
18
const DEFAULT_STORAGE_PREFIX : & str = "__acl" ;
20
- const DEFAULT_ACL_FIELD_NAME : & str = "__acl" ;
21
19
const DEFAULT_ACL_TYPE_NAME : & str = "__Acl" ;
22
20
23
21
const ERR_PARSE_BITFLAG : & str = "Value does not correspond to a permission" ;
@@ -27,13 +25,9 @@ const ERR_PARSE_ROLE: &str = "Value does not correspond to a role";
27
25
pub fn access_controllable ( attrs : TokenStream , item : TokenStream ) -> TokenStream {
28
26
let cratename = cratename ( ) ;
29
27
let attr_args = parse_macro_input ! ( attrs as AttributeArgs ) ;
30
- let mut input: ItemStruct = parse_macro_input ! ( item) ;
31
- let acl_field = syn:: Ident :: new ( DEFAULT_ACL_FIELD_NAME , Span :: call_site ( ) ) ;
28
+ let input: ItemStruct = parse_macro_input ! ( item) ;
32
29
let acl_type = syn:: Ident :: new ( DEFAULT_ACL_TYPE_NAME , Span :: call_site ( ) ) ;
33
30
let bitflags_type = new_bitflags_type_ident ( Span :: call_site ( ) ) ;
34
- if let Err ( e) = inject_acl_field ( & mut input, & acl_field, & acl_type) {
35
- return TokenStream :: from ( e. to_compile_error ( ) ) ;
36
- }
37
31
let ItemStruct { ident, .. } = input. clone ( ) ;
38
32
39
33
let macro_args = match MacroArgs :: from_list ( & attr_args) {
@@ -90,6 +84,7 @@ pub fn access_controllable(attrs: TokenStream, item: TokenStream) -> TokenStream
90
84
Permissions ,
91
85
Bearers ,
92
86
BearersSet { permission: #bitflags_type } ,
87
+ AclStorage ,
93
88
}
94
89
95
90
/// Generates a prefix by concatenating the input parameters.
@@ -100,6 +95,34 @@ pub fn access_controllable(attrs: TokenStream, item: TokenStream) -> TokenStream
100
95
[ base, specifier. as_slice( ) ] . concat( )
101
96
}
102
97
98
+ impl #ident {
99
+ fn acl_get_storage( & self ) -> Option <#acl_type> {
100
+ let base_prefix = <#ident as AccessControllable >:: acl_storage_prefix( ) ;
101
+ near_sdk:: env:: storage_read( & __acl_storage_prefix(
102
+ base_prefix,
103
+ __AclStorageKey:: AclStorage ,
104
+ ) )
105
+ . map( |acl_storage_bytes| {
106
+ #acl_type:: try_from_slice( & acl_storage_bytes)
107
+ . unwrap_or_else( |_| near_sdk:: env:: panic_str( "ACL: invalid acl storage format" ) )
108
+ } )
109
+ }
110
+
111
+ fn acl_get_or_init( & mut self ) -> #acl_type {
112
+ self . acl_get_storage( ) . unwrap_or_else( || self . acl_init_storage_unchecked( ) )
113
+ }
114
+
115
+ fn acl_init_storage_unchecked( & mut self ) -> #acl_type {
116
+ let base_prefix = <#ident as AccessControllable >:: acl_storage_prefix( ) ;
117
+ let acl_storage: #acl_type = Default :: default ( ) ;
118
+ near_sdk:: env:: storage_write(
119
+ & __acl_storage_prefix( base_prefix, __AclStorageKey:: AclStorage ) ,
120
+ & acl_storage. try_to_vec( ) . unwrap( ) ,
121
+ ) ;
122
+ acl_storage
123
+ }
124
+ }
125
+
103
126
impl #acl_type {
104
127
fn new_bearers_set( permission: #bitflags_type) -> :: near_sdk:: store:: UnorderedSet <:: near_sdk:: AccountId > {
105
128
let base_prefix = <#ident as AccessControllable >:: acl_storage_prefix( ) ;
@@ -474,6 +497,39 @@ pub fn access_controllable(attrs: TokenStream, item: TokenStream) -> TokenStream
474
497
}
475
498
}
476
499
500
+ fn get_default_permissioned_accounts( ) -> #cratename:: access_controllable:: PermissionedAccounts {
501
+ let roles = <#role_type>:: acl_role_variants( ) ;
502
+ let mut map = :: std:: collections:: HashMap :: new( ) ;
503
+ for role in roles {
504
+ let role: #role_type = :: std:: convert:: TryFrom :: try_from( role)
505
+ . unwrap_or_else( |_| :: near_sdk:: env:: panic_str( #ERR_PARSE_ROLE ) ) ;
506
+
507
+ map. insert(
508
+ role. into( ) ,
509
+ #cratename:: access_controllable:: PermissionedAccountsPerRole {
510
+ admins: Default :: default ( ) ,
511
+ grantees: Default :: default ( ) ,
512
+ }
513
+ ) ;
514
+ }
515
+
516
+ #cratename:: access_controllable:: PermissionedAccounts {
517
+ super_admins: Default :: default ( ) ,
518
+ roles: map,
519
+ }
520
+ }
521
+
522
+ macro_rules! return_if_none {
523
+ ( $res: expr, $default_value: expr) => {
524
+ match $res {
525
+ Some ( val) => val,
526
+ None => {
527
+ return $default_value;
528
+ }
529
+ }
530
+ } ;
531
+ }
532
+
477
533
// Note that `#[near-bindgen]` exposes non-public functions in trait
478
534
// implementations. This is [documented] behavior. Therefore some
479
535
// functions are made `#[private]` despite _not_ being public.
@@ -487,56 +543,56 @@ pub fn access_controllable(attrs: TokenStream, item: TokenStream) -> TokenStream
487
543
488
544
#[ private]
489
545
fn acl_init_super_admin( & mut self , account_id: :: near_sdk:: AccountId ) -> bool {
490
- self . #acl_field . init_super_admin( & account_id)
546
+ self . acl_get_or_init ( ) . init_super_admin( & account_id)
491
547
}
492
548
493
549
fn acl_role_variants( & self ) -> Vec <& ' static str > {
494
550
<#role_type>:: acl_role_variants( )
495
551
}
496
552
497
553
fn acl_is_super_admin( & self , account_id: :: near_sdk:: AccountId ) -> bool {
498
- self . #acl_field . is_super_admin( & account_id)
554
+ return_if_none! ( self . acl_get_storage ( ) , false ) . is_super_admin( & account_id)
499
555
}
500
556
501
557
fn acl_add_admin( & mut self , role: String , account_id: :: near_sdk:: AccountId ) -> Option <bool > {
502
558
let role: #role_type = :: std:: convert:: TryFrom :: try_from( role. as_str( ) ) . unwrap_or_else( |_| :: near_sdk:: env:: panic_str( #ERR_PARSE_ROLE ) ) ;
503
- self . #acl_field . add_admin( role, & account_id)
559
+ self . acl_get_or_init ( ) . add_admin( role, & account_id)
504
560
}
505
561
506
562
fn acl_is_admin( & self , role: String , account_id: :: near_sdk:: AccountId ) -> bool {
507
563
let role: #role_type = :: std:: convert:: TryFrom :: try_from( role. as_str( ) ) . unwrap_or_else( |_| :: near_sdk:: env:: panic_str( #ERR_PARSE_ROLE ) ) ;
508
- self . #acl_field . is_admin( role, & account_id)
564
+ return_if_none! ( self . acl_get_storage ( ) , false ) . is_admin( role, & account_id)
509
565
}
510
566
511
567
fn acl_revoke_admin( & mut self , role: String , account_id: :: near_sdk:: AccountId ) -> Option <bool > {
512
568
let role: #role_type = :: std:: convert:: TryFrom :: try_from( role. as_str( ) ) . unwrap_or_else( |_| :: near_sdk:: env:: panic_str( #ERR_PARSE_ROLE ) ) ;
513
- self . #acl_field . revoke_admin( role, & account_id)
569
+ self . acl_get_or_init ( ) . revoke_admin( role, & account_id)
514
570
}
515
571
516
572
fn acl_renounce_admin( & mut self , role: String ) -> bool {
517
573
let role: #role_type = :: std:: convert:: TryFrom :: try_from( role. as_str( ) ) . unwrap_or_else( |_| :: near_sdk:: env:: panic_str( #ERR_PARSE_ROLE ) ) ;
518
- self . #acl_field . renounce_admin( role)
574
+ self . acl_get_or_init ( ) . renounce_admin( role)
519
575
}
520
576
521
577
fn acl_revoke_role( & mut self , role: String , account_id: :: near_sdk:: AccountId ) -> Option <bool > {
522
578
let role: #role_type = :: std:: convert:: TryFrom :: try_from( role. as_str( ) ) . unwrap_or_else( |_| :: near_sdk:: env:: panic_str( #ERR_PARSE_ROLE ) ) ;
523
- self . #acl_field . revoke_role( role, & account_id)
579
+ self . acl_get_or_init ( ) . revoke_role( role, & account_id)
524
580
}
525
581
526
582
fn acl_renounce_role( & mut self , role: String ) -> bool {
527
583
let role: #role_type = :: std:: convert:: TryFrom :: try_from( role. as_str( ) ) . unwrap_or_else( |_| :: near_sdk:: env:: panic_str( #ERR_PARSE_ROLE ) ) ;
528
- self . #acl_field . renounce_role( role)
584
+ self . acl_get_or_init ( ) . renounce_role( role)
529
585
}
530
586
531
587
fn acl_grant_role( & mut self , role: String , account_id: :: near_sdk:: AccountId ) -> Option <bool > {
532
588
let role: #role_type = :: std:: convert:: TryFrom :: try_from( role. as_str( ) ) . unwrap_or_else( |_| :: near_sdk:: env:: panic_str( #ERR_PARSE_ROLE ) ) ;
533
- self . #acl_field . grant_role( role, & account_id)
589
+ self . acl_get_or_init ( ) . grant_role( role, & account_id)
534
590
}
535
591
536
592
537
593
fn acl_has_role( & self , role: String , account_id: :: near_sdk:: AccountId ) -> bool {
538
594
let role: #role_type = :: std:: convert:: TryFrom :: try_from( role. as_str( ) ) . unwrap_or_else( |_| :: near_sdk:: env:: panic_str( #ERR_PARSE_ROLE ) ) ;
539
- self . #acl_field . has_role( role, & account_id)
595
+ return_if_none! ( self . acl_get_storage ( ) , false ) . has_role( role, & account_id)
540
596
}
541
597
542
598
fn acl_has_any_role( & self , roles: Vec <String >, account_id: :: near_sdk:: AccountId ) -> bool {
@@ -546,61 +602,40 @@ pub fn access_controllable(attrs: TokenStream, item: TokenStream) -> TokenStream
546
602
:: std:: convert:: TryFrom :: try_from( role. as_str( ) ) . unwrap_or_else( |_| :: near_sdk:: env:: panic_str( #ERR_PARSE_ROLE ) )
547
603
} )
548
604
. collect( ) ;
549
- self . #acl_field . has_any_role( roles, & account_id)
605
+ return_if_none! ( self . acl_get_storage ( ) , false ) . has_any_role( roles, & account_id)
550
606
}
551
607
552
608
fn acl_get_super_admins( & self , skip: u64 , limit: u64 ) -> Vec <:: near_sdk:: AccountId > {
553
609
let permission = <#bitflags_type>:: from_bits(
554
610
<#role_type>:: acl_super_admin_permission( )
555
611
)
556
612
. unwrap_or_else( || :: near_sdk:: env:: panic_str( #ERR_PARSE_BITFLAG ) ) ;
557
- self . #acl_field . get_bearers( permission, skip, limit)
613
+ return_if_none! ( self . acl_get_storage ( ) , vec! [ ] ) . get_bearers( permission, skip, limit)
558
614
}
559
615
560
616
fn acl_get_admins( & self , role: String , skip: u64 , limit: u64 ) -> Vec <:: near_sdk:: AccountId > {
561
617
let role: #role_type = :: std:: convert:: TryFrom :: try_from( role. as_str( ) ) . unwrap_or_else( |_| :: near_sdk:: env:: panic_str( #ERR_PARSE_ROLE ) ) ;
562
618
let permission = <#bitflags_type>:: from_bits( role. acl_admin_permission( ) )
563
619
. unwrap_or_else( || :: near_sdk:: env:: panic_str( #ERR_PARSE_BITFLAG ) ) ;
564
- self . #acl_field . get_bearers( permission, skip, limit)
620
+ return_if_none! ( self . acl_get_storage ( ) , vec! [ ] ) . get_bearers( permission, skip, limit)
565
621
}
566
622
567
623
fn acl_get_grantees( & self , role: String , skip: u64 , limit: u64 ) -> Vec <:: near_sdk:: AccountId > {
568
624
let role: #role_type = :: std:: convert:: TryFrom :: try_from( role. as_str( ) ) . unwrap_or_else( |_| :: near_sdk:: env:: panic_str( #ERR_PARSE_ROLE ) ) ;
569
625
let permission = <#bitflags_type>:: from_bits( role. acl_permission( ) )
570
626
. unwrap_or_else( || :: near_sdk:: env:: panic_str( #ERR_PARSE_BITFLAG ) ) ;
571
- self . #acl_field . get_bearers( permission, skip, limit)
627
+ return_if_none! ( self . acl_get_storage ( ) , vec! [ ] ) . get_bearers( permission, skip, limit)
572
628
}
573
629
574
630
fn acl_get_permissioned_accounts( & self ) -> #cratename:: access_controllable:: PermissionedAccounts {
575
- self . #acl_field . get_permissioned_accounts( )
631
+ return_if_none! ( self . acl_get_storage ( ) , get_default_permissioned_accounts ( ) ) . get_permissioned_accounts( )
576
632
}
577
633
}
578
634
} ;
579
635
580
636
output. into ( )
581
637
}
582
638
583
- fn inject_acl_field (
584
- item : & mut ItemStruct ,
585
- field_name : & syn:: Ident ,
586
- acl_type : & syn:: Ident ,
587
- ) -> Result < ( ) , syn:: Error > {
588
- let fields = match item. fields {
589
- syn:: Fields :: Named ( ref mut fields) => fields,
590
- _ => {
591
- return Err ( syn:: Error :: new (
592
- item. ident . span ( ) ,
593
- "Expected to have named fields" ,
594
- ) )
595
- }
596
- } ;
597
-
598
- fields. named . push ( syn:: Field :: parse_named. parse2 ( quote ! {
599
- #field_name: #acl_type
600
- } ) ?) ;
601
- Ok ( ( ) )
602
- }
603
-
604
639
/// Defines attributes for the `access_control_any` macro.
605
640
#[ derive( Debug , FromMeta ) ]
606
641
pub struct MacroArgsAny {
0 commit comments