15
15
try : # Python 3
16
16
from http .server import HTTPServer , BaseHTTPRequestHandler
17
17
from urllib .parse import urlparse , parse_qs , urlencode
18
+ from html import escape
18
19
except ImportError : # Fall back to Python 2
19
20
from BaseHTTPServer import HTTPServer , BaseHTTPRequestHandler
20
21
from urlparse import urlparse , parse_qs
21
22
from urllib import urlencode
23
+ from cgi import escape
22
24
23
25
24
26
logger = logging .getLogger (__name__ )
@@ -77,25 +79,37 @@ def _qs2kv(qs):
77
79
for k , v in qs .items ()}
78
80
79
81
82
+ def _is_html (text ):
83
+ return text .startswith ("<" ) # Good enough for our purpose
84
+
85
+
86
+ def _escape (key_value_pairs ):
87
+ return {k : escape (v ) for k , v in key_value_pairs .items ()}
88
+
89
+
80
90
class _AuthCodeHandler (BaseHTTPRequestHandler ):
81
91
def do_GET (self ):
82
92
# For flexibility, we choose to not check self.path matching redirect_uri
83
93
#assert self.path.startswith('/THE_PATH_REGISTERED_BY_THE_APP')
84
94
qs = parse_qs (urlparse (self .path ).query )
85
95
if qs .get ('code' ) or qs .get ("error" ): # So, it is an auth response
86
- self . server . auth_response = _qs2kv (qs )
87
- logger .debug ("Got auth response: %s" , self . server . auth_response )
96
+ auth_response = _qs2kv (qs )
97
+ logger .debug ("Got auth response: %s" , auth_response )
88
98
template = (self .server .success_template
89
99
if "code" in qs else self .server .error_template )
90
- self ._send_full_response (
91
- template .safe_substitute (** self .server .auth_response ))
100
+ if _is_html (template .template ):
101
+ safe_data = _escape (auth_response )
102
+ else :
103
+ safe_data = auth_response
104
+ self ._send_full_response (template .safe_substitute (** safe_data ))
105
+ self .server .auth_response = auth_response # Set it now, after the response is likely sent
92
106
# NOTE: Don't do self.server.shutdown() here. It'll halt the server.
93
107
else :
94
108
self ._send_full_response (self .server .welcome_page )
95
109
96
110
def _send_full_response (self , body , is_ok = True ):
97
111
self .send_response (200 if is_ok else 400 )
98
- content_type = 'text/html' if body . startswith ( '<' ) else 'text/plain'
112
+ content_type = 'text/html' if _is_html ( body ) else 'text/plain'
99
113
self .send_header ('Content-type' , content_type )
100
114
self .end_headers ()
101
115
self .wfile .write (body .encode ("utf-8" ))
@@ -318,6 +332,7 @@ def __exit__(self, exc_type, exc_val, exc_tb):
318
332
default = "https://login.microsoftonline.com/common/oauth2/v2.0/authorize" )
319
333
p .add_argument ('client_id' , help = "The client_id of your application" )
320
334
p .add_argument ('--port' , type = int , default = 0 , help = "The port in redirect_uri" )
335
+ p .add_argument ('--timeout' , type = int , default = 60 , help = "Timeout value, in second" )
321
336
p .add_argument ('--host' , default = "127.0.0.1" , help = "The host of redirect_uri" )
322
337
p .add_argument ('--scope' , default = None , help = "The scope list" )
323
338
args = parser .parse_args ()
@@ -331,8 +346,8 @@ def __exit__(self, exc_type, exc_val, exc_tb):
331
346
auth_uri = flow ["auth_uri" ],
332
347
welcome_template =
333
348
"<a href='$auth_uri'>Sign In</a>, or <a href='$abort_uri'>Abort</a" ,
334
- error_template = "Oh no. $error" ,
349
+ error_template = "<html> Oh no. $error</html> " ,
335
350
success_template = "Oh yeah. Got $code" ,
336
- timeout = 60 ,
351
+ timeout = args . timeout ,
337
352
state = flow ["state" ], # Optional
338
353
), indent = 4 ))
0 commit comments