Пример #1
0
def show_configuration(args):
    config = {}
    for port in ports_iter():
        print('Port {}:'.format(port))
        config = port_config(port)
        pformat = pprint.pformat(config)
        pformat = re.sub(r'^', '  ', pformat, 0, re.MULTILINE)
        print(pformat)

    print('Client configuration:')
    config = {}
    set_setting(config, 'server_url',
                get_client_setting('server_url') or 'MISSING')
    if get_client_setting('ssl:ca_path'):
        set_setting(config, 'ssl:ca_path', get_client_setting('ssl:ca_path'))
    pformat = pprint.pformat(config)
    pformat = re.sub(r'^', '  ', pformat, 0, re.MULTILINE)
    print(pformat)
Пример #2
0
def main(args):
    if args.yes:
        maybe_changed = partial(maybe_changed_extended, use_default=True)
    else:
        maybe_changed = maybe_changed_extended

    generate_key('server', gpg_user_ids['server'])
    generate_key('client', gpg_user_ids['client'])
    import_key('server', gpg_user_ids['client'])
    import_key('client', gpg_user_ids['server'])

    default = not (get_client_setting('loaded')
                   and get_server_setting('loaded'))

    do_config = default if args.yes else \
        get_bool('Do you want to configure things interactively?', default)

    server_changed = client_changed = False

    if do_config:
        if isinstance(get_server_setting('port'), int):
            # Otherwise, the settings file has been edited to make the port
            # either a list of ports or a mapping, and we don't want to try to
            # configure it here.
            server_changed |= maybe_changed(
                'server', 'port', get_int,
                'What port should the server listen on?')

        server_changed |= maybe_changed(
            'server', 'local_port', get_int,
            'What local-only port should the server use?')

        configure_ssl = True
        port = get_server_setting('port')
        if isinstance(port, dict):
            for port_number, port_settings in port.items():
                if 'ssl' in port_settings:
                    # If there are already port-specific SSL settings, then
                    # don't try to configure SSL in this script.
                    configure_ssl = False
        if configure_ssl:
            default = bool(
                get_server_setting('ssl:certificate', None)
                or get_server_setting('ssl:key', None))
            configure_ssl = maybe_get_bool(
                'Do you want the server to use SSL?', default, args.yes)
        if not configure_ssl:
            if get_server_setting('ssl:certificate', None):
                set_server_setting('ssl:certificate', None)
                server_changed = True
            if get_server_setting('ssl:key', None):
                set_server_setting('ssl:key', None)
                server_changed = True
        else:
            while True:
                server_changed |= maybe_changed('server', 'ssl:certificate',
                                                get_string,
                                                'SSL certificate file path:')
                if os.path.exists(get_server_setting('ssl:certificate')):
                    break
                print('That file does not exist.')

            while True:
                server_changed |= maybe_changed('server', 'ssl:key',
                                                get_string,
                                                'SSL key file path:')
                if os.path.exists(get_server_setting('ssl:key')):
                    break
                print('That file does not exist.')

        server_changed |= maybe_changed('server', 'database:host',
                                        get_string_or_list,
                                        'Database host:port:')
        if get_server_setting('database:host'):
            server_changed |= maybe_changed('server',
                                            'database:replicaset',
                                            get_string_none,
                                            'Replicaset name:',
                                            empty_ok=True)
        server_changed |= maybe_changed('server', 'database:name', get_string,
                                        'Database name:')
        server_changed |= maybe_changed('server',
                                        'database:username',
                                        get_string_none,
                                        'Database username:'******'database:username'):
            server_changed |= maybe_changed('server', 'database:password',
                                            get_string, 'Database password:'******'Server', maybe_changed)
        server_changed |= maybe_changed(
            'server', 'audit_cron:enabled', get_bool,
            'Do you want to enable the audit cron job?')

        if get_server_setting('audit_cron:enabled'):
            server_changed |= maybe_changed(
                'server', 'audit_cron:email', get_string,
                'What email address should get the audit output?')

        port = get_server_setting('port')
        if port == 443:
            sample_url = 'https://hostname'
        elif port == 80:
            sample_url = 'http://hostname'
        else:
            sample_url = 'http://hostname:{}'.format(port)
        prompt = 'URL base, e.g., {}, for clients to reach server:'.format(
            sample_url)

        client_changed |= maybe_changed('client', 'server_url', get_string,
                                        prompt)

        client_changed |= maybe_changed('client',
                                        'geolocation_api_key',
                                        get_string,
                                        'Google geolocation API key, if any:',
                                        empty_ok=True)
        prompter = partial(get_int, minimum=1)
        client_changed |= maybe_changed(
            'client', 'schedule:collect_interval', prompter,
            'How often (minutes) do you want to collect data?')
        client_changed |= maybe_changed(
            'client', 'schedule:submit_interval', prompter,
            'How often (minutes) do you want re-try submits?')

        client_changed |= configure_logging('Client', maybe_changed)

        save_server_settings()
        if server_changed:
            print('Saved server settings.')

        save_client_settings()
        if client_changed:
            print('Saved client settings.')

    service_file = '/etc/systemd/system/penguindome-server.service'
    service_exists = os.path.exists(service_file)
    default = not service_exists

    if service_exists:
        prompt = ("Do you want to replace the server's systemd "
                  "configuration?")
    else:
        prompt = 'Do you want to add the server to systemd?'

    do_service = maybe_get_bool(prompt, default, args.yes)

    if do_service and not args.skipsystemctl:
        with NamedTemporaryFile('w+') as temp_service_file:
            temp_service_file.write(
                dedent('''\
                [Unit]
                Description=PenguinDome Server
                After=network.target

                [Service]
                Type=simple
                ExecStart={server_exe}

                [Install]
                WantedBy=multi-user.target
            '''.format(server_exe=os.path.join(top_dir, 'bin', 'server'))))
            temp_service_file.flush()
            os.chmod(temp_service_file.name, 0o644)
            shutil.copy(temp_service_file.name, service_file)
        subprocess.check_output(('systemctl', 'daemon-reload'),
                                stderr=subprocess.STDOUT)
        service_exists = True

    if service_exists and not args.skipsystemctl:
        try:
            subprocess.check_output(
                ('systemctl', 'is-enabled', 'penguindome-server'),
                stderr=subprocess.STDOUT)
        except Exception:
            if maybe_get_bool('Do you want to enable the server?', True,
                              args.yes):
                subprocess.check_output(
                    ('systemctl', 'enable', 'penguindome-server'),
                    stderr=subprocess.STDOUT)
                is_enabled = True
            else:
                is_enabled = False
        else:
            is_enabled = True

        if is_enabled:
            try:
                subprocess.check_output(
                    ('systemctl', 'status', 'penguindome-server'),
                    stderr=subprocess.STDOUT)
            except Exception:
                if maybe_get_bool('Do you want to start the server?', True,
                                  args.yes):
                    subprocess.check_output(
                        ('systemctl', 'start', 'penguindome-server'),
                        stderr=subprocess.STDOUT)
            else:
                if maybe_get_bool('Do you want to restart the server?',
                                  server_changed, args.yes):
                    subprocess.check_output(
                        ('systemctl', 'restart', 'penguindome-server'),
                        stderr=subprocess.STDOUT)

        if get_server_setting('audit_cron:enabled'):
            cron_file = '/etc/cron.d/penguindome-audit'
            cron_exists = os.path.exists(cron_file)

            if cron_exists:
                prompt = 'Do you want to replace the audit crontab?'
            else:
                prompt = 'Do you want to install the audit crontab?'

            do_crontab = maybe_get_bool(prompt, args.audit_crontab
                                        or not cron_exists, args.audit_crontab
                                        or args.yes)

            if do_crontab:
                email = get_server_setting('audit_cron:email')
                minute = int(random.random() * 60)
                minute2 = (minute + 1) % 60

                crontab = dedent('''\
                    MAILTO={email}
                    {minute2} * * * * root "{top_dir}/bin/issues" audit --cron
                '''.format(minute2=minute2, email=email, top_dir=top_dir))

                with NamedTemporaryFile('w+') as temp_cron_file:
                    temp_cron_file.write(crontab)
                    temp_cron_file.flush()
                    os.chmod(temp_cron_file.name, 0o644)
                    shutil.copy(temp_cron_file.name, cron_file)

                print('Installed {}'.format(cron_file))

    if (client_changed
            or not glob.glob(os.path.join(releases_dir, '*.tar.asc'))
            and not args.skipbuildrelease):
        if client_changed:
            prompt = ('Do you want to build a release with the new client '
                      'settings?')
        else:
            prompt = 'Do you want to build a client release?'

        if maybe_get_bool(prompt, True, args.yes):
            # Sometimes sign fails the first time because of GnuPG weirdness.
            # The client_release script will call sign as well, but we call it
            # first just in case it fails the first time.
            try:
                subprocess.check_output((os.path.join('bin', 'sign'), ),
                                        stderr=subprocess.STDOUT)
            except Exception:
                pass
            subprocess.check_output((os.path.join('bin', 'client_release'), ),
                                    stderr=subprocess.STDOUT)

    print('Done!')
