xaizek / rocketgit (License: AGPLv3+) (since 2018-12-09)
Light and fast Git hosting solution suitable to serve both as a hub or as a personal code storage with its tickets, pull requests, API and much more.
Commit 2ad8a84b27b80b66efa680f778dbf562d08da099

Another bulk commit.
Author: Catalin(ux) M. BOIE
Author date (UTC): 2011-03-15 04:10
Committer name: Catalin(ux) M. BOIE
Committer date (UTC): 2011-03-15 04:10
Parent(s): 71ffd566d62b019302ffaeebaae0ab5edddc93d3
Signing key:
Tree: 38c600112540a2a159527fc24bb29b01f793e209
File Lines added Lines deleted
TODO 27 1
admin/sql.php 15 3
inc/admin/admin.php 1 1
inc/admin/repos/repos.php 3 1
inc/admin/users/add.php 1 2
inc/admin/users/users.php 1 1
inc/keys.inc.php 2 0
inc/login/login.form.php 17 3
inc/login/login.php 7 4
inc/repo.inc.php 124 12
inc/repo/repo.form.php 8 1
inc/repo/repo.php 8 2
inc/user.inc.php 133 11
inc/user/forgot.form.php 37 0
inc/user/forgot.php 39 0
inc/user/forgot_mail.php 16 0
inc/xlog.inc.php 4 1
root/index.php 29 11
samples/cron 1 0
samples/gg 15 0
scripts/cron.php 77 0
scripts/ssh.php 101 37
tests/Makefile 1 0
tests/user.php 34 0
tests/util.php 10 0
File TODO changed (mode: 100644) (index 27052f2..070b936)
1 == BEFORE FIRST RELEASE! ==
2 [ ] Validate e-mails.
3 [ ] Validate repo names.
4 [ ] Validate user names.
5 [ ]
6
7 == Low priority ==
1 8 [ ] Count the numbers of clones/pushes/pulls. [ ] Count the numbers of clones/pushes/pulls.
2 9 [ ] Add memcache caching for all database lookups. [ ] Add memcache caching for all database lookups.
3 10 [ ] Allow to configure the limit of the patch size to prevent abuses. [ ] Allow to configure the limit of the patch size to prevent abuses.
 
6 13 [ ] Add a repo_prop_set/get function that will set/get a file in .git folder. THis way we can [ ] Add a repo_prop_set/get function that will set/get a file in .git folder. THis way we can
7 14 speed up some lookups (no need for database). Hm. speed up some lookups (no need for database). Hm.
8 15 [ ] When we delete an repository, we will do repo_prop_set(repo, disabled) and we will [ ] When we delete an repository, we will do repo_prop_set(repo, disabled) and we will
9 return OK, in the background we will do the removing. Do not forget to also remove clones. Hm.
16 return OK, in the background we will do the removing. Do not forget to also remove clones. Hm.
17 [ ] SSH keys section.
18 [ ] E-mail aliases section.
19 [ ] User details section (full name, e-mail, blog, avatar, mail notifications).
20 [ ] Change password section.
21 [ ] Check if user is over-quota on push.
22 [ ] The cron will have to:
23 [ ] Compute disk usage, ignoring hard links. Hm. Probably we will add
24 only the owner, even if the files have multiple links. TBD.
25 [ ] VACUUM tables.
26 [ ]
27 [ ] UTF-8 checks.
28 [ ] W3C validation on all pages.
29 [ ] Validate user and repo names. Probably other things.
30 [ ] What happens if a user is suspended? Do we allow forgot pass sending?
31 [ ] Do not allow session updates/any command if user is suspended after his/her login.
32 [ ] Timeout for connections (ssh/git-daemon/etc.)!
33 [ ] Check if we have to respect 4HEXA also on SSH. I think not.
34 [ ] Limit number of simultaneously connection per repo and per user. maybe also the time!
35 [ ]
File admin/sql.php changed (mode: 100644) (index afdd9d0..7ff98e8)
... ... if ($db === FALSE)
15 15 // create repos table // create repos table
16 16 $sql = "CREATE TABLE repos (repo_id INTEGER PRIMARY KEY, name TEXT, uid INTEGER" $sql = "CREATE TABLE repos (repo_id INTEGER PRIMARY KEY, name TEXT, uid INTEGER"
17 17 . ", itime INTEGER" . ", itime INTEGER"
18 . ", public INTEGER)";
18 . ", public INTEGER"
19 . ", disk_quota_mb INTEGER"
20 . ", max_commit_size INTEGER"
21 . ", master INTEGER"
22 . ")";
19 23 $res = sql_query($db, $sql); $res = sql_query($db, $sql);
20 24 if ($res === FALSE) if ($res === FALSE)
21 25 echo "WARN: Cannot create 'repo_access' table!\n"; echo "WARN: Cannot create 'repo_access' table!\n";
 
... ... if ($res === FALSE)
41 45 $sql = "CREATE TABLE users (uid INTEGER PRIMARY KEY, user TEXT, salt TEXT" $sql = "CREATE TABLE users (uid INTEGER PRIMARY KEY, user TEXT, salt TEXT"
42 46 . ", pass TEXT, email TEXT, itime INTEGER" . ", pass TEXT, email TEXT, itime INTEGER"
43 47 . ", suspended INTEGER" . ", suspended INTEGER"
44 . ", session_time INTEGER"
48 . ", session_time INTEGER DEFAULT 3600"
45 49 . ", last_seen INTEGER" . ", last_seen INTEGER"
46 . ", is_admin INTEGER)";
50 . ", is_admin INTEGER"
51 . ", disk_quota_mb INTEGER"
52 . ", disk_mb INTEGER"
53 . ")";
47 54 $res = sql_query($db, $sql); $res = sql_query($db, $sql);
48 55 if ($res === FALSE) if ($res === FALSE)
49 56 echo "WARN: Cannot create 'users' table!\n"; echo "WARN: Cannot create 'users' table!\n";
 
