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 90eed0aa343f735f717238e3937439737290ecfd

Mostly TOTP stuff for ssh
Author: Catalin(ux) M. BOIE
Author date (UTC): 2015-08-28 04:51
Committer name: Catalin(ux) M. BOIE
Committer date (UTC): 2015-08-28 04:51
Parent(s): e9197291380929dd53f02f7373e8a339d6bd65a2
Signing key:
Tree: c985f7e5a66ffdad617be88fe8f500f1be75ba97
File Lines added Lines deleted
TODO 19 2
inc/admin.inc.php 2 2
inc/cache.inc.php 50 1
inc/feedback/suggestion.php 1 2
inc/plan.inc.php 1 2
inc/ssh.inc.php 149 27
inc/struct.inc.php 8 5
inc/totp.inc.php 191 2
inc/user.inc.php 14 33
inc/user/home-page.php 3 2
root/themes/default/hints/ssh/key.html 4 2
root/themes/default/index.html 1 1
root/themes/default/user/login_first.html 1 1
root/themes/default/user/repo/deny_create.html 1 1
root/themes/default/user/settings/totp/hints.html 5 1
scripts/cache.php 8 3
scripts/cachec.php 5 4
scripts/cron.php 7 0
File TODO changed (mode: 100644) (index 3fe8a47..1d7461a)
1 1 == Where I stopped last time == == Where I stopped last time ==
2 [ ] retest login by token
2 3 [ ] [ ]
3 4
4 5 == BEFORE NEXT RELEASE == == BEFORE NEXT RELEASE ==
6 [ ] Do I need to update last time used for login_tokens when accessing by ssh?
7 Pretty sure, yes.
8 [ ] history: add 2fa ssh validation.
9 [ ] ionut: Check this to not be send X-PHP-Originating-Script: 0:user.inc.php
10 [ ] Test if IPv4/IPv6 address is shown at login time.
11 [ ] When listing repos on user homepage, we should not add also the user.
12 Check rg_repo_list.
13 [ ] totp for ssh is not finished yet. remember, totp for ssh seems to be only
14 for write access. for rg, this may not be true.
15 Also for https cloning/pushing. But, for ssh, I cannot provide the
16 'password/token', right? Also, for https, I cannot provide the token,
17 only user/pass. Maybe appending token to the pass.
18 [ ] Can I remove the redirect after login (that means another request)?
19 [ ] In the report, send also stats about the events, especially the failed ones.
20 [ ] Document backup procedure.
21 [ ] "Forgot password": rate limit it!
5 22 [ ] Add history for totp enrollment. [ ] Add history for totp enrollment.
6 23 [ ] Add history for logins/logouts/API. [ ] Add history for logins/logouts/API.
7 [ ] Add, next to the user, the enroll position for rocketgit.com.
8 Something like 'user number 454'.
9 24 [ ] Add max_requests per hour for plans and enforce them. [ ] Add max_requests per hour for plans and enforce them.
10 25 [ ] When setting last used, we need to pass the timestamp to the event and [ ] When setting last used, we need to pass the timestamp to the event and
11 26 we msut not use 'time()' because event may happen at a latter time! we msut not use 'time()' because event may happen at a latter time!
 
18 33 Check http://www.postgresql.org/docs/9.4/interactive/sql-grant.html Check http://www.postgresql.org/docs/9.4/interactive/sql-grant.html
19 34 web user must not be able to create roles/tables/databases/etc. web user must not be able to create roles/tables/databases/etc.
20 35 Hm. What about the settings?! I must be able to do a select... Hm. What about the settings?! I must be able to do a select...
36 [ ] totp: warn user if s/he is low on scratch login codes.
37 [ ] totp:scratch: delete them after use?
21 38 [ ] totp: Build a Android application which will be able to authenticate also [ ] totp: Build a Android application which will be able to authenticate also
22 39 the server to the user. the server to the user.
23 40 [ ] totp: update 'utime' for login tokens [ ] totp: update 'utime' for login tokens
File inc/admin.inc.php changed (mode: 100644) (index a0316fc..2353a2e)
... ... function rg_admin_report1_suggestions($db, $from, $to)
281 281 rg_sql_free_result($res); rg_sql_free_result($res);
282 282
283 283 // Yesterday - not yet because we do not have itime // Yesterday - not yet because we do not have itime
284 /*
284 $y_start = gmmktime(0, 0, 0, gmdate('m'), gmdate('d') - 1, gmdate('Y'));
285 $y_end = gmmktime(0, 0, 0, gmdate('m'), gmdate('d'), gmdate('Y')) - 1;
285 286 $sql = "SELECT uid, suggestion FROM suggestions" $sql = "SELECT uid, suggestion FROM suggestions"
286 287 . " WHERE itime >= $y_start" . " WHERE itime >= $y_start"
287 288 . " AND itime <= $y_end"; . " AND itime <= $y_end";
 
... ... function rg_admin_report1_suggestions($db, $from, $to)
302 303 . " (" . $count . "):\n" . $list; . " (" . $count . "):\n" . $list;
303 304 } }
304 305 rg_sql_free_result($res); rg_sql_free_result($res);
305 */
306 306
307 307 return $ret; return $ret;
308 308 } }
File inc/cache.inc.php changed (mode: 100644) (index 5702ab5..2e5a2c5)
... ... function rg_cache_core_adump($ns_var)
274 274 if (!isset($tree[$var])) if (!isset($tree[$var]))
275 275 return FALSE; return FALSE;
276 276
277 return implode(",", $tree[$var]);
277 return rg_array2string($tree[$var]);
278 278 } }
279 279
280 280
 
