#!/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 the ejabberd service """ import argparse import subprocess import time import os import re JWCHAT_CONFIG = '/etc/jwchat/config.js' EJABBERD_CONFIG = '/etc/ejabberd/ejabberd.yml' EJABBERD_BACKUP = '/var/log/ejabberd/ejabberd.dump' def parse_arguments(): """Return parsed command line arguments as dictionary""" parser = argparse.ArgumentParser() subparsers = parser.add_subparsers(dest='subcommand', help='Sub command') # Get whether ejabberd is installed subparsers.add_parser('get-installed', help='Get whether ejabberd is installed') # Update ejabberd and jwchat with new hostname hostname_change = subparsers.add_parser( 'change-hostname', help='Update ejabberd and jwchat with new hostname') hostname_change.add_argument('--old-hostname', help='Previous hostname') hostname_change.add_argument('--new-hostname', help='New hostname') # Register a new user account register = subparsers.add_parser('register', help='Register a new user account') register.add_argument('--username', help='Username for the new user account') register.add_argument('--password', help='Password for the new user account') return parser.parse_args() def subcommand_get_installed(_): """Get whether ejabberd is installed""" print('installed' if get_installed() else 'not installed') def subcommand_change_hostname(arguments): """Update ejabberd and jwchat with new hostname""" if not get_installed(): print('Failed to update XMPP hostname: ejabberd is not installed.') return old_hostname = arguments.old_hostname new_hostname = arguments.new_hostname # update jwchat's sitename, if it's installed if os.path.exists(JWCHAT_CONFIG): with open(JWCHAT_CONFIG, 'r') as conffile: lines = conffile.readlines() with open(JWCHAT_CONFIG, 'w') as conffile: for line in lines: if re.match(r'\s*var\s+SITENAME', line): conffile.write('var SITENAME = "' + new_hostname + '";') else: conffile.write(line) else: print('Skipping configuring jwchat hostname: %s not found' % JWCHAT_CONFIG) # update ejabberd hosts with open(EJABBERD_CONFIG, 'r') as conffile: lines = conffile.readlines() with open(EJABBERD_CONFIG, 'w') as conffile: in_hosts_section = False for line in lines: if in_hosts_section: if re.match(r'\s*-\s+"', line): conffile.write(line.replace(old_hostname, new_hostname)) else: in_hosts_section = False conffile.write(line) else: if re.match(r'\s*hosts:', line): in_hosts_section = True conffile.write(line) # update ejabberd backup database if os.path.exists(EJABBERD_BACKUP): with open(EJABBERD_BACKUP, 'r') as dumpfile: lines = dumpfile.readlines() with open(EJABBERD_BACKUP, 'w') as dumpfile: in_roster = False in_pubsub_node = False for line in lines: if in_roster: if re.match(r'\s+', line): dumpfile.write(line.replace( '>>,<<"' + old_hostname + '">>', '>>,<<"' + new_hostname + '">>')) continue else: in_roster = False # check other cases below if in_pubsub_node: if re.match(r'\s+', line): dumpfile.write(line.replace( '>>,<<"pubsub.' + old_hostname + '">>,<<', '>>,<<"pubsub.' + new_hostname + '">>,<<')) continue else: in_pubsub_node = False # check other cases below if re.match(r'\s*{passwd,', line): dumpfile.write(line.replace( '">>,<<"' + old_hostname + '">>},<<"', '">>,<<"' + new_hostname + '">>},<<"')) elif re.match(r'\s*{private_storage,', line): dumpfile.write(line.replace( '>>,<<"' + old_hostname + '">>,<<', '>>,<<"' + new_hostname + '">>,<<')) elif re.match(r'\s*{last_activity,', line): dumpfile.write(line.replace( '>>,<<"' + old_hostname + '">>},', '>>,<<"' + new_hostname + '">>},')) elif re.match(r'\s*{roster,', line): dumpfile.write(line.replace( '>>,<<"' + old_hostname + '">>,', '>>,<<"' + new_hostname + '">>,')) in_roster = True elif re.match(r'\s*{pubsub_state,', line): dumpfile.write(line.replace( '>>,<<"pubsub.' + old_hostname + '">>,<<', '>>,<<"pubsub.' + new_hostname + '">>,<<')) elif re.match(r'\s*{pubsub_node,', line): dumpfile.write(line.replace( ',{<<"pubsub.' + old_hostname + '">>,<<', ',{<<"pubsub.' + new_hostname + '">>,<<').replace( '>>,<<"/home/' + old_hostname + '">>},', '>>,<<"/home/' + new_hostname + '">>},')) in_pubsub_node = True else: dumpfile.write(line) subprocess.call(['service', 'ejabberd', 'restart']) # load backup database if os.path.exists(EJABBERD_BACKUP): time.sleep(10) subprocess.call(['ejabberdctl', 'load', EJABBERD_BACKUP]) os.remove(EJABBERD_BACKUP) else: print('Could not load ejabberd backup database: %s not found' % EJABBERD_BACKUP) def subcommand_register(arguments): """Register a new user account""" if not get_installed(): print('Failed to register XMPP account: ejabberd is not installed.') return username = arguments.username password = arguments.password hostname = subprocess.check_output(['hostname']) try: output = subprocess.check_output(['ejabberdctl', 'register', username, hostname, password]) print(output.decode()) except subprocess.CalledProcessError as e: print('Failed to register XMPP account:', e.output.decode()) def get_installed(): """Check if ejabberd is installed""" with open('/dev/null', 'w') as file_handle: status = subprocess.call(['which', 'ejabberdctl'], stdout=file_handle) return not status 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()