Skip to content

Commit

Permalink
Initial Commit
Browse files Browse the repository at this point in the history
  • Loading branch information
unknown authored and Viper-7 committed Mar 1, 2012
0 parents commit 89e7161
Show file tree
Hide file tree
Showing 146 changed files with 11,922 additions and 0 deletions.
61 changes: 61 additions & 0 deletions README
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
Viper-7's Codepad - version 4.0-alpha - Deployable at last!

This is still very much a work in progress, and is the result of a few hours of prep work, a single 14 hour marathon coding session, and my old core silverstripe codepad module, which hasn't been touched since I hacked it together in version 2 :/

Still, this is by far the most powerful codepad engine I have ever built. The framework can easily handle any target language, not just PHP, and with total control over the php.ini settings, request & response content, execution environment and command line, on a per-user or per-paste basis, I can finally have the freedom to implement all the features we've all been wanting ;)

And we still haven't gotten to the big part yet - It's deployable!

A large chunk of my effort has gone in to 3 management objects, PHP_Downloader, PHP_Compiler and PHP_Jailer. With these you can setup the codepad on any VPS you have (you'll need root access for this),

PHP_Downloader will take a php version number like "5.3", "5.4-dev", "5.2.16", "trunk", etc; and provide you with a bzip2 archive for that release. Currently the archive support is missing, which will cause some slight internal changes (I might replace the current method of fetching the latest release with it.)

PHP_Compiler will take a version number, a bzip2 archive and an array of configure options, then extract & compile that release, with complete & informative error detection along the way, and finally will deploy it as a usable engine outside the jail

PHP_Jailer takes that usable PHP installation, and deploys it inside a chroot jail, creating whatever it needs along the way. It will add a new user, "jailexec", which is what all pastes will be executed as. This user should have no filesystem permissions inside the jail aside from /tmp, and will be automatically restricted to the codepad's chroot jail.


From there, I have two Gearman workers:

One which runs as root outside the jail, "Manager", performing the grunt work of compiling & installing PHP, creating users, and updating database records while remaining strict & secure.

And the other, "Worker", which runs inside the jail as the jailexec user, and executes pastes via a mock CGI interface, where security is no problem, and so where the entire request/response transaction, shell environment, php extensions, and even custom php.ini's are all fair game - and the simple JSON interface via Gearman can easily support all kinda of meta-data and dynamic settings, and can be opened up into a public API with a few lines of code.


All of this comes together to mean you can order up your serving of php version, php extensions, php.ini, request/response processing (eg plain text vs html rendering, user-agent, etc), and have it automatically compiled (if required), and used to deliver your pasted code.


Pastes now remember what version they were pasted with implicitly, and we're ready for user tracking / accounts :D


For now - I think my brain needs a rest :P Will be back with more updates later - until then.. Enjoy :D




Dependencies:

A working webserver with PHP already up and running.
PHP extensions: PDO_mysql, DOMDocument, Gearman
Shell Utils: Gearman, Timelimit, Nice, Jailkit, ulimit (from bash), tar (bz2),
Front-end: SilverStripe CMS



Todo:

multiple preforked workers (queuing already works)
double check if a version already exists in a compiled state in PHP_Compiler
use archive version urls for older versions
refactor $jail_log/$jailuser_log/$user_log/etc to an array to be returned by PHP_Jailer
add shell error redirection in PHP_Jailer
replace debug echos in manager/lib/PHP_* classes with gearman job status updates
have manager automatically deploy a cut-down shared php install into the jail (/usr/local/php)
refactor $params['input'] in worker to $input
improve request/response data streaming code to support async requests as before (long polling)
refactor the core SS module code - preferably removing the hack in ModelAsController
rebuild ss module plugins from v3 to work with the new engine
(re)add more extensions (vld, xdebug, xhprof, imagick, anything else people think of) - user profile and/or per paste control? >:D
readd "make test" to PHP_Compiler
improve security (currently lacking a form honeypot, and per-paste disk & network traffic monitoring)
remap chroot's /tmp as noexec
128 changes: 128 additions & 0 deletions debian_init/codepad_manager
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
#! /bin/sh
### BEGIN INIT INFO
# Provides: codepad_manager
# Required-Start: $remote_fs $syslog
# Required-Stop: $remote_fs $syslog
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Example initscript
# Description: This file should be used to construct scripts to be
# placed in /etc/init.d.
### END INIT INFO

# Author: Foo Bar <foobar@baz.org>
#
# Please remove the "Author" lines above and replace them
# with your own name if you copy and modify this script.

# Do NOT "set -e"

# PATH should only include /usr/* if it runs after the mountnfs.sh script
PATH=/sbin:/usr/sbin:/bin:/usr/bin
DESC="Codepad Manager"
NAME=codepad_manager
SCRIPTNAME=/etc/init.d/$NAME

# Read configuration variable file if it is present
[ -r /etc/default/$NAME ] && . /etc/default/$NAME

# Load the VERBOSE setting and other rcS variables
. /lib/init/vars.sh

# Define LSB log_* functions.
# Depend on lsb-base (>= 3.2-14) to ensure that this file is present
# and status_of_proc is working.
. /lib/lsb/init-functions

#
# Function that starts the daemon/service
#
do_start()
{
cd /opt/codepad_core
/usr/local/php/bin/php /opt/codepad_core/manager.php 2>&1 &
echo $! > /var/run/codepad_manager.pid
}

#
# Function that stops the daemon/service
#
do_stop()
{
start-stop-daemon --stop --quiet --retry=TERM/5/KILL/5 --pidfile /var/run/codepad_manager.pid

rm -f $PIDFILE
}

#
# Function that sends a SIGHUP to the daemon/service
#
do_reload() {
#
# If the daemon can reload its configuration without
# restarting (for example, when it is sent a SIGHUP),
# then implement that here.
#
start-stop-daemon --stop --signal 1 --quiet --pidfile $PIDFILE --name $NAME
return 0
}

case "$1" in
start)
[ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME"
do_start
case "$?" in
0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
esac
;;
stop)
[ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME"
do_stop
case "$?" in
0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
esac
;;
status)
status_of_proc "$DAEMON" "$NAME" && exit 0 || exit $?
;;
#reload|force-reload)
#
# If do_reload() is not implemented then leave this commented out
# and leave 'force-reload' as an alias for 'restart'.
#
#log_daemon_msg "Reloading $DESC" "$NAME"
#do_reload
#log_end_msg $?
#;;
restart|force-reload)
#
# If the "reload" option is implemented then remove the
# 'force-reload' alias
#
log_daemon_msg "Restarting $DESC" "$NAME"
do_stop
case "$?" in
0|1)
do_start
case "$?" in
0) log_end_msg 0 ;;
1) log_end_msg 1 ;; # Old process is still running
*) log_end_msg 1 ;; # Failed to start
esac
;;
*)
# Failed to stop
log_end_msg 1
;;
esac
;;
*)
#echo "Usage: $SCRIPTNAME {start|stop|restart|reload|force-reload}" >&2
echo "Usage: $SCRIPTNAME {start|stop|status|restart|force-reload}" >&2
exit 3
;;
esac

