Git Repositories

Initial commit.
authorCyrille Pontvieux <jrd@enialis.net>
Tue, 15 Jan 2013 16:08:30 +0000 (17:08 +0100)
committerCyrille Pontvieux <jrd@enialis.net>
Tue, 15 Jan 2013 16:08:30 +0000 (17:08 +0100)
Translations should be added. For now, only French.

21 files changed:
.gitignore [new file with mode: 0644]
homegit/git-shell-commands/check [new file with mode: 0755]
homegit/gitrepo.sh [new file with mode: 0755]
homegit/makekeys.sh [new file with mode: 0755]
install.sh [new file with mode: 0755]
src/.admins [new file with mode: 0644]
src/account.php [new file with mode: 0644]
src/admin-users.php [new file with mode: 0644]
src/config.inc.php.example [new file with mode: 0644]
src/disconnect.php [new file with mode: 0644]
src/include.inc.php [new file with mode: 0644]
src/index.php [new file with mode: 0644]
src/nav.inc.php [new file with mode: 0644]
src/repo-del.php [new file with mode: 0644]
src/repo-histo.php [new file with mode: 0644]
src/repo-user-del.php [new file with mode: 0644]
src/repo-users.php [new file with mode: 0644]
src/style.css [new file with mode: 0644]
src/user-del-key.php [new file with mode: 0644]
src/user-del.php [new file with mode: 0644]
sudoers.d/git [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..f8d728c
--- /dev/null
@@ -0,0 +1 @@
+www
diff --git a/homegit/git-shell-commands/check b/homegit/git-shell-commands/check
new file mode 100755 (executable)
index 0000000..ec25370
--- /dev/null
@@ -0,0 +1,15 @@
+#!/bin/sh
+GITUSER="$1"
+eval set -- $SSH_ORIGINAL_COMMAND
+# $1 = command
+# $2 = repo path
+REPO="$2"
+if [ -d "$REPO" ] && [ -r "$REPO"/.users ]; then
+  if grep -q "^$GITUSER\$" "$REPO"/.users; then
+    eval "$@"
+  else
+    echo "Error: $GITUSER not authorized on $REPO" >&2
+  fi
+else
+  eval "$@"
+fi
diff --git a/homegit/gitrepo.sh b/homegit/gitrepo.sh
new file mode 100755 (executable)
index 0000000..975a015
--- /dev/null
@@ -0,0 +1,482 @@
+#!/bin/sh
+# vim: et ai cin sw=2 ts=2 tw=0:
+cd ~/
+
+usage() {
+  cat <<EOF
+$0 Action Parameters
+Action is one of:
+ - create Name [Description]
+ - destroy Name
+ - get Name Option
+   Option can be
+   * 'description'
+   * a git configuration option
+ - set Name Option Value
+ - list-users
+ - create-user Username Password [Key]
+   Password should be in md5
+ - change-user Username Password
+ - show-pwd Username
+ - destroy-user Username
+ - show-users Name
+ - add-user Name Username
+   Username should already exists
+ - del-user Name Username
+ - list-keys Username
+ - add-key Username Key
+ - del-key Username Key
+   del-key Username Position
+   Position starts from 1 as listed by list-keys
+ - graph Name
+   Show a graphical representation of the repository.
+EOF
+}
+
+checkparams() {
+  while [ -n "$1" ]; do
+    param="$1"
+    eval value="\$$param"
+    if [ -z "$value" ]; then
+      echo "$param is missing" >&2
+      exit 1
+    fi
+    shift
+  done
+}
+
+check_repo() {
+  REPO="$1"
+  if echo "$REPO" | grep -q '[^-_a-zA-Z0-9]'; then
+    echo "Repository name can only contains letters, numbers, hyphen and underscore" >&2
+    exit 2
+  fi
+}
+
+check_username() {
+  NAME="$1"
+  if echo "$NAME" | grep -q '[^-_a-zA-Z0-9]'; then
+    echo "User name can only contains letters, numbers, hyphen and underscore" >&2
+    exit 2
+  fi
+}
+
+create_repo() {
+  REPO="$1"
+  DESC="$2"
+  check_repo "$REPO"
+  if [ -d "$REPO".git ]; then
+    echo "$REPO already exists." >&2
+    exit 2
+  fi
+  mkdir "$REPO".git
+  (
+    cd "$REPO".git
+    git --bare init
+    git config core.sharedRepository 1
+    [ -n "$DESC" ] && echo "$DESC" > description
+  )
+}
+
+destroy_repo() {
+  REPO="$1"
+  check_repo "$REPO"
+  if [ ! -d "$REPO".git ]; then
+    echo "$REPO does not exist." >&2
+    exit 2
+  fi
+  rm -rf "$REPO".git
+}
+
+get_option() {
+  REPO="$1"
+  OPTION="$2"
+  check_repo "$REPO"
+  if [ ! -d "$REPO".git ]; then
+    echo "$REPO does not exist." >&2
+    exit 2
+  fi
+  if [ "$OPTION" = "description" ]; then
+    cat "$REPO".git/description
+  else
+    (
+      cd "$REPO".git
+      git --bare config "$OPTION"
+    )
+  fi
+}
+
+set_option() {
+  REPO="$1"
+  OPTION="$2"
+  OPT_VAL="$3"
+  check_repo "$REPO"
+  if [ ! -d "$REPO".git ]; then
+    echo "$REPO does not exist." >&2
+    exit 2
+  fi
+  if [ "$OPTION" = "description" ]; then
+    echo "$OPT_VAL" > "$REPO".git/description
+  else
+    (
+      cd "$REPO".git
+      git --bare config "$OPTION" "$OPT_VAL"
+    )
+  fi
+}
+
+list_users() {
+  for f in .keys/*.pwd; do
+    basename $f .pwd
+  done
+}
+
+create_user() {
+  USERNAME="$1"
+  PASSWD="$2"
+  KEY="$3"
+  check_username "$USERNAME"
+  if [ -f .keys/$USERNAME.pwd ]; then
+    echo "$USERNAME already exists." >&2
+    exit 2
+  fi
+  mkdir -p .keys
+  echo "$PASSWD" > .keys/$USERNAME.pwd
+  if [ -n "$KEY" ]; then
+    echo "$KEY" > .keys/$USERNAME.keys
+  else
+    touch .keys/$USERNAME.keys
+  fi
+  ./makekeys.sh
+}
+
+change_user() {
+  USERNAME="$1"
+  PASSWD="$2"
+  check_username "$USERNAME"
+  if [ ! -f .keys/$USERNAME.pwd ]; then
+    echo "$USERNAME does not exists." >&2
+    exit 2
+  fi
+  mkdir -p .keys
+  echo "$PASSWD" > .keys/$USERNAME.pwd
+}
+
+show_pwd() {
+  USERNAME="$1"
+  check_username "$USERNAME"
+  if [ ! -f .keys/$USERNAME.pwd ]; then
+    echo "$USERNAME does not exists." >&2
+    exit 2
+  fi
+  cat .keys/$USERNAME.pwd
+}
+
+destroy_user() {
+  USERNAME="$1"
+  check_username "$USERNAME"
+  if [ ! -f .keys/$USERNAME.pwd ]; then
+    echo "$USERNAME does not exists." >&2
+    exit 2
+  fi
+  rm .keys/$USERNAME.*
+  for p in ?*.git; do
+    [ -e $p/.users ] && sed -i "/^$USERNAME\$/d" $p/.users
+  done
+  ./makekeys.sh
+}
+
+add_user() {
+  REPO="$1"
+  USERNAME="$2"
+  check_repo "$REPO"
+  check_username "$USERNAME"
+  if [ ! -d "$REPO".git ]; then
+    echo "$REPO does not exist." >&2
+    exit 2
+  fi
+  if [ ! -f .keys/$USERNAME.pwd ]; then
+    echo "$USERNAME does not exists." >&2
+    exit 2
+  fi
+  [ -e "$REPO".git/.users ] || touch "$REPO".git/.users
+  grep -q "^$USERNAME\$" "$REPO".git/.users || echo "$USERNAME" >> "$REPO".git/.users
+}
+
+del_user() {
+  REPO="$1"
+  USERNAME="$2"
+  check_repo "$REPO"
+  check_username "$USERNAME"
+  if [ ! -d "$REPO".git ]; then
+    echo "$REPO does not exist." >&2
+    exit 2
+  fi
+  if [ -e "$REPO".git/.users ]; then
+    grep -q "^$USERNAME\$" "$REPO".git/.users && sed -i "/^$USERNAME\$/d" "$REPO".git/.users
+  fi
+}
+
+show_users() {
+  REPO="$1"
+  check_repo "$REPO"
+  if [ ! -d "$REPO".git ]; then
+    echo "$REPO does not exist." >&2
+    exit 2
+  fi
+  if [ -f "$REPO".git/.users ]; then
+    cat "$REPO".git/.users
+  fi
+}
+
+list_keys() {
+  USERNAME="$1"
+  check_username "$USERNAME"
+  if [ ! -f .keys/$USERNAME.pwd ]; then
+    echo "$USERNAME does not exists." >&2
+    exit 2
+  fi
+  cat .keys/$USERNAME.keys
+}
+
+add_key() {
+  USERNAME="$1"
+  KEY="$2"
+  check_username "$USERNAME"
+  if [ ! -f .keys/$USERNAME.pwd ]; then
+    echo "$USERNAME does not exists." >&2
+    exit 2
+  fi
+  echo "$KEY" >> .keys/$USERNAME.keys
+  ./makekeys.sh
+}
+
+del_key() {
+  USERNAME="$1"
+  KEY="$2"
+  check_username "$USERNAME"
+  if [ ! -f .keys/$USERNAME.pwd ]; then
+    echo "$USERNAME does not exists." >&2
+    exit 2
+  fi
+  if echo "$KEY" | grep -q "^[0-9]\+$"; then
+    if [ $KEY -eq 1 ]; then
+      sed -i -n '2,$p' .keys/$USERNAME.keys
+    else
+      prev=$(($KEY - 1))
+      next=$(($KEY + 1))
+      sed -i -n "1,${prev}p; ${next},\$p" .keys/$USERNAME.keys
+    fi
+  else
+    sed -i "/^$KEY\$/d" .keys/$USERNAME.keys
+  fi
+  ./makekeys.sh
+}
+
+graph() {
+  NAME="$1"
+  check_repo "$NAME"
+  if [ ! -d "$NAME".git ]; then
+    echo "$NAME does not exist." >&2
+    exit 2
+  fi
+  (
+    cd "$NAME".git
+    git log --all --oneline --graph --decorate=short
+  )
+}
+
+ACTION=''
+NAME=''
+REPO=''
+USERNAME=''
+PASSWD=''
+DESC=''
+OPTION=''
+OPT_VAL=''
+KEY=''
+while [ -n "$1" ]; do
+  case "$1" in
+    -h|--help)
+      usage
+      exit 0
+      ;;
+    *)
+      if [ -z "$ACTION" ]; then
+        if echo "$1" | grep -q '^\(create\|destroy\|get\|set\|list-users\|create-user\|change-user\|show-pwd\|destroy-user\|show-users\|add-user\|del-user\|list-keys\|add-key\|del-key\|graph\)$'; then
+          ACTION="$1"
+          shift
+        else
+          echo "Unrecognized action ($1)" >&2
+          exit 1
+        fi
+      else
+        if [ "$ACTION" = "list-users" ]; then
+          echo "Unrecognized parameter ($1)" >&2
+          exit 1
+        elif [ -z "$NAME" ]; then
+          NAME="$1"
+          shift
+        else
+          if [ "$ACTION" = "create" ]; then
+            if [ -z "$DESC" ]; then
+              DESC="$1"
+              shift
+            else
+              echo "Unrecognized parameter ($1)" >&2
+              exit 1
+            fi
+          elif [ "$ACTION" = "destroy" ]; then
+            echo "Unrecognized parameter ($1)" >&2
+            exit 1
+          elif [ "$ACTION" = "get" ] || [ "$ACTION" = "set" ]; then
+            if [ -z "$OPTION" ]; then
+              OPTION="$1"
+              shift
+            elif [ "$ACTION" = "set" ] && [ -z "$OPT_VAL" ]; then
+              OPT_VAL="$1"
+              shift
+            else
+              echo "Unrecognized parameter ($1)" >&2
+              exit 1
+            fi
+          elif [ "$ACTION" = "create-user" ]; then
+            if [ -z "$PASSWD" ]; then
+              PASSWD="$1"
+              shift
+            elif [ -z "$KEY" ]; then
+              KEY="$1"
+              shift
+            else
+              echo "Unrecognized parameter ($1)" >&2
+              exit 1
+            fi
+          elif [ "$ACTION" = "change-user" ]; then
+            if [ -z "$PASSWD" ]; then
+              PASSWD="$1"
+              shift
+            else
+              echo "Unrecognized parameter ($1)" >&2
+              exit 1
+            fi
+          elif [ "$ACTION" = "show-pwd" ]; then
+            echo "Unrecognized parameter ($1)" >&2
+            exit 1
+          elif [ "$ACTION" = "destroy-user" ]; then
+            echo "Unrecognized parameter ($1)" >&2
+            exit 1
+          elif [ "$ACTION" = "show-users" ]; then
+            echo "Unrecognized parameter ($1)" >&2
+            exit 1
+          elif [ "$ACTION" = "add-user" ] || [ "$ACTION" = "del-user" ]; then
+            if [ -z "$USERNAME" ]; then
+              USERNAME="$1"
+              shift
+            else
+              echo "Unrecognized parameter ($1)" >&2
+              exit 1
+            fi
+          elif [ "$ACTION" = "list-keys" ]; then
+            echo "Unrecognized parameter ($1)" >&2
+            exit 1
+          elif [ "$ACTION" = "add-key" ] || [ "$ACTION" = "del-key" ]; then
+            if [ -z "$KEY" ]; then
+              KEY="$1"
+              shift
+            else
+              echo "Unrecognized parameter ($1)" >&2
+              exit 1
+            fi
+          elif [ "$ACTION" = "graph" ]; then
+            echo "Unrecognized parameter ($1)" >&2
+            exit 1
+          fi
+        fi
+      fi
+      ;;
+  esac
+done
+case "$ACTION" in
+  "")
+    usage
+    exit 1
+    ;;
+  create)
+    REPO="$NAME"
+    checkparams REPO
+    create_repo "$REPO" "$DESC"
+    ;;
+  destroy)
+    REPO="$NAME"
+    checkparams REPO
+    destroy_repo "$REPO"
+    ;;
+  get)
+    REPO="$NAME"
+    checkparams REPO OPTION
+    get_option "$REPO" "$OPTION"
+    ;;
+  set)
+    REPO="$NAME"
+    checkparams REPO OPTION OPT_VAL
+    set_option "$REPO" "$OPTION" "$OPT_VAL"
+    ;;
+  list-users)
+    list_users "$REPO"
+    ;;
+  create-user)
+    USERNAME="$NAME"
+    checkparams USERNAME PASSWD
+    create_user "$USERNAME" "$PASSWD" "$KEY"
+    ;;
+  change-user)
+    USERNAME="$NAME"
+    checkparams USERNAME PASSWD
+    change_user "$USERNAME" "$PASSWD"
+    ;;
+  show-pwd)
+    USERNAME="$NAME"
+    checkparams USERNAME
+    show_pwd "$USERNAME"
+    ;;
+  destroy-user)
+    USERNAME="$NAME"
+    checkparams USERNAME
+    destroy_user "$USERNAME"
+    ;;
+  show-users)
+    REPO="$NAME"
+    checkparams REPO
+    show_users "$REPO"
+    ;;
+  add-user)
+    REPO="$NAME"
+    checkparams REPO USERNAME
+    add_user "$REPO" "$USERNAME"
+    ;;
+  del-user)
+    REPO="$NAME"
+    checkparams REPO USERNAME
+    del_user "$REPO" "$USERNAME"
+    ;;
+  list-keys)
+    USERNAME="$NAME"
+    checkparams USERNAME
+    list_keys "$USERNAME"
+    ;;
+  add-key)
+    USERNAME="$NAME"
+    checkparams USERNAME KEY
+    add_key "$USERNAME" "$KEY"
+    ;;
+  del-key)
+    USERNAME="$NAME"
+    checkparams USERNAME KEY
+    del_key "$USERNAME" "$KEY"
+    ;;
+  graph)
+    REPO="$NAME"
+    checkparams REPO
+    graph "$REPO"
+    ;;
+esac
diff --git a/homegit/makekeys.sh b/homegit/makekeys.sh
new file mode 100755 (executable)
index 0000000..04aca35
--- /dev/null
@@ -0,0 +1,10 @@
+#!/bin/sh
+# vim: et ai cin sw=2 ts=2 tw=0:
+cd ~/
+
+cat /dev/null > .ssh/authorized_keys.tmp
+for f in .keys/*.keys; do
+  u=$(basename $f .keys)
+  sed "s/^/command=\"check $u\" /" $f >> .ssh/authorized_keys.tmp
+done
+mv .ssh/authorized_keys.tmp .ssh/authorized_keys
diff --git a/install.sh b/install.sh
new file mode 100755 (executable)
index 0000000..d2aa22c
--- /dev/null
@@ -0,0 +1,98 @@
+#!/bin/sh
+# vim: set et ai sw=2 ts=2 tw=0:
+cd "$(dirname "$0")"
+
+usage() {
+  cat <<EOF
+install.sh -h git_host -u git_user -d git_home_dir -t web_title -w web_user
+  git_host: hostname to connect to in ssh for git access
+  git_user: user to connect to in ssh for git access
+  git_home_dir: where is the home dir of the git user
+  web_title: title of the web site
+  web_user: user running web site, usually apache or www or nobody
+EOF
+}
+GIT_HOST=''
+GIT_USER=''
+GIT_HOME_DIR=''
+WEB_TITLE=''
+WEB_USER=''
+opts=$(getopt -n install.sh -o 'h:u:d:t:w:' -- "$@")
+if [ $? -ne 0 ]; then
+  usage
+  exit 1
+fi
+eval set -- "$opts"
+while [ -n "$1" ] && [ "$1" != "--" ]; do
+  case "$1" in
+    -h)
+      GIT_HOST="$2"
+      shift 2
+      ;;
+    -u)
+      GIT_USER="$2"
+      shift 2
+      ;;
+    -d)
+      GIT_DIR="$2"
+      shift 2
+      ;;
+    -t)
+      WEB_TITLE="$2"
+      shift 2
+      ;;
+    -w)
+      WEB_USER="$2"
+      shift 2
+      ;;
+    *)
+      echo "Error, unrecognized argument: $1" >&2
+      shift
+      exit 1
+  esac
+done
+if [ -z "$GIT_HOST" ] || [ -z "$GIT_USER" ] || [ -z "$GIT_DIR" ] || [ -z "$WEB_TITLE" ] || [ -z "$WEB_USER" ]; then
+  usage
+  exit 1
+fi
+
+if [ $(id -u) -ne 0 ]; then
+  echo "You need to be root." >&2
+  exit 1
+fi
+
+if ! grep -q "^$GIT_USER:" /etc/passwd; then
+  echo "Git user '$GIT_USER' does not exist" >&2
+  exit 2
+fi
+if [ ! -d "$GIT_DIR" ]; then
+  echo "Git directory '$GIT_DIR' does not exist" >&2
+  exit 2
+fi
+if ! grep -q "^$WEB_USER:" /etc/passwd; then
+  echo "Web user '$WEB_USER' does not exist" >&2
+  exit 2
+fi
+
+usermod -s /usr/bin/git-shell $GIT_USER
+sed -i "s,^$GIT_USER:.*:\(.*\),$GIT_USER:*:\1," /etc/shadow
+GIT_GROUP=$(sed -n "/^$GIT_USER:/ s/^$GIT_USER:[^:]*:[^:]*:\([^:]*\):.*/\1/ p" /etc/passwd)
+usermod -a -G $GIT_GROUP $WEB_USER
+
+mkdir -p /etc/sudoers.d
+sed "s,WEB_USER,$WEB_USER,; s,GIT_USER,$GIT_USER,; s,GIT_DIR,$GIT_DIR,;" sudoers.d/git > /etc/sudoers.d/git
+chmod ug=r,o= /etc/sudoers.d/git
+
+cp -r homegit/* $GIT_DIR/
+
+cp -r src www
+cat <<EOF > www/config.inc.php
+<?php
+\$title = '$WEB_TITLE';
+\$githost = '$GIT_HOST';
+\$gituser = '$GIT_USER';
+\$gitdir = '$GIT_DIR';
+EOF
+
+echo "Installation complete."
+echo "Please copy the www folder to your website folder."
diff --git a/src/.admins b/src/.admins
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/src/account.php b/src/account.php
new file mode 100644 (file)
index 0000000..b8f0689
--- /dev/null
@@ -0,0 +1,67 @@
+<?php
+require('include.inc.php');
+if (!$logged) {
+  header('Location: index.php');
+  exit;
+} else {
+  $username = $_SESSION['username'];
+}
+$errorMsgKey = '';
+$errorMsgPwd = '';
+if (isset($_POST['submit_key'])) {
+  $fKey = $_POST['new-key'];
+  $res = gitrepoinfo('add-key', $username, $fKey);
+  if ($res === false) {
+    $errorMsgKey = "La clé n'a pas pu être ajoutée.";
+  }
+}
+if (isset($_POST['submit_pwd'])) {
+  $fPwd = $_POST['new-pwd'];
+  $res = gitrepoinfo('change-user', $username, md5($fPwd));
+  if ($res === false) {
+    $errorMsgPwd = "Le mot de passe n'a pas pu être changé.";
+  }
+}
+?>
+<html>
+  <head>
+    <title><?php echo "$title - $username"; ?></title>
+    <link href="style.css" rel="stylesheet" type="text/css" />
+  </head>
+  <body>
+    <h1><?php echo "$title - $username"; ?></h1>
+    <div id="nav"><a href="index.php">Index</a></div>
+    <div id="keys">
+      <div class="invite">Les clés SSH de <span><?php echo $username; ?> </span>:</div>
+      <table>
+        <tr>
+          <th class="key">Clé</th>
+          <th class="actions">Action</th>
+        </tr>
+<?php
+$keys = gitrepoinfo('list-keys', $username);
+$i = 0;
+foreach ($keys as $key) {
+  $i++;
+  $actions = "<a href=\"user-del-key.php?pos=$i\">Supprimer</a>";
+  echo "        <tr><td class=\"key\"><textarea readonly=\"readonly\">$key</textarea></td><td class=\"actions\">$actions</td></tr>\n";
+}
+?>
+      </table>
+    </div>
+    <hr/>
+    <div class="error"><?php echo $errorMsgKey; ?></div>
+    <form id="add-key" action="" method="POST">
+      <label for="new-key">Nouvelle clé SSH :</label><br/>
+      <textarea name="new-key" id="new-key"></textarea><br/>
+      <input type="submit" name="submit_key" value="Ajouter"/>
+    </form>
+    <hr/>
+    <div class="error"><?php echo $errorMsgPwd; ?></div>
+    <form id="change-pwd" action="" method="POST" autocomplete="off">
+      <label for="new-pwd">Nouveau mot de passe :</label><br/>
+      <input type="password" name="new-pwd" id="new-pwd" value=""/><br/>
+      <input type="submit" name="submit_pwd" value="Changer le mot de passe"/>
+    </form>
+  </body>
+</html>
diff --git a/src/admin-users.php b/src/admin-users.php
new file mode 100644 (file)
index 0000000..0af5668
--- /dev/null
@@ -0,0 +1,49 @@
+<?php
+require('include.inc.php');
+if (!$admin) {
+  header('Location: index.php');
+  exit;
+}
+$errorMsg = '';
+if (isset($_POST['submit_user_add'])) {
+  $fUser = $_POST['username'];
+  $fPwd = $_POST['password'];
+  $res = gitrepoinfo('create-user', $fUser, md5($fPwd));
+  if ($res === false) {
+    $errorMsg = "L'utilisateur n'a pas pu être ajouté.";
+  }
+}
+?>
+<html>
+  <head>
+  <title><?php echo "$title - Administration des utilisateurs"; ?></title>
+    <link href="style.css" rel="stylesheet" type="text/css" />
+  </head>
+  <body>
+    <h1><?php echo "$title - Administration des utilisateurs"; ?></h1>
+    <div id="nav"><a href="index.php">Index</a></div>
+    <div id="users">
+      <div class="invite">Les utilisateurs :</div>
+      <table>
+        <tr>
+          <th class="name">Utilisateur</th>
+          <th class="actions">Actions</th>
+        </tr>
+<?php
+$users = gitrepoinfo('list-users');
+foreach ($users as $user) {
+  $actions = "<a href=\"user-del.php?user=$user\">Supprimer</a>";
+  echo "        <tr><td class=\"name\">$user</td><td class=\"actions\">$actions</td></tr>\n";
+}
+?>
+      </table>
+    </div>
+    <hr/>
+    <div class="error"><?php echo $errorMsg; ?></div>
+    <form id="repo-add-user" action="" method="POST" autocomplete="off">
+      <label for="username">Login : </label><input type="text" name="username" id="username" value=""/>
+      <label for="password">MdP : </label><input type="password" name="password" id="password" value=""/>
+      <input type="submit" name="submit_user_add" value="Ajouter l'utilisateur au dépôt"/>
+    </form>
+  </body>
+</html>
diff --git a/src/config.inc.php.example b/src/config.inc.php.example
new file mode 100644 (file)
index 0000000..d44b5a7
--- /dev/null
@@ -0,0 +1,5 @@
+<?php
+$title = 'git.myhost.com';
+$githost = 'myhost.com';
+$gituser = 'git';
+$gitdir = '/home/git';
diff --git a/src/disconnect.php b/src/disconnect.php
new file mode 100644 (file)
index 0000000..9652136
--- /dev/null
@@ -0,0 +1,6 @@
+<?php
+require('include.inc.php');
+session_destroy();
+unset($_SESSION['username']);
+$logged = false;
+header('Location: index.php');
diff --git a/src/include.inc.php b/src/include.inc.php
new file mode 100644 (file)
index 0000000..51114fb
--- /dev/null
@@ -0,0 +1,71 @@
+<?php
+require('config.inc.php');
+setlocale(LC_CTYPE, 'fr_FR.UTF-8');
+session_start();
+$errorMsg = '';
+$logged = false;
+$admin = false;
+
+function gitrepoinfo($params) {
+  global $gituser, $gitdir;
+  $p = '';
+  foreach (func_get_args() as $param) {
+    $p .= ' ' . escapeshellarg($param);
+  }
+  exec("sudo -u $gituser $gitdir/gitrepo.sh $p", $ret, $state);
+  if ($state == 0) {
+    return $ret;
+  } else {
+    return false;
+  }
+}
+
+function isadmin($user) {
+  $admins = file('.admins');
+  if ($admins !== false) {
+    $admins = array_map('trim', $admins);
+    return in_array($user, $admins);
+  } else {
+    return false;
+  }
+}
+
+function auth() {
+  global $errorMsg, $logged, $admin;
+  if (isset($_POST['submit_auth'])) {
+    $fUsername = $_POST['username'];
+    $fPassword = $_POST['password'];
+    $password = implode('', gitrepoinfo('show-pwd', $fUsername));
+    if ($password !== false) {
+      if (empty($password)) {
+        // autorisé
+        $_SESSION['username'] = $fUsername;
+      } elseif (md5($fPassword) == $password) {
+        // autorisé
+        $_SESSION['username'] = $fUsername;
+      } else {
+        unset($_SESSION['username']);
+        $errorMsg = "Mot de passe incorrect.";
+      }
+    } else {
+      unset($_SESSION['username']);
+      $errorMsg = "L'utilisateur $fUsername n'existe pas.";
+    }
+    $logged = !empty($_SESSION['username']);
+    if ($logged) {
+      // Test si l'utilisateur est admin
+      $admin = isadmin($_SESSION['username']);
+      // Redirige pour éviter de reposter le formulaire.
+      header('Location: index.php');
+      exit;
+    }
+  } else {
+    $logged = !empty($_SESSION['username']);
+    if ($logged) {
+      // Test si l'utilisateur est admin
+      $admin = isadmin($_SESSION['username']);
+    }
+  }
+}
+
+auth();
diff --git a/src/index.php b/src/index.php
new file mode 100644 (file)
index 0000000..cb8648f
--- /dev/null
@@ -0,0 +1,71 @@
+<?php
+require('include.inc.php');
+$errorMsg = '';
+if ($admin && isset($_POST['submit_repo'])) {
+  $fRepo = $_POST['new-repo'];
+  $fDesc = $_POST['new-desc'];
+  $res = gitrepoinfo('create', $fRepo, $fDesc);
+  if ($res === false) {
+    $errorMsg = "La dépôt n'a pas pu être ajouté.";
+  }
+}
+?>
+<html>
+  <head>
+  <title><?php echo $title; ?></title>
+    <link href="style.css" rel="stylesheet" type="text/css" />
+  </head>
+  <body>
+    <h1><?php echo $title; ?></h1>
+<?php require('nav.inc.php'); ?>
+    <div id="repos">
+      <div class="invite">Les dépôts Git :</div>
+      <table>
+        <tr>
+          <th class="name">Nom</th>
+          <th class="address">Adresse</th>
+          <th class="member">Membre ?</th>
+          <th class="actions">Actions</th>
+        </tr>
+<?php
+$files = scandir($gitdir);
+foreach ($files as $file) {
+  if ($file[0] == '.') continue;
+  if (is_dir("$gitdir/$file") && preg_match('/\.git$/', $file)) {
+    $proj = preg_replace('/\.git$/', '', $file);
+    $desc = htmlspecialchars(file_get_contents("$gitdir/$file/description"));
+    if (preg_match('/^Unnamed repository;/', $desc)) {
+      $desc = "$proj";
+    }
+    $users = gitrepoinfo('show-users', $proj);
+    $membre = count($users) > 0 ? ' ? ' : ' — ';
+    if ($logged && count($users) > 0) {
+      if (in_array($_SESSION['username'], $users)) {
+        $membre = "Oui";
+      } else {
+        $membre = "Non";
+      }
+    }
+    $actions = "<a href=\"repo-users.php?repo=$proj\">Utilisateurs</a>&nbsp;<a href=\"repo-histo.php?repo=$proj\">Historique</a>";
+    if ($admin) {
+      $actions .= "&nbsp;<a href=\"repo-del.php?repo=$proj\">Supprimer</a>";
+    }
+    echo "        <tr><td class=\"name\" title=\"$desc\">$proj</td><td class=\"address\">$gituser@$githost:$gitdir/$file</td><td class=\"member\">$membre</td><td class=\"actions\">$actions</td></tr>\n";
+  }
+}
+?>
+      </table>
+    </div>
+<?php if ($admin) { ?>
+    <hr/>
+    <div class="error"><?php echo $errorMsg; ?></div>
+    <form id="repo-add" action="" method="POST">
+      <label for="new-repo">Nom du nouveau dépôt :</label>&nbsp;<input type="text" name="new-repo" id="new-repo" value=""/><br/>
+      <label for="new-desc">Description :</label>&nbsp;<input type="text" name="new-desc" id="new-desc" value=""/><br/>
+      <input type="submit" name="submit_repo" value="Ajouter le dépôt"/>
+    </form>
+    <hr/>
+    <a href="admin-users.php">Gestion des utilisateurs</a>
+<?php } ?>
+  </body>
+</html>
diff --git a/src/nav.inc.php b/src/nav.inc.php
new file mode 100644 (file)
index 0000000..4df7be0
--- /dev/null
@@ -0,0 +1,17 @@
+<div id="nav">
+<?php
+if ($logged) {
+  echo "<p>Vous êtes connecté en tant que <span>" . $_SESSION['username'] . "</span><br/>\n";
+  echo "<a href=\"account.php\">Mon compte</a>&nbsp;<a href=\"disconnect.php\">Se déconnecter</a></p>\n";
+} else {
+  echo "<div class=\"error\">$errorMsg</div>\n";
+  echo <<<EOF
+<form action="" method="POST">
+  <label for="username">Login : </label><input type="text" name="username" id="username" value=""/>
+  <label for="password">MdP : </label><input type="password" name="password" id="password" value=""/>
+  <input type="submit" name="submit_auth" value="Ok"/>
+</form>
+EOF;
+}
+?>
+</div>
diff --git a/src/repo-del.php b/src/repo-del.php
new file mode 100644 (file)
index 0000000..841a844
--- /dev/null
@@ -0,0 +1,10 @@
+<?php
+require('include.inc.php');
+if (!$logged || !$admin || empty($_GET['repo'])) {
+  header('Location: index.php');
+  exit;
+} else {
+  $repo = $_GET['repo'];
+}
+$res = gitrepoinfo('destroy', $repo);
+header('Location: index.php');
diff --git a/src/repo-histo.php b/src/repo-histo.php
new file mode 100644 (file)
index 0000000..8675026
--- /dev/null
@@ -0,0 +1,32 @@
+<?php
+require('include.inc.php');
+if (empty($_GET['repo'])) {
+  header('Location: index.php');
+  exit;
+} else {
+  $repo = $_GET['repo'];
+}
+?>
+<html>
+  <head>
+    <title><?php echo "$title - $repo"; ?></title>
+    <link href="style.css" rel="stylesheet" type="text/css" />
+  </head>
+  <body>
+    <h1><?php echo "$title - $repo"; ?></h1>
+    <div id="nav"><a href="index.php">Index</a></div>
+    <div id="users">
+      <div class="invite">Le graphe d'historique de <span><?php echo $repo; ?></span> :</div>
+      <pre>
+<?php
+  $grapheArray = gitrepoinfo('graph', $repo);
+  if ($grapheArray !== false) {
+    echo implode("\n", $grapheArray);
+  } else {
+    echo "Le projet n'est pas initialisé.";
+  }
+?>
+      </pre>
+    </div>
+  </body>
+</html>
diff --git a/src/repo-user-del.php b/src/repo-user-del.php
new file mode 100644 (file)
index 0000000..547280f
--- /dev/null
@@ -0,0 +1,11 @@
+<?php
+require('include.inc.php');
+if (!$logged || !$admin || empty($_GET['repo']) || empty($_GET['user'])) {
+  header('Location: index.php');
+  exit;
+} else {
+  $repo = $_GET['repo'];
+  $user = $_GET['user'];
+}
+$res = gitrepoinfo('del-user', $repo, $user);
+header("Location: repo-users.php?repo=$repo");
diff --git a/src/repo-users.php b/src/repo-users.php
new file mode 100644 (file)
index 0000000..db1784a
--- /dev/null
@@ -0,0 +1,63 @@
+<?php
+require('include.inc.php');
+if (empty($_GET['repo'])) {
+  header('Location: index.php');
+  exit;
+} else {
+  $repo = $_GET['repo'];
+}
+$errorMsg = '';
+if ($admin && isset($_POST['submit_user_add'])) {
+  $fUser = $_POST['username'];
+  $res = gitrepoinfo('add-user', $repo, $fUser);
+  if ($res === false) {
+    $errorMsg = "L'utilisateur n'a pas pu être ajouté.";
+  }
+}
+?>
+<html>
+  <head>
+    <title><?php echo "$title - $repo"; ?></title>
+    <link href="style.css" rel="stylesheet" type="text/css" />
+  </head>
+  <body>
+    <h1><?php echo "$title - $repo"; ?></h1>
+    <div id="nav"><a href="index.php">Index</a></div>
+    <div id="users">
+      <div class="invite">Les membres de <span><?php echo $repo; ?></span> :</div>
+      <table>
+        <tr>
+          <th class="name">Utilisateur</th>
+          <th class="actions">Actions</th>
+        </tr>
+<?php
+$users = gitrepoinfo('show-users', $repo);
+foreach ($users as $user) {
+  $actions = ' — ';
+  if ($admin) {
+    $actions = "<a href=\"repo-user-del.php?repo=$repo&user=$user\">Retirer</a>";
+  }
+  echo "        <tr><td class=\"name\">$user</td><td class=\"actions\">$actions</td></tr>\n";
+}
+?>
+      </table>
+    </div>
+<?php if ($admin) { ?>
+    <hr/>
+    <div class="error"><?php echo $errorMsg; ?></div>
+    <form id="repo-add-user" action="" method="POST">
+      <label for="new-repo">Nouveau membre :</label>&nbsp;
+      <select name="username">
+<?php
+$users = gitrepoinfo('list-users');
+foreach ($users as $user) {
+  $user = htmlspecialchars($user);
+  echo "        <option value=\"$user\">$user</option>\n";
+}
+?>
+      </select>
+      <input type="submit" name="submit_user_add" value="Ajouter l'utilisateur au dépôt"/>
+    </form>
+<?php } ?>
+  </body>
+</html>
diff --git a/src/style.css b/src/style.css
new file mode 100644 (file)
index 0000000..c37be61
--- /dev/null
@@ -0,0 +1,54 @@
+a, a:link, a:visited {
+  display: inline-block;
+  padding: 2px 5px 2px 5px;
+  text-decoration: none;
+  color: blue;
+  background-color: #AAA;
+  border: 1px solid black
+}
+a:hover {
+  color: red;
+}
+h1 {
+  text-align: center;
+}
+textarea {
+  width: 800px;
+  height: 100px;
+}
+table {
+  border: 1px solid black;
+  border-collapse: collapse;
+  width: 100%;
+}
+table .name,
+table .key,
+table .address {
+  text-align: left;
+}
+table .member,
+table .actions {
+  text-align: center;
+}
+table th {
+  background-color: #DDD;
+  text-align: center !important;
+}
+table tr:hover {
+  background-color: #AAA;
+}
+#nav {
+  background-color: #EEE;
+  padding: 5px 0 5px 20px;
+}
+#nav p span {
+  font-weight: bold;
+}
+div.invite {
+  margin-top: 10px;
+  margin-left: 20px;
+  margin-bottom: 10px;
+}
+div.invite span {
+  font-weight: bold;
+}
diff --git a/src/user-del-key.php b/src/user-del-key.php
new file mode 100644 (file)
index 0000000..9f81ab4
--- /dev/null
@@ -0,0 +1,11 @@
+<?php
+require('include.inc.php');
+if (!$logged || empty($_GET['pos'])) {
+  header('Location: index.php');
+  exit;
+} else {
+  $username = $_SESSION['username'];
+  $pos = $_GET['pos'];
+}
+$res = gitrepoinfo('del-key', $username, $pos);
+header('Location: account.php');
diff --git a/src/user-del.php b/src/user-del.php
new file mode 100644 (file)
index 0000000..7ad9ba4
--- /dev/null
@@ -0,0 +1,10 @@
+<?php
+require('include.inc.php');
+if (!$logged || !$admin || empty($_GET['user'])) {
+  header('Location: index.php');
+  exit;
+} else {
+  $user = $_GET['user'];
+}
+$res = gitrepoinfo('destroy-user', $user);
+header('Location: admin-users.php');
diff --git a/sudoers.d/git b/sudoers.d/git
new file mode 100644 (file)
index 0000000..128d3a6
--- /dev/null
@@ -0,0 +1,2 @@
+# vim: syn=sudoers:
+WEB_USER ALL = (GIT_USER) NOPASSWD: GIT_DIR/gitrepo.sh