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.
<root> / tests / ssh.php (20cf572d83a7490708ea9f91d7b21232f240017b) (5,829B) (mode 100644) [raw]
<?php
error_reporting(E_ALL | E_STRICT);
ini_set("track_errors", "On");

$INC = dirname(__FILE__) . "/../inc";
require_once(dirname(__FILE__) . "/config.php");
require_once($INC . "/init.inc.php");
require_once($INC . "/user.inc.php");
require_once("helpers.inc.php");
require_once("http.inc.php");

rg_log_set_file("ssh.log");

$rg_sql = "host=localhost user=rocketgit dbname=rocketgit connect_timeout=10";
$rg_no_db = TRUE;
require_once("common.php");

$_testns = 'ssh';
$rg_cache_enable = TRUE;
$rg_cache_debug = TRUE;
$rg_event_socket = "/var/lib/rocketgit/sockets/event.sock";

// This test makes sense only on my devel machine
if (php_uname("n") != "r1.embedromix.ro") {
	rg_log("OK!");
	exit(0);
}


rg_log("Creating a user...");
rg_test_create_user($db, $rg_ui);
rg_test_create_repo($db, $rg_ui, $repo);
$r = test_login($test_url, $rg_ui, $good_sid);
if ($r === FALSE) {
	rg_log("Cannot login!");
	exit(1);
}

$cmd = "ssh -i keys/" . $rg_ui['uid'] . " rocketgit@r1i";

$key = rg_test_upload_ssh_key($db, $rg_ui, $rg_ui['uid'], $good_sid);

rg_log('');
$list = array('', 'status', 'repos', 'repo', 'totp');
foreach ($list as $s) {
	rg_log('Connecting for [' . $s . ']');
	$r = shell_exec($cmd . ' ' . $s . ' 2>&1');
	if (!strstr($r, "Welcome to RocketGit")) {
		rg_log('r=' . $r);
		rg_log("Trying to get the help detected missing welcome!");
		exit(1);
	}
	if (strstr($r, 'Error: .')) {
		rg_log('r=' . $r);
		rg_log('Error is empty for \'' . $s . '\'! Not good!');
		exit(1);
	}
}

$list = array('remove-device', 'unenroll');
foreach ($list as $s) {
	rg_log('Connecting for [totp ' . $s . ']');
	$r = shell_exec($cmd . ' totp ' . $s . ' 2>&1');
	if (strstr($r, 'Error: .')) {
		rg_log('r=' . $r);
		rg_log('Error is empty for \'' . $s . '\'! Not good!');
		exit(1);
	}
}


rg_log('');
rg_log_enter('Testing wrong command');
$r = shell_exec($cmd . ' wrongcmd ' . ' 2>&1');
if (!strstr($r, "nknown command")) {
	rg_log('r=' . $r);
	rg_log("Wrong answer for a wrong command!");
	exit(1);
}
rg_log_exit();


rg_log('');
rg_log('Testing enroll procedure');
$r = shell_exec($cmd . ' totp enroll');
$t = explode('enter the following code: ', $r);
$t = explode('.', $t[1]);
$key = trim($t[0]);
rg_log("key=$key");

$tc = intval(time() / 30) - 1; // we try one in the past
$token = rg_totp_compute($key, $tc, 6);
$r = shell_exec($cmd . ' totp enroll ' . $token);
if (!strstr($r, 'Success!')) {
	rg_log('r=' . $r);
	rg_log('Cannot enroll!');
	exit(1);
}


rg_log('');
rg_log('Testing \'val\' command');
$tc = intval(time() / 30);
$token = rg_totp_compute($key, $tc, 6);
$r = shell_exec($cmd . ' totp val ' . $token . ' 2m');
if (!strstr($r, 'Success!')) {
	rg_log('r=' . $r);
	rg_log('Cannot validate ip!');
	exit(1);
}
$t = explode('valid till ', $r);
$t = explode(' (', $t[1]);
$exp = trim($t[0]);
rg_log('exp=' . $exp);

