<?php
require_once($INC . "/sql.inc.php");
require_once($INC . "/state.inc.php");
$rg_keys_error = "";
function rg_keys_set_error($str)
{
global $rg_keys_error;
rg_log("\tError: $str");
$rg_keys_error = $str;
}
function rg_keys_error()
{
global $rg_keys_error;
return $rg_keys_error;
}
/*
* Validate key
*/
function rg_keys_valid($s)
{
$v = explode(" ", $s);
if (!isset($v[1])) {
rg_keys_set_error("Malformed input (missing fields)");
return FALSE;
}
$decoded = base64_decode(trim($v[1]));
if ($decoded === FALSE) {
rg_keys_set_error("Malformed input (base64 failed)");
return FALSE;
}
return $decoded;
}
/*
* Generates the fingerprint of a key
*/
function rg_keys_fingerprint($key)
{
$decoded = rg_keys_valid($key);
if ($decoded === FALSE)
return rg_keys_error();
$digest = md5($decoded);
$a = array();
for ($i = 0; $i < 16; $i++)
$a[] = substr($digest, $i * 2, 2);
return implode(":", $a);
}
/*
* Remove a key from database
*/
function rg_keys_remove($db, $rg_ui, $key_id)
{
// mark dirty
if (rg_state_set($db, "authorized_keys", 1) === FALSE) {
rg_keys_set_error("Cannot make state dirty (" . rg_state_error() . ")!");
return FALSE;
}
// TODO: move this to caller?
$e_key_id = sprintf("%u", $key_id);
$sql = "DELETE FROM keys"
. " WHERE uid = " . $rg_ui['uid']
. " AND key_id = $e_key_id";
$res = rg_sql_query($db, $sql);
if ($res === FALSE) {
rg_keys_set_error("Cannot delete key $key_id (" . rg_sql_error() . ")");
return FALSE;
}
rg_sql_free_result($res);
return TRUE;
}
/*
* Add a key
* Returns the key_id of the key.
*/
function rg_keys_add($db, $rg_ui, $key)
{
$itime = time();
$e_key = rg_sql_escape($db, $key);
if (rg_keys_valid($key) === FALSE)
return FALSE;
// set dirty
if (rg_state_set($db, "authorized_keys", 1) === FALSE) {
rg_keys_set_error("cannot make state dirty: " . rg_state_error());
return FALSE;
}
$sql = "INSERT INTO keys (itime, uid, key)"
. " VALUES ($itime, " . $rg_ui['uid'] . ", '$e_key')";
$res = rg_sql_query($db, $sql);
if ($res === FALSE) {
rg_keys_set_error("Cannot insert key (" . rg_sql_error() . ")");
return FALSE;
}
rg_sql_free_result($res);
return rg_sql_last_id($db);
}
/*
* Regenerates authorized_keys files
*/
function rg_keys_regen($db)
{
global $rg_keys_file;
global $rg_scripts;
global $rg_ssh_paras;
$dirty = rg_state_get($db, "authorized_keys");
if ($dirty == 0) {
// Skip generation because is not dirty
return TRUE;
}
// create .ssh folder if does not exists
$dir = dirname($rg_keys_file);
if (!file_exists($dir)) {
if (!@mkdir($dir, 0700, TRUE)) {
rg_keys_set_error("cannot create dir $dir ($php_errormsg)");
return FALSE;
}
}
$tmp = $rg_keys_file . ".tmp";
$f = @fopen($tmp, "w");
if ($f === FALSE) {
rg_keys_set_error("cannot open file $tmp ($php_errormsg)");
return FALSE;
}
if (chmod($tmp, 0600) === FALSE) {
rg_keys_set_error("cannot chmod tmp file ($php_errmsg)");
fclose($f);
return FALSE;
}
$sql = "SELECT uid, key FROM keys";
$res = rg_sql_query($db, $sql);
if ($res === FALSE) {
rg_keys_set_error("cannot query (" . rg_sql_error() . ")");
return FALSE;
}
while (($row = rg_sql_fetch_array($res))) {
rg_log("Writing key [" . $row['key'] . "] for uid " . $row['uid']);
$buf = "command=\"/usr/bin/php " . $rg_scripts . "/scripts/remote.php"
. " " . $row['uid'] . "\""
. "," . $rg_ssh_paras
. " " . $row['key'] . "\n";
if (@fwrite($f, $buf) === FALSE) {
rg_keys_set_error("cannot write. Disk space problems? ($php_errormsg)");
fclose($f);
unlink($tmp);
rg_sql_free_result($res);
return FALSE;
}
}
rg_sql_free_result($res);
fclose($f);
if (@rename($tmp, $rg_keys_file) === FALSE) {
rg_keys_set_error("cannot rename $tmp to $rg_keys_file ($php_errormsg)");
unlink($tmp);
return FALSE;
}
// mark file as clean
rg_state_set($db, "authorized_keys", 0);
return TRUE;
}
/*
* List keys
*/
function rg_keys_list($db, $rg_ui, $url)
{
rg_log("keys_list: rg_uid=" . $rg_ui['uid'] . ", url=$url...");
$sql = "SELECT * FROM keys WHERE uid = " . $rg_ui['uid'];
$res = rg_sql_query($db, $sql);
if ($res === FALSE) {
rg_keys_set_error("Cannot query (" . rg_sql_error() . ")");
return FALSE;
}
$ret = "<table>\n";
$ret .= "<tr>\n";
$ret .= " <th>Date (UTC)</th>\n";
$ret .= " <th>Fingerprint</th>\n";
$ret .= " <th>Operations</th>\n";
$ret .= "</tr>\n";
while (($row = rg_sql_fetch_array($res))) {
$ret .= "<tr>\n";
$ret .= " <td>" . gmdate("Y-m-d H:i:s", $row['itime']) . "</td>\n";
$ret .= " <td>" . rg_keys_fingerprint($row['key']) . "</td>\n";
$oper = "";
$oper = "[<a href=\"$url&key_id=" . $row['key_id']
. "&delete=1\">Delete!</a>]";
$ret .= " <td>" . $oper . "</td>\n";
$ret .= "</tr>\n";
}
$ret .= "</table>\n";
rg_sql_free_result($res);
return $ret;
}
?>
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