diff --git a/src/gam.py b/src/gam.py index cb930a99..ae4bf86d 100755 --- a/src/gam.py +++ b/src/gam.py @@ -71,9 +71,7 @@ from oauth2client.contrib.dictionary_storage import DictionaryStorage import utils from var import * -# Nasty hack to support StaticX. -# - we do this in gam.py because if we do it in var.py StaticX can't get right path at all. -# - StaticX is frozen but it seems to mix up the path checking results. +# Finding path method varies between Python source, PyInstaller and StaticX if os.environ.get('STATICX_PROG_PATH', False): # StaticX static executable GM_Globals[GM_GAM_PATH] = os.path.dirname(os.environ['STATICX_PROG_PATH']) @@ -84,6 +82,21 @@ else: # Source code GM_Globals[GM_GAM_PATH] = os.path.dirname(os.path.realpath(__file__)) +# override httplib2._build_ssl_context so we can force min/max TLS values +# actual function replacement happens in processGAM command so we have config options set +def _build_ssl_context(disable_ssl_certificate_validation, ca_certs, cert_file=None, key_file=None): + context = ssl.SSLContext(httplib2.DEFAULT_TLS_VERSION) + context.verify_mode = ssl.CERT_REQUIRED + context.check_hostname = True + context.load_verify_locations(ca_certs) + if cert_file: + context.load_cert_chain(cert_file, key_file) + if GC_Values[GC_TLS_MIN_VERSION]: + context.minimum_version = getattr(ssl.TLSVersion, GC_Values[GC_TLS_MIN_VERSION]) + if GC_Values[GC_TLS_MAX_VERSION]: + context.maximum_version = getattr(ssl.TLSVersion, GC_Values[GC_TLS_MAX_VERSION]) + return context + # Override some oauth2client.tools strings saving us a few GAM-specific mods to oauth2client oauth2client.tools._FAILED_START_MESSAGE = """ Failed to start a local webserver listening on either port 8080 @@ -569,6 +582,8 @@ def SetGlobalVariables(): _getOldEnvVar(GC_USER_MAX_RESULTS, 'GAM_USER_MAX_RESULTS') _getOldEnvVar(GC_CSV_HEADER_FILTER, 'GAM_CSV_HEADER_FILTER') _getOldEnvVar(GC_CSV_ROW_FILTER, 'GAM_CSV_ROW_FILTER') + _getOldEnvVar(GC_TLS_MIN_VERSION, 'GAM_TLS_MIN_VERSION') + _getOldEnvVar(GC_TLS_MAX_VERSION, 'GAM_TLS_MAX_VERSION') _getOldSignalFile(GC_DEBUG_LEVEL, 'debug.gam', filePresentValue=4, fileAbsentValue=0) _getOldSignalFile(GC_NO_VERIFY_SSL, 'noverifyssl.txt') _getOldSignalFile(GC_NO_BROWSER, 'nobrowser.txt') @@ -692,12 +707,9 @@ def doGAMVersion(checkForArgs=True): doGAMCheckForUpdates(forceCheck=True) if extended: print(ssl.OPENSSL_VERSION) - proot = os.path.dirname(importlib.import_module('httplib2').__file__) - ca_path = os.path.join(proot, 'cacerts.txt') - s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - ssl_sock = ssl.wrap_socket(s, cert_reqs=ssl.CERT_NONE, ca_certs=ca_path) - ssl_sock.connect(('www.googleapis.com', 443)) - cipher_name, tls_ver, _ = ssl_sock.cipher() + httpc = httplib2.Http() + httpc.request('https://www.googleapis.com') + cipher_name, tls_ver, _ = httpc.connections['https:www.googleapis.com'].sock.cipher() print('www.googleapis.com connects using %s %s' % (tls_ver, cipher_name)) def handleOAuthTokenError(e, soft_errors): @@ -13252,6 +13264,8 @@ def ProcessGAMCommand(args): GM_Globals[GM_SYSEXITRC] = 0 try: SetGlobalVariables() + # override here so we have GV set + httplib2._build_ssl_context = _build_ssl_context command = sys.argv[1].lower() if command == 'batch': i = 2 @@ -14038,6 +14052,6 @@ if __name__ == "__main__": if sys.platform.startswith('win'): freeze_support() win32_unicode_argv() # cleanup sys.argv on Windows - if sys.version_info[0] < 3 or sys.version_info[1] < 5: - systemErrorExit(5, 'GAM requires Python 3.5 or newer. You are running %s.%s.%s. Please upgrade your Python version or use one of the binary GAM downloads.' % sys.version_info[:3]) + if sys.version_info[0] < 3 or sys.version_info[1] < 7: + systemErrorExit(5, 'GAM requires Python 3.7 or newer. You are running %s.%s.%s. Please upgrade your Python version or use one of the binary GAM downloads.' % sys.version_info[:3]) sys.exit(ProcessGAMCommand(sys.argv)) diff --git a/src/travis/linux-x86_64-install.sh b/src/travis/linux-x86_64-install.sh index 132f0908..6816630d 100755 --- a/src/travis/linux-x86_64-install.sh +++ b/src/travis/linux-x86_64-install.sh @@ -8,7 +8,7 @@ cp GamCommands.txt gam this_glibc_ver=$(ldd --version | awk '/ldd/{print $NF}') GAM_ARCHIVE=gam-$GAMVERSION-$GAMOS-$PLATFORM-$this_glibc_ver.tar.xz tar cfJ $GAM_ARCHIVE gam/ -echo "PyInstaller GAM info:" +echo "PyInstaller GAM info:" du -h gam/gam time gam/gam version extended @@ -17,9 +17,9 @@ if [[ "$dist" == "xenial" ]]; then $python -OO -m staticx gam/gam gam/gam-staticx strip gam/gam-staticx rm gam/gam - cp staticx-gam.sh gam/gam + mv gam/gam-staticx gam/gam tar cfJ $GAM_LEGACY_ARCHIVE gam/ echo "Legacy StaticX GAM info:" - du -h gam/gam-staticx + du -h gam/gam time gam/gam version extended fi diff --git a/src/var.py b/src/var.py index c4019f55..61146161 100644 --- a/src/var.py +++ b/src/var.py @@ -629,6 +629,7 @@ GM_CACHE_DISCOVERY_ONLY = 'gcdo' GM_MAP_BUILDING_ID_TO_NAME = 'bi2n' # Dictionary mapping Building Name to ID GM_MAP_BUILDING_NAME_TO_ID = 'bn2i' + # _DEFAULT_CHARSET = ['mbcs', 'utf-8'][os.name != 'nt'] _FN_CLIENT_SECRETS_JSON = 'client_secrets.json' @@ -720,6 +721,10 @@ GC_USER_MAX_RESULTS = 'user_max_results' GC_CSV_HEADER_FILTER = 'csv_header_filter' # CSV Rows GAM should filter GC_CSV_ROW_FILTER = 'csv_row_filter' +# Minimum TLS Version required for HTTPS connections +GC_TLS_MIN_VERSION = 'tls_min_ver' +# Maximum TLS Version used for HTTPS connections +GC_TLS_MAX_VERSION = 'tls_max_ver' GC_Defaults = { GC_ACTIVITY_MAX_RESULTS: 100, @@ -751,6 +756,8 @@ GC_Defaults = { GC_USER_MAX_RESULTS: 500, GC_CSV_HEADER_FILTER: '', GC_CSV_ROW_FILTER: '', + GC_TLS_MIN_VERSION: 'TLSv1_2', + GC_TLS_MAX_VERSION: None, } GC_Values = {} @@ -797,6 +804,8 @@ GC_VAR_INFO = { GC_USER_MAX_RESULTS: {GC_VAR_TYPE: GC_TYPE_INTEGER, GC_VAR_LIMITS: (1, 500)}, GC_CSV_HEADER_FILTER: {GC_VAR_TYPE: GC_TYPE_STRING}, GC_CSV_ROW_FILTER: {GC_VAR_TYPE: GC_TYPE_STRING}, + GC_TLS_MIN_VERSION: {GC_VAR_TYPE: GC_TYPE_STRING}, + GC_TLS_MAX_VERSION: {GC_VAR_TYPE: GC_TYPE_STRING}, } # Google API constants