Sunil Mohan Adapa ebabb2f8aa
sharing: Finish implementation
Signed-off-by: Sunil Mohan Adapa <sunil@medhas.org>
Reviewed-by: Joseph Nuthalapati <njoseph@thoughtworks.com>
2018-03-12 18:27:06 +05:30

202 lines
5.9 KiB
Python
Executable File

#!/usr/bin/python3
#
# This file is part of FreedomBox.
#
# 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 <http://www.gnu.org/licenses/>.
#
"""
Configuration helper for the sharing app.
"""
import argparse
import json
import os
import pathlib
import re
import augeas
from plinth import action_utils
APACHE_CONFIGURATION = '/etc/apache2/conf-available/sharing-freedombox.conf'
def parse_arguments():
parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers(dest='subcommand', help='Sub command')
subparsers.add_parser('list', help='List all existing shares')
add_parser = subparsers.add_parser('add', help='Add a new share')
add_parser.add_argument('--name', required=True, help='Name of the share')
add_parser.add_argument('--path', required=True, help='Disk path to share')
add_parser.add_argument('--groups', nargs='*',
help='List of groups that can access the share')
remove_parser = subparsers.add_parser('remove',
help='Remove an existing share')
remove_parser.add_argument('--name', required=True,
help='Name of the share to remove')
subparsers.required = True
return parser.parse_args()
def load_augeas():
"""Initialize augeas for this app's configuration file."""
aug = augeas.Augeas(
flags=augeas.Augeas.NO_LOAD + augeas.Augeas.NO_MODL_AUTOLOAD)
aug.set('/augeas/load/Httpd/lens', 'Httpd.lns')
aug.set('/augeas/load/Httpd/incl[last() + 1]', APACHE_CONFIGURATION)
aug.load()
aug.defvar('conf', '/files' + APACHE_CONFIGURATION)
return aug
def subcommand_add(arguments):
"""Add a share to Apache configuration."""
name = arguments.name
path = arguments.path
groups = arguments.groups
url = '/share/' + name
if not os.path.exists(APACHE_CONFIGURATION):
pathlib.Path(APACHE_CONFIGURATION).touch()
aug = load_augeas()
shares = _list(aug)
if any([share for share in shares if share['name'] == name]):
raise Exception('Share already present')
aug.set('$conf/directive[last() + 1]', 'Alias')
aug.set('$conf/directive[last()]/arg[1]', url)
aug.set('$conf/directive[last()]/arg[2]', path)
aug.set('$conf/Location[last() + 1]/arg', url)
aug.set('$conf/Location[last()]/directive[last() + 1]', 'Include')
aug.set('$conf/Location[last()]/directive[last()]/arg',
'includes/freedombox-sharing.conf')
aug.set('$conf/Location[last()]/directive[last() + 1]', 'Include')
aug.set('$conf/Location[last()]/directive[last()]/arg',
'includes/freedombox-single-sign-on.conf')
aug.set('$conf/Location[last()]/IfModule/arg', 'mod_auth_pubtkt.c')
aug.set('$conf/Location[last()]/IfModule/directive[1]', 'TKTAuthToken')
for group_name in groups:
aug.set('$conf/Location[last()]/IfModule/directive[1]/arg[last() + 1]',
group_name)
aug.save()
with action_utils.WebserverChange() as webserver_change:
webserver_change.enable('sharing-freedombox')
def subcommand_remove(arguments):
"""Remove a share from Apache configuration."""
url_to_remove = '/share/' + arguments.name
aug = load_augeas()
for directive in aug.match('$conf/directive'):
if aug.get(directive) != 'Alias':
continue
url = aug.get(directive + '/arg[1]')
if url == url_to_remove:
aug.remove(directive)
for location in aug.match('$conf/Location'):
url = aug.get(location + '/arg')
if url == url_to_remove:
aug.remove(location)
aug.save()
with action_utils.WebserverChange() as webserver_change:
webserver_change.enable('sharing-freedombox')
def _get_name_from_url(url):
"""Return the name of the share given the URL for it."""
matches = re.match(r'/share/([a-z0-9\-]*)', url)
if not matches:
raise ValueError
return matches[1]
def _list(aug=None):
"""List all Apache configuration shares."""
if not aug:
aug = load_augeas()
shares = []
for match in aug.match('$conf/directive'):
if aug.get(match) != 'Alias':
continue
url = aug.get(match + '/arg[1]')
path = aug.get(match + '/arg[2]')
try:
name = _get_name_from_url(url)
shares.append({
'name': name,
'path': path,
'url': '/share/' + name
})
except ValueError:
continue
for location in aug.match('$conf/Location'):
url = aug.get(location + '/arg')
try:
name = _get_name_from_url(url)
except ValueError:
continue
groups = []
for group in aug.match(location + '//directive["TKTAuthToken"]/arg'):
groups.append(aug.get(group))
for share in shares:
if share['name'] == name:
share['groups'] = groups
return shares
def subcommand_list(_):
"""List all Apache configuration shares and print as JSON."""
print(json.dumps({'shares': _list()}))
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()