<?php
$INC = isset($INC) ? $INC : dirname(__FILE__);
require_once($INC . "/user.inc.php");
require_once($INC . "/workers.inc.php");
/*
* Event functions
*/
$rg_admin_functions = array(
6000 => "rg_admin_invite",
6001 => "rg_admin_invite_one"
);
rg_event_register_functions($rg_admin_functions);
/*
* Event for invites
*/
function rg_admin_invite($db, $event)
{
$ret = array();
rg_log_ml("DEBUG: event[list]=" . print_r($event['list'], TRUE));
foreach ($event['list'] as $line) {
$line = trim($line);
if (empty($line))
continue;
$t = explode('|', $line, 2);
$ret[] = array_merge($event,
array(
'category' => 6001,
'prio' => 100,
'email' => trim($t[0]),
'name' => trim($t[1])
)
);
}
return $ret;
}
/*
* Event for invites (one e-mail version)
*/
function rg_admin_invite_one($db, $event)
{
global $rg_admin_email, $rg_admin_name;
$admin_name = "=?UTF-8?B?"
. base64_encode($rg_admin_name) . "?=";
$rg = array();
$subject = str_replace('{NAME}', $event['name'], $event['subject']);
$subject = "=?UTF-8?B?" . base64_encode(trim($subject)) . "?=";
$header = rg_template("mail/common.head.txt", $rg, FALSE /*xss*/);
$header = trim($header);
$header .= "\nFrom: $admin_name <" . $rg_admin_email . ">";
rg_log_ml("DEBUG: header=$header");
$body = str_replace('{NAME}', $event['name'], $event['body']);
$r = mail($event['email'], $subject, $body, $header,
"-f $rg_admin_email");
if ($r === FALSE)
return FALSE;
return array();
}
/*
* Deals with invites
*/
function rg_admin_invites_high_level($db, $rg)
{
rg_log_enter("admin_invites_high_level");
$ret = "";
$inv = array();
$inv['list'] = "";
$inv['subject'] = "";
$inv['body'] = "";
$errmsg = array();
$show_form = TRUE;
while (1) {
if (rg_var_int("doit") == 0)
break;
$inv['list'] = rg_var_str('inv::list');
$inv['subject'] = rg_var_str('inv::subject');
$inv['body'] = rg_var_str('inv::body');
while (isset($_FILES['inv::file'])) {
if (empty($_FILES['inv::file']['tmp_name']))
break;
rg_log_ml("DEBUG: we have a file uploaded: " . print_r($_FILES, TRUE));
if ($_FILES['inv::file']['error'] !== UPLOAD_ERR_OK) {
$errmsg[] = "error in upload (1); try again";
break;
}
if (!is_uploaded_file($_FILES['inv::file']['tmp_name'])) {
$errmsg[] = "error in upload (2); try again";
break;
}
$inv['body'] = @file_get_contents($_FILES['inv::file']['tmp_name']);
if ($inv['body'] === FALSE) {
$errmsg[] = "error in upload (3); try again";
break;
}
break;
}
if (!rg_valid_referer()) {
$errmsg[] = "invalid referer; try again";
break;
}
if (!rg_token_valid($db, $rg, 'admin_invites_hl', FALSE)) {
$errmsg[] = "invalid token; try again";
break;
}
if (empty($inv['list'])) {
$errmsg[] = "list is empty";
break;
}
if (empty($inv['subject'])) {
$errmsg[] = "subject is empty";
break;
}
if (empty($inv['body'])) {
$errmsg[] = "body is empty";
break;
}
$list = explode("\n", trim($inv['list']));
foreach ($list as $line) {
$line = trim($line);
if (empty($line))
continue;
$t = explode('|', $line, 2);
if (count($t) != 2) {
$errmsg[] = 'invalid line: ' . rg_xss_safe($line);
} else {
if (!strstr($t[0], '@'))
$errmsg[] = 'invalid e-mail in line: ' . rg_xss_safe($line);
}
}
if (!empty($errmsg))
break;
$event = array(
'category' => 6000,
'prio' => 50,
'ui' => $rg['login_ui']);
$event = array_merge($event, $inv);
$event['list'] = $list;
$r = rg_event_add($db, $event);
if ($r !== TRUE) {
$errmsg[] = "cannot add event (" . rg_event_error() . ")";
break;
}
rg_event_signal_daemon('', 0);
$ret .= rg_template("admin/invites/sent.html", $rg, TRUE /* xss */);
$show_form = FALSE;
break;
}
if ($show_form) {
$rg['inv'] = $inv;
$rg['HTML:errmsg'] = rg_template_errmsg($errmsg);
$rg['rg_form_token'] = rg_token_get($db, $rg, 'admin_invites_hl');
$ret .= rg_template("admin/invites/invites.html", $rg, TRUE /* xss */);
}
rg_log_exit();
return $ret;
}
/*
* Prepares an instalation for first use
*/
function rg_init($db, $rg)
{
rg_prof_start("rg_init");
rg_log_enter("rg_init");
$ret = '';
$doit = rg_var_uint('doit');
if ($doit == 0) {
$rg['init']['username'] = 'admin';
$rg['init']['realname'] = '';
$rg['init']['email'] = '';
$rg['init']['pass'] = '';
$rg['init']['pass2'] = '';
$rg['init']['session_time'] = 600;
}
$errmsg = array();
$load_form = TRUE;
while ($doit == 1) {
$rg['init'] = array();
$rg['init']['uid'] = 0;
$rg['init']['is_admin'] = 1;
$rg['init']['rights'] = rg_rights_all('user');
$rg['init']['confirm_token'] = '';
$rg['init']['plan_id'] = 1;
$rg['init']['username'] = rg_var_str('init::username');
$rg['init']['realname'] = rg_var_str('init::realname');
$rg['init']['email'] = rg_var_str('init::email');
$rg['init']['pass'] = rg_var_str('init::pass');
$rg['init']['pass2'] = rg_var_str('init::pass2');
$rg['init']['session_time'] = rg_var_uint('init::session_time');
$rg['init']['confirmed'] = time(); /* = no need to confirm */
$rg['init']['ask_for_email_confirmation'] = 0;
if (!rg_valid_referer()) {
$errmsg[] = "invalid referer; try again";
break;
}
if (!rg_token_valid($db, $rg, 'init', FALSE)) {
$errmsg[] = "invalid token; try again";
break;
}
if (!strstr($rg['init']['email'], '@')) {
$errmsg[] = 'invalid e-mail';
break;
}
$r = rg_user_edit($db, $rg['init']);
if ($r === FALSE) {
$errmsg[] = rg_user_error();
break;
}
rg_state_set($db, 'first_install', time());
// Makes no sense to confirm the admin account
$rg['rg_account_email_confirm'] = 0;
$ret .= rg_template('user/create_ok.html', $rg, TRUE /* xss */);
$load_form = FALSE;
break;
}
if ($load_form) {
$rg['HTML:errmsg'] = rg_template_errmsg($errmsg);
$rg['rg_form_token'] = rg_token_get($db, $rg, 'init');
$ret .= rg_template("admin/init.html", $rg, TRUE /* xss */);
}
rg_log_exit();
rg_prof_end("rg_init");
return $ret;
}
/*
* Helper for rg_admin_report1 - suggestion report
*/
function rg_admin_report1_suggestions($db, $from, $to)
{
$ret = '';
// Total
$sql = "SELECT COUNT(*) AS total FROM suggestions";
$res = rg_sql_query($db, $sql);
if ($res === FALSE) {
$total = 'ERR';
} else {
$row = rg_sql_fetch_array($res);
$total = $row['total'];
}
rg_sql_free_result($res);
// Yesterday
$yesterday_text = '';
$y_start = gmmktime(0, 0, 0, gmdate('m'), gmdate('d') - 1, gmdate('Y'));
$y_end = gmmktime(0, 0, 0, gmdate('m'), gmdate('d'), gmdate('Y')) - 1;
$sql = "SELECT uid, suggestion FROM suggestions"
. " WHERE itime >= $y_start"
. " AND itime <= $y_end";
$res = rg_sql_query($db, $sql);
if ($res === FALSE) {
$yesterday = "ERR";
} else {
$count = 0;
$list = '';
while (($row = rg_sql_fetch_array($res))) {
$count++;
$list .= sprintf("%8u %s\n",
$row['uid'], $row['suggestion']);
}
$yesterday = $count;
if ($count)
$yesterday_text = "\nYesterday suggestions:\n" . $list;
}
rg_sql_free_result($res);
$ret .= "\nTotal suggestions: " . $total;
$ret .= "\nYesterday suggestions: " . $yesterday;
$ret .= $yesterday_text;
return $ret;
}
/*
* Send some daily statistics to the admin
*/
function rg_admin_report1($db, $rg)
{
global $rg_admin_email;
global $rg_web_url;
$body = '';
$y_start = gmmktime(0, 0, 0, gmdate("m"), gmdate("d") - 1);
$y_end = gmmktime(0, 0, 0, gmdate("m"), gmdate("d")) - 1;
$body .= "Report between " . gmdate('Y-m-d H:i:s', $y_start)
. " and " . gmdate('Y-m-d H:i:s', $y_end) . " UTC\n";
$body .= 'For site ' . $rg_web_url . "\n";
$list = array(
'users' => 'users',
'repos' => 'repositories',
'bugs' => 'bugs',
'bug_notes' => 'bug notes',
'repo_history' => 'repo history',
'keys' => 'keys',
'login_tokens' => 'login tokens',
'scratch_codes' => 'scratch codes',
'merge_requests' => 'pull requests',
'webhooks' => 'webhooks',
'rights' => 'rights',
'events' => 'events',
'build_jobs' => 'build jobs',
'apikeys' => 'api keys',
'workers' => 'workers');
$total_yesterday_changes = 0;
foreach ($list as $table => $text) {
// Yesterday
$sql = "SELECT COUNT(*) AS count FROM " . $table
. " WHERE itime >= $y_start"
. " AND itime <= $y_end";
$res = rg_sql_query($db, $sql);
if ($res === FALSE) {
$yesterday = "ERR";
} else {
$row = rg_sql_fetch_array($res);
$yesterday = $row['count'];
$total_yesterday_changes += $row['count'];
}
rg_sql_free_result($res);
// Total
$sql = "SELECT COUNT(*) AS total FROM " . $table;
$res = rg_sql_query($db, $sql);
if ($res === FALSE) {
$total = "ERR";
} else {
$row = rg_sql_fetch_array($res);
$total = $row['total'];
}
rg_sql_free_result($res);
$body .= "\n" . $yesterday . "\t" . $total
. "\t" . "yesterday / total " . $text;
}
$body .= "\n";
$sql = 'SELECT username, realname, email FROM users'
. ' WHERE itime >= ' . $y_start
. ' AND itime <= ' . $y_end;
$res = rg_sql_query($db, $sql);
if ($res === FALSE) {
$users = "ERR";
} else {
$users = 0;
$list = '';
while (($row = rg_sql_fetch_array($res))) {
$users++;
$list .= "\t" . $row['username']
. "\t" . $row['realname']
. "\t" . $row['email']
. "\n";
}
if ($users)
$body .= "\nYesterday users (" . $users . "):\n"
. $list;
}
rg_sql_free_result($res);
$sql = "SELECT name, description, public FROM repos"
. " WHERE itime >= $y_start"
. " AND itime <= $y_end";
$res = rg_sql_query($db, $sql);
if ($res === FALSE) {
$repos = "ERR";
} else {
$repos = 0;
$list = '';
while (($row = rg_sql_fetch_array($res))) {
$repos++;
$desc = substr($row['description'], 0, 50) . '...';
$desc = preg_replace('/\s/', ' ', $desc);
$list .= "\t" . $row['name'] . " - " . $desc
. ($row['public'] == 1 ? " (public)" : " (private)") . "\n";
}
if ($repos)
$body .= "\nYesterday repos (" . $repos . "):\n" . $list;
}
rg_sql_free_result($res);
$sug = rg_admin_report1_suggestions($db, $y_start, $y_end);
$body .= "\n" . $sug;
$rg['ui']['ignore_confirmed'] = 1;
$rg['ui']['email'] = $rg_admin_email;
$rg['mail'] = array();
$rg['mail']['subject'] = 'RocketGit report'
. ' [' . $users . 'u]'
. ' [' . $repos . 'r]'
. ' [' . $total_yesterday_changes . 'c]';
if (!empty($rg_web_url))
$rg['mail']['subject'] .= ' (' . $rg_web_url . ')';
$rg['mail']['body'] = $body;
rg_mail_template("mail/admin/report1", $rg);
}
/*
* Function to clean the log files
* It is called by both crons (under apache and under rocketgit users)
*/
function rg_clean_logs($dir)
{
global $rg_logs_lifetime;
if ($rg_logs_lifetime == 0)
return;
$files = glob($dir . "/*.log");
if ($files === FALSE) {
rg_log("Cannot select logs for delete");
return FALSE;
}
$limit_ts = gmmktime(0, 0, 0, gmdate('m'), gmdate('d') - $rg_logs_lifetime);
$limit = gmdate("Ymd", $limit_ts);
//rg_log("limit_ts=$limit_ts limit=$limit");
foreach ($files as $file) {
$ymd = preg_replace('/.*-([0-9]*)\.log/', '$1', $file);
//rg_log("file=$file ymd=$ymd");
if ($ymd >= $limit)
continue;
//rg_log("Deleting old log file $file");
$r = unlink($file);
if ($r === FALSE)
rg_log("Cannot delete file $file!");
}
}
/*
* Admin ->Settings -> SSH menu
*/
function rg_admin_settings_ssh($db, $rg)
{
global $rg_max_ssh_keys;
rg_log_enter('admin_settings_ssh');
$ret = '';
$errmsg = array();
$hints = array();
while ($rg['doit'] == 1) {
if (!rg_valid_referer()) {
$errmsg[] = 'invalid referer; try again';
break;
}
if (!rg_token_valid($db, $rg, 'admin_settings_ssh', FALSE)) {
$errmsg[] = 'invalid token; try again';
break;
}
$v = rg_var_uint('max_ssh_keys');
$r = rg_state_set($db, 'max_ssh_keys', $v);
if ($r === FALSE) {
$errmsg[] = 'cannot set state; try again';
break;
}
$v = rg_var_int('ssh_key_min_bits_rsa');
$r = rg_state_set($db, 'ssh_key_min_bits_rsa', $v);
if ($r === FALSE) {
$errmsg[] = 'cannot set state; try again';
break;
}
$v = rg_var_int('ssh_key_allow_dsa');
$r = rg_state_set($db, 'ssh_key_allow_dsa', $v);
if ($r === FALSE) {
$errmsg[] = 'cannot set state; try again';
break;
}
$v = rg_var_int('ssh_key_min_bits_ecdsa');
$r = rg_state_set($db, 'ssh_key_min_bits_ecdsa', $v);
if ($r === FALSE) {
$errmsg[] = 'cannot set state; try again';
break;
}
$v = rg_var_int('AuthorizedKeysCommand');
$r = rg_state_set($db, 'AuthorizedKeysCommand', $v);
if ($r === FALSE) {
$errmsg[] = 'cannot set state; try again';
break;
}
// Nobody will force the regeneration, so, do it here!
$ev = array(
'category' => 'rg_keys_event_regen',
'prio' => 10,
'ui' => array('uid' => $rg['login_ui']['uid'])
);
$r = rg_event_add($db, $ev);
if ($r !== TRUE) {
$errmsg[] = 'cannot add event';
break;
}
$ret .= rg_template('admin/settings/ok.html',
$rg, TRUE /*xss*/);
break;
}
// Load defaults
while (1) {
$r = rg_state_get($db, 'max_ssh_keys');
if ($r === FALSE) {
$ret = rg_template('admin/settings/load_err.html',
$rg, TRUE /*xss*/);
break;
}
if (empty($r))
$r = $rg_max_ssh_keys;
$rg['max_ssh_keys'] = $r;
$r = rg_state_get($db, 'ssh_key_min_bits_rsa');
if ($r === FALSE) {
$ret = rg_template('admin/settings/load_err.html',
$rg, TRUE /*xss*/);
break;
}
if (empty($r))
$r = 2048;
$rg['ssh_key_min_bits_rsa'] = $r;
$r = rg_state_get($db, 'ssh_key_allow_dsa');
if ($r === FALSE) {
$ret = rg_template('admin/settings/load_err.html',
$rg, TRUE /*xss*/);
break;
}
if (empty($r))
$r = 0;
$rg['ssh_key_allow_dsa'] = $r;
$r = rg_state_get($db, 'ssh_key_min_bits_ecdsa');
if ($r === FALSE) {
$ret = rg_template('admin/settings/load_err.html',
$rg, TRUE /*xss*/);
break;
}
if (empty($r))
$r = 256;
$rg['ssh_key_min_bits_ecdsa'] = $r;
$r = rg_state_get($db, 'AuthorizedKeysCommand');
if ($r === FALSE) {
$ret = rg_template('admin/settings/load_err.html',
$rg, TRUE /*xss*/);
break;
}
if (empty($r))
$r = 0;
$rg['AuthorizedKeysCommand'] = $r;
$hints[]['HTML:hint'] = rg_template('admin/settings/ssh/hints.html',
$rg, TRUE /*xss*/);
$rg['HTML:hints'] = rg_template_table('hints/list', $hints, $rg);
$rg['HTML:errmsg'] = rg_template_errmsg($errmsg);
$rg['rg_form_token'] = rg_token_get($db, $rg,
'admin_settings_ssh');
$ret .= rg_template('admin/settings/ssh/main.html',
$rg, TRUE /*xss*/);
break;
}
rg_log_exit();
return $ret;
}
/*
* Deals with Admin -> Settings menu
*/
function rg_admin_settings($db, &$rg, $paras)
{
rg_log_enter('admin_settings');
$ret = '';
$_op = empty($paras) ? 'ssh' : array_shift($paras);
$rg['url_up'] = $rg['url'];
$rg['url'] .= '/' . $_op;
$rg['admin_settings_menu'][$_op] = 1;
$rg['HTML:menu_level2'] = rg_template('admin/settings/menu.html',
$rg, TRUE /*xss*/);
switch ($_op) {
case 'ssh':
$ret .= rg_admin_settings_ssh($db, $rg);
break;
default:
$ret .= rg_template('invalid_menu.html', $rg, TRUE /*xss*/);
break;
}
rg_log_exit();
return $ret;
}
?>