From 01e8b3bba0ba459287b89022e3225509b704c13e Mon Sep 17 00:00:00 2001 From: aewens Date: Thu, 17 Jan 2019 23:32:03 +0100 Subject: [PATCH] Initial commit --- LICENSE | 2 +- share | 95 +++++++++++++++++++++++++++++++++++++++++ uscripts | 126 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 222 insertions(+), 1 deletion(-) create mode 100755 share create mode 100755 uscripts diff --git a/LICENSE b/LICENSE index 547d63d..f617cbf 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) . All rights reserved. +Copyright (c) 2019 Austin Ewens. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. diff --git a/share b/share new file mode 100755 index 0000000..2c0b490 --- /dev/null +++ b/share @@ -0,0 +1,95 @@ +#!/usr/bin/env python3 + +from os import (stat, utime, fdopen, supports_fd, O_CREAT, O_APPEND, + open as osopen) +from os.path import exists, isfile +from argparse import ArgumentParser +from sys import exit, stderr +from email.mime.text import MIMEText +from subprocess import Popen, PIPE +from getpass import getuser +from pwd import getpwuid +from socket import gethostname +from shlex import split as shell_split + +def eprint(*args, **kwargs): + print(*args, file=stderr, **kwargs) + +def touch(fname, mode=0o666, dir_fd=None, **kwargs): + flags = O_CREAT | O_APPEND + with fdopen(osopen(fname, flags=flags, mode=mode, dir_fd=dir_fd)) as f: + utime(f.fileno() if utime in supports_fd else fname, + dir_fd=None if supports_fd else dir_fd, **kwargs) + +def ownership(filename): + return getpwuid(stat(filename).st_uid).pw_name + +def mail(user, subject, body): + domain = gethostname() + message = MIMEText(body) + message["From"] = "{}@{}".format(user, domain) + message["To"] = "root@{}".format(domain) + message["Subject"] = subject + command = shell_split("/usr/sbin/sendmail -t -oi") + proc = Popen(command, stdin=PIPE, universal_newlines=True) + proc.communicate(message.as_string()) + +def share_list(config_file, splitter): + scripts = None + with open(config_file, "r") as cfgfile: + scripts = cfgfile.read().split("\n") + if len(scripts) == 1 and len(scripts[0]) == 0: + print("There are currently no shared user scripts") + exit(0) + for script in scripts: + name, path, desc, author = script.split(splitter) + print("{}\t{} (made by {})".format(name, desc, author).expandtabs()) + +def share_submit(queue_file, splitter): + script_path = input("Absolute path to script: ") + if not isfile(script_path): + eprint("ERROR: That script does not exist") + exit(1) + user = getuser() + owner = ownership(script_path) + if user != owner: + eprint("ERROR: You do not own this script") + exit(1) + script_name = script_path.split("/")[-1] + script_desc = input("Description of script: ") + with open(queue_file, "a") as queue: + queue.write("{0}{4}{1}{4}{2}{4}{3}".format(script_name, script_path, + script_desc, user, splitter)) + subject = "Submission of '{}' script".format(script_name) + body = "\n".join([ + "Path to script: {}".format(script_path), + "Description: {}".format(script_desc), + "Author: {}".format(user) + ]) + mail(user, subject, body) + print("SUCCESS: Your script has been submitted for approval") + +config_file = "/center/etc/shared" +splitter = "%%" +if not exists(config_file): + touch(config_file) + +queue_file = "{}.queue".format(config_file) +if not exists(queue_file): + touch(queue_file) + +description = "Allows users to share their scripts with the server" +parser = ArgumentParser(prog="share", description=description) +subparsers = parser.add_subparsers(title="commands", dest="commands") +subparsers.required = False +list_parser = subparsers.add_parser("list", help="list all shared scripts") +submit_parser = subparsers.add_parser("submit", + help="starts interactive prompt to share your script") +arguments = parser.parse_args() + +if arguments.commands == "list": + share_list(config_file, splitter) +elif arguments.commands == "submit": + share_submit(queue_file, splitter) +else: + parser.print_help() \ No newline at end of file diff --git a/uscripts b/uscripts new file mode 100755 index 0000000..2b632c9 --- /dev/null +++ b/uscripts @@ -0,0 +1,126 @@ +#!/usr/bin/env python3 + +from os import symlink +from os.path import exists +from argparse import ArgumentParser +from sys import exit, stderr +from argparse import ArgumentParser +from getpass import getuser +from email.mime.text import MIMEText +from subprocess import Popen, PIPE +from socket import gethostname + +def eprint(*args, **kwargs): + print(*args, file=stderr, **kwargs) + +def mail(sender, user, subject, body): + domain = gethostname() + message = MIMEText(body) + message["From"] = "{}@{}".format(sender, domain) + message["To"] = "{}@{}".format(user, domain) + message["Subject"] = subject + command = shell_split("/usr/sbin/sendmail -t -oi") + proc = Popen(command, stdin=PIPE, universal_newlines=True) + proc.communicate(message.as_string()) + +def remove_script_from_queue(queue_file, splitter, scripts, index): + script_name = sorted(list(scripts.keys()))[index] + del scripts[script_name] + lines = list() + for name, attrs in scripts: + path = attrs.get("path", "") + desc = attrs.get("desc", "") + user = attrs.get("user", "") + lines.append(splitter.join([name, path, desc, user])) + with open(queue_file, "w") as qfile: + qfile.write("\n".join(lines)) + +description = "Administrative tool for handling shared user script submissions" +parser = ArgumentParser(prog="uscript", description=description) +parser.add_argument("-l", "--list", dest="list", action="store_true", + help="list all submitted scripts") +parser.add_argument("-a", "--approve", dest="approve", nargs="?", + help="approval of script index based on position from --list") +parser.add_argument("-R", "--reject", dest="reject", nargs="?", + help="rejection of script index based on position from --list") +arguments = parser.parse_args() + +config_file = "/center/etc/shared" +queue_file = "{}.queue".format("/center/etc/shared") +splitter = "%%" +queued = None + +if not exists(queue_file): + print("No scripts are queued") + exit(0) + +with open(queue_file, "r") as qfile: + queued = qfile.read().split("\n") + +if len(queued) == 1 and len(queued[0]) == 0: + print("No scripts are queued") + exit(0) + +scripts = dict() +names = list() +for queue in queued: + name, path, desc, user = queue.split(splitter) + scripts[name] = { + "path": path, + "desc": desc, + "user": user + } + names.append(name) +names = sorted(names) + +if arguments.list: + header = "Index\tScript\tAuthor".expandtabs() + print(header) + print("-" * len(header)) + for n, name in enumerate(names): + author = scripts[name]["user"] + print("{}\t{}\t{}".format(n, name, author).expandtabs()) + +approved = arguments.approve +rejected = arguments.reject +if approved is not None: + approved = int(approved) + if 0 > approved >= len(names): + eprint("ERROR: That index does not exist, see --list") + exit(1) + script_name = names[approved] + script = scripts[script_name] + script_path = script["path"] + user = script["user"] + sender = getuser() + user_bin = "/center/bin" + symlink(script_path, "{}/{}".format(user_bin, script_name)) + remove_script_from_queue(queue_file, splitter, scripts, approved) + subject = "{} has been approved".format(script_name) + body = "".join([ + "Congratulations! Your script '{}' has been ".format(script_name), + "approved by {} and has been added to the server's ".format(sender), + "user script repository found at /center/bin." + ]) + mail(sender, user, subject, body) + print("'{}' has been approved, email has been sent".format(script_name)) + +if rejected is not None: + rejected = int(rejected) + if 0 > rejected >= len(names): + eprint("ERROR: That index does not exist, see --list") + exit(1) + script_name = names[rejected] + script = scripts[script_name] + user = script["user"] + sender = getuser() + remove_script_from_queue(queue_file, splitter, scripts, rejected) + print("'{}' has been rejected".format(script_name)) + reason = input("Provide reason for user ({}): ".format(author)) + subject = "{} has been rejected".format(script_name) + body = "".join([ + "Unfortunately, your script '{}' has been ".format(script_name), + "rejected by {} for the following reason(s):\n{}".format(sender) + ]) + mail(sender, user, subject, body) + print("'{}' has been rejected, email has been sent".format(script_name)) \ No newline at end of file