Пример #3
0
def configure_client(args):
    changed = False
    url = get_client_setting('server_url')
    if url:
        url = list(urlparse(url))
    else:
        url = ['', '', '', '', '', '']
    if ':' in url[1]:
        hostname, port = url[1].split(':')
        port = int(port)
    else:
        hostname = url[1]
        port = 443 if url[0] == 'https' else 80

    if args.hostname:
        if hostname != args.hostname:
            hostname = args.hostname
            changed = True

    if args.port:
        if port != args.port:
            port = args.port
            changed = True
        if port == 443 and args.ssl is None:
            args.ssl = True

    if args.ssl:
        if url[0] != 'https':
            url[0] = 'https'
            changed = True
    elif args.ssl is False:
        if url[0] != 'http':
            url[0] = 'http'
            changed = True

    if port == 443 and url[0] != 'https':
        print("\n"
              "WARNING: Are you sure you don't want to use SSL on port 443?\n")

    verbose_port = port or 80
    try:
        server_port_ssl = get_port_setting(
            verbose_port, 'ssl:enabled',
            bool(get_port_setting(verbose_port, 'ssl:certificate')))
    except:
        server_port_ssl = False
    if server_port_ssl and url[0] != 'https':
        print('\n'
              'WARNING: Port {} on the server is using SSL.\n'
              '         Does the client need to?\n'.format(verbose_port))
    elif not server_port_ssl and url[0] != 'http':
        print('\n'
              'WARNING: Port {} on the server is not using SSL.\n'
              '         Are you sure the client should?\n'.format(
                  verbose_port))

    if not hostname:
        sys.exit('You must specify hostname.')
    if url[0] not in ('http', 'https'):
        changed = True
        url[0] = 'https' if port == 443 else 80
    if port and ((url[0] == 'http' and port != 80) or
                 (url[0] == 'https' and port != 443)):
        loc = '{}:{}'.format(hostname, port)
        if url[1] != loc:
            changed = True
            url[1] = loc
    else:
        url[1] = hostname

    if args.ssl_ca_file is False:
        if get_client_setting('ssl:ca_path'):
            set_client_setting('ssl:ca_path', None)
            changed = True
    elif args.ssl_ca_file:
        try:
            server_port = int(args.ssl_ca_file)
        except:
            pass
        else:
            args.ssl_ca_file = get_port_setting(server_port, 'ssl:certificate')
            if not args.ssl_ca_file:
                sys.exit('Server port {} does not have an SSL certificate.'
                         .format(server_port))
        client_file = os.path.join('client', 'cacert.pem')
        if not os.path.exists(args.ssl_ca_file):
            sys.exit('The file {} does not exist.'.format(args.ssl_ca_file))
        if not (os.path.exists(client_file) and
                filecmp.cmp(args.ssl_ca_file, client_file)):
            shutil.copy(args.ssl_ca_file, client_file)
            changed = True
        if get_client_setting('ssl:ca_path') != client_file:
            set_client_setting('ssl:ca_path', client_file)
            changed = True

    url = urlunparse(url)
    url = re.sub(r'/+$', '', url)
    if changed:
        set_client_setting('server_url', url)
        save_client_settings()
        print('Updated client configuration.')
        show_configuration(args)
        print("\n"
              "WARNING: Don't forget to build a new client release.\n")
    else:
        print('Client configuration unchanged.')