:
126 changes: 126 additions & 0 deletions debian_init/codepad_worker
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
#! /bin/sh
### BEGIN INIT INFO
# Provides: codepad_worker
# Required-Start: $remote_fs $syslog
# Required-Stop: $remote_fs $syslog
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Example initscript
# Description: This file should be used to construct scripts to be
# placed in /etc/init.d.
### END INIT INFO

# Author: Foo Bar <foobar@baz.org>
#
# Please remove the "Author" lines above and replace them
# with your own name if you copy and modify this script.

# Do NOT "set -e"

# PATH should only include /usr/* if it runs after the mountnfs.sh script
PATH=/sbin:/usr/sbin:/bin:/usr/bin
DESC="Codepad Worker"
NAME=codepad_worker
SCRIPTNAME=/etc/init.d/$NAME

# Read configuration variable file if it is present
[ -r /etc/default/$NAME ] && . /etc/default/$NAME

# Load the VERBOSE setting and other rcS variables
. /lib/init/vars.sh

# Define LSB log_* functions.
# Depend on lsb-base (>= 3.2-14) to ensure that this file is present
# and status_of_proc is working.
. /lib/lsb/init-functions

#
# Function that starts the daemon/service
#
do_start()
{
jk_chrootlaunch -j /opt/codepad -u jailexec -p /var/run/codepad_worker.pid -x /usr/local/php/bin/php -- /bin/worker.php &
}

#
# Function that stops the daemon/service
#
do_stop()
{
start-stop-daemon --stop --quiet --retry=TERM/5/KILL/5 --pidfile /var/run/codepad_worker.pid

rm -f $PIDFILE
}

#
# Function that sends a SIGHUP to the daemon/service
#
do_reload() {
#
# If the daemon can reload its configuration without
# restarting (for example, when it is sent a SIGHUP),
# then implement that here.
#
start-stop-daemon --stop --signal 1 --quiet --pidfile $PIDFILE --name $NAME
return 0
}

case "$1" in
start)
[ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME"
do_start
case "$?" in
0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
esac
;;
stop)
[ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME"
do_stop
case "$?" in
0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
esac
;;
status)
status_of_proc "$DAEMON" "$NAME" && exit 0 || exit $?
;;
#reload|force-reload)
#
# If do_reload() is not implemented then leave this commented out
# and leave 'force-reload' as an alias for 'restart'.
#
#log_daemon_msg "Reloading $DESC" "$NAME"
#do_reload
#log_end_msg $?
#;;
restart|force-reload)
#
# If the "reload" option is implemented then remove the
# 'force-reload' alias
#
log_daemon_msg "Restarting $DESC" "$NAME"
do_stop
case "$?" in
0|1)
do_start
case "$?" in
0) log_end_msg 0 ;;
1) log_end_msg 1 ;; # Old process is still running
*) log_end_msg 1 ;; # Failed to start
esac
;;
*)
# Failed to stop
log_end_msg 1
;;
esac
;;
*)
#echo "Usage: $SCRIPTNAME {start|stop|restart|reload|force-reload}" >&2
echo "Usage: $SCRIPTNAME {start|stop|status|restart|force-reload}" >&2
exit 3
;;
esac

:
Loading

0 comments on commit 89e7161

Please sign in to comment.