... ... function rg_cache_merge($ns_var, $list, $flags)
547 547 return $ret; return $ret;
548 548 } }
549 549
550 /*
551 * Push an array in a queue
552 */
553 function rg_cache_apush($ns_var, $value, $flags)
554 {
555 global $rg_cache_socket;
556 global $rg_cache_timeout;
557 global $rg_cache_enable;
558 global $rg_cache_debug;
559
560 rg_prof_start("cache_apush");
561 if ($rg_cache_debug)
562 rg_log_ml_enter("cache_apush: flags=$flags"
563 . " $ns_var = " . print_r($value, TRUE));
564
565 $ret = FALSE;
566 while (1) {
567 rg_cache_core_apush($ns_var, $value);
568
569 if ($rg_cache_enable === FALSE)
570 break;
571
572 $f = '';
573 if ($flags & RG_SOCKET_NO_WAIT)
574 $f .= 'W';
575
576 $c = rg_socket($rg_cache_socket, "APUSH F=$f " . $ns_var . "="
577 . rg_cache_prepare($value) . "\n", $rg_cache_timeout, 3, $flags);
578 if ($c === FALSE)
579 break;
580
581 if ($flags & RG_SOCKET_NO_WAIT) {
582 $ret = TRUE;
583 break;
584 }
585
586 if (strncmp($c, "OK", 2) != 0)
587 break;
588
589 $ret = TRUE;
590 break;
591 }
592
593 if ($rg_cache_debug)
594 rg_log_exit();
595 rg_prof_end("cache_apush");
596 return $ret;
597 }
598
550 599 ?> ?>
File inc/feedback/suggestion.php changed (mode: 100644) (index d8613c9..97a133e)
... ... while (1) {
29 29 break; break;
30 30 } }
31 31
32 $r = rg_user_suggestion($db, $rg['login_ui']['uid'],
33 $rg['login_ui']['email'], $suggestion);
32 $r = rg_user_suggestion($db, $rg['login_ui']['uid'], $suggestion);
34 33 if ($r === FALSE) { if ($r === FALSE) {
35 34 $errmsg[] = "could not add suggestion (" . rg_user_error() . ")!"; $errmsg[] = "could not add suggestion (" . rg_user_error() . ")!";
36 35 break; break;
File inc/plan.inc.php changed (mode: 100644) (index 25508cb..b0c04a1)
... ... function rg_plan_remove($db, $list)
110 110 $sql = "DELETE FROM plans WHERE id IN (" . $sql_list . ")"; $sql = "DELETE FROM plans WHERE id IN (" . $sql_list . ")";
111 111 $res = rg_sql_query($db, $sql); $res = rg_sql_query($db, $sql);
112 112 if ($res === FALSE) { if ($res === FALSE) {
113 rg_plan_set_error("cannot remove plan $id"
114 . " (" . rg_sql_error() . ")");
113 rg_plan_set_error('cannot remove plans');
115 114 break; break;
116 115 } }
117 116 rg_sql_free_result($res); rg_sql_free_result($res);
File inc/ssh.inc.php changed (mode: 100644) (index 40e6e5d..9a4be66)
... ... function rg_ssh_totp($db, $uid, $paras)
118 118 break; break;
119 119 } }
120 120
121 $confirm = array_shift($paras);
121 $token = array_shift($paras);
122 $token = sprintf("%06u", $token);
122 123
123 $lt = rg_totp_list($db, $uid);
124 if ($lt['ok'] != 1) {
124 $v = rg_totp_verify_all($db, $uid, $token);
125 if ($v['ok'] != 1) {
125 126 echo "An internal error occured; please try again later.\n"; echo "An internal error occured; please try again later.\n";
126 127 break; break;
127 128 } }
129 if ($v['id'] == 0) {
130 echo "Invalid confirmation token.\n";
131 break;
132 }
133 echo "Success!\n";
134 break;
135
136 case 'val':
137 $token = array_shift($paras);
138 $token = sprintf("%06u", $token);
139 $days = 0;
140 $hours = 0;
141 $minutes = 0;
142 if (empty($paras)) {
143 $hours = 24;
144 } else {
145 $s_expire = array_shift($paras);
146 $val = intval($s_expire);
147 if (stristr($s_expire, 'd'))
148 $days = $val;
149 else if (stristr($s_expire, 'h'))
150 $hours = $val;
151 else if (stristr($s_expire, 'm'))
152 $minutes = $val;
153 }
154 //rg_log("token=$token days=$days hours=$hours minutes=$minutes");
155
156 $v = rg_totp_verify_all($db, $uid, $token);
157 if ($v['ok'] != 1) {
158 echo "An internal error occured; please try again later.\n";
159 break;
160 }
161 if ($v['id'] == 0) {
162 echo "Invalid token.\n";
163 break;
164 }
165
166 $expire_ts = gmmktime(gmdate('H') + $hours,
167 gmdate('i') + $minutes, gmdate('s'), gmdate('m'),
168 gmdate('d') + $days, gmdate('Y'));
169 rg_log("expire_ts=$expire_ts");
170 $r = rg_totp_add_ip($db, $uid, $v['id'], $ip, $expire_ts);
171 if ($r === FALSE) {
172 echo "An internal error occured; please try again later.\n";
173 break;
174 }
175
176 echo "Success! IP $ip added and is valid till "
177 . gmdate("Y-m-d H:i:s", $expire_ts) . " UTC.\n";
178 break;
179
180 case 'list-val':
181 $r = rg_totp_list_ip($db, $uid);
182 if ($r['ok'] != 1) {
183 echo "An internal error occured; please try again later.\n";
184 break;
185 }
186
187 // we provide the list only from a validated ip
188 $found = FALSE;
189 foreach ($r['list'] as $t) {
190 if (strcmp($t['ip'], $ip) == 0) {
191 $found = TRUE;
192 break;
193 }
194 }
195
196 if (!$found || empty($r['list'])) {
197 echo "No validated IPs are pesent.\n";
198 break;
199 }
200
201 echo 'Insert date (UTC) Expire date (UTC) IP' . "\n";
202 foreach ($r['list'] as $t) {
203 echo gmdate('Y-m-d H:i:s', $t['itime'])
204 . ' ' . gmdate('Y-m-d H:i:s', $t['expire'])
205 . ' ' . $t['ip']
206 . "\n";
207 }
208 break;
209
210 case 'unenroll':
211 $token = array_shift($paras);
212 $token = sprintf("%06u", $token);
213
214 $v = rg_totp_verify_all($db, $uid, $token);
215 if ($v['ok'] != 1) {
216 echo "An internal error occured; please try again later.\n";
217 break;
218 }
219 if ($v['id'] == 0) {
220 echo "Invalid token.\n";
221 break;
222 }
223
224 $a = array($v['id'] => '');
225 $r = rg_totp_remove($db, $uid, $a);
226 if ($r !== TRUE) {
227 echo "Error: " . rg_totp_error() . "\n";
228 break;
229 }
230
231 echo "Success!\n";
232 break;
233
234 case 'inval':
235 if (empty($paras)) {
236 echo "Please specify the IP address.\n";
237 break;
238 }
128 239
129 $done = FALSE;
130 $ierror = FALSE;
131 foreach ($lt['list'] as $_id => $t) {
132 $_r = rg_totp_verify($t['secret'], $confirm);
133 if ($_r === TRUE) {
134 if (strcmp($t['conf'], 't') != 0) {
135 $x = rg_totp_conf($db, $uid, $t['id']);
136 if ($x !== TRUE) {
137 $ierror = TRUE;
138 break;
139 }
140 }
240 $del_ip = array_shift($paras);
141 241
142 $done = TRUE;
242 $r = rg_totp_list_ip($db, $uid);
243 if ($r['ok'] != 1) {
244 echo "An internal error occured; please try again later.\n";
245 break;
246 }
247
248 // we allow the deletion only from a validated ip
249 $found = FALSE;
250 foreach ($r['list'] as $t) {
251 if (strcmp($t['ip'], $ip) == 0) {
252 $found = TRUE;
143 253 break; break;
144 254 } }
145 255 } }
256 if (!$found) {
257 echo "You are not allowed to delete the IPs."
258 . " Try 'val' command first.\n";
259 break;
260 }
146 261
147 if ($ierror)
262 $r = rg_totp_del_ip($db, $uid, $del_ip);
263 if ($r !== TRUE) {
264 echo "Error: " . rg_totp_error() . "!\n";
148 265 break; break;
266 }
149 267
150 if ($done === FALSE)
151 echo "Invalid confirmation token; try to re-enroll\n";
152 else
153 echo "Success!\n";
268 echo "Success!\n";
154 269 break; break;
155 270
156 case 'val': break;
157 271 default: default:
158 272 echo "Posible TOTP commands:\n"; echo "Posible TOTP commands:\n";
159 echo " enroll\n";
160 echo " val\n";
161 echo " inval - Invalidate IP address\n";
273 echo " enroll [token] - adds a new device in the system\n";
274 echo " val [X(m|h|d)] - adds your IP to the allow list for X time\n";
275 echo " default is 24 hours;\n";
276 echo " you can specify m for minutes, h for hours and d for days\n";
277 echo " list-val - list the already validated IPs\n";
278 echo " inval ip|all - Invalidate IP address(es)\n";
279 echo " unenroll token - remove a device from TOTP system\n";
162 280 break; break;
163 281 } }
164 282
 
