#!/usr/bin/python3 # -*- mode: python -*- # # This file is part of Plinth. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as # published by the Free Software Foundation, either version 3 of the # License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Affero General Public License for more details. # # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . # """ Configuration helper for Plint PageKite inteface TODO: Use augeas for manipulating /etc/pagekite.d/* files """ # Disable warning about invalid module name # pylint: disable-msg=C0103 import argparse import os import re import subprocess CONFIG_DIR = '/etc/pagekite.d' SERVICE_FILE_MAP = { 'http': { 'file': '80_httpd.rc', 'match': 'http:', 'line': 'service_on = http:@kitename : localhost:80 : @kitesecret'}, 'ssh': { 'file': '80_sshd.rc', 'match': 'raw/22:', 'line': 'service_on = raw/22:@kitename : localhost:22 : @kitesecret'}} def parse_arguments(): """Return parsed command line arguments as dictionary""" parser = argparse.ArgumentParser() subparsers = parser.add_subparsers(dest='subcommand', help='Sub command') # Get installed status subparsers.add_parser('get-installed', help='Get whether PakeKite is installed') # Start PageKite subparsers.add_parser('start', help='Start PageKite service') # Stop PageKite subparsers.add_parser('stop', help='Stop PageKite service') # Get status subparsers.add_parser('get-status', help='Get whether PakeKite is enabled') # Set status set_status = subparsers.add_parser('set-status', help='Enable/disable PageKite') set_status.add_argument('enable', choices=['enable', 'disable']) # Get kite details subparsers.add_parser('get-kite', help='Get configured kite name and secret') # Set kite details set_kite = subparsers.add_parser('set-kite', help='Configure kite name and its secret') set_kite.add_argument('--kite-name', help='Name of the kite (eg: mybox.pagekite.me)') set_kite.add_argument('--kite-secret', help='Secret for the kite') # Get service status get_service = subparsers.add_parser('get-service-status', help='Get whether service is enabled') get_service.add_argument('service', choices=['http', 'ssh']) # Set service status set_service = subparsers.add_parser('set-service-status', help='Enable/disable a service') set_service.add_argument('service', choices=['http', 'ssh']) set_service.add_argument('enable', choices=['enable', 'disable']) return parser.parse_args() def subcommand_get_installed(_): """Print whether PageKite is installed""" with open('/dev/null', 'w') as file_handle: status = subprocess.call(['which', 'pagekite'], stdout=file_handle) print('installed' if not status else 'not installed') def subcommand_start(_): """Start PageKite service""" status = subprocess.call(['service', 'pagekite', 'start']) if status: raise Exception('Unable to start PageKite server') def subcommand_stop(_): """Stop PageKite service""" status = subprocess.call(['service', 'pagekite', 'stop']) if status: raise Exception('Unable to stop PageKite server') def subcommand_get_status(_): """Print status of the pagekite service""" is_enabled = is_pagekite_enabled() print('enabled' if is_enabled else 'disabled') def is_pagekite_enabled(): """Return if pagekite is enabled""" service_file_path = os.path.join(CONFIG_DIR, '10_account.rc') try: with open(service_file_path, 'r') as file_object: for line in file_object: regex = r'^[ \t]*abort_not_configured' if re.match(regex, line): return False except Exception: return True return True def subcommand_set_status(arguments): """Enable/disable the pagekite service""" enable = arguments.enable == 'enable' is_enabled = is_pagekite_enabled() if enable and is_enabled: print('already enabled') return if not enable and not is_enabled: print('already disabled') return if enable: pagekite_enable() print('enabled') else: pagekite_disable() print('disabled') def pagekite_enable(): """Enable the pagekite daemon""" file_path = os.path.join(CONFIG_DIR, '10_account.rc') file_path_new = os.path.join(CONFIG_DIR, '10_account.rc.new') with open(file_path, 'r') as read_file_object, \ open(file_path_new, 'w') as write_file_object: for line in read_file_object: if not re.match('^[ \t]*abort_not_configured', line): write_file_object.write(line) os.rename(file_path_new, file_path) def pagekite_disable(): """Disable the pagekite daemon""" file_path = os.path.join(CONFIG_DIR, '10_account.rc') with open(file_path, 'a') as file_object: file_object.write('abort_not_configured\n') def subcommand_get_kite(_): """Print details of the currently configure kite""" kite_name = '' kite_secret = '' file_path = os.path.join(CONFIG_DIR, '10_account.rc') with open(file_path, 'r') as file_object: for line in file_object: match = re.match(r'[ \t]*kitename[ \t]*=[ \t]*(.*)', line) if match: kite_name = match.group(1) continue match = re.match(r'[ \t]*kitesecret[ \t]*=[ \t]*(.*)', line) if match: kite_secret = match.group(1) continue print(kite_name) print(kite_secret) def subcommand_set_kite(arguments): """Set details of the kite""" kite_name = arguments.kite_name kite_secret = arguments.kite_secret file_path = os.path.join(CONFIG_DIR, '10_account.rc') file_path_new = os.path.join(CONFIG_DIR, '10_account.rc.new') with open(file_path, 'r') as read_file_object, \ os.fdopen(os.open(file_path_new, os.O_WRONLY | os.O_CREAT, 0o400), 'w') as write_file_object: for line in read_file_object: if re.match(r'[ \t]*kitename[ \t]*=.*', line): write_file_object.write( 'kitename = {kite_name}\n'.format(kite_name=kite_name)) continue if re.match(r'[ \t]*kitesecret[ \t]*=.*', line): write_file_object.write('kitesecret = {kite_secret}\n' .format(kite_secret=kite_secret)) continue write_file_object.write(line) os.rename(file_path_new, file_path) def subcommand_get_service_status(arguments): """Print status of the pagekite service""" is_enabled = is_service_enabled(arguments.service) print('enabled' if is_enabled else 'disabled') def is_service_enabled(service): """Return if a service is enabled""" service = SERVICE_FILE_MAP[service] service_file_path = os.path.join(CONFIG_DIR, service['file']) if not os.path.isfile(service_file_path): return False try: with open(service_file_path, 'r') as file_object: for line in file_object: regex = '[ \t]*service_on[ \t]*=[ \t]*{match}' regex = regex.format(match=service['match']) if re.match(regex, line): return True except Exception: return False return False def subcommand_set_service_status(arguments): """Enable/disable a pagekite service""" enable = arguments.enable == 'enable' is_enabled = is_service_enabled(arguments.service) if enable and is_enabled: print('already enabled') return if not enable and not is_enabled: print('already disabled') return if enable: service_enable(arguments.service) print('enabled') else: service_disable(arguments.service) print('disabled') def service_enable(service_name): """Enable a service""" service = SERVICE_FILE_MAP[service_name] service_file_path = os.path.join(CONFIG_DIR, service['file']) with open(service_file_path, 'w') as file_object: file_object.write(''' # Expose the local {service_name} daemon # File auto-generated by Plinth {line} '''.format(service_name=service_name, line=service['line'])) def service_disable(service_name): """Disable a service""" service = SERVICE_FILE_MAP[service_name] service_file_path = os.path.join(CONFIG_DIR, service['file']) service_file_path_new = os.path.join(CONFIG_DIR, service['file'] + '.plinthbak') os.rename(service_file_path, service_file_path_new) def main(): """Parse arguments and perform all duties""" arguments = parse_arguments() subcommand = arguments.subcommand.replace('-', '_') subcommand_method = globals()['subcommand_' + subcommand] subcommand_method(arguments) if __name__ == "__main__": main()