Projects STRLCPY got-your-back Commits 5030dd38
🤬
  • ■ ■ ■ ■ ■
    gyb.py
    skipped 45 lines
    46 46  import sys
    47 47  import os
    48 48  import os.path
     49 +import ipaddress
     50 +import multiprocessing
     51 +from socket import gethostbyname
     52 +from urllib.parse import urlencode, urlparse, parse_qs
     53 +import wsgiref.simple_server
     54 +import wsgiref.util
    49 55  import time
    50 56  import calendar
    51 57  import random
    skipped 795 lines
    847 853   print(content)
    848 854   return long_url
    849 855   
     856 +def _localhost_to_ip():
     857 + '''returns IPv4 or IPv6 loopback address which localhost resolves to.
     858 + If localhost does not resolve to valid loopback IP address then returns
     859 + 127.0.0.1'''
     860 + # TODO gethostbyname() will only ever return ipv4
     861 + # find a way to support IPv6 here and get preferred IP
     862 + # note that IPv6 may be broken on some systems also :-(
     863 + # for now IPv4 should do.
     864 + local_ip = gethostbyname('localhost')
     865 + local_ipaddress = ipaddress.ip_address(local_ip)
     866 + ip4_local_range = ipaddress.ip_network('127.0.0.0/8')
     867 + ip6_local_range = ipaddress.ip_network('::1/128')
     868 + if local_ipaddress not in ip4_local_range and \
     869 + local_ipaddress not in ip6_local_range:
     870 + local_ip = '127.0.0.1'
     871 + return local_ip
     872 + 
     873 +def _wait_for_http_client(d):
     874 + wsgi_app = google_auth_oauthlib.flow._RedirectWSGIApp(MESSAGE_LOCAL_SERVER_SUCCESS)
     875 + wsgiref.simple_server.WSGIServer.allow_reuse_address = False
     876 + # Convert hostn to IP since apparently binding to the IP
     877 + # reduces odds of firewall blocking us
     878 + local_ip = _localhost_to_ip()
     879 + for port in range(8080, 8099):
     880 + try:
     881 + local_server = wsgiref.simple_server.make_server(
     882 + local_ip,
     883 + port,
     884 + wsgi_app,
     885 + handler_class=wsgiref.simple_server.WSGIRequestHandler
     886 + )
     887 + break
     888 + except OSError:
     889 + pass
     890 + redirect_uri_format = (
     891 + "http://{}:{}/" if d['trailing_slash'] else "http://{}:{}"
     892 + )
     893 + # provide redirect_uri to main process so it can formulate auth_url
     894 + d['redirect_uri'] = redirect_uri_format.format(*local_server.server_address)
     895 + # wait until main process provides auth_url
     896 + # so we can open it in web browser.
     897 + while 'auth_url' not in d:
     898 + time.sleep(0.1)
     899 + if d['open_browser']:
     900 + webbrowser.open(d['auth_url'], new=1, autoraise=True)
     901 + local_server.handle_request()
     902 + authorization_response = wsgi_app.last_request_uri.replace("http", "https")
     903 + d['code'] = authorization_response
     904 + local_server.server_close()
     905 + 
     906 +def _wait_for_user_input(d):
     907 + sys.stdin = open(0)
     908 + code = input(MESSAGE_CONSOLE_AUTHORIZATION_CODE)
     909 + d['code'] = code
     910 + 
     911 +MESSAGE_CONSOLE_AUTHORIZATION_PROMPT = '''\nGo to the following link in your browser:
     912 +\n\t{url}\n
     913 +IMPORTANT: If you get a browser error that the site can't be reached AFTER you
     914 +click the Allow button, copy the URL from the browser where the error occurred
     915 +and paste that here instead.
     916 +'''
     917 +MESSAGE_CONSOLE_AUTHORIZATION_CODE = 'Enter verification code or browser URL: '
     918 +MESSAGE_LOCAL_SERVER_SUCCESS = ('The authentication flow has completed. You may'
     919 + ' close this browser window and return to GAM.')
     920 + 
     921 +MESSAGE_AUTHENTICATION_COMPLETE = ('\nThe authentication flow has completed.\n')
     922 + 
    850 923  class ShortURLFlow(google_auth_oauthlib.flow.InstalledAppFlow):
    851  - def authorization_url(self, **kwargs):
    852  - long_url, state = super(ShortURLFlow, self).authorization_url(**kwargs)
    853  - short_url = shorten_url(long_url)
    854  - return short_url, state
     924 + def authorization_url(self, **kwargs):
     925 + long_url, state = super(ShortURLFlow, self).authorization_url(**kwargs)
     926 + short_url = shorten_url(long_url)
     927 + return short_url, state
     928 + 
     929 + 
     930 + def run_dual(self,
     931 + use_console_flow,
     932 + authorization_prompt_message='',
     933 + console_prompt_message='',
     934 + web_success_message='',
     935 + open_browser=True,
     936 + redirect_uri_trailing_slash=True,
     937 + **kwargs):
     938 + mgr = multiprocessing.Manager()
     939 + d = mgr.dict()
     940 + d['trailing_slash'] = redirect_uri_trailing_slash
     941 + d['open_browser'] = use_console_flow
     942 + http_client = multiprocessing.Process(target=_wait_for_http_client,
     943 + args=(d,))
     944 + user_input = multiprocessing.Process(target=_wait_for_user_input,
     945 + args=(d,))
     946 + http_client.start()
     947 + # we need to wait until web server starts on avail port
     948 + # so we know redirect_uri to use
     949 + while 'redirect_uri' not in d:
     950 + time.sleep(0.1)
     951 + self.redirect_uri = d['redirect_uri']
     952 + d['auth_url'], _ = self.authorization_url(**kwargs)
     953 + print(MESSAGE_CONSOLE_AUTHORIZATION_PROMPT.format(url=d['auth_url']))
     954 + user_input.start()
     955 + userInput = False
     956 + while True:
     957 + time.sleep(0.1)
     958 + if not http_client.is_alive():
     959 + user_input.terminate()
     960 + break
     961 + elif not user_input.is_alive():
     962 + userInput = True
     963 + http_client.terminate()
     964 + break
     965 + while True:
     966 + code = d['code']
     967 + if code.startswith('http'):
     968 + parsed_url = urlparse(code)
     969 + parsed_params = parse_qs(parsed_url.query)
     970 + code = parsed_params.get('code', [None])[0]
     971 + try:
     972 + self.fetch_token(code=code)
     973 + break
     974 + except Exception as e:
     975 + if not userInput:
     976 + controlflow.system_error_exit(8, str(e))
     977 + display.print_error(str(e))
     978 + _wait_for_user_input(d)
     979 + sys.stdout.write(MESSAGE_AUTHENTICATION_COMPLETE)
     980 + return self.credentials
    855 981   
    856  -MESSAGE_CONSOLE_AUTHORIZATION_PROMPT = '\nGo to the following link in your browser:\n\n\t{url}\n'
    857  -MESSAGE_CONSOLE_AUTHORIZATION_CODE = 'Enter verification code: '
    858  -MESSAGE_LOCAL_SERVER_AUTHORIZATION_PROMPT = '\nYour browser has been opened to visit:\n\n\t{url}\n\nIf your browser is on a different machine then press CTRL+C and delete the oauthbrowser.txt file in the same folder as GYB.\n'
    859  -MESSAGE_LOCAL_SERVER_SUCCESS = 'The authentication flow has completed. You may close this browser window and return to GYB.'
    860 982  def _run_oauth_flow(client_id, client_secret, scopes, access_type, login_hint=None):
    861 983   client_config = {
    862 984   'installed': {
    skipped 9 lines
    872 994   kwargs['login_hint'] = login_hint
    873 995   # Needs to be set so oauthlib doesn't puke when Google changes our scopes
    874 996   os.environ['OAUTHLIB_RELAX_TOKEN_SCOPE'] = 'true'
    875  - if not os.path.isfile(os.path.join(options.config_folder, 'oauthbrowser.txt')):
    876  - flow.run_console(
    877  - authorization_prompt_message=MESSAGE_CONSOLE_AUTHORIZATION_PROMPT,
    878  - authorization_code_message=MESSAGE_CONSOLE_AUTHORIZATION_CODE,
    879  - **kwargs)
    880  - else:
    881  - flow.run_local_server(
    882  - authorization_prompt_message=MESSAGE_LOCAL_SERVER_AUTHORIZATION_PROMPT,
    883  - success_message=MESSAGE_LOCAL_SERVER_SUCCESS,
    884  - **kwargs)
     997 + flow.run_dual(use_console_flow=True, **kwargs)
    885 998   return flow.credentials
    886 999   
    887 1000  def getCRMService(login_hint):
    skipped 1658 lines
Please wait...
Page is in error, reload to recover