# HG changeset patch # User Josef "Jeff" Sipek # Date 1150663718 14400 # Node ID eee271568e8ae6d95ddcc2247eb43fc0ed7afa3b # Parent 092039246d7335342e9a68be90fa625bd3780647 Initial version of pyhgsh diff -r 092039246d73 -r eee271568e8a contrib/pyhgsh/TODO --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/contrib/pyhgsh/TODO Sun Jun 18 16:48:38 2006 -0400 @@ -0,0 +1,12 @@ +- use cmd module to provide a more powerful shell + (http://docs.python.org/lib/module-cmd.html) +- command execution + - verify that the repository is in the list of allowed repositories + - make sure that we are executing 'hg serve' and nothing else +- implement interactive commands: + - clone + - init + - pull + - push +- convert pyhgsh.repos to format similar to hgrc + - use this config file to define all config options diff -r 092039246d73 -r eee271568e8a contrib/pyhgsh/pyhgsh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/contrib/pyhgsh/pyhgsh Sun Jun 18 16:48:38 2006 -0400 @@ -0,0 +1,194 @@ +#!/usr/bin/python +# +# pyhgsh - restricted login shell for mercurial implemented in Python +# +# Copyright 2006 Josef "Jeff" Sipek +# +# This software may be used and distributed according to the terms of the +# GNU General Public License, incorporated herein by reference. +# +# this program is login shell for dedicated mercurial user account. it +# only allows few actions: +# +# 1. run hg in server mode on specific repository. +# +# 2. run interactive shell, allows for repository maintainance +# +# only tested on linux yet. patches for non-linux systems welcome. +# + +import os +import sys + +name = "pyhgsh" +version = "0.5" + +prompt = "> " +repofile= "pyhgsh.repos" + +repos = [] + +def debugexit(argv, code): + print argv + sys.exit(0) + +def write(str): + sys.stdout.write(str) + +def valid_repo(r): + " returns true if r is in list of repos" + global repos + + for okr in repos: + if okr == r: + return True + + return False + +def cmd_help(args): + print name + ": The Python Mercurial shell" + print "" + print "available commands:" + print "" + for c in cmds: + print " %s\t%s" % (c[0], c[2]) + +def cmd_verify(args): + try: + repo = args[0] + except IndexError: + print name + ": you must specify a valid repository" + return + + if not valid_repo(repo): + print name + ": '%s' is not a valid repository" % (repo,) + return + + os.system("hg -R %s verify" % (repo,)) + +def cmd_repos(args): + for r in repos: + print r + +def cmd_quit(args): + sys.exit(0) + +def cmd_version(args): + print name + " (version " + version + ")" + os.system("hg version | head -1") + +def cmd_invalid(cmd): + print name + ": Invalid command '%s'" % (cmd,) + +def interactive(): + """ + This is an interactive shell handler + """ + print "" + cmd_help([]) + print "" + + while True: + write(prompt) + + try: + line = sys.stdin.readline() + tok = line.strip().split(" ") + except KeyboardInterrupt: + # ctrl-c + print "" + continue + + if len(line) == 0: + # ctrl-d ? + print "" + cmd_quit([]) + + if tok[0] != "": + # non-empty command + ok = False + for c in cmds: + if tok[0] == c[0]: + # command found, execute + c[1](tok[1:]) + ok = True + break + + if not ok: + # command not found + cmd_invalid(tok[0]) + +def execute(cmd): + """ + Request for execution of a command handler + """ + + # this is the potentially exploitable area of the shell therefore we + # must make sure that everything is checked properly before we + # execute the command + + tok = cmd.split(" ") + + # it must be a hg call + if tok[0] != "hg": + print "Not a hg call" + return + + # FIXME: hacky + if cmd.find(";") != -1: + print "Detected attept to exploit shell" + return + + # FIXME: make sure the repo is allowed + + os.system(cmd) + +def main(argv): + """ + main, get things prepared + """ + + argv.pop(0) + + # read in list of allowed repositories + global repos + f = open(repofile) + repos = f.readlines() + f.close() + + for i in range(len(repos)): + repos[i] = repos[i].strip() + + if len(argv) == 0: + # no args + interactive() + + elif len(argv) == 2: + if argv[0] == "-c": + # execute command + execute(argv[1]) + + else: + # unknown + debugexit(argv, 1) + + else: + # unkown + debugexit(argv, 1) + +# commented out commands are not implemented +cmds = ( +# ("clone", cmd_clone, "clone a repository"), + ("help", cmd_help, "this screen help"), +# ("init", cmd_init, "init a repository"), +# ("pull", cmd_pull, "pull changes from one repository to another"), +# ("push", cmd_push, "push changes from one repository to another"), + ("quit", cmd_quit, "close this session"), + ("repos", cmd_repos, "list repositories available"), + ("verify", cmd_verify, "verify a repository"), + ("version", cmd_version, "display version"), +) + +if __name__ == "__main__": + main(sys.argv) +