... ... function rg_ssh_dispatch($db, $uid, $cmd)
178 296 case 'repos': rg_ssh_repos($db, $uid); break; case 'repos': rg_ssh_repos($db, $uid); break;
179 297 case 'repo': rg_ssh_repo($db, $uid, $paras); break; case 'repo': rg_ssh_repo($db, $uid, $paras); break;
180 298 case 'totp': rg_ssh_totp($db, $uid, $paras); break; case 'totp': rg_ssh_totp($db, $uid, $paras); break;
181 case '':
182 echo "Available commmands: status, repos, repo, totp.\n";
299 default:
300 echo "Available commmands:\n"
301 . " status - show some status about the user\n"
302 . " repos - list repos and information about them\n"
303 . " repo - list info about a repo\n"
304 . " totp - two-factor authentication commands\n";
183 305 break; break;
184 306 } }
185 307
File inc/struct.inc.php changed (mode: 100644) (index 2541bc7..b3b984c)
... ... $rg_sql_struct[32]['other'] = array(
414 414 "repo_license" => "ALTER TABLE repos ADD license TEXT NOT NULL DEFAULT ''" "repo_license" => "ALTER TABLE repos ADD license TEXT NOT NULL DEFAULT ''"
415 415 ); );
416 416
417 /* TODO
418 417 $rg_sql_struct[33] = array(); $rg_sql_struct[33] = array();
419 418 $rg_sql_struct[33]['tables'] = array(); $rg_sql_struct[33]['tables'] = array();
420 419 $rg_sql_struct[33]['other'] = array( $rg_sql_struct[33]['other'] = array(
 
... ... $rg_sql_struct[33]['other'] = array(
431 430 . ", conf BOOLEAN NOT NULL DEFAULT 't')", . ", conf BOOLEAN NOT NULL DEFAULT 't')",
432 431 "login_tokens_i_uid" => "login_tokens_i_uid" =>
433 432 "CREATE INDEX login_tokens_i_uid ON login_tokens(uid)", "CREATE INDEX login_tokens_i_uid ON login_tokens(uid)",
433 'login_tokens_ip' => "CREATE TABLE login_tokens_ip ("
434 . "uid INT NOT NULL DEFAULT 0"
435 . ", ip TEXT NOT NULL DEFAULT ''"
436 . ", itime INT NOT NULL DEFAULT 0"
437 . ", expire INT NOT NULL DEFAULT 0"
438 . ", token_id INT NOT NULL DEFAULT 0)",
439 "login_tokens_ip_i_uid" =>
440 "CREATE INDEX login_tokens_ip_i_uid ON login_tokens_ip(uid)"
434 441 ); );
435 442
436 TODO: do not fill email in suggestions CODE - we have the uid!
437 TODO: change report1 to activate yesterday suggestions!
438 */
439
440 443 // This must be the last line // This must be the last line
441 444 $rg_sql_schema_ver = count($rg_sql_struct); $rg_sql_schema_ver = count($rg_sql_struct);
442 445
File inc/totp.inc.php changed (mode: 100644) (index c9b0574..b3006ab)
... ... function rg_totp_set_last_use($db, $uid, $id, $ts)
237 237 return $ret; return $ret;
238 238 } }
239 239
240 /*
241 * Validates a token
242 * Also, it marks the tokens as 'confirmed' if needed
243 */
244 function rg_totp_verify_all($db, $uid, $token)
245 {
246 rg_prof_start('totp_verify_all');
247 rg_log_enter('totp_verify_all token=' . $token);
248
249 $ret = array();
250 $ret['ok'] = 0;
251 while (1) {
252 if (strlen($token) < 6)
253 break;
254
255 $lt = rg_totp_list($db, $uid);
256 if ($lt['ok'] != 1)
257 break;
258
259 $ret['ok'] = 1;
260 $ret['enrolled'] = 0;
261 $ret['id'] = 0;
262 $ret['conf_error'] = 0;
263 foreach ($lt['list'] as $_id => $t) {
264 $ret['enrolled'] = 1;
265
266 $_r = rg_totp_verify($t['secret'], $token);
267 if ($_r !== TRUE)
268 continue;
269
270 $ret['id'] = $t['id'];
271 if (strcmp($t['conf'], 't') != 0) {
272 $x = rg_totp_conf($db, $uid, $t['id']);
273 if ($x !== TRUE) {
274 $ret['conf_error'] = 1;
275 break;
276 }
277 }
278 break;
279 }
280
281 break;
282 }
283
284 rg_log_exit();
285 rg_prof_end('totp_verify_all');
286 return $ret;
287 }
288
240 289 /* /*
241 290 * Add a new secret login token to database * Add a new secret login token to database
242 291 */ */
 