... ... $res = sql_query($db, $sql);
54 61 if ($res === FALSE) if ($res === FALSE)
55 62 echo "WARN: Cannot create 'sess' table!\n"; echo "WARN: Cannot create 'sess' table!\n";
56 63
64 $sql = "CREATE TABLE forgot_pass (token TEXT PRIMARY KEY, uid INTEGER, expire INTEGER)"
65 $res = sql_query($db, $sql);
66 if ($res === FALSE)
67 echo "WARN: Cannot create 'forgot_pass' table!\n";
68
57 69 echo "Done!\n"; echo "Done!\n";
58 70 ?> ?>
File inc/admin/admin.php changed (mode: 100644) (index e206e85..9e60be1)
1 1 <?php <?php
2 xlog("/admin");
2 xlog("/inc/admin");
3 3
4 4 if ($gg_ui['is_admin'] != 1) { if ($gg_ui['is_admin'] != 1) {
5 5 $_admin = "You do not have access here!"; $_admin = "You do not have access here!";
File inc/admin/repos/repos.php changed (mode: 100644) (index 4a0e298..577cf13)
... ... $_admin_repos_body = "";
15 15
16 16 switch ($subsubop) { switch ($subsubop) {
17 17 case 1: // list case 1: // list
18 $_admin_repos_body .= repo_list($db, $_admin_repos_url . "&amp;subsubop=$subsubop", 0);
18 $_only_master = 0;
19 $_uid = 0;
20 $_admin_repos_body .= repo_list($db, $_admin_repos_url . "&amp;subsubop=$subsubop", $_uid, $_only_master);
19 21 break; break;
20 22 } }
21 23
File inc/admin/users/add.php changed (mode: 100644) (index bd02e82..38d55a2)
... ... if ($doit == 1) {
7 7 $xuser = @$_REQUEST['xuser']; $xuser = @$_REQUEST['xuser'];
8 8 $email = @$_REQUEST['email']; $email = @$_REQUEST['email'];
9 9 $xpass = @$_REQUEST['xpass']; $xpass = @$_REQUEST['xpass'];
10 xlog("xxx: " . print_r($_REQUEST, TRUE));
11 10 $is_admin = @intval($_REQUEST['is_admin']); $is_admin = @intval($_REQUEST['is_admin']);
12 11
13 $_ui = user_info($db, 0, $xuser);
12 $_ui = user_info($db, 0, $xuser, "");
14 13 if ($_ui['ok'] == 0) { if ($_ui['ok'] == 0) {
15 14 $_user_add .= "Error: Internal error!"; $_user_add .= "Error: Internal error!";
16 15 } else if ($_ui['exists'] == 0) { } else if ($_ui['exists'] == 0) {
File inc/admin/users/users.php changed (mode: 100644) (index ef85c8a..c45c3ba)
1 1 <?php <?php
2 xlog("/admin/users");
2 xlog("/inc/admin/users");
3 3
4 4 $subsubop = @intval($_REQUEST['subsubop']); $subsubop = @intval($_REQUEST['subsubop']);
5 5
File inc/keys.inc.php changed (mode: 100644) (index f813cdd..507b9c7)
... ... $keys_error = "";
7 7 function keys_set_error($str) function keys_set_error($str)
8 8 { {
9 9 global $keys_error; global $keys_error;
10
11 xlog("\tError: $str");
10 12 $keys_error = $str; $keys_error = $str;
11 13 } }
12 14
File inc/login/login.form.php changed (mode: 100644) (index 182216f..26ea6eb)
1 1 <?php <?php
2 $_form = '';
2 3
3 $_form = '
4 <form type="post" action="' . $_SERVER['PHP_SELF'] . '">
4 if (!empty($error))
5 $_form .= "<font color=red>$error</font>\n";
6
7 $_form .= '
8 <form method="post" action="' . $_SERVER['PHP_SELF'] . '">
5 9 <input type="hidden" name="op" value="' . $op . '"> <input type="hidden" name="op" value="' . $op . '">
6 10 <input type="hidden" name="doit" value="1"> <input type="hidden" name="doit" value="1">
7 11
8 12 User: <input type="text" name="user" value="' . $user . '"><br /> User: <input type="text" name="user" value="' . $user . '"><br />
9 13 Password: <input type="password" name="pass" value="' . $pass . '"><br /> Password: <input type="password" name="pass" value="' . $pass . '"><br />
10 <input type="submit" value="Go!">
14 <input type="submit" value="Login">
15 </form>
16 <br />
17
18 Forgot your password?<br />
19 <form method="post" action="' . $_SERVER['PHP_SELF'] . '">
20 <input type="hidden" name="op" value="7">
21 <input type="hidden" name="doit" value="1">
22
23 E-mail: <input type="text" name="email" value=""><br />
24 <input type="submit" value="Recover password">
11 25 </form> </form>
12 26 '; ';
13 27
File inc/login/login.php changed (mode: 100644) (index 267d01d..d677c0c)
1 1 <?php <?php
2 xlog("/inc/login/login.php");
2 3
3 4 $doit = @intval($_REQUEST['doit']); $doit = @intval($_REQUEST['doit']);
4 5 $user = @$_COOKIE['user']; $user = @$_COOKIE['user'];
 
... ... $pass = "";
6 7
7 8 $_login = "<br />\n"; $_login = "<br />\n";
8 9
9 if ($doit == 0) {
10 include($INC . "/login/login.form.php");
11 $_login .= $_form;
12 }
10 $error = "";
11 if ($doit == 1)
12 $error = "Invalid user and/or pass.";
13
14 include($INC . "/login/login.form.php");
15 $_login .= $_form;
13 16
14 17 ?> ?>
File inc/repo.inc.php changed (mode: 100644) (index 9463070..69506c4)
1 1 <?php <?php
2 require_once($INC . "/util.inc.php");
2 3 require_once($INC . "/xlog.inc.php"); require_once($INC . "/xlog.inc.php");
3 4 require_once($INC . "/db.inc.php"); require_once($INC . "/db.inc.php");
4 5 require_once($INC . "/user.inc.php"); require_once($INC . "/user.inc.php");
 
... ... function repo_error()
19 20 return $repo_error; return $repo_error;
20 21 } }
21 22
23 /*
24 * Returns the path to a repository based on repo_id
25 */
26 function repo_id2base($repo_id)
27 {
28 global $gg_base_repo;
29
30 $r3 = sprintf("%03u", $repo_id / 1000);
31
32 return $gg_base_repo . "/"
33 . $r3[0] . "/" . $r3[1] . "/" . $r3[2];
34 }
35
36 /*
37 * Return info about a repo
38 */
39 function repo_info($db, $repo_id, $repo)
40 {
41 xlog("repo_info: $repo_id, repo=$repo...");
42
43 $ret['ok'] = 0;
44
45 $repo_id = sprintf("%u", $repo_id);
46 if ($repo_id > 0) {
47 $add = " AND repo_id = $repo_id";
48 } else if (!empty($repo)) {
49 $e_repo = sql_escape($db, $repo);
50 $add = " AND name = '$e_repo'";
51 } else {
52 $ret['errmsg'] = "No repo_id or name specified!";
53 return $ret;
54 }
55
56 $sql = "SELECT * FROM repos WHERE 1 = 1" . $add;
57 $res = sql_query($db, $sql);
58 if ($res === FALSE) {
59 $ret['errmsg'] = "Cannot query (" . sql_error() . ")";
60 xlog("\t" . $ret['errmsg']);
61 return $ret;
62 }
63 $ret['ok'] = 1;
64 $ret['exists'] = 0;
65 $row = sql_fetch_array($res);
66 sql_free_result($res);
67 if (!isset($row['repo_id'])) {
68 xlog("\tRepo not found!");
69 return $ret;
70 }
71
72 $row['exists'] = 1;
73 $row['ok'] = 1;
74 return $row;
75 }
76
22 77 /* /*
23 78 * Check if a uid has access to repository * Check if a uid has access to repository
24 79 */ */
25 function repo_allow($db, $repo_id, $uid, $perms)
80 function repo_allow($db, $ri, $uid, $perms)
26 81 { {
27 xlog("repo_allow: repo_id=$repo_id, uid=$uid, perms=$perms...");
82 xlog("repo_allow: uid=$uid, perms=$perms...");
28 83
29 $e_repo_id = sprintf("%u", $repo_id);
30 84 $e_uid = sprintf("%u", $uid); $e_uid = sprintf("%u", $uid);
31 85 $e_perms = preg_replace("/[^A-Z]/", "", $perms); $e_perms = preg_replace("/[^A-Z]/", "", $perms);
32 86
33 if (empty($e_perms))
87 if (empty($e_perms)) {
88 xlog("\tNo perms passed!");
34 89 return FALSE; return FALSE;
90 }
91
92 // anonymouse access?
93 if ($uid == 0) {
94 if ($ri['ok'] == 0)
95 return FALSE;
96 if ($ri['exists'] != 1)
97 return FALSE;
98 if ($ri['public'] == 0) {
99 xlog("\tRepo is not public!");
100 return FALSE;
101 }
102 if (($ri['public'] == 1) && (strcmp($perms, "W") == 0)) {
103 xlog("\tRepo is public, but no write allowed!");
104 return FALSE;
105 }
106
107 return TRUE;
108 }
35 109
36 110 if (strcmp($perms, "R") == 0) if (strcmp($perms, "R") == 0)
37 111 $perms_add = " AND (perm = 'R' OR perm = 'W')"; $perms_add = " AND (perm = 'R' OR perm = 'W')";
 
... ... function repo_allow($db, $repo_id, $uid, $perms)
39 113 $perms_add = " AND perm = 'W'"; $perms_add = " AND perm = 'W'";
40 114
41 115 $sql = "SELECT 1 AS junk FROM repo_access" $sql = "SELECT 1 AS junk FROM repo_access"
42 . " WHERE repo_id = $e_repo_id"
116 . " WHERE repo_id = " . $ri['repo_id']
43 117 . " AND uid = $e_uid" . " AND uid = $e_uid"
44 118 . $perms_add; . $perms_add;
45 119 $res = sql_query($db, $sql); $res = sql_query($db, $sql);
 
... ... function repo_allow($db, $repo_id, $uid, $perms)
60 134
61 135 /* /*
62 136 * Add a repository * Add a repository
137 * @master - makes sense only for clones - who is the master.
63 138 */ */
64 function repo_create($db, $uid, $name, $public)
139 function repo_create($db, $master, $uid, $name, $public, $max_commit_size)
65 140 { {
66 xlog("repo_create: name=[$name], public=$public...");
141 xlog("repo_create: name=[$name], master=$master, public=$public"
142 . ", max_commit_size=$max_commit_size"
143 . "...");
67 144
68 145 $name = htmlspecialchars($name); $name = htmlspecialchars($name);
69 146 $e_name = sql_escape($db, $name); $e_name = sql_escape($db, $name);
70 147
71 148 $itime = time(); $itime = time();
72 149
73 $sql = "INSERT INTO repos (uid, name, itime, public)"
74 . " VALUES ($uid, '$e_name', $itime, $public)";
150 $sql = "INSERT INTO repos (uid, master, name, itime, public"
151 . ", max_commit_size)"
152 . " VALUES ($uid, $master, '$e_name', $itime, $public"
153 . ", $max_commit_size)";
75 154 $res = sql_query($db, $sql); $res = sql_query($db, $sql);
76 155 if ($res === FALSE) { if ($res === FALSE) {
77 156 repo_set_error("Cannot insert (" . sql_error() . ")"); repo_set_error("Cannot insert (" . sql_error() . ")");
 
... ... function repo_create($db, $uid, $name, $public)
83 162 /* /*
84 163 * List repositories * List repositories
85 164 */ */
86 function repo_list($db, $url, $uid)
165 function repo_list($db, $url, $uid, $only_master)
87 166 { {
88 xlog("repo_list: url=$url, uid=$uid...");
167 xlog("repo_list: url=$url, uid=$uid, only_master=$only_master...");
89 168
90 169 $add = ""; $add = "";
91 170 if ($uid > 0) if ($uid > 0)
92 171 $add = " AND uid = $uid"; $add = " AND uid = $uid";
93 172
94 $sql = "SELECT * FROM repos WHERE 1 = 1" . $add;
173 if ($only_master == 1)
174 $add .= " AND master = 0";
175
176 $sql = "SELECT * FROM repos WHERE 1 = 1"
177 . $add
178 . " ORDER BY name";
95 179 $res = sql_query($db, $sql); $res = sql_query($db, $sql);
96 180 if ($res === FALSE) if ($res === FALSE)
97 181 return FALSE; return FALSE;
 
... ... function repo_list($db, $url, $uid)
99 183 $ret = "<table>\n"; $ret = "<table>\n";
100 184 $ret .= "<tr>\n"; $ret .= "<tr>\n";
101 185 $ret .= " <th>Name</th>\n"; $ret .= " <th>Name</th>\n";
186 if ($only_master == 0)
187 $ret .= " <th>Master?</th>\n";
102 188 $ret .= " <th>Creation date (UTC)</th>\n"; $ret .= " <th>Creation date (UTC)</th>\n";
103 189 $ret .= " <th>Public</th>\n"; $ret .= " <th>Public</th>\n";
190 $ret .= " <th>Disk current/max</th>\n";
191 $ret .= " <th>Max commit size</th>\n";
104 192 $ret .= " <th>Operations</th>\n"; $ret .= " <th>Operations</th>\n";
105 193 $ret .= "</tr>\n"; $ret .= "</tr>\n";
106 194 while (($row = sql_fetch_array($res))) { while (($row = sql_fetch_array($res))) {
107 195 $ret .= "<tr>\n"; $ret .= "<tr>\n";
108 196 $ret .= " <td>" . $row['name'] . "</td>\n"; $ret .= " <td>" . $row['name'] . "</td>\n";
197 if ($only_master == 0)
198 $ret .= " <td>" . ($row['master'] == 0 ? "Yes" : "No") . "</td>\n";
109 199 $ret .= " <td>" . date("Y-m-d H:i:s", $row['itime']) . "</td>\n"; $ret .= " <td>" . date("Y-m-d H:i:s", $row['itime']) . "</td>\n";
110 200 $ret .= " <td>" . ($row['public'] == 1 ? "Yes" : "No") . "</td>\n"; $ret .= " <td>" . ($row['public'] == 1 ? "Yes" : "No") . "</td>\n";
201
202 $_max = "ulimited";
203 if ($row['disk_quota_mb'] > 0)
204 $_max = gg_1024($row['disk_quota_mb']);
205 $ret .= " <td>" . $row['disk_mb'] . "/" . $_max . "</td>\n";
206
207 $_v = "ulimited";
208 if ($row['max_commit_size'] > 0)
209 $_v = gg_1024($row['max_commit_size']);
210 $ret .= " <td>" . $_v . "</td>\n";
211
111 212 $ret .= " <td>-</td>\n"; $ret .= " <td>-</td>\n";
112 213 $ret .= "</tr>\n"; $ret .= "</tr>\n";
113 214 } }
 
... ... function repo_list($db, $url, $uid)
116 217
117 218 return $ret; return $ret;
118 219 } }
220
221 /*
222 * Computes the size of a repository
223 */
224 function repo_disk_mb($path)
225 {
226 xlog("repo_disk_mb: path=$path...");
227
228 return 10;
229 }
230
119 231 ?> ?>
File inc/repo/repo.form.php changed (mode: 100644) (index ab8add9..4fede90)
... ... $_form = '
24 24 </td> </td>
25 25 </tr> </tr>
26 26
27 <tr>
28 <td>Max commit size (bytes):</td>
29 <td>
30 <input type="text" name="max_commit_size" value="' . $max_commit_size . '"><br />
31 </td>
32 </tr>
33
27 34 <tr> <tr>
28 35 <td colspan="2"><input type="submit" value="Go!"></td> <td colspan="2"><input type="submit" value="Go!"></td>
29 36 </tr> </tr>
 
... ... $_form = '
33 40 '; ';
34 41
35 42
36 ?>
43 ?>
File inc/repo/repo.php changed (mode: 100644) (index 3d10172..194bbaa)
1 1 <?php <?php
2 xlog("/inc/repo/repo.php");
3
2 4 $subop = @intval($_REQUEST['subop']); $subop = @intval($_REQUEST['subop']);
3 5 $public = @intval($_REQUEST['public']); $public = @intval($_REQUEST['public']);
4 6 $name = @$_REQUEST['name']; $name = @$_REQUEST['name'];
7 $max_commit_size = @intval($_REQUEST['max_commit_size']);
5 8
6 9 // menu // menu
7 10 $_url = $_SERVER['PHP_SELF'] . "?op=$op"; $_url = $_SERVER['PHP_SELF'] . "?op=$op";
 
... ... $_body = "";
16 19 switch ($subop) { switch ($subop) {
17 20 case 1: // create case 1: // create
18 21 if ($doit == 1) { if ($doit == 1) {
19 $_r = repo_create($db, $uid, $name, $public);
22 $master = 1;
23 $_r = repo_create($db, $master, $uid, $name, $public,
24 $max_commit_size);
20 25 $_body = "bau!"; $_body = "bau!";
21 26 } else { } else {
22 27 include($INC . "/repo/repo.form.php"); include($INC . "/repo/repo.form.php");
 
... ... case 1: // create
25 30 break; break;
26 31
27 32 case 2: //list case 2: //list
28 $_body .= repo_list($db, "", $uid);
33 $only_masters = 1;
34 $_body .= repo_list($db, "", $uid, $only_masters);
29 35 break; break;
30 36 } }
31 37
File inc/user.inc.php changed (mode: 100644) (index ead7291..dffe347)
1 1 <?php <?php
2 require_once($INC . "/util.inc.php");
2 3 require_once($INC . "/xlog.inc.php"); require_once($INC . "/xlog.inc.php");
3 4 require_once($INC . "/db.inc.php"); require_once($INC . "/db.inc.php");
4 5 require_once($INC . "/sess.inc.php"); require_once($INC . "/sess.inc.php");
 
... ... function gg_user_error()
22 23 */ */
23 24 function user_add($db, $user, $pass, $email, $is_admin) function user_add($db, $user, $pass, $email, $is_admin)
24 25 { {
26 global $gg_session_time;
27
25 28 xlog("user_add: user=$user, pass=$pass, email=$email, is_admin=$is_admin..."); xlog("user_add: user=$user, pass=$pass, email=$email, is_admin=$is_admin...");
26 29
27 30 $itime = time(); $itime = time();
28 $e_salt = sha1(mt_rand() . microtime(TRUE));
31 $e_salt = gg_id(40);
29 32 $e_sha1pass = sha1($e_salt . "===" . $pass); $e_sha1pass = sha1($e_salt . "===" . $pass);
33 $session_time = $gg_session_time;
30 34
31 35 $e_user = sql_escape($db, $user); $e_user = sql_escape($db, $user);
32 36 $e_email = sql_escape($db, $email); $e_email = sql_escape($db, $email);
33 37
34 $sql = "INSERT INTO users (user, salt, pass, email, itime, is_admin)"
38 $sql = "INSERT INTO users (user, salt, pass, email, itime, is_admin, session_time)"
35 39 . " VALUES ('$e_user', '$e_salt', '$e_sha1pass', '$e_email'" . " VALUES ('$e_user', '$e_salt', '$e_sha1pass', '$e_email'"
36 . ", $itime, $is_admin)";
40 . ", $itime, $is_admin, $session_time)";
37 41 $res = sql_query($db, $sql); $res = sql_query($db, $sql);
38 42 if ($res === FALSE) { if ($res === FALSE) {
39 43 gg_user_set_error("Cannot insert user (" . sql_error() . ")!"); gg_user_set_error("Cannot insert user (" . sql_error() . ")!");
 
... ... function user_remove($db, $uid)
65 69 /* /*
66 70 * Returns info about a user (by uid or user fields) * Returns info about a user (by uid or user fields)
67 71 */ */
68 function user_info($db, $uid, $user)
72 function user_info($db, $uid, $user, $email)
69 73 { {
70 xlog("user_info: uid=[$uid], user=[$user]...");
74 xlog("user_info: uid=[$uid], user=[$user], email=[$email]...");
71 75
72 76 $ret = array(); $ret = array();
73 77 $ret['ok'] = 0; $ret['ok'] = 0;
 
... ... function user_info($db, $uid, $user)
75 79
76 80 if ($uid > 0) { if ($uid > 0) {
77 81 $add = " AND uid = " . sprintf("%u", $uid); $add = " AND uid = " . sprintf("%u", $uid);
78 } else {
82 } else if (!empty($user)) {
79 83 $e_user = sql_escape($db, $user); $e_user = sql_escape($db, $user);
80 84 $add = " AND user = '$e_user'"; $add = " AND user = '$e_user'";
85 } else if (!empty($email)) {
86 $e_email = sql_escape($db, $email);
87 $add = " AND email = '$e_email'";
88 } else {
89 return FALSE;
81 90 } }
82 91
83 92 $sql = "SELECT * FROM users WHERE 1 = 1" . $add; $sql = "SELECT * FROM users WHERE 1 = 1" . $add;
 
... ... function user_login($db, $sid, &$ui)
108 117 xlog("user_login: sid=$sid..."); xlog("user_login: sid=$sid...");
109 118
110 119 if (($uid = sess_valid($db, $sid))) { if (($uid = sess_valid($db, $sid))) {
111 $ui = user_info($db, $uid, "");
120 $ui = user_info($db, $uid, "", "");
112 121 sess_update($db, $sid); sess_update($db, $sid);
113 122 return $uid; return $uid;
114 123 } }
 
... ... function user_login($db, $sid, &$ui)
119 128 if (empty($user) || empty($pass)) if (empty($user) || empty($pass))
120 129 return FALSE; return FALSE;
121 130
122 $ui = user_info($db, 0, $user);
131 $ui = user_info($db, 0, $user, "");
123 132 if ($ui['ok'] == 0) { if ($ui['ok'] == 0) {
124 133 gg_user_set_error("Internal error"); gg_user_set_error("Internal error");
125 134 return FALSE; return FALSE;
 
... ... function user_login($db, $sid, &$ui)
137 146 return FALSE; return FALSE;
138 147 } }
139 148
140 $sid = sha1(mt_rand() . microtime(TRUE));
149 $sid = gg_id(40);
141 150 sess_add($db, $ui['uid'], $sid, $ui['session_time']); sess_add($db, $ui['uid'], $sid, $ui['session_time']);
142 151 setcookie("sid", $sid, 0); setcookie("sid", $sid, 0);
143 152
 
... ... function user_list($db, $url)
224 233 $ret .= "<tr>\n"; $ret .= "<tr>\n";
225 234 $ret .= " <th>Name</th>\n"; $ret .= " <th>Name</th>\n";
226 235 $ret .= " <th>E-mail</th>\n"; $ret .= " <th>E-mail</th>\n";
227 $ret .= " <th>Admin</th>\n";
236 $ret .= " <th>Admin?</th>\n";
228 237 $ret .= " <th>Creation date</th>\n"; $ret .= " <th>Creation date</th>\n";
238 $ret .= " <th>Quota</th>\n";
229 239 $ret .= " <th>Suspended?</th>\n"; $ret .= " <th>Suspended?</th>\n";
230 240 $ret .= " <th>Session time</th>\n"; $ret .= " <th>Session time</th>\n";
231 241 $ret .= " <th>Last seen</th>\n"; $ret .= " <th>Last seen</th>\n";
 
... ... function user_list($db, $url)
237 247 $ret .= " <td>" . $row['email'] . "</td>\n"; $ret .= " <td>" . $row['email'] . "</td>\n";
238 248 $ret .= " <td>" . ($row['is_admin'] == 1 ? "Yes" : "No") . "</td>\n"; $ret .= " <td>" . ($row['is_admin'] == 1 ? "Yes" : "No") . "</td>\n";
239 249 $ret .= " <td>" . date("Y-m-d H:i:s", $row['itime']) . "</td>\n"; $ret .= " <td>" . date("Y-m-d H:i:s", $row['itime']) . "</td>\n";
250 $_v = "unlimited";
251 if ($row['disk_quota_mb'] > 0)
252 $_v = gg_1024($row['disk_quota_mb']);
253 $ret .= " <td>" . $_v . "</td>\n";
240 254 $ret .= " <td>" . ($row['suspended'] == 0 ? "No" : "Yes") . "</th>\n"; $ret .= " <td>" . ($row['suspended'] == 0 ? "No" : "Yes") . "</th>\n";
241 255 $ret .= " <td>" . $row['session_time'] . "s</td>\n"; $ret .= " <td>" . $row['session_time'] . "s</td>\n";
242 256 $ret .= " <td>" . date("Y-m-d H:i:s", $row['last_seen']) . "</td>\n"; $ret .= " <td>" . date("Y-m-d H:i:s", $row['last_seen']) . "</td>\n";
 
... ... function user_list($db, $url)
251 265 } }
252 266 $ret .= "[<a href=\"$_url&amp;suspend=$v\">$t</a>]"; $ret .= "[<a href=\"$_url&amp;suspend=$v\">$t</a>]";
253 267 // admin // admin
254 $v = 1; $t = "Make admin";
268 $v = 1; $t = "Admin";
255 269 if ($row['is_admin'] == 1) { if ($row['is_admin'] == 1) {
256 270 $t = "Remove admin"; $t = "Remove admin";
257 271 $v = 0; $v = 0;
 
... ... function user_list($db, $url)
268 282
269 283 return $ret; return $ret;
270 284 } }
285
286 /*
287 * Returns uid by token, if not expired
288 */
289 function user_forgot_pass_uid($db, $token)
290 {
291 $ret = array();
292 $ret['ok'] = 0;
293 $ret['uid'] = 0;
294
295 xlog("user_forgot_pass_uid: token=$token");
296
297 $now = time();
298 $e_token = sql_escape($db, $token);
299
300 $sql = "SELECT uid FROM forgot_pass"
301 . " WHERE token = '$e_token'"
302 . " AND expire > $now";
303 $res = sql_query($db, $sql);
304 if ($res === FALSE)
305 return $ret;
306
307 $ret['ok'] = 1;
308
309 $row = sql_fetch_array($res);
310 sql_free_result($res);
311 if (!isset($row['uid']))
312 return $ret;
313
314 $ret['uid'] = $row['uid'];
315
316 return $ret;
317 }
318
319 /*
320 * Reset password function (send mail)
321 */
322 function user_forgot_pass_mail($db, $email)
323 {
324 xlog("user_forgot_pass_mail: email=$email");
325
326 $expire = time() + 24 * 3600;
327 $token = gg_id(40);
328
329 $r = user_info($db, 0, "", $email);
330 if ($r['ok'] == 0)
331 return FALSE;
332 if ($r['exists'] == 0)
333 return FALSE;
334 $uid = $r['uid'];
335
336 // store token in database
337 $sql = "INSERT INTO forgot_pass (token, uid, expire)"
338 . " VALUES ('$token', $uid, $expire)";
339 $res = sql_query($db, $sql);
340 if ($res === FALSE) {
341 gg_user_set_error("Cannot query!");
342 return FALSE;
343 }
344 sql_free_result($res);
345
346 if (!mail($email, "Forgot password",
347 "Hello!\nIf you want to reset the password, follow:\n"
348 . "http://" . $_SERVER['SERVER_NAME'] . "/" . $_SERVER['PHP_SELF'] . "?op=6&token=$token")) {
349 gg_user_set_error("Cannot send mail!");
350 return FALSE;
351 }
352
353 return TRUE;
354 }
355
356 /*
357 * After reseting the pass, we have to destroy all 'reset pass' requests
358 */
359 function user_forgot_pass_destroy($db, $uid)
360 {
361 xlog("user_forgot_pass_destroy: token=$token");
362
363 $sql = "DELETE FROM forgot_pass WHERE uid = $uid";
364 $res = sql_query($db, $sql);
365 if ($res === FALSE) {
366 gg_user_set_error("Cannot query!");
367 return FALSE;
368 }
369 sql_free_result($res);
370
371 return TRUE;
372 }
373
374 function user_set_pass($db, $uid, $pass)
375 {
376 xlog("user_set_pass...");
377
378 $e_salt = gg_id(40);
379 $e_sha1pass = sha1($e_salt . "===" . $pass);
380
381 $sql = "UPDATE users SET"
382 ." salt = '$e_salt'"
383 . ", pass = '$e_sha1pass'"
384 . " WHERE uid = " . $uid;
385 $res = sql_query($db, $sql);
386 if ($res === FALSE)
387 return FALSE;
388 sql_free_result($res);
389
390 return TRUE;
391 }
392
271 393 ?> ?>
File inc/user/forgot.form.php added (mode: 100644) (index 0000000..c4b1021)
1 <?php
2
3 $_forgot_form = "";
4
5 if (!empty($error))
6 $_forgot_form .= "<font color=red>$error</font><br />\n";
7
8 $_forgot_form .= '
9 <form type="post" action="' . $_SERVER['PHP_SELF'] . '">
10 <input type="hidden" name="op" value="' . $op . '">
11 <input type="hidden" name="token" value="' . $_REQUEST['token'] . '">
12 <input type="hidden" name="doit" value="1">
13
14 <table>
15 <tr>
16 <td>New password:</td>
17 <td>
18 <input type="password" name="pass1" value=""><br />
19 </td>
20 </tr>
21
22 <tr>
23 <td>New password (retype):</td>
24 <td>
25 <input type="password" name="pass2" value=""><br />
26 </td>
27 </tr>
28
29 <tr>
30 <td colspan="2"><input type="submit" value="Change password"></td>
31 </tr>
32
33 </table>
34 </form>
35 ';
36
37 ?>
File inc/user/forgot.php added (mode: 100644) (index 0000000..7138b70)
1 <?php
2 xlog("/inc/user/forgot.php");
3
4 $token = @$_REQUEST['token'];
5 $pass1 = @$_REQUEST['pass1'];
6 $pass2 = @$_REQUEST['pass2'];
7
8 $_forgot = "<br />\n";
9
10 $_hide_form = 0;
11
12 if ($doit == 1) {
13 $error = "";
14 if (strcmp($pass1, $pass2) != 0) {
15 $error .= "Passwords mismatch.";
16 } else {
17 $r = user_forgot_pass_uid($db, $token);
18 if ($r['ok'] != 1) {
19 $error .= "Internal error, try again later.";
20 } else if ($r['uid'] == 0) {
21 $error .= "Invalid (or expired) reset pass URL!";
22 } else {
23 if (user_set_pass($db, $r['uid'], $pass1)) {
24 user_forgot_pass_destroy($db, $r['uid']);
25 $_forgot .= "OK!";
26 $_hide_form = 1;
27 } else {
28 $error .= "Internal error - try later!";
29 }
30 }
31 }
32 }
33
34 if ($_hide_form == 0) {
35 include($INC . "/user/forgot.form.php");
36 $_forgot .= $_forgot_form;
37 }
38
39 ?>
File inc/user/forgot_mail.php added (mode: 100644) (index 0000000..597f7f1)
1 <?php
2 xlog("/inc/user/forgot_mail.php");
3
4 $email = @$_REQUEST['email'];
5
6 $_forgot = "<br />\n";
7
8 if ($doit == 1) {
9 $r = user_forgot_pass_mail($db, $email);
10 if ($r === FALSE)
11 $_forgot .= "Cannot send mail!";
12 else
13 $_forgot .= "E-mail was sent!";
14 }
15
16 ?>
File inc/xlog.inc.php changed (mode: 100644) (index b073370..c7b2caa)
1 1 <?php <?php
2 require_once($INC . "/util.inc.php");
2 3
3 4 $_xlog_file = "/tmp/gg.log"; $_xlog_file = "/tmp/gg.log";
4 5 $_xlog_fd = FALSE; $_xlog_fd = FALSE;
6 $_xlog_sid = gg_id(6);
5 7
6 8 function xlog_set_file($file) function xlog_set_file($file)
7 9 { {
 
... ... function xlog($str)
14 16 { {
15 17 global $_xlog_file; global $_xlog_file;
16 18 global $_xlog_fd; global $_xlog_fd;
19 global $_xlog_sid;
17 20
18 21 if ($_xlog_fd === FALSE) { if ($_xlog_fd === FALSE) {
19 22 $_xlog_fd = @fopen($_xlog_file, "a+"); $_xlog_fd = @fopen($_xlog_file, "a+");
 
... ... function xlog($str)
24 27 $buf = date("Y-m-d H:i:s"); $buf = date("Y-m-d H:i:s");
25 28 if (!empty($_SERVER['REMOTE_ADDR'])) if (!empty($_SERVER['REMOTE_ADDR']))
26 29 $buf .= " " . $_SERVER['REMOTE_ADDR']; $buf .= " " . $_SERVER['REMOTE_ADDR'];
27 $buf .= " " . $str . "\n";
30 $buf .= " " . $_xlog_sid . " " . $str . "\n";
28 31
29 32 fwrite($_xlog_fd, $buf); fwrite($_xlog_fd, $buf);
30 33 } }
File root/index.php changed (mode: 100644) (index 0398183..c7d2be5)
1 1 <?php <?php
2 2 error_reporting(E_ALL); error_reporting(E_ALL);
3 3
4 $_s = microtime(TRUE);
5
4 6 $INC = dirname(__FILE__) . "/../inc"; $INC = dirname(__FILE__) . "/../inc";
5 7 $ROOT = dirname(__FILE__); $ROOT = dirname(__FILE__);
6 8
 
... ... if ($db === FALSE)
49 51
50 52 // deal with login // deal with login
51 53 $uid = user_login($db, $sid, $gg_ui); $uid = user_login($db, $sid, $gg_ui);
52 if (($op == 1) && ($doit == 1) && ($uid == 0))
54 if (($op == 1) && ($doit == 1) && ($uid > 0))
53 55 $op = 0; $op = 0;
54 56
55 57 // deal with logout // deal with logout
 
... ... if ($op == 9) {
59 61 $gg_ui = FALSE; $gg_ui = FALSE;
60 62 } }
61 63
64 // auto-login user by forgot-pass token
65 if ($op == 6) {
66 // TODO
67 }
68
62 69 // menu // menu
63 70 $url = $_SERVER['PHP_SELF'] . "?a=1"; $url = $_SERVER['PHP_SELF'] . "?a=1";
64 71 $menu = ""; $menu = "";
65 $u = "Not logged in";
66 if (isset($gg_ui['user']))
67 $u = $gg_ui['user'];
68 $menu .= "[$u]<br />\n";
69 72 $menu .= "[<a href=\"$url&amp;op=1\">Login</a>]"; $menu .= "[<a href=\"$url&amp;op=1\">Login</a>]";
70 $menu .= "&nbsp;[<a href=\"$url&amp;op=2\">Repositories</a>]";
71 if ($gg_ui['is_admin'] == 1)
72 $menu .= "&nbsp;[<a href=\"$url&amp;op=3\">Admin</a>]";
73 $menu .= "&nbsp;[<a href=\"$url&amp;op=9\">Logout</a>]";
73 if (isset($gg_ui['user'])) {
74 $menu .= "&nbsp;[<a href=\"$url&amp;op=2\">Repositories</a>]";
75 if ($gg_ui['is_admin'] == 1)
76 $menu .= "&nbsp;[<a href=\"$url&amp;op=3\">Admin</a>]";
77 $menu .= "&nbsp;[<a href=\"$url&amp;op=9\">Logout</a>]";
78 $menu .= "&nbsp;&nbsp;&nbsp;[" . $gg_ui['user'] . "]";
79 }
80 $menu .= "<br />\n";
74 81
75 82
76 83 $body = ""; $body = "";
 
... ... case 3:
89 96 include($INC . "/admin/admin.php"); include($INC . "/admin/admin.php");
90 97 $body .= $_admin; $body .= $_admin;
91 98 break; break;
99
100 case 6: // forgot pass link
101 include($INC . "/user/forgot.php");
102 $body .= $_forgot;
103 break;
104
105 case 7: // forgot pass - send mail
106 include($INC . "/user/forgot_mail.php");
107 $body .= $_forgot;
108 break;
92 109 } }
93 110
94 111 $body .= "</body>"; $body .= "</body>";
95 112 $body .= "</html>\n"; $body .= "</html>\n";
96 113
97 echo $head . $menu . "<br />\n" . $body;
114 echo $head . $menu . $body;
98 115
99 xlog("Done!");
116 $_diff = sprintf("%u", (microtime(TRUE) - $_s) * 1000);
117 xlog("Done in $_diff ms.");
100 118 ?> ?>
File samples/cron added (mode: 100644) (index 0000000..028fe23)
1 * * * * * gg php /BIG1T/sync1/Dev/gg/scripts/cron.php
File samples/gg added (mode: 100644) (index 0000000..fc7d98b)
1 # default: off
2 # description: The git dæmon allows git repositories to be exported using \
3 # the git:// protocol.
4
5 service git
6 {
7 flags = IPv6
8 disable = no
9 socket_type = stream
10 wait = no
11 user = nobody
12 server = /usr/bin/php
13 server_args = /BIG1T/sync1/Dev/gg/scripts/ssh.php
14 log_on_failure += USERID
15 }
File scripts/cron.php added (mode: 100644) (index 0000000..1422a27)
1 <?php
2 // This is called by cron
3 error_reporting(E_ALL);
4
5 $now = time();
6
7 require_once("/etc/gg/config.php");
8
9 $INC = dirname(__FILE__) . "/../inc";
10 require_once($INC . "/xlog.inc.php");
11 require_once($INC . "/db.inc.php");
12 require_once($INC . "/repo.inc.php");
13
14 xlog_set_file("/tmp/gg_cron.log");
15
16 $sql_debug = $gg_db_debug;
17
18 $db = sql_open($gg_db);
19 if ($db === FALSE) {
20 xlog("Cannot connect to database!");
21 // TODO: inform admin - already by e-mail?
22 exit(1);
23 }
24
25 if (date("H") == 0) {
26 xlog("Compute repository sizes if dirty...");
27 // delete 'dirty' files
28 $sql = "SELECT * FROM repos";
29 $res = sql_query($db, $sql);
30 if ($res === FALSE) {
31 xlog("Cannot run query (" . sql_error() . ")!");
32 exit(1); // TODO: we should only skip this part not all scripts
33 }
34 while (($row = sql_fetch_array($res))) {
35 xlog("Processing repository [" . $row['name'] . "]...");
36 $repo_path = repo_id2base($row['repo_id']) . "/" . $row['name'] . ".git";
37 $disk_mb = repo_disk_mb($repo_path);
38 $sql = "UPDATE repos SET disk_mb = $disk_mb"
39 . " WHERE repo_id = " . $row['repo_id'];
40 $res2 = sql_query($db, $sql);
41 if ($res2 === FALSE) {
42 xlog("Cannot run query!");
43 } else {
44 @unlink($repo_path . "/gg/dirty");
45 sql_free_result($res2);
46 }
47 }
48 sql_free_result($res);
49 }
50
51 xlog("Update user quota...");
52
53 // Send notifications
54
55 // Clean old forgot_pass entries
56 if (date("H") == 0) {
57 xlog("Clean old forget_pass entries...");
58 $sql = "DELETE FROM forgot_pass WHERE expire < $now";
59 $res = sql_query($db, $sql);
60 sql_free_result($res);
61 }
62
63 // this has to be the last thing that touches the database
64 if (date("H") == 0) {
65 xlog("Run VACUUM on database...");
66 $sql = "VACUUM";
67 $res = sql_query($db, $sql);
68 sql_free_result($res);
69
70 xlog("Run ANALYZE on database...");
71 $sql = "ANALYZE";
72 $res = sql_query($db, $sql);
73 sql_free_result($res);
74 }
75
76 xlog("Done!");
77 ?>
File scripts/ssh.php changed (mode: 100644) (index 757a20a..bb3009e)
1 1 <?php <?php
2 // This is called by a remote client that does push or fetch
2 3 error_reporting(E_ALL); error_reporting(E_ALL);
3 4
4 5 $_start = microtime(TRUE); $_start = microtime(TRUE);
 
... ... $_start = microtime(TRUE);
6 7 require_once("/etc/gg/config.php"); require_once("/etc/gg/config.php");
7 8
8 9 $INC = dirname(__FILE__) . "/../inc"; $INC = dirname(__FILE__) . "/../inc";
10 require_once($INC . "/util.inc.php");
9 11 require_once($INC . "/xlog.inc.php"); require_once($INC . "/xlog.inc.php");
10 12 require_once($INC . "/db.inc.php"); require_once($INC . "/db.inc.php");
11 13 require_once($INC . "/repo.inc.php"); require_once($INC . "/repo.inc.php");
 
... ... $sql_debug = $gg_db_debug;
14 16
15 17 function fatal($str) function fatal($str)
16 18 { {
17 xlog($str);
18 fwrite(STDERR, "FATAL ERROR: " . $str . "\n");
19 global $access_type;
20
21 xlog("Sending error: " . $str);
22 $str2 = "FATAL ERROR: " . $str . "\n";
23 if ($access_type == 2) { //git
24 $str3 = "\n" . $str2;
25 $len = strlen($str3) + 4;
26 $str4 = sprintf("%04x", $len) . $str3;
27 fwrite(STDERR, $str4);
28 } else { // ssh
29 fwrite(STDERR, $str2);
30 }
19 31 exit(1); exit(1);
20 32 } }
21 33
22 34 xlog("Start..."); xlog("Start...");
35 //xlog("_SERVER: " . print_r($_SERVER, TRUE));
23 36
24 37 umask(0022); umask(0022);
25 38
26 $ssh_conn = @$_SERVER['SSH_CONNECTION'];
27 xlog("SSH_CONNECTION: $ssh_conn.");
39 if (isset($_SERVER['SSH_CONNECTION'])) {
40 xlog("SSH connection: " . @$_SERVER['SSH_CONNECTION']);
41 $access_type = 1;
28 42
29 // first parameter must be uid of the user
30 $uid = @$_SERVER['argv'][1];
31 if (empty($uid))
32 fatal("uid not provided!");
33 xlog("uid is $uid.");
43 // we do not have host info
44 $host = "";
34 45
35 $cmd = trim(@$_SERVER['SSH_ORIGINAL_COMMAND']);
36 if (empty($cmd))
37 fatal("No SSH_ORIGINAL_COMMAND provided!");
38 xlog("SSH_ORIGINAL_COMMAND is [$cmd].");
46 // first parameter must be uid of the user
47 $uid = @$_SERVER['argv'][1];
48 if (empty($uid))
49 fatal("uid not provided!");
50 xlog("\tuid is $uid.");
39 51
40 // extract command
41 if (strncmp($cmd, "git-upload-pack", 15) == 0) {
42 $op = "git-upload-pack";
52 $cmd_repo = trim(@$_SERVER['SSH_ORIGINAL_COMMAND']);
53 if (empty($cmd_repo))
54 fatal("No SSH_ORIGINAL_COMMAND provided!");
55 } else {
56 xlog("git-daemon connection...");
57 $access_type = 2;
58
59 // we have no client info
60 $uid = 0;
61
62 $f = @fopen("php://stdin", "r");
63 if ($f === FALSE)
64 fatal("\tCannot open stdin!");
65 $line = @fread($f, 8000);
66 if ($line === FALSE)
67 fatal("\tCannot read!");
68 fclose($f);
69 $line_len = strlen($line);
70
71 if ($line_len < 4)
72 fatal("\tLine is too short!");
73 $len = @hexdec(substr($line, 0, 4));
74 if ($line_len < $len)
75 fatal("Too less data ($line_len/$len) received!");
76
77 // parse something like: 002bgit-upload-pack /aa.git.host=localhost
78 $line = substr($line, 4);
79 $v = explode("\0", $line);
80 $cmd_repo = trim($v[0]);
81 $host = trim(substr($v[1], 5));
82 }
83
84 // extract command and compute permissions
85 if (strncmp($cmd_repo, "git-upload-pack", 15) == 0) {
86 $cmd = "git-upload-pack";
43 87 $perms = "R"; $perms = "R";
44 } else if (strncmp($cmd, "git-receive-pack", 16) == 0) {
45 $op = "git-receive-pack";
88 } else if (strncmp($cmd_repo, "git-receive-pack", 16) == 0) {
89 $cmd = "git-receive-pack";
46 90 $perms = "W"; $perms = "W";
47 91 } else { } else {
48 92 fatal("Unknown command!"); fatal("Unknown command!");
49 93 } }
50 xlog("real operation is $op, perms is [$perms].");
51 94
52 95 // extract repository name // extract repository name
53 $repo = substr($cmd, strlen($op));
96 $repo = substr($cmd_repo, strlen($cmd));
54 97 $repo = trim($repo, "' "); $repo = trim($repo, "' ");
98 $repo = ltrim($repo, "/");
99 $repo = preg_replace('/\.git$/' , '', $repo);
100
101 xlog("host=[$host] cmd=[$cmd] repo=[$repo] perms=[$perms].");
102
103 // validity/security checks
55 104 if (empty($repo)) if (empty($repo))
56 105 fatal("Repo is invalid!"); fatal("Repo is invalid!");
57 // security checks
58 106 if (preg_match('/\.\./', $repo)) if (preg_match('/\.\./', $repo))
59 107 fatal("Repo must not contain [..]!"); fatal("Repo must not contain [..]!");
60 xlog("repo is [$repo].");
61
62 // Check if repository exists
63 $path = $gg_base_repo . "/" . $repo;
64 if (!file_exists($path))
65 fatal("Cannot find repo $path!");
66 xlog("path is [$path].");
67
68 // check access - uid is allowed to access this repo?
69 $repo_id = sprintf("%u", @file_get_contents($path . "/gg/repo_id"));
70 if ($repo_id == 0)
71 fatal("Invalid repo!");
72 xlog("repo_id is [$repo_id]");
108 if (preg_match('/\//', $repo))
109 fatal("Repo must not contain [/]!");
73 110
74 111 $db = sql_open($gg_db); $db = sql_open($gg_db);
75 112 if ($db === FALSE) if ($db === FALSE)
76 113 fatal("Internal error (db)!"); fatal("Internal error (db)!");
77 114
78 if (!repo_allow($db, $repo_id, $uid, $perms))
79 fatal("You do not have access to this repository!");
115 // load info about the repository
116 $ri = repo_info($db, 0, $repo);
117 if ($ri['ok'] != 1)
118 fatal("Temporary error!");
119 if ($ri['exists'] != 1)
120 fatal("Repo does not exists!");
121
122 if (!repo_allow($db, $ri, $uid, $perms))
123 fatal("You do not have this type of access to this repository!");
124
125 // TODO: limit per connection
80 126
81 $run = "git-shell -c \"" . $op . " '" . escapeshellcmd($path) . "'\"";
127 // TODO: limit time and/or cpu
128
129 $repo_base = repo_id2base($ri['repo_id']);
130 $repo_path = $repo_base . "/" . $repo . ".git";
131 xlog("repo_path=$repo_path.");
132
133 $run = "git-shell -c \"" . $cmd . " '" . escapeshellcmd($repo_path) . "'\"";
82 134 xlog("Running [$run]..."); xlog("Running [$run]...");
83 135 passthru($run, $ret); passthru($run, $ret);
84 136 xlog("[$run] returned $ret."); xlog("[$run] returned $ret.");
85 137
86 138 $diff = sprintf("%u", (microtime(TRUE) - $_start) * 1000); $diff = sprintf("%u", (microtime(TRUE) - $_start) * 1000);
87 139 xlog("Took " . $diff . "ms."); xlog("Took " . $diff . "ms.");
140
141 @file_put_contents($repo_path . "/gg/last_access",
142 "repo: " . $repo . " ($repo_path)"
143 . "\nat: " . sprintf("%u", $_start)
144 . "\nuid: " . $uid
145 . "\ncmd: $cmd"
146 . "\nperms: $perms"
147 . "\nTook: " . $diff . "ms");
148
149 // Mark repository dirty for disk statistics and other stuff
150 if (strcmp($cmd, "git-receive-pack") == 0)
151 @file_put_contents($gg_path . "/dirty", "");
88 152 ?> ?>
File tests/Makefile changed (mode: 100644) (index 196fb8f..7771f05)
1 1 .PHONY: test .PHONY: test
2 2 test: test:
3 php util.php
3 4 php db.php php db.php
4 5 php keys.php php keys.php
File tests/user.php added (mode: 100644) (index 0000000..7e5f149)
1 <?php
2 $INC = "../inc";
3 require_once($INC . "/user.inc.php");
4
5 @unlink("user.sqlite");
6
7 $db = sql_open("sqlite:user.sqlite");
8 if ($db === FALSE) {
9 echo "Cannot create a database (" . sql_error() . ")!";
10 exit(1);
11 }
12
13 $sql = "CREATE TABLE users (email TEXT PRIMARY KEY, forgot_pass_token TEXT, forgot_pass_expire INTEGER)";
14 $res = sql_query($db, $sql);
15 if ($res === FALSE) {
16 echo "Cannot create users table!";
17 exit(1);
18 }
19
20 $sql = "INSERT INTO users VALUES ('gg@localhost', '', 0)";
21 $res = sql_query($db, $sql);
22 if ($res === FALSE) {
23 echo "Cannot insert a user!";
24 exit(1);
25 }
26
27 $v = user_forgot_pass($db, "gg@localhost");
28 if ($v === FALSE) {
29 echo "Error: " . user_error() . "!\n";
30 exit(1);
31 }
32
33 @unlink("user.sqlite");
34 ?>
File tests/util.php added (mode: 100644) (index 0000000..5b96512)
1 <?php
2 $INC = "../inc";
3 require_once($INC . "/util.inc.php");
4
5 $id = gg_id(16);
6 if (strlen($id) != 16) {
7 echo "Cannot generate an id!\n";
8 exit(1);
9 }
10 ?>
Hints

Before first commit, do not forget to setup your git environment:
git config --global user.name "your_name_here"
git config --global user.email "your@email_here"

Clone this repository using HTTP(S):
git clone https://code.reversed.top/user/xaizek/rocketgit

Clone this repository using ssh (do not forget to upload a key first):
git clone ssh://rocketgit@code.reversed.top/user/xaizek/rocketgit

You are allowed to anonymously push to this repository.
This means that your pushed commits will automatically be transformed into a pull request:
... clone the repository ...
... make some changes and some commits ...
git push origin master