rg_log('');
rg_log('Reuse of the token must be forbidden (device)');
$r = shell_exec($cmd . ' totp val ' . $token . ' 2m');
if (!strstr($r, 'cannot reuse')) {
	rg_log('r=' . $r);
	rg_log('we get no error on token reuse!');
	exit(1);
}


rg_log('');
rg_log('Testing \'list-val\' command');
$r = shell_exec($cmd . ' totp list-val');
if (!strstr($r, $exp)) {
	rg_log('r=' . $r);
	rg_log('Invalid output for list-val!');
	exit(1);
}


rg_log('');
rg_log('Testing \'inval\' command - wrong ip');
$tc = intval(time() / 30) + 1; // we try one in the future
$token = rg_totp_compute($key, $tc, 6);
$r = shell_exec($cmd . ' totp inval 1.1.1.1');
if (!strstr($r, 'ip not found')) {
	rg_log('r=' . $r);
	rg_log('Cannot invalidate ip!');
	exit(1);
}


rg_log('');
rg_log('Testing \'inval\' command - all');
$tc = intval(time() / 30) + 1; // we try one in the future
$token = rg_totp_compute($key, $tc, 6);
$r = shell_exec($cmd . ' totp inval all');
if (!strstr($r, 'Success!')) {
	rg_log('r=' . $r);
	rg_log('Cannot invalidate all!');
	exit(1);
}


rg_log('');
rg_log('Testing \'remove-device\'');
$tc = intval(time() / 30) + 2;
$token = rg_totp_compute($key, $tc, 6);
$_cmd = $cmd . ' totp remove-device ' . $token;
rg_log('Sending cmd ' . $_cmd);
$r = shell_exec($_cmd);
if (!strstr($r, 'Success!')) {
	rg_log('r=' . $r);
	rg_log('Cannot remove device!');
	exit(1);
}


$sc = rg_test_sc_generate($db, $rg_ui, $good_sid);
$sql = "UPDATE scratch_codes SET sc = '0' || substring(sc from 1 for 7)"
	. " WHERE uid = " . $rg_ui['uid'];
$res = rg_sql_query($db, $sql);
rg_sql_free_result($res);
// we want to test with a short code, so, insert one and flush cache
$key = 'user::' . $rg_ui['uid'] . '::login_tokens::sc';
rg_cache_unset($key, 0);
foreach ($sc as &$t)
	$t = substr($t, 0, 7);


rg_log('');
rg_log('Testing \'unenroll\'');
$token = array_pop($sc);
$token = ltrim($token, '0');
$_cmd = $cmd . ' totp unenroll ' . $token;
rg_log('Sending cmd ' . $_cmd);
$r = shell_exec($_cmd);
if (!strstr($r, 'You are now unenrolled')) {
	rg_log('r=' . $r);
	rg_log('Cannot unenroll!');
	exit(1);
}

rg_log('');
rg_log('After enroll we should not be able to use the scratch codes');
$token = array_pop($sc);
$r = shell_exec($cmd . ' totp val ' . $token . ' 2m');
if (strstr($r, 'Success!')) {
	rg_log('r=' . $r);
	rg_log('Seems we are able to use scratch codes after unenroll!');
	exit(1);
}


$sc = rg_test_sc_generate($db, $rg_ui, $good_sid);


rg_log('');
rg_log('sc: testing \'val\' cmd...');
$token = array_pop($sc);
$_cmd = $cmd . ' totp val ' . $token . ' 2m';
rg_log('Sending cmd ' . $_cmd);
$r = shell_exec($_cmd);
if (!strstr($r, 'Success!')) {
	rg_log('r=' . $r);
	rg_log('Cannot validate ip!');
	exit(1);
}


rg_log('');
rg_log('Reuse of the scratch code must be forbidden (sc)');
$_cmd = $cmd . ' totp val ' . $token . ' 2m';
rg_log('Sending cmd ' . $_cmd);
$r = shell_exec($_cmd);
if (!strstr($r, 'invalid token')) {
	rg_log('r=' . $r);
	rg_log('we get no error on token reuse!');
	exit(1);
}


rg_log("OK!");
?>
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