123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286 |
- #!/usr/bin/python3
- # Copyright 2021 The Chromium Authors. All rights reserved.
- # Use of this source code is governed by a BSD-style license that can be
- # found in the LICENSE file.
- import argparse
- import hashlib
- import json
- import logging
- import os
- import shutil
- import socket
- import subprocess
- import sys
- from pathlib import Path
- from typing import Callable
- SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
- HOST_HASH = hashlib.md5(socket.gethostname().encode()).hexdigest()
- URL_FORWARDER_DESKTOP_ENTRY = 'crd-url-forwarder.desktop'
- # XFCE4's default settings app changes default browser setting on Cinnamon/GNOME
- # to xfce4-web-browser, which redirects GNOME apps to use the XFCE default
- # browser setting.
- XFCE4_WEB_BROWSER_DESKTOP_ENTRY = 'xfce4-web-browser.desktop'
- HOST_SETTINGS_PATH = os.path.join(
- os.environ['HOME'],
- '.config/chrome-remote-desktop/host#{}.settings.json'.format(HOST_HASH))
- X_SESSIONS_DIR = '/usr/share/xsessions/'
- XDG_SETTING_DEFAULT_WEB_BROWSER = 'default-web-browser'
- def env_with_current_desktop(desktop_env: str) -> dict[str, str]:
- """Returns an environment variable dictionary with XDG_CURRENT_DESKTOP set to
- |desktop_env|."""
- env = os.environ.copy()
- env['XDG_CURRENT_DESKTOP'] = desktop_env
- return env
- def get_default_browser(desktop_env: str) -> str:
- """Returns the XDG default-web-browser setting for the given desktop
- environment."""
- args = ['xdg-settings', 'get', XDG_SETTING_DEFAULT_WEB_BROWSER]
- env = env_with_current_desktop(desktop_env)
- try:
- return subprocess.check_output(args, env=env).decode('utf-8').strip()
- except CalledProcessError as e:
- print('Failed to execute', args, ':', e, file=sys.stderr)
- return ''
- def set_default_browser(desktop_env: str, desktop_entry: str) -> None:
- """Sets the XDG default-web-browser setting for the given desktop
- environment."""
- args = [
- 'xdg-settings', 'set', XDG_SETTING_DEFAULT_WEB_BROWSER, desktop_entry]
- env = env_with_current_desktop(desktop_env)
- subprocess.run(args, env=env)
- def set_default_browser_to_url_forwarder(
- desktop_env: str,
- backup_dict: dict[str, str],
- backup_key: str) -> None:
- """Sets default browser on the given desktop environment to the remote URL
- forwarder and backs up the previous default browser.
- Args:
- desktop_env: The desktop environment to be configured.
- backup_dict: The dictionary to backup the previous default browser.
- backup_key: The key that the previous default browser will be stored in
- backup_dict with.
- """
- current_entry = get_default_browser(desktop_env)
- if not current_entry:
- print('Cannot get default browser for', desktop_env, file=sys.stderr)
- return
- if current_entry == URL_FORWARDER_DESKTOP_ENTRY:
- print('Default browser for', desktop_env, 'is already',
- URL_FORWARDER_DESKTOP_ENTRY, file=sys.stderr)
- return
- backup_dict[backup_key] = current_entry
- if current_entry == XFCE4_WEB_BROWSER_DESKTOP_ENTRY:
- print('Default browser for', desktop_env, 'has been set to',
- XFCE4_WEB_BROWSER_DESKTOP_ENTRY, ', which effectively forces',
- desktop_env, 'to use XFCE\'s default browser setting.')
- # We can't back up XFCE's default browser here for local fallback, since it
- # might have been changed to the URL forwarder already.
- return
- set_default_browser(desktop_env, URL_FORWARDER_DESKTOP_ENTRY)
- print('Default browser for', desktop_env, 'has been successfully set to',
- URL_FORWARDER_DESKTOP_ENTRY)
- def load_host_settings_file() -> dict[str, str]:
- """Loads and returns the host settings JSON."""
- if not os.path.isfile(HOST_SETTINGS_PATH):
- return {}
- with open(HOST_SETTINGS_PATH, 'r') as settings_file:
- try:
- return json.load(settings_file)
- except JSONDecodeError as e:
- print('Failed to load JSON file:', e, file=sys.stderr)
- return {}
- def save_host_settings_file(settings: dict[str, str]) -> None:
- """Saves the host settings JSON to the file."""
- with open(HOST_SETTINGS_PATH, 'w') as settings_file:
- json.dump(settings, settings_file)
- def get_supported_desktop_envs_and_settings_key() -> dict[str, str]:
- desktop_envs_and_settings_keys = dict()
- for x_session_desktop_path in Path(X_SESSIONS_DIR).glob('*.desktop'):
- desktop_name = os.path.basename(x_session_desktop_path)
- if desktop_name.startswith('xfce'):
- desktop_envs_and_settings_keys['XFCE'] = 'previous_default_browser_xfce'
- elif desktop_name.startswith('cinnamon'):
- desktop_envs_and_settings_keys['X-Cinnamon'] = \
- 'previous_default_browser_cinnamon'
- elif desktop_name.startswith('gnome'):
- desktop_envs_and_settings_keys['GNOME'] = 'previous_default_browser_gnome'
- if not desktop_envs_and_settings_keys:
- # Add X-Generic for generic fallback.
- desktop_envs_and_settings_keys['X-Generic'] = \
- 'previous_default_browser_generic'
- return desktop_envs_and_settings_keys
- def setup_url_forwarder() -> None:
- settings = load_host_settings_file()
- desktop_envs_and_setting_keys = get_supported_desktop_envs_and_settings_key()
- for desktop_env, setting_key in desktop_envs_and_setting_keys.items():
- set_default_browser_to_url_forwarder(desktop_env, settings, setting_key)
- # For previous default browsers that have been set to the XFCE4 web browser,
- # replace them with the actual previous default browser configured for XFCE4
- # so that the URL forwarder doesn't launch itself recursively in case of local
- # fallback.
- for desktop_env, setting_key in desktop_envs_and_setting_keys.items():
- if (setting_key in settings and
- settings[setting_key] == XFCE4_WEB_BROWSER_DESKTOP_ENTRY):
- if 'XFCE' not in desktop_envs_and_setting_keys:
- print('Default browser for', desktop_env, 'is set to',
- XFCE4_WEB_BROWSER_DESKTOP_ENTRY, 'but XFCE is not found',
- file=sys.stderr)
- break
- xfce_setting_key = desktop_envs_and_setting_keys['XFCE']
- if xfce_setting_key not in settings:
- print('Cannot find', xfce_setting_key, 'in host settings.')
- break
- settings[setting_key] = settings[xfce_setting_key]
- save_host_settings_file(settings)
- # There are also x-www-browser and gnome-www-browser in the Debian Alternative
- # system. Most apps don't use them directly. xdg-open uses them if the session
- # does not have a display (i.e. interactive shell). Configuring them requires
- # sudo permission, and we always have a desktop environment, so we are not
- # changing them for now.
- # There is also a BROWSER environment variable. xdg-open may also use it when
- # the session does not have a display. We can't export a environment variable
- # back to the parent process anyway, so we don't change it here.
- def restore_default_browser(
- desktop_env: str,
- backup_dict: dict[str, str],
- backup_key: str) -> None:
- """Restores XDG default-web-browser to backup_dict[backup_key] on the given
- desktop environment.
- Args:
- desktop_env: The desktop environment to be configured.
- backup_dict: The dictionary where the previous configuration can be found.
- backup_key: The dictionary key to find the previous configuration.
- """
- if (backup_key not in backup_dict) or not backup_dict[backup_key]:
- print("No setting to restore from", backup_key, file=sys.stderr)
- return
- previous_setting = backup_dict[backup_key]
- if (previous_setting == URL_FORWARDER_DESKTOP_ENTRY or
- previous_setting == XFCE4_WEB_BROWSER_DESKTOP_ENTRY):
- print('Setting to restore from', backup_key, 'is', previous_setting,
- '. Ignored.', file=sys.stderr)
- return
- current_entry = get_default_browser(desktop_env)
- if current_entry == XFCE4_WEB_BROWSER_DESKTOP_ENTRY:
- print('Default browser for', desktop_env, 'is',
- XFCE4_WEB_BROWSER_DESKTOP_ENTRY, '. Ignored.', file=sys.stderr)
- return
- if current_entry != URL_FORWARDER_DESKTOP_ENTRY:
- print('Default browser for', desktop_env, 'is no longer',
- URL_FORWARDER_DESKTOP_ENTRY,
- '. Previously stored setting will not be restored.', file=sys.stderr)
- return
- set_default_browser(desktop_env, previous_setting)
- print('Default browser for', desktop_env, 'has been successfully restored to',
- previous_setting)
- def restore_previous_settings() -> None:
- settings = load_host_settings_file()
- for desktop_env, setting_key in (
- get_supported_desktop_envs_and_settings_key().items()):
- restore_default_browser(desktop_env, settings, setting_key)
- def check_default_browser_is_url_forwarder(desktop_env: str) -> None:
- """Checks if the default browser is set to the remote URL forwarder on the
- given desktop environment. Exits with 1 if it's not the case."""
- if (desktop_env != 'XFCE' and
- get_default_browser(desktop_env) == XFCE4_WEB_BROWSER_DESKTOP_ENTRY):
- print('Default browser for', desktop_env, 'is',
- XFCE4_WEB_BROWSER_DESKTOP_ENTRY,
- '. Checking default browser for XFCE instead...')
- check_default_browser_is_url_forwarder('XFCE')
- return
- if get_default_browser(desktop_env) != URL_FORWARDER_DESKTOP_ENTRY:
- print('Default browser for', desktop_env, 'is not',
- URL_FORWARDER_DESKTOP_ENTRY)
- sys.exit(1)
- def check_url_forwarder_setup() -> None:
- for desktop_env in get_supported_desktop_envs_and_settings_key().keys():
- check_default_browser_is_url_forwarder(desktop_env)
- print('Chrome Remote Desktop URL forwarder is properly set up.')
- sys.exit(0)
- def main() -> None:
- parser = argparse.ArgumentParser(
- usage='Usage: %(prog)s [options]',
- description='Set up a URL forwarder so that URLs will be opened on the '
- 'Chrome Remote Desktop client. This script must be run within the remote '
- 'desktop\'s session.')
- parser.add_argument('--setup', dest='setup', default=False,
- action='store_true',
- help='Set up the URL forwarder.')
- parser.add_argument('--restore', dest='restore', default=False,
- action='store_true',
- help='Remove the URL forwarder and restore default '
- 'browser settings.')
- parser.add_argument('--check-setup', dest='check_setup', default=False,
- action='store_true',
- help='Exit with 0 if the URL forwarder is properly set '
- 'up, or 1 otherwise.')
- options = parser.parse_args()
- if options.setup:
- setup_url_forwarder()
- elif options.restore:
- restore_previous_settings()
- elif options.check_setup:
- check_url_forwarder_setup()
- else:
- parser.print_usage()
- if __name__ == '__main__':
- logging.basicConfig(level=logging.DEBUG,
- format='%(asctime)s:%(levelname)s:%(message)s')
- sys.exit(main())
|