1- // Copyright (c) Microsoft Corporation.
2- // Licensed under the MIT License.
3-
4- using System . Net . Http . Json ;
5- using Microsoft . DevProxy . Plugins . MinimalPermissions ;
6- using Microsoft . Extensions . Logging ;
7- using Titanium . Web . Proxy . Http ;
8-
9- namespace Microsoft . DevProxy . Plugins ;
10-
11- public class GraphUtils
12- {
13- // throttle requests per workload
14- public static string BuildThrottleKey ( Request r ) => BuildThrottleKey ( r . RequestUri ) ;
15-
16- public static string BuildThrottleKey ( Uri uri )
17- {
18- if ( uri . Segments . Length < 3 )
19- {
20- return uri . Host ;
21- }
22-
23- // first segment is /
24- // second segment is Graph version (v1.0, beta)
25- // third segment is the workload (users, groups, etc.)
26- // segment can end with / if there are other segments following
27- var workload = uri . Segments [ 2 ] . Trim ( '/' ) ;
28-
29- // TODO: handle 'me' which is a proxy to other resources
30-
31- return workload ;
32- }
33-
34- internal static string GetScopeTypeString ( PermissionsType type )
35- {
36- return type switch
37- {
38- PermissionsType . Application => "Application" ,
39- PermissionsType . Delegated => "DelegatedWork" ,
40- _ => throw new InvalidOperationException ( $ "Unknown scope type: { type } ")
41- } ;
42- }
43-
44- internal static async Task < IEnumerable < string > > UpdateUserScopesAsync ( IEnumerable < string > minimalScopes , IEnumerable < ( string method , string url ) > endpoints , PermissionsType permissionsType , ILogger logger )
45- {
46- var userEndpoints = endpoints . Where ( e => e . url . Contains ( "/users/{" , StringComparison . OrdinalIgnoreCase ) ) ;
47- if ( ! userEndpoints . Any ( ) )
48- {
49- return minimalScopes ;
50- }
51-
52- var newMinimalScopes = new HashSet < string > ( minimalScopes ) ;
53-
54- var url = $ "https://graphexplorerapi.azurewebsites.net/permissions?scopeType={ GetScopeTypeString ( permissionsType ) } ";
55- using var httpClient = new HttpClient ( ) ;
56- var urls = userEndpoints . Select ( e => {
57- logger . LogDebug ( "Getting permissions for {method} {url}" , e . method , e . url ) ;
58- return $ "{ url } &requesturl={ e . url } &method={ e . method } ";
59- } ) ;
60- var tasks = urls . Select ( u => {
61- logger . LogTrace ( "Calling {url}..." , u ) ;
62- return httpClient . GetFromJsonAsync < PermissionInfo [ ] > ( u ) ;
63- } ) ;
64- await Task . WhenAll ( tasks ) ;
65-
66- foreach ( var task in tasks )
67- {
68- var response = await task ;
69- if ( response is null )
70- {
71- continue ;
72- }
73-
74- // there's only one scope so it must be minimal already
75- if ( response . Length < 2 )
76- {
77- continue ;
78- }
79-
80- if ( newMinimalScopes . Contains ( response [ 0 ] . Value ) )
81- {
82- logger . LogDebug ( "Replacing scope {old} with {new}" , response [ 0 ] . Value , response [ 1 ] . Value ) ;
83- newMinimalScopes . Remove ( response [ 0 ] . Value ) ;
84- newMinimalScopes . Add ( response [ 1 ] . Value ) ;
85- }
86- }
87-
88- logger . LogDebug ( "Updated minimal scopes. Original: {original}, New: {new}" , string . Join ( ", " , minimalScopes ) , string . Join ( ", " , newMinimalScopes ) ) ;
89-
90- return newMinimalScopes ;
91- }
1+ // Copyright (c) Microsoft Corporation.
2+ // Licensed under the MIT License.
3+
4+ using System . Net . Http . Json ;
5+ using Microsoft . DevProxy . Plugins . MinimalPermissions ;
6+ using Microsoft . Extensions . Logging ;
7+ using Titanium . Web . Proxy . Http ;
8+
9+ namespace Microsoft . DevProxy . Plugins ;
10+
11+ public class GraphUtils
12+ {
13+ // throttle requests per workload
14+ public static string BuildThrottleKey ( Request r ) => BuildThrottleKey ( r . RequestUri ) ;
15+
16+ public static string BuildThrottleKey ( Uri uri )
17+ {
18+ if ( uri . Segments . Length < 3 )
19+ {
20+ return uri . Host ;
21+ }
22+
23+ // first segment is /
24+ // second segment is Graph version (v1.0, beta)
25+ // third segment is the workload (users, groups, etc.)
26+ // segment can end with / if there are other segments following
27+ var workload = uri . Segments [ 2 ] . Trim ( '/' ) ;
28+
29+ // TODO: handle 'me' which is a proxy to other resources
30+
31+ return workload ;
32+ }
33+
34+ internal static string GetScopeTypeString ( GraphPermissionsType type )
35+ {
36+ return type switch
37+ {
38+ GraphPermissionsType . Application => "Application" ,
39+ GraphPermissionsType . Delegated => "DelegatedWork" ,
40+ _ => throw new InvalidOperationException ( $ "Unknown scope type: { type } ")
41+ } ;
42+ }
43+
44+ internal static async Task < IEnumerable < string > > UpdateUserScopesAsync ( IEnumerable < string > minimalScopes , IEnumerable < ( string method , string url ) > endpoints , GraphPermissionsType permissionsType , ILogger logger )
45+ {
46+ var userEndpoints = endpoints . Where ( e => e . url . Contains ( "/users/{" , StringComparison . OrdinalIgnoreCase ) ) ;
47+ if ( ! userEndpoints . Any ( ) )
48+ {
49+ return minimalScopes ;
50+ }
51+
52+ var newMinimalScopes = new HashSet < string > ( minimalScopes ) ;
53+
54+ var url = $ "https://graphexplorerapi.azurewebsites.net/permissions?scopeType={ GetScopeTypeString ( permissionsType ) } ";
55+ using var httpClient = new HttpClient ( ) ;
56+ var urls = userEndpoints . Select ( e => {
57+ logger . LogDebug ( "Getting permissions for {method} {url}" , e . method , e . url ) ;
58+ return $ "{ url } &requesturl={ e . url } &method={ e . method } ";
59+ } ) ;
60+ var tasks = urls . Select ( u => {
61+ logger . LogTrace ( "Calling {url}..." , u ) ;
62+ return httpClient . GetFromJsonAsync < GraphPermissionInfo [ ] > ( u ) ;
63+ } ) ;
64+ await Task . WhenAll ( tasks ) ;
65+
66+ foreach ( var task in tasks )
67+ {
68+ var response = await task ;
69+ if ( response is null )
70+ {
71+ continue ;
72+ }
73+
74+ // there's only one scope so it must be minimal already
75+ if ( response . Length < 2 )
76+ {
77+ continue ;
78+ }
79+
80+ if ( newMinimalScopes . Contains ( response [ 0 ] . Value ) )
81+ {
82+ logger . LogDebug ( "Replacing scope {old} with {new}" , response [ 0 ] . Value , response [ 1 ] . Value ) ;
83+ newMinimalScopes . Remove ( response [ 0 ] . Value ) ;
84+ newMinimalScopes . Add ( response [ 1 ] . Value ) ;
85+ }
86+ }
87+
88+ logger . LogDebug ( "Updated minimal scopes. Original: {original}, New: {new}" , string . Join ( ", " , minimalScopes ) , string . Join ( ", " , newMinimalScopes ) ) ;
89+
90+ return newMinimalScopes ;
91+ }
9292}
0 commit comments