@@ -20,7 +20,7 @@ use std::{
20
20
21
21
use graphql_parser:: {
22
22
query:: { Mutation , Query , SelectionSet } ,
23
- schema:: ObjectType ,
23
+ schema:: { EnumType , EnumValue , ObjectType } ,
24
24
} ;
25
25
26
26
use graphql_parser:: {
@@ -118,7 +118,7 @@ impl fmt::Display for Error {
118
118
}
119
119
120
120
struct PermissionsAndNextSelection < ' a , ' b > {
121
- permission_vec : Vec < String > ,
121
+ permission_vec : Vec < & ' a str > ,
122
122
next_selection : NextSelection < ' a , ' b > ,
123
123
}
124
124
@@ -130,7 +130,7 @@ struct NextSelection<'a, 'b> {
130
130
fn parse_grapqhql_schema < ' a : ' b , ' b > (
131
131
schema_doc : & ' a [ graphql_parser:: schema:: Definition < ' a , & ' a str > ] ,
132
132
query_doc : & ' b [ graphql_parser:: query:: Definition < ' b , & ' b str > ] ,
133
- ) -> Vec < String > {
133
+ ) -> Vec < & ' a str > {
134
134
let mut permission_list = vec ! [ ] ;
135
135
136
136
// dequeue of (parsed_query_selection: SelectionSet, schema_type_field: Field)
@@ -272,7 +272,7 @@ fn get_type_or_typex_with_name<'a, 'b>(
272
272
. flatten ( )
273
273
}
274
274
275
- fn get_field_directives < ' a > ( field : & ' a graphql_parser:: schema:: Field < ' _ , & ' a str > ) -> Vec < String > {
275
+ fn get_field_directives < ' a > ( field : & ' a graphql_parser:: schema:: Field < ' _ , & ' a str > ) -> Vec < & ' a str > {
276
276
let mut perm_vec = vec ! [ ] ;
277
277
field. directives . iter ( ) . for_each ( |directive| {
278
278
if directive. name == "scopes" {
@@ -281,7 +281,7 @@ fn get_field_directives<'a>(field: &'a graphql_parser::schema::Field<'_, &'a str
281
281
if let query:: Value :: List ( val) = & arg. 1 {
282
282
val. iter ( ) . for_each ( |val| {
283
283
if let query:: Value :: Enum ( en) = val {
284
- perm_vec. push ( en . to_string ( ) ) ;
284
+ perm_vec. push ( * en ) ;
285
285
}
286
286
} ) ;
287
287
}
@@ -295,7 +295,7 @@ fn get_field_directives<'a>(field: &'a graphql_parser::schema::Field<'_, &'a str
295
295
fn check_graphql_and_perms < ' a > (
296
296
val : & ' a Value ,
297
297
path : & ' a graphql_parser:: schema:: Document < ' a , & ' a str > ,
298
- ) -> Vec < String > {
298
+ ) -> Vec < & ' a str > {
299
299
let mut operations = vec ! [ ] ;
300
300
301
301
match val {
@@ -488,7 +488,7 @@ pub(crate) fn scan_directory<'a>(
488
488
) ;
489
489
reporter. add_app ( opts. appkey . clone ( ) . unwrap_or_default ( ) , name. to_owned ( ) ) ;
490
490
491
- let mut perm_interp = Interp :: < PermissionChecker > :: new (
491
+ let mut perm_interp = Interp :: < PermissionChecker < ' _ > > :: new (
492
492
& proj. env ,
493
493
false ,
494
494
true ,
@@ -618,6 +618,40 @@ pub(crate) fn scan_directory<'a>(
618
618
& mut path. to_owned ( )
619
619
} ;
620
620
621
+ let mut scope_path = path. clone ( ) ;
622
+
623
+ scope_path. push ( "schema/shared/agg-shared-scopes.nadel" ) ;
624
+
625
+ let scope_map = fs:: read_to_string ( & scope_path) . unwrap_or_default ( ) ;
626
+
627
+ let ast = parse_schema :: < & str > ( & scope_map) . unwrap_or_default ( ) ;
628
+
629
+ let mut scope_name_to_oauth = HashMap :: new ( ) ;
630
+
631
+ ast. definitions . iter ( ) . for_each ( |val| {
632
+ if let graphql_parser:: schema:: Definition :: TypeDefinition ( TypeDefinition :: Enum (
633
+ EnumType { values, .. } ,
634
+ ) ) = val
635
+ {
636
+ values. iter ( ) . for_each (
637
+ |EnumValue {
638
+ directives, name, ..
639
+ } | {
640
+ if let Some ( directive) = directives. first ( ) {
641
+ if let graphql_parser:: schema:: Value :: String ( oauth_scope) = & directive
642
+ . arguments
643
+ . first ( )
644
+ . expect ( "Should only be one directive" )
645
+ . 1
646
+ {
647
+ scope_name_to_oauth. insert ( * name, & * * oauth_scope) ;
648
+ }
649
+ }
650
+ } ,
651
+ )
652
+ }
653
+ } ) ;
654
+
621
655
path. push ( "schema/*/*.nadel" ) ;
622
656
623
657
let joined_schema = glob ( path. to_str ( ) . unwrap_or_default ( ) )
@@ -629,21 +663,21 @@ pub(crate) fn scan_directory<'a>(
629
663
let ast = parse_schema :: < & str > ( & joined_schema) ;
630
664
631
665
if let std:: result:: Result :: Ok ( doc) = ast {
632
- let mut used_graphql_perms: Vec < String > = definition_analysis_interp
666
+ let mut used_graphql_perms: Vec < & str > = definition_analysis_interp
633
667
. value_manager
634
668
. varid_to_value_with_proj
635
669
. values ( )
636
670
. flat_map ( |val| check_graphql_and_perms ( val, & doc) )
637
671
. collect ( ) ;
638
672
639
- let graphql_perms_varid: Vec < String > = definition_analysis_interp
673
+ let graphql_perms_varid: Vec < & str > = definition_analysis_interp
640
674
. value_manager
641
675
. varid_to_value
642
676
. values ( )
643
677
. flat_map ( |val| check_graphql_and_perms ( val, & doc) )
644
678
. collect ( ) ;
645
679
646
- let graphql_perms_defid: Vec < String > = definition_analysis_interp
680
+ let graphql_perms_defid: Vec < & str > = definition_analysis_interp
647
681
. value_manager
648
682
. defid_to_value
649
683
. values ( )
@@ -653,14 +687,26 @@ pub(crate) fn scan_directory<'a>(
653
687
used_graphql_perms. extend_from_slice ( & graphql_perms_defid) ;
654
688
used_graphql_perms. extend_from_slice ( & graphql_perms_varid) ;
655
689
656
- let final_perms: Vec < & String > = perm_interp
690
+ let oauth_scopes: HashSet < & str > = used_graphql_perms
691
+ . iter ( )
692
+ . copied ( )
693
+ . filter_map ( |val| {
694
+ if !scope_name_to_oauth. contains_key ( & val) {
695
+ warn ! ( "Scope is not contained in the scope definitions" )
696
+ }
697
+
698
+ scope_name_to_oauth. get ( & val) . copied ( )
699
+ } )
700
+ . collect ( ) ;
701
+
702
+ let final_perms: HashSet < & String > = perm_interp
657
703
. permissions
658
704
. iter ( )
659
- . filter ( |f| !used_graphql_perms . contains ( & * * f ) )
705
+ . filter ( |f| !oauth_scopes . contains ( f . as_str ( ) ) )
660
706
. collect ( ) ;
661
707
662
708
if run_permission_checker && !final_perms. is_empty ( ) {
663
- reporter. add_vulnerabilities ( [ PermissionVuln :: new ( perm_interp . permissions ) ] ) ;
709
+ reporter. add_vulnerabilities ( [ PermissionVuln :: new ( final_perms ) ] ) ;
664
710
}
665
711
}
666
712
0 commit comments