... ... function rg_totp_enroll($db, $uid, $name, $secret, $ip, $conf)
278 327 return $ret; return $ret;
279 328 } }
280 329
330 /*
331 * Add an ip to login_tokens_ip table
332 */
333 function rg_totp_add_ip($db, $uid, $token_id, $ip, $expire_ts)
334 {
335 rg_prof_start('totp_add_ip');
336 rg_log_enter('totp_add_ip ip=' . $ip . ' expire_ts=' . $expire_ts);
337
338 $ret = FALSE;
339 while (1) {
340 $params = array('uid' => $uid,
341 'token_id' => $token_id,
342 'ip' => $ip,
343 'itime' => time(),
344 'expire' => $expire_ts);
345 $sql = 'INSERT INTO login_tokens_ip'
346 . ' (uid, ip, itime, expire, token_id)'
347 . ' VALUES (@@uid@@, @@ip@@, @@itime@@, @@expire@@'
348 . ', @@token_id@@)';
349 $res = rg_sql_query_params($db, $sql, $params);
350 if ($res === FALSE) {
351 rg_totp_set_error('cannot insert login token ip; try again later');
352 break;
353 }
354 rg_sql_free_result($res);
355
356 $key = 'user' . '::' . $uid . '::' . 'login_tokens_ip';
357 rg_cache_apush($key, $params, RG_SOCKET_NO_WAIT);
358
359 $ret = TRUE;
360 break;
361 }
362
363 rg_log_exit();
364 rg_prof_end('totp_add_ip');
365 return $ret;
366 }
367
368 /*
369 * Del an ip from login_tokens_ip table
370 */
371 function rg_totp_del_ip($db, $uid, $ip)
372 {
373 rg_prof_start('totp_del_ip');
374 rg_log_enter('totp_del_ip ip=' . $ip);
375
376 $ret = FALSE;
377 while (1) {
378 $params = array('uid' => $uid, 'ip' => $ip);
379 if (strcasecmp($ip, 'all') == 0) {
380 $sql = 'DELETE FROM login_tokens_ip'
381 . ' WHERE uid = @@uid@@';
382 } else {
383 $sql = 'DELETE FROM login_tokens_ip'
384 . ' WHERE uid = @@uid@@'
385 . ' AND ip = @@ip@@';
386 }
387 $res = rg_sql_query_params($db, $sql, $params);
388 if ($res === FALSE) {
389 rg_totp_set_error('cannot delete ip; try again later');
390 break;
391 }
392 $aff = rg_sql_affected_rows($res);
393 rg_sql_free_result($res);
394
395 if ($aff == 0) {
396 rg_totp_set_error('ip not found');
397 break;
398 }
399
400 $key = 'user' . '::' . $uid . '::' . 'login_tokens_ip';
401 rg_cache_unset($key, RG_SOCKET_NO_WAIT);
402
403 $ret = TRUE;
404 break;
405 }
406
407 rg_log_exit();
408 rg_prof_end('totp_del_ip');
409 return $ret;
410 }
411
281 412 /* /*
282 413 * Confirm a SSH enrollment process * Confirm a SSH enrollment process
283 414 */ */
 