Пример #4
0
def configure_port(args, add=False):
    if args.ssl_self_signed and (args.certificate or args.key):
        sys.exit('--certificate and --key are incompatible with '
                 '--ssl-self-signed.')

    changed = False
    port = args.port
    ports = get_server_setting('port', None)
    if not ports:
        ports = []
    elif isinstance(ports, int):
        ports = [ports]
    if isinstance(ports, list):
        ports = {port: {} for port in ports}
        set_server_setting('port', ports)

    if port in ports:
        if add:
            sys.exit('Port {} is already present.'.format(args.port))
        which = 'Configured'
    else:
        ports[port] = {}
        changed = True
        which = 'Added'

    if not ports[port]:
        ports[port] = {}
    port_settings = ports[port]
    gps = partial(get_port_setting, port)

    def ss(setting, value):
        nonlocal changed
        set_setting(port_settings, setting, value)
        changed = True

    if args.deprecated is not None:
        if bool(gps('deprecated')) != args.deprecated:
            ss('deprecated', args.deprecated)

    if args.ssl_self_signed:
        cert_file, key_file = make_self_signed_cert(args.ssl_self_signed)
        ss('ssl:certificate', cert_file)
        ss('ssl:key', key_file)
        if args.ssl is not False:
            args.ssl = True

    if args.certificate and gps('ssl:certificate') != args.certificate:
        if not (args.key or gps('ssl:key')):
            sys.exit('You must specify both a certificate and a key.')
        if not os.path.exists(args.certificate):
            sys.exit('The certificate file {} does not exist'.format(
                args.certificate))
        ss('ssl:certificate', args.certificate)

    if args.key and gps('ssl:key') != args.key:
        if not gps('ssl:certificate'):
            sys.exit('You must specify both a certificate and a key.')
        if not os.path.exists(args.key):
            sys.exit('The key file {} does not exist'.format(
                args.key))
        ss('ssl:key', args.key)

    if args.ssl:
        if not (gps('ssl:certificate') and gps('ssl:key')):
            sys.exit('You must specify a certificate and key to enable SSL.')
        if not gps('ssl:enabled', bool(gps('ssl:certificate'))):
            ss('ssl:enabled', True)
    elif args.ssl is False:
        if gps('ssl:enabled', bool(gps('ssl:certificate'))):
            ss('ssl:enabled', False)

    if changed:
        save_server_settings()

        url = get_client_setting('server_url')
        if url:
            url = urlparse(url)
            if ':' in url[1]:
                _, client_port = url[1].split(':')
                client_port = int(client_port)
            else:
                client_port = {'http': 80, 'https': 443}[url[0]]
            client_ssl = {'http': False, 'https': True}[url[0]]
            if port == client_port:
                if client_ssl != gps(
                        'ssl:enabled', bool(gps('ssl:certificate'))):
                    print('\n'
                          'WARNING: Client is configured to use port {} and {}'
                          'using SSL.\n'
                          '         Should it be?\n'.format(
                              port, '' if client_ssl else 'not '))
                if gps('deprecated'):
                    print('\n'
                          'WARNING: Client is configured to use deprecated '
                          'port {}.\n'
                          '         Do you need to change the client port?'.
                          format(port))

        print('{} port {}.'.format(which, port))

        print("\n"
              "WARNING: Don't forget to restart the server.\n")

        if args.ssl_self_signed and args.ssl:
            print("\n"
                  "WARNING: Don't forget to configure client CA file\n"
                  "         (see help for 'configure-client').\n")

        show_configuration(args)
    else:
        print('No changes.')