1
+ from json import loads , dumps
2
+ from urllib .request import urlopen , Request
3
+ from urllib .parse import urlencode
4
+ from urllib .error import HTTPError
5
+ import time
6
+ import sys
7
+ import os
8
+
9
+ tenantId = "72f988bf-86f1-41af-91ab-2d7cd011db47"
10
+ appId = "c2fe4cd0-be4a-468b-aa4f-078c67dcab6e"
11
+
12
+ uploadService = "https://perfcontrib.azurewebsites.net"
13
+ uploadEndpoint = f"{ uploadService } /api/UploadPerfData"
14
+ authEndpoint = f"{ uploadService } /.auth/login/aad"
15
+ authDetailsEndpoint = f"{ uploadService } /.auth/me"
16
+
17
+ aadUrl = f"https://login.microsoftonline.com/{ tenantId } "
18
+
19
+ def get_token () -> str :
20
+ path = os .path .expanduser ("~/.perfcontrib" )
21
+
22
+ token : str | None = None
23
+
24
+ try :
25
+ if not os .path .exists (path ):
26
+ os .makedirs (path )
27
+ with open (os .path .expanduser ("~/.perfcontrib/token" )) as tokenfile :
28
+ token = tokenfile .readline ()
29
+ except FileNotFoundError :
30
+ pass
31
+
32
+ if token :
33
+ try :
34
+ with urlopen (Request (authDetailsEndpoint ,
35
+ headers = { "X-ZUMO-AUTH" : token })) as response :
36
+ print ("Using cached credentials." )
37
+ except HTTPError as error :
38
+ token = None
39
+
40
+ if not token :
41
+ token = authenticate ()
42
+
43
+ if token :
44
+ with open (os .path .expanduser ("~/.perfcontrib/token" ), "w" ) as tokenfile :
45
+ tokenfile .write (token )
46
+
47
+ return token
48
+
49
+ def authenticate () -> str :
50
+ authBody = {
51
+ "tenant" : tenantId ,
52
+ "client_id" : appId ,
53
+ "scope" : "User.Read openid profile" ,
54
+ }
55
+
56
+ authBodyEncoded = urlencode (authBody ).encode ()
57
+
58
+ with urlopen (Request (f"{ aadUrl } /oauth2/v2.0/devicecode" , data = authBodyEncoded )) as response :
59
+ devicecodeResponse = loads (response .read ().decode ('utf-8' ))
60
+
61
+ print (devicecodeResponse ["message" ])
62
+
63
+ authBody2 = {
64
+ "tenant" : tenantId ,
65
+ "grant_type" : "urn:ietf:params:oauth:grant-type:device_code" ,
66
+ "client_id" : appId ,
67
+ "device_code" : devicecodeResponse ["device_code" ]
68
+ }
69
+
70
+ authBody2Encoded = urlencode (authBody2 ).encode ()
71
+
72
+ authStatus = "waiting"
73
+ print ("waiting" , end = "" , flush = True )
74
+ while (authStatus == "waiting" ):
75
+ # Try to get the access token. if we encounter an error check the reason.
76
+ # If the reason is we are waiting then sleep for some time.
77
+ # If the reason is the user has declined or we timed out then quit.
78
+ try :
79
+ with urlopen (Request (f"{ aadUrl } /oauth2/v2.0/token" , data = authBody2Encoded )) as response :
80
+ tokenResponse = loads (response .read ().decode ('utf-8' ))
81
+ authStatus = "done"
82
+ except Exception as ex :
83
+ reason = loads (ex .read ().decode ('utf-8' ))["error" ]
84
+ if reason == "authorization_pending" :
85
+ print ("." , end = "" , flush = True )
86
+ time .sleep (5 )
87
+ elif reason == "authorization_declined" :
88
+ authStatus = "failed"
89
+ elif reason == "expired_token" :
90
+ authStatus = "failed"
91
+
92
+ print ()
93
+
94
+ if authStatus == "failed" : raise "Authentication failed"
95
+
96
+ idToken = tokenResponse ["id_token" ]
97
+
98
+ print ("Thanks." )
99
+ authBody3 = {
100
+ "access_token" : idToken
101
+ }
102
+
103
+ authBody3Json = dumps (authBody3 ).encode ()
104
+
105
+ with urlopen (Request (authEndpoint ,
106
+ data = authBody3Json ,
107
+ headers = {"Content-Type" : "application/json" })) as response :
108
+ aadLoginResponse = loads (response .read ().decode ('utf-8' ))
109
+
110
+ token = aadLoginResponse ["authenticationToken" ]
111
+
112
+ return token
113
+
114
+ def upload (filename : str ) -> None :
115
+ token = get_token ()
116
+
117
+ print ("Uploading." )
118
+
119
+ with urlopen (Request (uploadEndpoint ,
120
+ headers = { "X-ZUMO-AUTH" : token , "Content-Type" : "application/octet-stream" , "X-Filename" : filename },
121
+ data = open (filename ,"rb" ))) as response :
122
+ print (response .read ().decode ('utf-8' ))
123
+
124
+ if __name__ == "__main__" :
125
+ upload (sys .argv [1 ])
0 commit comments