1- import logging , multiprocessing , os , platform , secrets , time , urllib .parse
1+ import multiprocessing , secrets , time , urllib .parse
22from .NetworkUtils import NetworkUtils
3- from flask import Flask , request
3+ from http .server import BaseHTTPRequestHandler , HTTPServer
4+ from urllib .parse import urlparse , parse_qs
5+ from functools import partial
6+
7+
8+ class CredentialRequestHandler (BaseHTTPRequestHandler ):
9+ def __init__ (self , username : str , password : str , token : str , * args , ** kwargs ):
10+ self .username = username
11+ self .password = password
12+ self .token = token
13+ super ().__init__ (* args , ** kwargs )
14+
15+ def log_request (self , code : str = "-" , size : str = "-" ) -> None :
16+ # We do not want to log each and every incoming request
17+ pass
18+
19+ def do_POST (self ):
20+ query_components = parse_qs (urlparse (self .path ).query )
21+
22+ self .send_response (200 )
23+ self .end_headers ()
24+
25+ if "token" in query_components and query_components ["token" ][0 ] == self .token :
26+ content_length = int (self .headers ["Content-Length" ])
27+ prompt = self .rfile .read (content_length ).decode ("utf-8" )
28+
29+ response = self .password if "Password for" in prompt else self .username
30+ self .wfile .write (response .encode ("utf-8" ))
431
532
633class CredentialEndpoint (object ):
7- def __init__ (self , username , password ):
34+ def __init__ (self , username : str , password : str ):
835 """
936 Creates an endpoint manager for the supplied credentials
1037 """
@@ -17,7 +44,7 @@ def __init__(self, username, password):
1744 # Generate a security token to require when requesting credentials
1845 self .token = secrets .token_hex (16 )
1946
20- def args (self ):
47+ def args (self ) -> [ str ] :
2148 """
2249 Returns the Docker build arguments for creating containers that require Git credentials
2350 """
@@ -33,7 +60,7 @@ def args(self):
3360 "HOST_TOKEN_ARG=" + urllib .parse .quote_plus (self .token ),
3461 ]
3562
36- def start (self ):
63+ def start (self ) -> None :
3764 """
3865 Starts the HTTP endpoint as a child process
3966 """
@@ -49,36 +76,22 @@ def start(self):
4976 time .sleep (2 )
5077
5178 # Verify that the endpoint started correctly
52- if self .endpoint .is_alive () == False :
79+ if not self .endpoint .is_alive ():
5380 raise RuntimeError ("failed to start the credential endpoint" )
5481
55- def stop (self ):
82+ def stop (self ) -> None :
5683 """
5784 Stops the HTTP endpoint child process
5885 """
5986 self .endpoint .terminate ()
6087 self .endpoint .join ()
6188
6289 @staticmethod
63- def _endpoint (username , password , token ) :
90+ def _endpoint (username : str , password : str , token : str ) -> None :
6491 """
6592 Implements a HTTP endpoint to provide Git credentials to Docker containers
6693 """
67- server = Flask (__name__ )
68-
69- # Disable the first-run banner message
70- os .environ ["WERKZEUG_RUN_MAIN" ] = "true"
71-
72- # Disable Flask log output (from <https://stackoverflow.com/a/18379764>)
73- log = logging .getLogger ("werkzeug" )
74- log .setLevel (logging .ERROR )
75-
76- @server .route ("/" , methods = ["POST" ])
77- def credentials ():
78- if "token" in request .args and request .args ["token" ] == token :
79- prompt = request .data .decode ("utf-8" )
80- return password if "Password for" in prompt else username
81- else :
82- return "Invalid security token"
94+ handler = partial (CredentialRequestHandler , username , password , token )
8395
84- server .run (host = "0.0.0.0" , port = 9876 )
96+ server = HTTPServer (("0.0.0.0" , 9876 ), RequestHandlerClass = handler )
97+ server .serve_forever ()
0 commit comments