... ... function rg_totp_remove($db, $uid, $list)
386 517
387 518 $params = array('uid' => $uid); $params = array('uid' => $uid);
388 519 $sql_list = implode(', ', $my_list); $sql_list = implode(', ', $my_list);
520
521 $sql = 'DELETE FROM login_tokens_ip'
522 . ' WHERE uid = @@uid@@'
523 . ' AND token_id IN (' . $sql_list . ')';
524 $res = rg_sql_query_params($db, $sql, $params);
525 if ($res === FALSE) {
526 rg_totp_set_error('cannot remove login tokens ips');
527 break;
528 }
529 rg_sql_free_result($res);
530
389 531 $sql = 'DELETE FROM login_tokens' $sql = 'DELETE FROM login_tokens'
390 532 . ' WHERE uid = @@uid@@' . ' WHERE uid = @@uid@@'
391 533 . ' AND id IN (' . $sql_list . ')'; . ' AND id IN (' . $sql_list . ')';
392 534 $res = rg_sql_query_params($db, $sql, $params); $res = rg_sql_query_params($db, $sql, $params);
393 535 if ($res === FALSE) { if ($res === FALSE) {
394 rg_totp_set_error('cannot remove login token ' . $id
395 . ' (' . rg_sql_error() . ')');
536 rg_totp_set_error('cannot remove login token');
396 537 break; break;
397 538 } }
398 539 rg_sql_free_result($res); rg_sql_free_result($res);
 
