changeset 2425:eee271568e8a default tip

Initial version of pyhgsh
author Josef "Jeff" Sipek <jeffpc@optonline.net>
date Sun, 18 Jun 2006 16:48:38 -0400
parents 092039246d73
children
files contrib/pyhgsh/TODO contrib/pyhgsh/pyhgsh
diffstat 2 files changed, 206 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /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
--- /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 <jsipek@cs.sunysb.edu>
+#
+# 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)
+