<?php require_once($INC . "/util.inc.php"); require_once($INC . "/log.inc.php"); require_once($INC . "/sql.inc.php"); require_once($INC . "/user.inc.php"); require_once($INC . "/git.inc.php"); require_once($INC . "/rights.inc.php"); $rg_repo_empty = "4b825dc642cb6eb9a060e54bf8d69288fbee4904"; $rg_repo_error = ""; $rg_repo_rights = array( "A" => "Admin", "F" => "Fetch", "P" => "Push", "S" => "Create annotated tag", "Y" => "Create un-annotated tag", "U" => "Modify un-annotated tag", "u" => "Delete un-annotated tag", "C" => "Create branch", "D" => "Delete branch", "O" => "Non fast-forwards", "M" => "Merge commits", "W" => "Bad whitespace" ); // What rights are on by default $rg_repo_rights_default = "FM"; rg_rights_register("repo", $rg_repo_rights); function rg_repo_set_error($str) { global $rg_repo_error; rg_log("\tError: $str"); $rg_repo_error = $str; } function rg_repo_error() { global $rg_repo_error; return $rg_repo_error; } /* * Enforce name */ function rg_repo_ok($repo) { global $rg_repo_allow; global $rg_repo_max_len; if (empty($repo)) { rg_repo_set_error("Invalid repository name (empty)"); return FALSE; } if (rg_chars_allow($repo, $rg_repo_allow) === FALSE) { rg_repo_set_error("Invalid repository name (invalid chars)"); return FALSE; } if (preg_match('/\.\./', $repo) > 0) { rg_repo_set_error("Invalid repository name (..)"); return FALSE; } if (strlen($repo) > $rg_repo_max_len) { rg_repo_set_error("Repository name is too long"); return FALSE; } return TRUE; } /* * Returns the path to a repository based on name */ function rg_repo_name2base($repo) { global $rg_base_repo; $len = strlen($repo); $v = $repo; if ($len == 1) $v .= "_"; return $rg_base_repo . "/" . $v[0] . "/" . $v[1] . "/"; } /* * Return info about a repo */ function rg_repo_info($db, $repo_id, $repo) { rg_log("repo_info: repo_id/repo=[$repo_id/$repo]..."); $ret['ok'] = 0; $ret['exists'] = 0; if ($repo_id > 0) { $add = " AND repo_id = $repo_id"; } else if (!empty($repo)) { $e_repo = rg_sql_escape($db, $repo); $add = " AND name = '$e_repo'"; } else { $ret['errmsg'] = "No repo_id or name specified!"; return $ret; } $sql = "SELECT * FROM repos WHERE 1 = 1" . $add; $res = rg_sql_query($db, $sql); if ($res === FALSE) { $ret['errmsg'] = "Cannot query (" . rg_sql_error() . ")"; rg_log("\t" . $ret['errmsg']); return $ret; } $ret['ok'] = 1; $row = rg_sql_fetch_array($res); rg_sql_free_result($res); if (!isset($row['repo_id'])) { rg_log("\tRepo not found!"); return $ret; } $row['exists'] = 1; $row['ok'] = 1; return $row; } /* * Check if a uid has access to repository */ function rg_repo_allow($db, $ri, $rg_ui, $needed_rights) { rg_log("repo_allow: repo_id=" . $ri['repo_id'] . " rg_uid=" . $rg_ui['uid'] . ", needed_rights=$needed_rights..."); if ($rg_ui['is_admin'] == 1) { rg_log("\tUser is admin, allow!"); return TRUE; } if (empty($needed_rights)) { rg_log("\tNo perms passed!"); return FALSE; } // anonymous acess (git://...) if ($rg_ui['uid'] == 0) { $db_rights = $ri['default_rights']; } else { $rr = rg_repo_rights_get($db, $ri, $rg_ui['uid'], 0); if ($rr['ok'] != 1) { rg_repo_set_error("cannot get rights from db"); return FALSE; } $db_rights = $rr['rights']; } rg_log("\tdb rights: " . $db_rights); if (rg_rights_allow($db_rights, $needed_rights) !== TRUE) { rg_repo_set_error("no rights ($needed_rights) vs ($db_rights)"); return FALSE; } rg_log("\tAllow access!"); return TRUE; } /* * Add a repository * @master - makes sense only for clones - who is the master. * TODO: put all fields into an array! */ function rg_repo_create($db, $master, $rg_ui, $name, $max_commit_size, $description, $rights, $max_users) { // TODO: reorder parameters - are not logical rg_log("repo_create: rg_uid=" . $rg_ui['uid'] . ", name=[$name], master=$master" . ", max_commit_size=$max_commit_size" . ", description=[$description]" . ", rights=$rights, max_users=$max_users..."); // TODO: test if user is allowed to add a repository if (rg_repo_ok($name) === FALSE) return FALSE; // First, test if it already exists $ri = rg_repo_info($db, 0, $name); if ($ri['ok'] != 1) return FALSE; if ($ri['exists'] == 1) { rg_repo_set_error("Repository already exists."); return FALSE; } $e_name = rg_sql_escape($db, $name); $e_description = rg_sql_escape($db, $description); $itime = time(); $sql = "INSERT INTO repos (uid, master, name, itime" . ", max_commit_size, description, git_dir_done, default_rights" . ", max_users)" . " VALUES (" . $rg_ui['uid'] . ", $master, '$e_name', $itime" . ", $max_commit_size, '$e_description', 0, '$rights', $max_users)"; $res = rg_sql_query($db, $sql); if ($res === FALSE) { rg_repo_set_error("Cannot insert (" . rg_sql_error() . ")"); return FALSE; } rg_sql_free_result($res); // git repo creation will be delayed for serialization reasons // and for permission reasons (we are apache here) return TRUE; } /* * Delete a repo */ function rg_repo_delete($db, $repo_id, $rg_ui) { rg_log("repo_delete: rg_uid=" . $rg_ui['uid'] . ", repo_id=$repo_id"); // TODO: Check rights // Only mark it as such, deletion will happen in background $sql = "UPDATE repos SET deleted = 1 WHERE repo_id = $repo_id"; $res = rg_sql_query($db, $sql); if ($res === FALSE) { rg_repo_set_error("Cannot delete (" . rg_sql_error() . ")"); return FALSE; } rg_sql_free_result($res); return TRUE; } /* * Update a repository * TODO: check rights - also for create? */ function rg_repo_update($db, &$new) { rg_log("repo_update: repo_id=" . $new['repo_id'] . ", name=[" . $new['name'] . "]" . ", max_commit_size=" . $new['max_commit_size'] . ", description=[" . $new['description'] . "]" . ", default_rights=" . $new['default_rights'] . ", max_users=" . $new['max_users']); if (rg_repo_ok($new['name']) !== TRUE) return FALSE; // First, test if it already exists $ri = rg_repo_info($db, 0, $new['name']); if ($ri['ok'] != 1) return FALSE; if (($ri['exists'] == 1) && ($ri['repo_id'] != $new['repo_id'])) { rg_repo_set_error("Name already taken."); return FALSE; } // Second, test if repo_id is valid $ri = rg_repo_info($db, $new['repo_id'], ""); if ($ri['ok'] != 1) return FALSE; if ($ri['exists'] == 0) { rg_repo_set_error("Repo " . $new['repo_id'] . " does not exists."); return FALSE; } $e_name = rg_sql_escape($db, $new['name']); $e_description = rg_sql_escape($db, $new['description']); $sql = "UPDATE repos SET name = '$e_name'" . ", max_commit_size = " . $new['max_commit_size'] . ", description = '$e_description'" . ", default_rights = '" . $new['default_rights'] . "'" . ", max_users = " . $new['max_users'] . " WHERE repo_id = " . $new['repo_id']; $res = rg_sql_query($db, $sql); if ($res === FALSE) { rg_repo_set_error("Cannot update (" . rg_sql_error() . ")"); return FALSE; } rg_sql_free_result($res); return TRUE; } /* * List repositories */ function rg_repo_list_query($db, $url, $sql) { global $rg_ui; rg_log("repo_list_query: url=$url, sql=$sql..."); $res = rg_sql_query($db, $sql); if ($res === FALSE) return FALSE; $admin_mode = 0; if ($rg_ui['is_admin'] == 1) $admin_mode = 1; $ret = "<table>\n"; $ret .= "<tr>\n"; $ret .= " <th>Name</th>\n"; if ($admin_mode == 1) $ret .= " <th>Owner</th>\n"; $ret .= " <th>Description</th>\n"; $ret .= " <th>Clone of</th>\n"; $ret .= " <th>Creation date (UTC)</th>\n"; $ret .= " <th>Default rights</th>\n"; $ret .= " <th>Disk used/max</th>\n"; $ret .= " <th>Max commit size</th>\n"; $ret .= " <th>Max users</th>\n"; $ret .= "</tr>\n"; while (($row = rg_sql_fetch_array($res))) { $ret .= "<tr>\n"; $_link = rg_re_repopage($row['repo_id'], $row['name']); $ret .= " <td><a href=\"$_link\">" . $row['name'] . "</a></td>\n"; if ($admin_mode == 1) { $_ui = rg_user_info($db, $row['uid'], "", ""); if ($_ui['exists'] != 1) $v = "?" . $row['uid'] . "?"; else $v = $_ui['username']; $ret .= " <td>$v</td>\n"; } $ret .= " <td><small>" . nl2br($row['description']) . "</small></td>\n"; if ($row['master'] > 0) { $master_repo = "?"; $_mi = rg_repo_info($db, $row['master'], ""); if ($_mi['exists'] = 1) $master_repo = $_mi['name']; } $ret .= " <td>" . ($row['master'] == 0 ? "-" : $master_repo) . "</td>\n"; $ret .= " <td>" . gmdate("Y-m-d H:i:s", $row['itime']) . "</td>\n"; // rights $_r = implode(", ", rg_rights_text("repo", $row['default_rights'])); $ret .= " <td>" . $_r . "</td>\n"; $_max = "ulimited"; if ($row['disk_quota_mb'] > 0) $_max = rg_1024($row['disk_quota_mb'] * 1024 * 1024); $ret .= " <td>" . $row['disk_used_mb'] . "/" . $_max . "</td>\n"; $_v = "ulimited"; if ($row['max_commit_size'] > 0) $_v = rg_1024($row['max_commit_size']); $ret .= " <td>" . $_v . "</td>\n"; $_v = "ulimited"; if ($row['max_users'] > 0) $_v = $row['max_users']; $ret .= " <td>" . $_v . "</td>\n"; $ret .= "</tr>\n"; } $ret .= "</table>\n"; rg_sql_free_result($res); return $ret; } /* * */ function rg_repo_list($db, $url, $rg_ui) { rg_log("repo_list: url=$url, rg_uid=" . $rg_ui['uid']); $add = ""; if ($rg_ui['uid'] > 0) $add = " AND uid = " . $rg_ui['uid']; $sql = "SELECT * FROM repos" . " WHERE deleted = 0" . $add . " ORDER BY name"; return rg_repo_list_query($db, $url, $sql); } /* * */ function rg_repo_search($db, $q, $masters) { rg_log("repo_search: q=$q, masters=$masters..."); $add = ""; if ($masters == 1) $add = " AND master = 0"; $e_q = rg_sql_escape($db, $q); $sql = "SELECT * FROM repos" . " WHERE deleted = 0" . " AND name ILIKE '%$e_q%'" . $add . " ORDER BY name" . " LIMIT 10"; return rg_repo_list_query($db, "", $sql); } /* * Computes the size of a repository */ function rg_repo_disk_mb($path) { rg_log("repo_disk_mb: path=$path..."); // TODO return 10; } /* * Mark a git repo as done */ function rg_repo_git_done($db, $repo_id) { rg_log("repo_git_done: repo_id=$repo_id..."); $sql = "UPDATE repos SET git_dir_done = 1" . " WHERE repo_id = $repo_id"; $res = rg_sql_query($db, $sql); if ($res === FALSE) { rg_repo_set_error("Cannot query (" . rg_sql_error() . ")"); return FALSE; } rg_sql_free_result($res); return TRUE; } /* * Get rights for a user */ function rg_repo_rights_get($db, $ri, $uid, $flags) { rg_log("rg_repo_rights_get: repo_id=" . $ri['repo_id'] . ", uid=$uid" . " flags=$flags..."); $ret = array(); $ret['ok'] = 0; $ret['rights'] = ""; $repo_id = $ri['repo_id']; // Give all rights to owner if ($ri['uid'] == $uid) { rg_log("\tuid $uid is the owner."); $rights = rg_rights_all("repo"); if (($flags & RG_RIGHTS_FILL_EXISTS) == 0) { rg_log("\tNo need to fill 'exists' field. Return."); $ret['rights'] = $rights; $ret['ok'] = 1; return $ret; } } else { $rights = $ri['default_rights']; } $r = rg_rights_get($db, "repo", $repo_id, $uid); if ($r['ok'] !== 1) { rg_repo_set_error("Cannot get rights (" . rg_rights_error() . ")!"); return FALSE; } $ret['rights'] = rg_rights_combine($rights, $r['rights']); rg_log("\tFinal rights($rights + " . $r['rights'] . ")=" . $ret['rights']); $ret['ok'] = 1; return $ret; } /* * Add rights for a repo */ function rg_repo_rights_set($db, $ri, $uid, $rights) { rg_log("rg_repo_rights_set: repo_id=" . $ri['repo_id'] . ", uid=$uid, rights=$rights..."); $r = rg_rights_set($db, "repo", $ri['repo_id'], $uid, $rights); if ($r !== TRUE) { rg_repo_set_error("Cannot alter rights (" . rg_rights_error() . ")!"); return FALSE; } return TRUE; } /* * List rights for a repo */ function rg_repo_rights_list($db, $ri, $url) { rg_log("rg_repo_rights_list: repo_id=" . $ri['repo_id'] . " url=$url"); $r = rg_rights_list($db, "repo", $ri['repo_id'], $url); if ($r === FALSE) { rg_repo_set_error("Cannot list rights (" . rg_rights_error() . ")"); return FALSE; } return $r; } /* * Returns TRUE if a repo is over limit */ function rg_repo_over_limit($ri) { if ($ri['disk_quota_mb'] == 0) return FALSE; if ($ri['disk_used_mb'] >= $ri['disk_quota_mb']) return TRUE; return FALSE; } ?>