... ... function rg_totp_remove($db, $uid, $list)
412 553 return $ret; return $ret;
413 554 } }
414 555
556 /*
557 * Returns a list of login tokens IPs from database
558 */
559 function rg_totp_list_ip($db, $uid)
560 {
561 rg_prof_start('totp_list_ip');
562 rg_log_enter('totp_list_ip');
563
564 while (1) {
565 $key = 'user' . '::' . $uid . '::' . 'login_tokens_ip';
566 $list = rg_cache_get($key);
567 if ($list !== FALSE) {
568 $ret['list'] = $list;
569 $ret['ok'] = 1;
570 break;
571 }
572
573 $ret = array();
574 $ret['ok'] = 0;
575
576 $params = array('uid' => $uid, 'now' => time());
577 $sql = 'SELECT * FROM login_tokens_ip'
578 . ' WHERE uid = @@uid@@'
579 . ' AND expire >= @@now@@'
580 . ' ORDER BY itime';
581 $res = rg_sql_query_params($db, $sql, $params);
582 if ($res === FALSE) {
583 rg_totp_set_error('cannot load login tokens ip');
584 break;
585 }
586
587 $ret['list'] = array();
588 while (($row = rg_sql_fetch_array($res))) {
589 unset($row['uid']);
590 $ret['list'][] = $row;
591 }
592 rg_sql_free_result($res);
593
594 rg_cache_set($key, $ret['list'], RG_SOCKET_NO_WAIT);
595 $ret['ok'] = 1;
596 break;
597 }
598
599 rg_log_exit();
600 rg_prof_end('totp_list_ip');
601 return $ret;
602 }
603
415 604 /* /*
416 605 * High-level function for listing tokens * High-level function for listing tokens
417 606 */ */
File inc/user.inc.php changed (mode: 100644) (index 975e84f..0874f6b)
... ... function rg_user_login_by_user_pass($db, $user, $pass, $login_token, $lock_ip,
901 901 break; break;
902 902 } }
903 903
904 $lt = rg_totp_list($db, $ui0['uid']);
905 if ($lt['ok'] != 1) {
904 $vi = rg_totp_verify_all($db, $ui0['uid'], $login_token);
905 if ($vi['ok'] != 1) {
906 906 rg_user_set_error('login token error: ' . rg_totp_error()); rg_user_set_error('login token error: ' . rg_totp_error());
907 907 break; break;
908 908 } }
909
910 $used_login_token_id = 0;
911 if (!empty($lt['list'])) {
912 $lt_good = FALSE;
913 foreach ($lt['list'] as $_id => $t) {
914 $_r = rg_totp_verify($t['secret'], $login_token);
915 if ($_r === TRUE) {
916 if (strcmp($t['conf'], 't') != 0)
917 rg_totp_conf($db, $ui0['uid'], $t['id']);
918
919 $used_login_token_id = $t['id'];
920 $lt_good = TRUE;
921 break;
922 }
923
924 rg_log("DEBUG: token " . $t['id'] . " does not verify");
925 }
926
927 if ($lt_good !== TRUE) {
928 rg_user_set_error('invalid user, pass or login_token');
929 rg_log('invalid token');
930 break;
931 }
909 if (($vi['enrolled'] == 1) && ($vi['id'] == 0)) {
910 rg_user_set_error('invalid user, pass or login_token');
911 rg_log('invalid token');
912 break;
932 913 } }
933 914
934 915 $event = array( $event = array(
935 916 'category' => 2001, 'category' => 2001,
936 917 'prio' => 100, 'prio' => 100,
937 918 'uid' => $ui0['uid'], 'uid' => $ui0['uid'],
938 'used_login_token_id' => $used_login_token_id,
919 'used_login_token_id' => $vi['id'],
939 920 'ts' => time()); 'ts' => time());
940 921 $r = rg_event_add($db, $event); $r = rg_event_add($db, $event);
941 922 if ($r !== TRUE) { if ($r !== TRUE) {
 
... ... function rg_user_confirm($db, $token)
1418 1399 /* /*
1419 1400 * Add a suggestion to database * Add a suggestion to database
1420 1401 */ */
1421 function rg_user_suggestion($db, $uid, $email, $suggestion)
1402 function rg_user_suggestion($db, $uid, $suggestion)
1422 1403 { {
1423 1404 rg_prof_start("user_suggestion"); rg_prof_start("user_suggestion");
1424 rg_log_enter("user_suggestion: uid=$uid email=$email suggestion=$suggestion");
1405 rg_log_enter("user_suggestion: uid=$uid suggestion=$suggestion");
1425 1406
1426 1407 $ret = FALSE; $ret = FALSE;
1427 1408 while (1) { while (1) {
1428 $params = array("uid" => $uid,
1429 "email" => $email,
1430 "sug" => $suggestion);
1431 $sql = "INSERT INTO suggestions (uid, email, suggestion)"
1432 . " VALUES (@@uid@@, @@email@@, @@sug@@)";
1409 $params = array('uid' => $uid,
1410 'itime' => time(),
1411 'sug' => $suggestion);
1412 $sql = "INSERT INTO suggestions (uid, itime, suggestion)"
1413 . " VALUES (@@uid@@, @@itime@@, @@sug@@)";
1433 1414 $res = rg_sql_query_params($db, $sql, $params); $res = rg_sql_query_params($db, $sql, $params);
1434 1415 if ($res === FALSE) { if ($res === FALSE) {
1435 1416 rg_user_set_error("cannot add suggestion (" . rg_sql_error() . ")"); rg_user_set_error("cannot add suggestion (" . rg_sql_error() . ")");
File inc/user/home-page.php changed (mode: 100644) (index cdbe2bb..c15e96b)
... ... rg_log("FILE: /inc/user/home-page");
3 3
4 4 $_home = ''; $_home = '';
5 5
6 $_home .= '<div class="main_title">Home page</div>';
7
8 6 $page_ui = rg_user_info($db, 0, $user, ""); $page_ui = rg_user_info($db, 0, $user, "");
9 7 if ($page_ui['exists'] == 0) { if ($page_ui['exists'] == 0) {
10 8 $_home .= rg_template("user/invalid.html", $rg, TRUE /* xss */); $_home .= rg_template("user/invalid.html", $rg, TRUE /* xss */);
11 9 return; return;
12 10 } }
13 11
12 $_home .= '<div class="main_title">Home page of user '
13 . $page_ui['username'] . ' (#' . $page_ui['uid'] . ')</div>';
14
14 15 // list of repositories // list of repositories
15 16 $_home .= rg_repo_list($db, $rg, "", $page_ui['uid']); $_home .= rg_repo_list($db, $rg, "", $page_ui['uid']);
16 17 ?> ?>
File root/themes/default/hints/ssh/key.html changed (mode: 100644) (index a488684..fb1a7dc)
1 1 How to create a SSH key for RocketGit:<br /> How to create a SSH key for RocketGit:<br />
2 2 <div class="xcode"> <div class="xcode">
3 ssh-keygen -C "Key for RocketGit" -f ~/.ssh/rocketgit1<br />
3 ssh-keygen -t rsa -b 4096 -o -C "Key for RocketGit" -f ~/.ssh/rocketgit1<br />
4 or<br />
5 ssh-keygen -t ed25519 -C "Key for RocketGit" -f ~/.ssh/rocketgit1<br />
4 6 cat ~/.ssh/rocketgit1.pub<br /> cat ~/.ssh/rocketgit1.pub<br />
5 7 </div> </div>
6 8 Now, copy in clipboard starting with "ssh-...", including the comment Now, copy in clipboard starting with "ssh-...", including the comment
7 and paste it in the form above.<br />
9 and paste it in the form above. Do not worry about spaces or wrapping.<br />
8 10 <br /> <br />
9 11
10 12 To force the use of this key when you connect to the server,<br /> To force the use of this key when you connect to the server,<br />
File root/themes/default/index.html changed (mode: 100644) (index a348d65..472dbd5)
34 34 <a href="/op/logout?token=@@logout_token@@">Logout</a> <a href="/op/logout?token=@@logout_token@@">Logout</a>
35 35 }}{{ }}{{
36 36 <a href="/op/create_account">Create account</a> <a href="/op/create_account">Create account</a>
37 <a href="/op/login">Sign in</a>
37 <a href="/op/login">Login</a>
38 38 }} }}
39 39 </div> </div>
40 40 </div> </div>
File root/themes/default/user/login_first.html changed (mode: 100644) (index 80000cc..722e917)
1 1 <div class="mess error"> <div class="mess error">
2 Please sign in first.
2 Please login first.
3 3 </div> </div>
File root/themes/default/user/repo/deny_create.html changed (mode: 100644) (index 771e286..1e08a94)
1 1 <div class="mess error"> <div class="mess error">
2 You are not allowed to create an anonymous repo. Please sign in first.
2 You are not allowed to create an anonymous repo. Please login first.
3 3 </div> </div>
File root/themes/default/user/settings/totp/hints.html changed (mode: 100644) (index c0395a6..4cfcc51)
1 Login token feature implements
1 Login token feature implements two-factor authentication (2FA) using
2 2 <a href="https://en.wikipedia.org/wiki/Time-based_One-time_Password_Algorithm" target="_blank"> <a href="https://en.wikipedia.org/wiki/Time-based_One-time_Password_Algorithm" target="_blank">
3 3 TOTP (Time-based One-time Password Algorithm) TOTP (Time-based One-time Password Algorithm)
4 4 </a> and will add an extra protection to your login process.<br /> </a> and will add an extra protection to your login process.<br />
 
... ... How it works:<br />
12 12 <i>Authenticator</i> for Windows Phone). <i>Authenticator</i> for Windows Phone).
13 13 </li> </li>
14 14
15 <li>
16 Make sure that the device clock is synchronized automatically.
17 </li>
18
15 19 <li> <li>
16 20 Using the just installed application, scan the QR Code (if shown) Using the just installed application, scan the QR Code (if shown)
17 21 or the secret provided on screen. or the secret provided on screen.
File scripts/cache.php changed (mode: 100644) (index 66b6865..bd7e87d)
... ... function rg_handle_command($k, &$conn_table, $cmd)
49 49
50 50 $a = explode(" ", $cmd, 3); $a = explode(" ", $cmd, 3);
51 51 $buf = "ER Invalid command\n"; $buf = "ER Invalid command\n";
52 $no_wait = FALSE;
52 53 while (1) { while (1) {
53 54 // We must have at least 2 parameters: cmd and flags // We must have at least 2 parameters: cmd and flags
54 55 if (!isset($a[1])) if (!isset($a[1]))
 
... ... function rg_handle_command($k, &$conn_table, $cmd)
61 62 break; break;
62 63 } }
63 64 $flags = substr($flags, 2); $flags = substr($flags, 2);
64 $no_wait = FALSE;
65 65 if (strstr($flags, 'W')) if (strstr($flags, 'W'))
66 66 $no_wait = TRUE; $no_wait = TRUE;
67 67
 
... ... function rg_handle_command($k, &$conn_table, $cmd)
147 147 break; break;
148 148 $ns_var = trim($ns_var_value[0]); $ns_var = trim($ns_var_value[0]);
149 149 $value = trim($ns_var_value[1]); $value = trim($ns_var_value[1]);
150 rg_cache_core_apush("normal::" . $ns_var, $value);
151 $buf = "OK\n";
150 $value = unserialize(stripcslashes($value));
151 if ($value !== FALSE) {
152 rg_cache_core_apush("normal::" . $ns_var, $value);
153 $buf = "OK\n";
154 } else {
155 $buf = "ER cannot unserialize data\n";
156 }
152 157 break; break;
153 158 } }
154 159
File scripts/cachec.php changed (mode: 100644) (index 40d77f3..4a8d8d5)
... ... rg_prof_start("MAIN");
28 28 rg_log_set_file($rg_log_dir . "/cachec.log"); rg_log_set_file($rg_log_dir . "/cachec.log");
29 29 rg_log_set_sid("000000"); // to spread the logs rg_log_set_sid("000000"); // to spread the logs
30 30
31 rg_log("Start...");
32
33 31 $master = @socket_create(AF_UNIX, SOCK_STREAM, 0); $master = @socket_create(AF_UNIX, SOCK_STREAM, 0);
34 32 if ($master === FALSE) { if ($master === FALSE) {
35 33 rg_internal_error("Cannot create events socket!"); rg_internal_error("Cannot create events socket!");
 
... ... if ($in === FALSE) {
51 49 do { do {
52 50 echo "Command: "; echo "Command: ";
53 51 $r = fgets($in, 4096); $r = fgets($in, 4096);
52 $r = trim($r);
53 if (strlen($r) == 0)
54 break;
55
56 $r .= "\n";
54 57 $r = socket_send($master, $r, strlen($r), 0); $r = socket_send($master, $r, strlen($r), 0);
55 58 $r = socket_recv($master, $buf, 4096, 0); $r = socket_recv($master, $buf, 4096, 0);
56 59 echo $buf; echo $buf;
 
... ... do {
58 61
59 62 socket_close($master); socket_close($master);
60 63
61 rg_log("Exiting...");
62
63 64 rg_prof_end("MAIN"); rg_prof_end("MAIN");
64 65 rg_prof_log(); rg_prof_log();
65 66 ?> ?>
File scripts/cron.php changed (mode: 100644) (index 64cca7e..76587ef)
... ... if (gmdate("i") == "01") {
159 159 rg_sql_free_result($res); rg_sql_free_result($res);
160 160 } }
161 161
162 if (gmdate("Hi") == "0605") {
163 rg_log("Clean old login_tokens_ip entries...");
164 $sql = "DELETE FROM login_tokens_ip WHERE expire < $now";
165 $res = rg_sql_query($db, $sql);
166 rg_sql_free_result($res);
167 }
168
162 169 rg_log_cron(); rg_log_cron();
163 170
164 171 rg_sql_struct_slaves_update($db); rg_sql_struct_slaves_update($db);
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