|
6 | 6 | __author__ = 'Simon Robinson'
|
7 | 7 | __copyright__ = 'Copyright (c) 2024 Simon Robinson'
|
8 | 8 | __license__ = 'Apache 2.0'
|
9 |
| -__version__ = '2024-05-25' # ISO 8601 (YYYY-MM-DD) |
| 9 | +__version__ = '2024-06-28' # ISO 8601 (YYYY-MM-DD) |
10 | 10 | __package_version__ = '.'.join([str(int(i)) for i in __version__.split('-')]) # for pyproject.toml usage only
|
11 | 11 |
|
12 | 12 | import abc
|
@@ -322,7 +322,7 @@ def format_host_port(address):
|
322 | 322 | host, port, *_ = address
|
323 | 323 | with contextlib.suppress(ValueError):
|
324 | 324 | ip = ipaddress.ip_address(host)
|
325 |
| - host = '[%s]' % host if type(ip) is ipaddress.IPv6Address else host |
| 325 | + host = '[%s]' % host if isinstance(ip, ipaddress.IPv6Address) else host |
326 | 326 | return '%s:%d' % (host, port)
|
327 | 327 |
|
328 | 328 | @staticmethod
|
@@ -365,13 +365,13 @@ def _get_boto3_client(store_id):
|
365 | 365 | except ModuleNotFoundError:
|
366 | 366 | Log.error('Unable to load AWS SDK - please install the `boto3` module: `python -m pip install boto3`')
|
367 | 367 | return None, None
|
368 |
| - else: |
369 |
| - # allow a profile to be chosen by prefixing the store_id - the separator used (`||`) will not be in an ARN |
370 |
| - # or secret name (see: https://docs.aws.amazon.com/secretsmanager/latest/apireference/API_CreateSecret.html) |
371 |
| - split_id = store_id.split('||', maxsplit=1) |
372 |
| - if '||' in store_id: |
373 |
| - return split_id[1], boto3.session.Session(profile_name=split_id[0]).client('secretsmanager') |
374 |
| - return store_id, boto3.client(service_name='secretsmanager') |
| 368 | + |
| 369 | + # allow a profile to be chosen by prefixing the store_id - the separator used (`||`) will not be in an ARN |
| 370 | + # or secret name (see: https://docs.aws.amazon.com/secretsmanager/latest/apireference/API_CreateSecret.html) |
| 371 | + split_id = store_id.split('||', maxsplit=1) |
| 372 | + if '||' in store_id: |
| 373 | + return split_id[1], boto3.session.Session(profile_name=split_id[0]).client('secretsmanager') |
| 374 | + return store_id, boto3.client(service_name='secretsmanager') |
375 | 375 |
|
376 | 376 | @staticmethod
|
377 | 377 | def _create_secret(aws_client, store_id):
|
@@ -824,7 +824,7 @@ def get_oauth2_credentials(username, password, reload_remote_accounts=True):
|
824 | 824 | headers={
|
825 | 825 | 'x5t#S256': base64.urlsafe_b64encode(jwt_certificate_fingerprint).decode('utf-8')
|
826 | 826 | })
|
827 |
| - except FileNotFoundError: |
| 827 | + except (FileNotFoundError, OSError): # catch OSError due to GitHub issue 257 (quoted paths) |
828 | 828 | return (False, 'Unable to create credentials assertion for account %s - please check that the '
|
829 | 829 | '`jwt_certificate_path` and `jwt_key_path` values are correct' % username)
|
830 | 830 |
|
@@ -912,7 +912,7 @@ def get_oauth2_credentials(username, password, reload_remote_accounts=True):
|
912 | 912 |
|
913 | 913 | except OAuth2Helper.TokenRefreshError as e:
|
914 | 914 | # always clear access tokens - can easily request another via the refresh token (with no user interaction)
|
915 |
| - has_access_token = True if config.get(username, 'access_token', fallback=None) else False |
| 915 | + has_access_token = bool(config.get(username, 'access_token', fallback=None)) |
916 | 916 | config.remove_option(username, 'access_token')
|
917 | 917 | config.remove_option(username, 'access_token_expiry')
|
918 | 918 |
|
@@ -986,6 +986,7 @@ def start_redirection_receiver_server(token_request):
|
986 | 986 | Log.format_host_port((parsed_uri.hostname, parsed_port)))
|
987 | 987 |
|
988 | 988 | class LoggingWSGIRequestHandler(wsgiref.simple_server.WSGIRequestHandler):
|
| 989 | + # pylint: disable=arguments-differ |
989 | 990 | def log_message(self, _format_string, *args):
|
990 | 991 | Log.debug('Local server auth mode (%s): received authentication response' % Log.format_host_port(
|
991 | 992 | (parsed_uri.hostname, parsed_port)), *args)
|
@@ -1150,22 +1151,22 @@ def get_service_account_authorisation_token(key_type, key_path_or_contents, oaut
|
1150 | 1151 | import requests
|
1151 | 1152 | import google.oauth2.service_account
|
1152 | 1153 | import google.auth.transport.requests
|
1153 |
| - except ModuleNotFoundError: |
1154 |
| - raise Exception('Unable to load Google Auth SDK - please install the `requests` and `google-auth` modules: ' |
1155 |
| - '`python -m pip install requests google-auth`') |
| 1154 | + except ModuleNotFoundError as e: |
| 1155 | + raise ModuleNotFoundError('Unable to load Google Auth SDK - please install the `requests` and ' |
| 1156 | + '`google-auth` modules: `python -m pip install requests google-auth`') from e |
1156 | 1157 |
|
1157 | 1158 | if key_type == 'file':
|
1158 | 1159 | try:
|
1159 |
| - with open(key_path_or_contents) as key_file: |
| 1160 | + with open(key_path_or_contents, mode='r', encoding='utf-8') as key_file: |
1160 | 1161 | service_account = json.load(key_file)
|
1161 | 1162 | except IOError as e:
|
1162 |
| - raise FileNotFoundError('Unable to open service account key file %s for account %s', |
| 1163 | + raise FileNotFoundError('Unable to open service account key file %s for account %s' % |
1163 | 1164 | (key_path_or_contents, username)) from e
|
1164 | 1165 | elif key_type == 'key':
|
1165 | 1166 | service_account = json.loads(key_path_or_contents)
|
1166 | 1167 | else:
|
1167 |
| - raise Exception('Service account key type not specified for account %s - `client_id` must be set to ' |
1168 |
| - '`file` or `key`' % username) |
| 1168 | + raise KeyError('Service account key type not specified for account %s - `client_id` must be set to ' |
| 1169 | + '`file` or `key`' % username) |
1169 | 1170 |
|
1170 | 1171 | credentials = google.oauth2.service_account.Credentials.from_service_account_info(service_account)
|
1171 | 1172 | credentials = credentials.with_scopes(oauth2_scope.split(' '))
|
@@ -2044,7 +2045,7 @@ def process_data(self, byte_data):
|
2044 | 2045 | if not re.search(' SASL-IR', updated_response, re.IGNORECASE):
|
2045 | 2046 | updated_response = updated_response.replace(' AUTH=PLAIN', ' AUTH=PLAIN SASL-IR')
|
2046 | 2047 | updated_response = re.sub(' LOGINDISABLED', '', updated_response, count=1, flags=re.IGNORECASE)
|
2047 |
| - byte_data = (b'%s\r\n' % updated_response.encode('utf-8')) |
| 2048 | + byte_data = b'%s\r\n' % updated_response.encode('utf-8') |
2048 | 2049 |
|
2049 | 2050 | super().process_data(byte_data)
|
2050 | 2051 |
|
@@ -2842,9 +2843,9 @@ def create_config_menu(self):
|
2842 | 2843 | if len(self.proxies) <= 0:
|
2843 | 2844 | # note that we don't actually allow no servers when loading the config, so no need to generate a menu
|
2844 | 2845 | return items # (avoids creating and then immediately regenerating the menu when servers are loaded)
|
2845 |
| - else: |
2846 |
| - for server_type in ['IMAP', 'POP', 'SMTP']: |
2847 |
| - items.extend(App.get_config_menu_servers(self.proxies, server_type)) |
| 2846 | + |
| 2847 | + for server_type in ['IMAP', 'POP', 'SMTP']: |
| 2848 | + items.extend(App.get_config_menu_servers(self.proxies, server_type)) |
2848 | 2849 |
|
2849 | 2850 | config_accounts = AppConfig.accounts()
|
2850 | 2851 | items.append(pystray.MenuItem('Accounts (+ last authenticated activity):', None, enabled=False))
|
@@ -2977,7 +2978,7 @@ def create_authorisation_window(self, request):
|
2977 | 2978 | # pywebview 3.6+ moved window events to a separate namespace in a non-backwards-compatible way
|
2978 | 2979 | # noinspection PyDeprecation
|
2979 | 2980 | pywebview_version = pkg_resources.parse_version(pkg_resources.get_distribution('pywebview').version)
|
2980 |
| - # the version zero check is due to a bug in the Ubuntu 22.04 python-pywebview package - see GitHub #242 |
| 2981 | + # the version zero check is due to a bug in the Ubuntu 24.04 python-pywebview package - see GitHub #242 |
2981 | 2982 | # noinspection PyDeprecation
|
2982 | 2983 | if pkg_resources.parse_version('0') < pywebview_version < pkg_resources.parse_version('3.6'):
|
2983 | 2984 | # noinspection PyUnresolvedReferences
|
@@ -3174,10 +3175,10 @@ def macos_launchctl(command):
|
3174 | 3175 | output = subprocess.check_output(['/bin/launchctl', command, proxy_command], stderr=subprocess.STDOUT)
|
3175 | 3176 | except subprocess.CalledProcessError:
|
3176 | 3177 | return False
|
3177 |
| - else: |
3178 |
| - if output and command != 'list': |
3179 |
| - return False # load/unload gives no output unless unsuccessful (return code is always 0 regardless) |
3180 |
| - return True |
| 3178 | + |
| 3179 | + if output and command != 'list': |
| 3180 | + return False # load/unload gives no output unless unsuccessful (return code is always 0 regardless) |
| 3181 | + return True |
3181 | 3182 |
|
3182 | 3183 | @staticmethod
|
3183 | 3184 | def started_at_login(_):
|
|
0 commit comments