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 e9197291380929dd53f02f7373e8a339d6bd65a2

Added TOTP feature and some other minor stuff
Author: Catalin(ux) M. BOIE
Author date (UTC): 2015-08-23 12:07
Committer name: Catalin(ux) M. BOIE
Committer date (UTC): 2015-08-24 05:21
Parent(s): 1ae7c17d523aec8e6a303264e2c35934c459fc9d
Signing key:
Tree: 6b707e8b29831a73c932d7cc182872bbc1685813
File Lines added Lines deleted
README 2 0
TODO 48 16
inc/admin.inc.php 3 4
inc/admin/admin.php 5 5
inc/admin/plans/plans.php 4 3
inc/admin/repos/repos.php 3 3
inc/admin/users/users.php 4 3
inc/bug.inc.php 1 1
inc/dispatch/dispatch.php 1 1
inc/events.inc.php 2 4
inc/fixes.inc.php 1 1
inc/git.inc.php 25 21
inc/keys.inc.php 15 8
inc/login/login.php 4 2
inc/mr.inc.php 1 1
inc/plan.inc.php 2 2
inc/repo/repo.php 5 4
inc/sess.inc.php 8 8
inc/ssh.inc.php 89 8
inc/struct.inc.php 14 4
inc/totp.inc.php 562 0
inc/user.inc.php 141 64
inc/user/home-page.php 3 1
inc/user/keys/keys.php 47 47
inc/user/repo-page.php 2 1
inc/user/repo/bug/main.php 2 0
inc/user/settings.php 10 5
inc/util.inc.php 81 26
root/index.php 1 3
root/themes/default/access_denied.html 1 1
root/themes/default/admin/db_error.html 1 1
root/themes/default/admin/invites/invites.html 1 1
root/themes/default/admin/invites/sent.html 1 1
root/themes/default/admin/menu.html 6 4
root/themes/default/admin/plans/add_ok.html 1 1
root/themes/default/admin/plans/list/nodata.html 1 1
root/themes/default/admin/plans/menu.html 2 2
root/themes/default/admin/repos/menu.html 2 2
root/themes/default/admin/users/bad_admin.html 1 1
root/themes/default/admin/users/bad_remove.html 1 1
root/themes/default/admin/users/bad_suspend.html 1 1
root/themes/default/admin/users/bad_unadmin.html 1 1
root/themes/default/admin/users/bad_unsuspend.html 1 1
root/themes/default/admin/users/menu.html 2 2
root/themes/default/donate.html 1 1
root/themes/default/download-vm.html 1 1
root/themes/default/download.html 1 1
root/themes/default/features.html 1 1
root/themes/default/hints/repo/bug/add.html 2 1
root/themes/default/index.html 6 10
root/themes/default/internal_err.html 1 1
root/themes/default/mail/user/key/new.body.txt 7 2
root/themes/default/main.css 52 44
root/themes/default/main.html 0 1
root/themes/default/ok.html 1 1
root/themes/default/pricing.html 6 4
root/themes/default/repo/add_edit.html 1 1
root/themes/default/repo/bug/bug_add_edit.html 1 1
root/themes/default/repo/bug/deleted.html 1 1
root/themes/default/repo/bug/deny_close.html 1 1
root/themes/default/repo/bug/deny_delete.html 1 1
root/themes/default/repo/bug/deny_edit.html 1 1
root/themes/default/repo/bug/deny_reopen.html 1 1
root/themes/default/repo/bug/list/nodata.html 1 1
root/themes/default/repo/bug/main.html 4 4
root/themes/default/repo/bug/not_found.html 1 1
root/themes/default/repo/create_ok.html 1 1
root/themes/default/repo/edit_ok.html 1 1
root/themes/default/repo/fstat/nodata.html 1 1
root/themes/default/repo/history/nodata.html 1 1
root/themes/default/repo/invalid.html 1 1
root/themes/default/repo/list/header.html 0 1
root/themes/default/repo/list/nodata.html 1 1
root/themes/default/repo/log/nodata.html 1 1
root/themes/default/repo/main.html 1 1
root/themes/default/repo/menu.html 5 4
root/themes/default/repo/mr/list/nodata.html 1 1
root/themes/default/repo/no_git_dir.html 1 1
root/themes/default/repo/not_init.html 1 1
root/themes/default/repo/source.html 3 3
root/themes/default/repo/tree/nodata.html 1 1
root/themes/default/suggestion_sent.html 1 1
root/themes/default/tos.html 4 4
root/themes/default/user/add_edit.html 2 0
root/themes/default/user/bad_token.html 1 1
root/themes/default/user/create_na.html 1 1
root/themes/default/user/create_ok.html 1 1
root/themes/default/user/edit_ok.html 1 1
root/themes/default/user/email_conf.html 1 1
root/themes/default/user/invalid.html 1 1
root/themes/default/user/keys/add.html 1 1
root/themes/default/user/keys/add_ok.html 3 0
root/themes/default/user/keys/list/header.html 1 1
root/themes/default/user/keys/list/line.html 1 1
root/themes/default/user/keys/list/nodata.html 1 1
root/themes/default/user/keys/main.html 1 1
root/themes/default/user/keys/remove_ok.html 1 1
root/themes/default/user/login.html 5 0
root/themes/default/user/login_first.html 3 0
root/themes/default/user/logout.html 1 1
root/themes/default/user/logout_err.html 1 1
root/themes/default/user/pass_changed.html 1 1
root/themes/default/user/repo/delete/deny.html 1 1
root/themes/default/user/repo/delete/done.html 1 1
root/themes/default/user/repo/delete/no.html 1 1
root/themes/default/user/repo/deny.html 1 1
root/themes/default/user/repo/deny_create.html 2 2
root/themes/default/user/repo/deny_edit.html 1 1
root/themes/default/user/repo/menu.html 6 6
root/themes/default/user/repo/rights/delete_ok.html 1 1
root/themes/default/user/repo/rights/deny.html 1 1
root/themes/default/user/repo/rights/grant_ok.html 1 1
root/themes/default/user/settings/menu.html 6 3
root/themes/default/user/settings/totp/delete_ok.html 3 0
root/themes/default/user/settings/totp/enroll_ok.html 4 0
root/themes/default/user/settings/totp/hints.html 33 0
root/themes/default/user/settings/totp/list/footer.html 5 0
root/themes/default/user/settings/totp/list/header.html 18 0
root/themes/default/user/settings/totp/list/line.html 9 0
root/themes/default/user/settings/totp/list/nodata.html 5 0
root/themes/default/user/settings/totp/list_err.html 3 0
root/themes/default/user/settings/totp/main.html 39 0
root/themes/default/user/settings/totp/ver_error.html 2 0
root/themes/default/warning.html 1 1
scripts/events.php 1 1
scripts/remote.php 5 5
File README changed (mode: 100644) (index 34183fe..4fe4e0b)
100 100 . Point your browser to the newly created server and you will be asked to . Point your browser to the newly created server and you will be asked to
101 101 create the admin account. create the admin account.
102 102
103 . You may want to install qrencode to be able to export two factor
104 authentication keys as QR pictures.
103 105
104 106 == Thanks == == Thanks ==
105 107 . Special thanks to my family that supports me in this project. . Special thanks to my family that supports me in this project.
File TODO changed (mode: 100644) (index aea65d9..3fe8a47)
1 1 == Where I stopped last time == == Where I stopped last time ==
2 2 [ ] [ ]
3 3
4 == CSRF logic ==
5 - Generate a token for a specific form (call rg_token_get with an $op)
6 Why I do not use a key per user not a master key?! Maybe because I have
7 to store it in db. Why not? Because of caching of the pages...
8 - For a form, we create a token based on sess, ua, tag and a random string.
9 We store it in sess::SID::token::tag to be reused next time we
10 load that specific form.
11 Also, we store it in sess::SID::used_tokens::TOKEN=0 to optimize
12 for when we receive the POST request (to not lookup in db).
13 - When checking the validity, we look it up in sess::SID::used_tokens and
14 compare with 0. If true, we know that token is valid and not used.
15
16
17 4 == BEFORE NEXT RELEASE == == BEFORE NEXT RELEASE ==
5 [ ] Add history for totp enrollment.
6 [ ] 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 [ ] Add max_requests per hour for plans and enforce them.
10 [ ] When setting last used, we need to pass the timestamp to the event and
11 we msut not use 'time()' because event may happen at a latter time!
12 [ ] Protect login by country/ua?
13 [ ] Improve input forms to be friendly with mobile phones: give html5 hints.
14 [ ] Use guestmount when building VM images?
15 [ ] Main web application must not have access to e-mail column, maybe others.
16 Only the queue processor must be able to use it. This is to avoid
17 XSS and the stealing of sensitive information.
18 Check http://www.postgresql.org/docs/9.4/interactive/sql-grant.html
19 web user must not be able to create roles/tables/databases/etc.
20 Hm. What about the settings?! I must be able to do a select...
21 [ ] totp: Build a Android application which will be able to authenticate also
22 the server to the user.
23 [ ] totp: update 'utime' for login tokens
24 [ ] totp: mark last timestamp used for ok login to not be able to reuse the
25 token; what if the time is in the future? we will not cache it.
26 [ ] totp: login: prevent auto filling/caching of login token
27 switch to 'password' type?
28 [ ] totp: hints:
29 only for admin: install qrencode package...
30 AWS asks for two consecutive codes. why?
31 Google also provides a list of backup tokens to be printed.
32 "If you want to activate the TOTP extra step, follow the instructions:
33 show the qr code or the key, wait for user to enter it
34 and if everything is ok, just activate it.
35 Instruct user to remove the token if the phone is lost. But, remind
36 user that the account may not be compromised without pass.
37 [ ] totp: think about loosing the phone.
38 [ ] totp: how to set it up:
39 press a menu to activate it, show QR code if possible, show base32 key
40 also, ask user to enter the token to finish the activation.
41 warn about time desync; maybe ask the user to press the 'sync' in
42 the mobile app.
43 [ ] totp: we may validate the login on one ip and keep ip for x hours.
44 [ ] totp: what if I encrypt key with the password and decrypt only at login?
45 (If somebody steals the database, will not have the keys).
46 [ ] totp: hints for ssh
47 [ ] totp: Implement 2 factor auth
48 (check https://korg.wiki.kernel.org/userdoc/gitolite_2fa)
49 [ ] Use PAM (man pam_start) to be able to use any type of auth, including LDAP.
50 [ ] http://www.cybertec.at/shrinking-the-storage-footprint-of-data/
18 51 [ ] Allow repo admins to delete notes/bugs/etc. [ ] Allow repo admins to delete notes/bugs/etc.
19 52 [ ] Seems that some other unit test is messing with repo.php ids. [ ] Seems that some other unit test is messing with repo.php ids.
20 53 Change ids to be protected from interference. Change ids to be protected from interference.
21 54 [ ] Use bintray.com to distribute isos? [ ] Use bintray.com to distribute isos?
55 [ ] When session expires and I press logout, no message is shown.
22 56 [ ] When creating an account, seems the email is cached, not the username! [ ] When creating an account, seems the email is cached, not the username!
23 57 Check! Check!
24 58 [ ] Users should be able to check the plans. [ ] Users should be able to check the plans.
 
... ... to store it in db. Why not? Because of caching of the pages...
33 67 messages. The user must agree to be spammed. Best, no notification messages. The user must agree to be spammed. Best, no notification
34 68 is ever issued. User may go to project to activate them if s/he wants. is ever issued. User may go to project to activate them if s/he wants.
35 69 Better, show some notifications in the top bar? Better, show some notifications in the top bar?
70 Or in a weekly e-mail with the status.
36 71 (see Linus Torvalds post about GitHub) (see Linus Torvalds post about GitHub)
37 72 [ ] Add a cache based on content. For example, if a repo was last changed [ ] Add a cache based on content. For example, if a repo was last changed
38 73 at timestamp t1, add a cache entry 'history''t1' with the content at timestamp t1, add a cache entry 'history''t1' with the content
 
... ... to store it in db. Why not? Because of caching of the pages...
64 99 logout token. What if the user is not logged in?! Yep, we can do it. logout token. What if the user is not logged in?! Yep, we can do it.
65 100 ETag! What about the cookies?! ETag! What about the cookies?!
66 101 Also, we may want to reuse the logout token? Also, we may want to reuse the logout token?
67 [ ] When sending mail with the new key, append also the fingerprints.
68 102 [ ] Why 'not github' articles, should be integrated somewhere: [ ] Why 'not github' articles, should be integrated somewhere:
69 103 http://www.valdyas.org/fading/index.cgi/2015/05/29#no-github http://www.valdyas.org/fading/index.cgi/2015/05/29#no-github
70 104 http://www.adamhyde.net/why-github-is-bad-for-open-source/ http://www.adamhyde.net/why-github-is-bad-for-open-source/
 
... ... to store it in db. Why not? Because of caching of the pages...
89 123 [ ] Add a random token in header to prevent watermarking (this is the name?). [ ] Add a random token in header to prevent watermarking (this is the name?).
90 124 [ ] User home page link is missing from top bar! use login_ui::homepage. [ ] User home page link is missing from top bar! use login_ui::homepage.
91 125 [ ] Add "Spread the word!" on website. [ ] Add "Spread the word!" on website.
92 [ ] Give up on submenu1/2 and integrate them when needed?
93 126 [ ] https://www.kernel.org/pub/software/scm/git/docs/gitworkflows.html [ ] https://www.kernel.org/pub/software/scm/git/docs/gitworkflows.html
94 127 [ ] git-name-rev is nice. [ ] git-name-rev is nice.
95 128 [ ] git pack-redundant should be called after git gc? And then prune-packed? [ ] git pack-redundant should be called after git gc? And then prune-packed?
 
... ... But, we have a problem with the expiration time!
276 309 [ ] Warning if user has not enabled cookies? [ ] Warning if user has not enabled cookies?
277 310 [ ] Seems that Etag is not working for main.css!!! At least. [ ] Seems that Etag is not working for main.css!!! At least.
278 311 [ ] bad_token.html must not be in user/ [ ] bad_token.html must not be in user/
279 [ ] On create_account page, submenu1 and submenu2 are with @@...@@!
280 312 [ ] The merge request name is not so good. Maybe include also the user? [ ] The merge request name is not so good. Maybe include also the user?
281 313 [ ] I do at least two times a request to database for uid 22 in hook_update.log [ ] I do at least two times a request to database for uid 22 in hook_update.log
282 314 [ ] git update-ref supports "ref:" to update a ref. Should we? [ ] git update-ref supports "ref:" to update a ref. Should we?
File inc/admin.inc.php changed (mode: 100644) (index c789d85..a0316fc)
... ... function rg_admin_invite_one($db, $event)
47 47 global $rg_admin_email, $rg_admin_name; global $rg_admin_email, $rg_admin_name;
48 48
49 49 $admin_name = "=?UTF-8?B?" $admin_name = "=?UTF-8?B?"
50 . base64_encode($rg_admin_name) . "?=";
50 . base64_encode($rg_admin_name) . "?=";
51 51
52 52 $rg = array(); $rg = array();
53 53 $subject = str_replace('{NAME}', $event['name'], $event['subject']); $subject = str_replace('{NAME}', $event['name'], $event['subject']);
 
... ... function rg_admin_invites_high_level($db, $rg)
167 167 $errmsg[] = "cannot add event (" . rg_event_error() . ")"; $errmsg[] = "cannot add event (" . rg_event_error() . ")";
168 168 break; break;
169 169 } }
170
171 rg_event_signal_daemon("", 0);
170 rg_event_signal_daemon('', 0);
172 171
173 172 $ret .= rg_template("admin/invites/sent.html", $rg, TRUE /* xss */); $ret .= rg_template("admin/invites/sent.html", $rg, TRUE /* xss */);
174 173 $show_form = FALSE; $show_form = FALSE;
175 break;
174 break;
176 175 } }
177 176
178 177 if ($show_form) { if ($show_form) {
File inc/admin/admin.php changed (mode: 100644) (index b47d4d2..c91ff06)
... ... if ($rg['login_ui']['is_admin'] != 1) {
8 8 return; return;
9 9 } }
10 10
11 $_subop = empty($paras) ? "" : array_shift($paras);
11 $_subop = empty($paras) ? 'plans' : array_shift($paras);
12
13 $rg['admin_menu'][$_subop] = 1;
14 $_admin .= rg_template("admin/menu.html", $rg, TRUE /* xss */);
12 15
13 16 switch ($_subop) { switch ($_subop) {
14 17 case 'plans': case 'plans':
 
... ... case 'repos': // repos
27 30 break; break;
28 31
29 32 case 'invites': // invites case 'invites': // invites
30 $_admin = rg_admin_invites_high_level($db, $rg);
33 $_admin .= rg_admin_invites_high_level($db, $rg);
31 34 break; break;
32 35 } }
33 36
34 $rg['menu']['sub1'][$_subop] = 1;
35 $rg['HTML:submenu1'] = rg_template("admin/menu.html", $rg, TRUE /* xss */);
36
37 37 ?> ?>
File inc/admin/plans/plans.php changed (mode: 100644) (index 318fed5..9b91310)
... ... $_admin_plans = "";
5 5
6 6 $_op = empty($paras) ? "list" : array_shift($paras); $_op = empty($paras) ? "list" : array_shift($paras);
7 7 rg_log("DEBUG: _op=$_op sparas=" . rg_array2string($paras)); rg_log("DEBUG: _op=$_op sparas=" . rg_array2string($paras));
8
9 $rg['admin_plans_menu'][$_op] = 1;
10 $_admin_plans .= rg_template("admin/plans/menu.html", $rg, TRUE /* xss */);
11
8 12 switch ($_op) { switch ($_op) {
9 13 case 'list': // list case 'list': // list
10 14 $_admin_plans .= rg_plan_list_high_level($db, $rg); $_admin_plans .= rg_plan_list_high_level($db, $rg);
 
... ... case 'add': // add
20 24 break; break;
21 25 } }
22 26
23 $rg['menu']['sub2'][$_op] = 1;
24 $rg['HTML:submenu2'] = rg_template("admin/plans/menu.html", $rg, TRUE /* xss */);
25
26 27 ?> ?>
File inc/admin/repos/repos.php changed (mode: 100644) (index 901bfb6..a705d6a)
... ... $_admin_repos = "";
5 5
6 6 $_op = empty($paras) ? "list" : array_shift($paras); $_op = empty($paras) ? "list" : array_shift($paras);
7 7
8 $rg['admin_repos_menu'][$_op] = 1;
9 $_admin_repos .= rg_template("admin/repos/menu.html", $rg, TRUE /* xss */);
10
8 11 switch ($_op) { switch ($_op) {
9 12 case 'add': case 'add':
10 13 $_admin_repos .= "Not yet implemented"; $_admin_repos .= "Not yet implemented";
 
... ... default: // list
16 19 break; break;
17 20 } }
18 21
19 $rg['menu']['sub2'][$_op] = 1;
20 $rg['HTML:submenu2'] = rg_template("admin/repos/menu.html", $rg, TRUE /* xss */);
21
22 22 ?> ?>
File inc/admin/users/users.php changed (mode: 100644) (index 576500d..40c7d57)
... ... $target_ui = rg_user_info($db, 0, $target, "");
9 9
10 10 // TODO: security: CSRF! // TODO: security: CSRF!
11 11 $_show_list = 1; $_show_list = 1;
12
13 $rg['admin_users_menu'][$_op] = 1;
14 $_admin_users .= rg_template("admin/users/menu.html", $rg, TRUE /* xss */);
15
12 16 switch ($_op) { switch ($_op) {
13 17 case 'add': // add case 'add': // add
14 18 case 'edit': // edit case 'edit': // edit
 
... ... case 'remove':
45 49 break; break;
46 50 } }
47 51
48 $rg['menu']['sub2'][$_op] = 1;
49 $rg['HTML:submenu2'] = rg_template("admin/users/menu.html", $rg, TRUE /* xss */);
50
51 52 if ($_show_list == 1) if ($_show_list == 1)
52 53 $_admin_users .= rg_user_list($db); $_admin_users .= rg_user_list($db);
53 54
File inc/bug.inc.php changed (mode: 100644) (index d5c6568..b050efe)
... ... function rg_bug_next_id($db, $repo_id)
247 247 break; break;
248 248 } }
249 249
250 rg_log("\tDEBUG: next_bug_id=" . $next_bug_id);
250 rg_log("DEBUG: next_bug_id=" . $next_bug_id);
251 251
252 252 rg_log_exit(); rg_log_exit();
253 253 rg_prof_end("bug_next_id"); rg_prof_end("bug_next_id");
File inc/dispatch/dispatch.php changed (mode: 100644) (index 6fe5607..630eaba)
... ... case 'logout':
16 16 if (!rg_token_valid($db, $rg, 'logout', TRUE)) if (!rg_token_valid($db, $rg, 'logout', TRUE))
17 17 break; break;
18 18
19 rg_user_set_last_seen($db, $rg['login_ui']['uid']);
19 rg_user_set_last_seen($db, $rg['login_ui']['uid'], time(), $rg['ip']);
20 20
21 21 if (rg_sess_destroy($db, $rg['sid'], $rg['login_ui'])) { if (rg_sess_destroy($db, $rg['sid'], $rg['login_ui'])) {
22 22 $body .= rg_template("user/logout.html", $rg, TRUE /* xss */); $body .= rg_template("user/logout.html", $rg, TRUE /* xss */);
File inc/events.inc.php changed (mode: 100644) (index b9cc87a..70682b0)
... ... function rg_event_register_functions($functions)
35 35 { {
36 36 global $rg_event_split_functions; global $rg_event_split_functions;
37 37
38 if (empty($functions)) {
39 rg_event_set_error("Cannot register empty array");
38 if (empty($functions))
40 39 return FALSE; return FALSE;
41 }
42 40
43 41 foreach ($functions as $type => $function) foreach ($functions as $type => $function)
44 42 $rg_event_split_functions[$type] = $function; $rg_event_split_functions[$type] = $function;
 
... ... function rg_event_notify(&$notify_list, $ev_id, $misc)
214 212 $buf_len = strlen($buf); $buf_len = strlen($buf);
215 213 foreach ($notify_list[$ev_id] as $index => $info) { foreach ($notify_list[$ev_id] as $index => $info) {
216 214 $fd = $info['fd']; $fd = $info['fd'];
217 rg_log("\tNotify [$ev_id] [fd=$fd]...");
215 rg_log("Notify [$ev_id] [fd=$fd]...");
218 216 $r = @socket_send($fd, $buf, $buf_len, 0); $r = @socket_send($fd, $buf, $buf_len, 0);
219 217 if ($r === FALSE) if ($r === FALSE)
220 218 rg_log("Error in sending."); rg_log("Error in sending.");
File inc/fixes.inc.php changed (mode: 100644) (index e3fa9d2..1c035d6)
... ... function rg_fixes_user_index_by_id_one($uid, $username)
201 201 while (1) { while (1) {
202 202 $user_path_uid = rg_user_path_by_id($uid); $user_path_uid = rg_user_path_by_id($uid);
203 203 $user_path_name = rg_user_path_by_name($username); $user_path_name = rg_user_path_by_name($username);
204 rg_log("\tuser_path=[$user_path_uid][$user_path_name]");
204 rg_log("user_path=[$user_path_uid][$user_path_name]");
205 205
206 206 // parend dir exits? if not, create it // parend dir exits? if not, create it
207 207 $p = dirname($user_path_uid); $p = dirname($user_path_uid);
File inc/git.inc.php changed (mode: 100644) (index 5a441f9..c8dbf68)
... ... function rg_git_install_hooks($dst)
74 74
75 75 } }
76 76
77 rg_log("\tRemoving original hooks dir...");
77 rg_log("Removing original hooks dir...");
78 78 if (!rg_rmdir($dst . "/hooks")) { if (!rg_rmdir($dst . "/hooks")) {
79 79 rg_git_set_error("cannot remove hooks dir" rg_git_set_error("cannot remove hooks dir"
80 80 . " (" . rg_util_error() . ")"); . " (" . rg_util_error() . ")");
81 81 break; break;
82 82 } }
83 83
84 rg_log("\tLink hooks dir...");
84 rg_log("Link hooks dir...");
85 85 if (symlink($rg_scripts . "/hooks", $dst . "/hooks") === FALSE) { if (symlink($rg_scripts . "/hooks", $dst . "/hooks") === FALSE) {
86 86 rg_git_set_error("cannot make symlink [$rg_scripts/hooks]" rg_git_set_error("cannot make symlink [$rg_scripts/hooks]"
87 87 . "->[$dst/] ($php_errormsg)."); . "->[$dst/] ($php_errormsg).");
 
... ... function rg_git_whitespace_ok($old, $new)
351 351 . " " . escapeshellarg($old) . " " . escapeshellarg($old)
352 352 . " " . escapeshellarg($new); . " " . escapeshellarg($new);
353 353 $a = rg_exec($cmd); $a = rg_exec($cmd);
354 rg_log("\ta:" . rg_array2string($a));
354 rg_log("a:" . rg_array2string($a));
355 355 if ($a['ok'] != 1) { if ($a['ok'] != 1) {
356 356 rg_git_set_error("error on diff (" . $a['errmsg'] . ")"); rg_git_set_error("error on diff (" . $a['errmsg'] . ")");
357 357 $ret = $a['data']; // TODO: should we return FALSE?! $ret = $a['data']; // TODO: should we return FALSE?!
 
... ... function rg_git_diff2array($diff, &$extra)
639 639 } }
640 640
641 641 if (empty($line)) { if (empty($line)) {
642 //rg_log("\tWARN: empty line [$line]!");
642 //rg_log("WARN: empty line [$line]!");
643 643 continue; continue;
644 644 } }
645 645
 
... ... function rg_git_diff2array($diff, &$extra)
666 666
667 667 // Ignore, for now, "\ No newline at end of file" (TODO) // Ignore, for now, "\ No newline at end of file" (TODO)
668 668 if (strncmp($line, "\\", 1) == 0) { if (strncmp($line, "\\", 1) == 0) {
669 rg_log("\tINFO: warn line: [$line].");
669 rg_log("INFO: warn line: [$line].");
670 670 continue; continue;
671 671 } }
672 672
 
... ... function rg_git_log($path, $max, $from, $to, $also_patch)
692 692 $ret = FALSE; $ret = FALSE;
693 693 while (1) { while (1) {
694 694 if (!file_exists($path . "/refs/heads/master")) { if (!file_exists($path . "/refs/heads/master")) {
695 rg_log("\tRepo is empty.");
695 rg_log("Repo is empty.");
696 696 break; break;
697 697 } }
698 698
 
... ... function rg_git_update_branch($db, $a)
1169 1169 global $rg_git_zero; global $rg_git_zero;
1170 1170
1171 1171 rg_prof_start("git_update_branch"); rg_prof_start("git_update_branch");
1172 rg_log("git_update_branch: " . rg_array2string($a));
1172 rg_log_enter("git_update_branch: " . rg_array2string($a));
1173 1173
1174 while (1) {
1174 1175 $_x = array(); $_x = array();
1175 1176 $_x['obj_id'] = $a['repo_id']; $_x['obj_id'] = $a['repo_id'];
1176 1177 $_x['type'] = 'repo_refs'; $_x['type'] = 'repo_refs';
 
... ... function rg_git_update_branch($db, $a)
1189 1190 $x = $_x; $x = $_x;
1190 1191 $x['needed_rights'] = 'D'; $x['needed_rights'] = 'D';
1191 1192 if (rg_rights_allow($db, $x) !== TRUE) if (rg_rights_allow($db, $x) !== TRUE)
1192 rg_git_fatal($a['refname'] . "\nNo rights to delete"
1193 . " a branch.");
1193 rg_git_fatal($a['refname']
1194 . "\nYou have no rights to delete a branch.");
1194 1195 $history['history_category'] = REPO_CAT_GIT_BRANCH_DELETE; $history['history_category'] = REPO_CAT_GIT_BRANCH_DELETE;
1195 1196 $history['history_message'] = 'Reference ' . $a['refname'] $history['history_message'] = 'Reference ' . $a['refname']
1196 1197 . ' deleted'; . ' deleted';
1197 1198 rg_repo_history_insert($db, $history); rg_repo_history_insert($db, $history);
1198 return;
1199 break;
1199 1200 } }
1200 1201
1201 1202 // If we have 'H' (anonymous push), we have also create branch // If we have 'H' (anonymous push), we have also create branch
 
... ... function rg_git_update_branch($db, $a)
1204 1205 $x = $_x; $x = $_x;
1205 1206 $x['needed_rights'] = 'H|C'; $x['needed_rights'] = 'H|C';
1206 1207 if (rg_rights_allow($db, $x) !== TRUE) if (rg_rights_allow($db, $x) !== TRUE)
1207 rg_git_fatal($a['refname'] . "\nYou have no rights"
1208 . " to create a branch.");
1208 rg_git_fatal($a['refname']
1209 . "\nYou have no rights to create a branch.");
1209 1210 $check_fast_forward = 0; $check_fast_forward = 0;
1210 1211 } }
1211 1212
 
... ... function rg_git_update_branch($db, $a)
1222 1223 } }
1223 1224
1224 1225 if (strcmp($merge_base, $a['old_rev']) != 0) if (strcmp($merge_base, $a['old_rev']) != 0)
1225 rg_git_fatal($a['refname'] . "\nNon fast-forward is"
1226 . " not allowed.");
1226 rg_git_fatal($a['refname']
1227 . "\nYou have no rights to do a non fast-forward push");
1227 1228 } }
1228 1229
1229 1230 // Check if user pushes a merge commit // Check if user pushes a merge commit
 
... ... function rg_git_update_branch($db, $a)
1232 1233 $x['needed_rights'] = 'M'; $x['needed_rights'] = 'M';
1233 1234 if (rg_rights_allow($db, $x) !== TRUE) { if (rg_rights_allow($db, $x) !== TRUE) {
1234 1235 if (rg_git_rev_ok($a['new_rev'] . "^2")) if (rg_git_rev_ok($a['new_rev'] . "^2"))
1235 rg_git_fatal($a['refname'] . "\nNo rights to push merges.");
1236 rg_git_fatal($a['refname']
1237 . "\nYou have no rights to push merges.");
1236 1238 } }
1237 1239
1238 1240 // Check for bad whitespace // Check for bad whitespace
 
... ... function rg_git_update_branch($db, $a)
1243 1245 $w = rg_git_whitespace_ok($a['old_rev'], $a['new_rev']); $w = rg_git_whitespace_ok($a['old_rev'], $a['new_rev']);
1244 1246 if ($w !== TRUE) if ($w !== TRUE)
1245 1247 rg_git_fatal($a['refname'] rg_git_fatal($a['refname']
1246 . "\nNo rights to push bad whitespace:"
1248 . "\nYou have no rights to push bad whitespace:"
1247 1249 . "\n" . $w); . "\n" . $w);
1248 1250 } }
1249 1251
 
... ... function rg_git_update_branch($db, $a)
1266 1268 $w = rg_git_whitespace_ok($a['old_rev'], $a['new_rev']); $w = rg_git_whitespace_ok($a['old_rev'], $a['new_rev']);
1267 1269 if ($w !== TRUE) { if ($w !== TRUE) {
1268 1270 rg_git_fatal($a['refname'] rg_git_fatal($a['refname']
1269 . "\nNo rights to push bad whitespace on path [$file]:"
1271 . "\nYou have no rights to push bad whitespace on path [$file]:"
1270 1272 . "\n" . $w); . "\n" . $w);
1271 1273 } }
1272 1274 } }
 
... ... function rg_git_update_branch($db, $a)
1277 1279 $x['needed_rights'] = 'P'; $x['needed_rights'] = 'P';
1278 1280 $x['misc'] = $a['refname']; $x['misc'] = $a['refname'];
1279 1281 if (rg_rights_allow($db, $x) !== TRUE) { if (rg_rights_allow($db, $x) !== TRUE) {
1280 rg_log("\tPush is not allowed, let's see the anon one");
1282 rg_log("Push is not allowed, let's see the anon one");
1281 1283 $x['needed_rights'] = 'H'; $x['needed_rights'] = 'H';
1282 1284 if (rg_rights_allow($db, $x) !== TRUE) { if (rg_rights_allow($db, $x) !== TRUE) {
1283 1285 $_z = array(); $_z = array();
 
... ... function rg_git_update_branch($db, $a)
1314 1316 $history['history_message'] = 'Anonymous push to ref ' $history['history_message'] = 'Anonymous push to ref '
1315 1317 . $a['refname']; . $a['refname'];
1316 1318
1317 // TODO: we shoult notify by e-mail that a merge request is
1319 // TODO: we should notify by e-mail that a merge request is
1318 1320 // waiting. // waiting.
1319 1321 } else { } else {
1320 1322 rg_log("We are allowed to push."); rg_log("We are allowed to push.");
 
... ... function rg_git_update_branch($db, $a)
1348 1350 } }
1349 1351 } }
1350 1352 rg_repo_history_insert($db, $history); rg_repo_history_insert($db, $history);
1353 }
1351 1354
1355 rg_log_exit();
1352 1356 rg_prof_end("git_update_branch"); rg_prof_end("git_update_branch");
1353 1357 } }
1354 1358
 
... ... function rg_git_log2listing($log, $rg, $commit_table)
1559 1563 $ret .= "<br />\n" $ret .= "<br />\n"
1560 1564 . nl2br(rg_xss_safe($i['vars']['body'])); . nl2br(rg_xss_safe($i['vars']['body']));
1561 1565
1562 $ret .= "<br />\n"
1566 $ret .= "<br />\n"
1563 1567 . "<b>Author</b>: " . rg_xss_safe($i['vars']['author name']); . "<b>Author</b>: " . rg_xss_safe($i['vars']['author name']);
1564 1568
1565 1569 if (!empty($i['vars']['commiter name'])) if (!empty($i['vars']['commiter name']))
1566 1570 $ret .= "<br />\n" $ret .= "<br />\n"
1567 1571 . "<b>Commiter</b>: " . rg_xss_safe($i['vars']['commiter name']); . "<b>Commiter</b>: " . rg_xss_safe($i['vars']['commiter name']);
1568 1572
1569 $ret .= "<br />\n"
1573 $ret .= "<br />\n"
1570 1574 . "<b>Date (UTC)</b>: " . gmdate("Y-m-d H:i", $i['vars']['author date']); . "<b>Date (UTC)</b>: " . gmdate("Y-m-d H:i", $i['vars']['author date']);
1571 1575 $ret .= "<br />\n"; $ret .= "<br />\n";
1572 1576
File inc/keys.inc.php changed (mode: 100644) (index ecdb7b8..2999cea)
... ... function rg_keys_event_notify_user($db, $event)
96 96 rg_prof_start("keys_event_notify_user"); rg_prof_start("keys_event_notify_user");
97 97 rg_log("keys_event_notify_user: event=" . rg_array2string($event)); rg_log("keys_event_notify_user: event=" . rg_array2string($event));
98 98
99 // TODO: load info about the keys and put the fingerprint in e-mail
100 // TODO: Maybe put also the body in the e-mail, so it can be re-uploaded.
101 // TODO: Maybe add also the statistics.
102 // TODO: Do not forget that here we have a list
103 // TODO: Take care: we already deleted the keys. We cannot inspect
99 // TODO: del: Maybe add also the statistics.
100 // TODO: del: Do not forget that here we have a list
101 // TODO: del: Take care: we already deleted the keys. We cannot inspect
104 102 // them anymore! Maybe put info in the event. // them anymore! Maybe put info in the event.
105 103
106 104 $r = rg_mail_template("mail/user/key/" . $event['op'], $event); $r = rg_mail_template("mail/user/key/" . $event['op'], $event);
 
... ... function rg_keys_event_notify_user($db, $event)
117 115 function rg_keys_info($key) function rg_keys_info($key)
118 116 { {
119 117 rg_prof_start("keys_info"); rg_prof_start("keys_info");
118 rg_log_enter('rg_keys_info key=' . $key);
120 119
121 120 $ret = array(); $ret = array();
122 121 $ret['ok'] = 0; $ret['ok'] = 0;
123 122 while(1) { while(1) {
123 if (empty($key)) {
124 rg_keys_set_error('you did not uploaded the key');
125 break;
126 }
127
124 128 if (strpos($key, "PRIVATE KEY") !== FALSE) { if (strpos($key, "PRIVATE KEY") !== FALSE) {
125 129 rg_keys_set_error("private instead of public key"); rg_keys_set_error("private instead of public key");
126 130 break; break;
 
... ... function rg_keys_info($key)
136 140
137 141 if ((strncmp($ret['type'], 'ssh-', 4) != 0) if ((strncmp($ret['type'], 'ssh-', 4) != 0)
138 142 && (strncmp($ret['type'], 'ecdsa-', 6) != 0)) { && (strncmp($ret['type'], 'ecdsa-', 6) != 0)) {
143 rg_log('key: ' . $key);
139 144 rg_keys_set_error("key does not start with ssh- or ecdsa-"); rg_keys_set_error("key does not start with ssh- or ecdsa-");
140 145 break; break;
141 146 } }
 
... ... function rg_keys_info($key)
252 257 break; break;
253 258 } }
254 259
260 rg_log_exit();
255 261 rg_prof_end("keys_info"); rg_prof_end("keys_info");
256 262 return $ret; return $ret;
257 263 } }
 
... ... function rg_keys_remove($db, $ui, $list)
292 298 . " (" . rg_event_error() . ")"); . " (" . rg_event_error() . ")");
293 299 break; break;
294 300 } }
295 rg_event_signal_daemon("", 0);
301 rg_event_signal_daemon('', 0);
296 302
297 303 $ret = TRUE; $ret = TRUE;
298 304 break; break;
 
... ... function rg_keys_add($db, $ui, $key)
391 397
392 398 $event = array("category" => 1000, "prio" => 50, $event = array("category" => 1000, "prio" => 50,
393 399 'ui' => array('email' => $ui['confirmed'] > 0 ? $ui['email'] : ""), 'ui' => array('email' => $ui['confirmed'] > 0 ? $ui['email'] : ""),
394 "key_id" => $key_id);
400 'ki' => $ki,
401 'key_id' => $key_id);
395 402 $r = rg_event_add($db, $event); $r = rg_event_add($db, $event);
396 403 if ($r !== TRUE) { if ($r !== TRUE) {
397 404 rg_keys_set_error("cannot add event" rg_keys_set_error("cannot add event"
 
... ... function rg_keys_add($db, $ui, $key)
407 414 } }
408 415 $do_rollback = 0; $do_rollback = 0;
409 416
410 rg_event_signal_daemon("", 0);
417 rg_event_signal_daemon('', 0);
411 418
412 419 $ret = $key_id; $ret = $key_id;
413 420 break; break;
File inc/login/login.php changed (mode: 100644) (index cc23c71..d86739b)
... ... rg_log("FILE: /inc/login/login");
3 3
4 4 $user = rg_var_str("user"); $user = rg_var_str("user");
5 5 $pass = rg_var_str("pass"); $pass = rg_var_str("pass");
6 $login_token = rg_var_str("login_token");
6 7 $lock_ip = rg_var_uint("lock_ip"); $lock_ip = rg_var_uint("lock_ip");
7 8
8 9 $_login = ""; $_login = "";
 
... ... while ($rg['doit'] == 1) {
20 21 break; break;
21 22 } }
22 23
23 $r = rg_user_login_by_user_pass($db, $user, $pass, $lock_ip,
24 $rg['login_ui']);
24 $r = rg_user_login_by_user_pass($db, $user, $pass, $login_token,
25 $lock_ip, $rg['login_ui']);
25 26 if ($r === FALSE) { if ($r === FALSE) {
26 27 $errmsg[] = rg_user_error(); $errmsg[] = rg_user_error();
27 28 break; break;
 
... ... while ($rg['doit'] == 1) {
34 35
35 36 $rg['user'] = $user; $rg['user'] = $user;
36 37 $rg['pass'] = $pass; $rg['pass'] = $pass;
38 $rg['login_token'] = $login_token;
37 39 $rg['HTML:errmsg'] = rg_template_errmsg($errmsg); $rg['HTML:errmsg'] = rg_template_errmsg($errmsg);
38 40 $rg['forgot_send'] = rg_re_url("/op/forgot_send"); $rg['forgot_send'] = rg_re_url("/op/forgot_send");
39 41 $rg['create_account'] = rg_re_url("/op/create_account"); $rg['create_account'] = rg_re_url("/op/create_account");
File inc/mr.inc.php changed (mode: 100644) (index 3734143..3032737)
... ... function rg_mr_queue_process($db)
142 142 continue; continue;
143 143
144 144 $path = $rg_mr_queue . "/" . $file; $path = $rg_mr_queue . "/" . $file;
145 rg_log("\tLoading merge request from $path...");
145 rg_log("Loading merge request from $path...");
146 146 $d = rg_mr_queue_load_file($path); $d = rg_mr_queue_load_file($path);
147 147 if ($d['ok'] != 1) { if ($d['ok'] != 1) {
148 148 $ret = FALSE; $ret = FALSE;
File inc/plan.inc.php changed (mode: 100644) (index 306ef98..25508cb)
... ... function rg_plan_list_high_level($db, $rg)
246 246 break; break;
247 247
248 248 if (!rg_valid_referer()) { if (!rg_valid_referer()) {
249 $del_errmsg[] = "invalid referer; try again";
249 $del_errmsg[] = 'invalid referer; try again';
250 250 break; break;
251 251 } }
252 252
253 253 if (!rg_token_valid($db, $rg, 'plan_list', FALSE)) { if (!rg_token_valid($db, $rg, 'plan_list', FALSE)) {
254 $del_errmsg[] = "Invalid token. Try again.";
254 $del_errmsg[] = 'invalid token; try again.';
255 255 break; break;
256 256 } }
257 257
File inc/repo/repo.php changed (mode: 100644) (index 140840f..a420c89)
... ... rg_log("FILE: /inc/repo/repo");
3 3
4 4 // This page is shown when user press main menu "My repositories" // This page is shown when user press main menu "My repositories"
5 5
6 $_repo = "";
6 $_repo = '';
7 7
8 8 if (empty($paras)) { if (empty($paras)) {
9 9 if (rg_repo_have($db, $rg['login_ui']['uid']) == 0) if (rg_repo_have($db, $rg['login_ui']['uid']) == 0)
 
... ... if (empty($paras)) {
13 13 } else { } else {
14 14 $_subop = array_shift($paras); $_subop = array_shift($paras);
15 15 } }
16
17 $rg['repo_menu'][$_subop] = 1;
18 $_repo = rg_template("repo/menu.html", $rg, TRUE /* xss */);
19
16 20 switch ($_subop) { switch ($_subop) {
17 21 case 'create': case 'create':
18 22 $rg['form_url'] = "/op/repo/create"; $rg['form_url'] = "/op/repo/create";
 
... ... case 'list':
29 33 break; break;
30 34 } }
31 35
32 $rg['menu']['sub1'][$_subop] = 1;
33 $rg['HTML:submenu1'] = rg_template("repo/menu.html", $rg, TRUE /* xss */);
34
35 36 ?> ?>
File inc/sess.inc.php changed (mode: 100644) (index 95e92a4..b7916a4)
... ... function rg_sess_add($db, $uid, $sid, $session_time, $lock_ip)
31 31 . ", @@session_time@@, @@ip@@)"; . ", @@session_time@@, @@ip@@)";
32 32 $res = rg_sql_query_params($db, $sql, $params); $res = rg_sql_query_params($db, $sql, $params);
33 33 if ($res === FALSE) { if ($res === FALSE) {
34 rg_log("\tCannot insert (" . rg_sql_error() . ")!");
34 rg_log("Cannot insert (" . rg_sql_error() . ")!");
35 35 break; break;
36 36 } }
37 37 rg_sql_free_result($res); rg_sql_free_result($res);
 
... ... function rg_sess_valid($db, $sid)
65 65 $sql = "SELECT * FROM sess WHERE sid = @@sid@@"; $sql = "SELECT * FROM sess WHERE sid = @@sid@@";
66 66 $res = rg_sql_query_params($db, $sql, $params); $res = rg_sql_query_params($db, $sql, $params);
67 67 if ($res === FALSE) { if ($res === FALSE) {
68 rg_log("\tCannot select (" . rg_sql_error() . ")!");
68 rg_log("Cannot select (" . rg_sql_error() . ")!");
69 69 break; break;
70 70 } }
71 71 $rows = rg_sql_num_rows($res); $rows = rg_sql_num_rows($res);
 
... ... function rg_sess_valid($db, $sid)
78 78 } }
79 79
80 80 if ($r === FALSE) { if ($r === FALSE) {
81 rg_log("\tSession not found.");
81 rg_log("Session not found.");
82 82 break; break;
83 83 } }
84 84
85 85 $now = time(); $now = time();
86 86 if ($r['expire'] < $now) { if ($r['expire'] < $now) {
87 rg_log("\tSession too old (" . ($now - $r['expire']) . "s).");
87 rg_log("Session too old (" . ($now - $r['expire']) . "s).");
88 88 break; break;
89 89 } }
90 90
91 91 $ip = @$_SERVER['REMOTE_ADDR']; $ip = @$_SERVER['REMOTE_ADDR'];
92 92 if (!empty($r['ip']) && (strcmp($r['ip'], $ip) != 0)) { if (!empty($r['ip']) && (strcmp($r['ip'], $ip) != 0)) {
93 rg_log("\tSession invalid because of IP"
93 rg_log("Session invalid because of IP"
94 94 . " login=" . $r['ip'] . " now=$ip."); . " login=" . $r['ip'] . " now=$ip.");
95 95 break; break;
96 96 } }
97 97
98 98 $uid = $r['uid']; $uid = $r['uid'];
99 rg_log("\tSession valid, uid=$uid, expire=+"
99 rg_log("Session valid, uid=$uid, expire=+"
100 100 . ($r['expire'] - $now) . "s"); . ($r['expire'] - $now) . "s");
101 101 $ret = $r; $ret = $r;
102 102 break; break;
 
... ... function rg_sess_update($db, $sess)
133 133 . " WHERE sid = @@sid@@"; . " WHERE sid = @@sid@@";
134 134 $res = rg_sql_query_params($db, $sql, $sess); $res = rg_sql_query_params($db, $sql, $sess);
135 135 if ($res === FALSE) { if ($res === FALSE) {
136 rg_log("\tCannot update (" . rg_sql_error() . ")!");
136 rg_log("Cannot update (" . rg_sql_error() . ")!");
137 137 // We will not exit here. At least in cache to be ok // We will not exit here. At least in cache to be ok
138 138 } else { } else {
139 139 $sess['last_db_write'] = $now; $sess['last_db_write'] = $now;
 
... ... function rg_sess_destroy($db, $sid, &$ui)
165 165 $sql = "DELETE FROM sess WHERE sid = @@sid@@"; $sql = "DELETE FROM sess WHERE sid = @@sid@@";
166 166 $res = rg_sql_query_params($db, $sql, $params); $res = rg_sql_query_params($db, $sql, $params);
167 167 if ($res === FALSE) { if ($res === FALSE) {
168 rg_log("\tCannot delete (" . rg_sql_error() . ")!");
168 rg_log("Cannot delete (" . rg_sql_error() . ")!");
169 169 break; break;
170 170 } }
171 171 rg_sql_free_result($res); rg_sql_free_result($res);
File inc/ssh.inc.php changed (mode: 100644) (index d00ebef..40e6e5d)
... ... require_once($INC . "/sql.inc.php");
6 6 require_once($INC . "/state.inc.php"); require_once($INC . "/state.inc.php");
7 7 require_once($INC . "/prof.inc.php"); require_once($INC . "/prof.inc.php");
8 8 require_once($INC . "/repo.inc.php"); require_once($INC . "/repo.inc.php");
9 require_once($INC . "/totp.inc.php");
9 10
10 11 function rg_ssh_status($db, $uid) function rg_ssh_status($db, $uid)
11 12 { {
 
... ... function rg_ssh_status($db, $uid)
14 15 echo "Here will be the status.\n"; echo "Here will be the status.\n";
15 16
16 17 // also details about payments: warn if disk space is low etc. // also details about payments: warn if disk space is low etc.
17
18 exit(0);
19 18 } }
20 19
21 20 /* /*
 
... ... function rg_ssh_repos($db, $uid)
45 44 echo "You have no repository.\n"; echo "You have no repository.\n";
46 45 } }
47 46 rg_sql_free_result($res); rg_sql_free_result($res);
48
49 exit(0);
50 47 } }
51 48
52 49 /* /*
 
... ... function rg_ssh_repo($db, $uid, $paras)
86 83 echo "Master: " . $mri['name'] . "\n"; echo "Master: " . $mri['name'] . "\n";
87 84 } }
88 85 } }
86 }
89 87
90 exit(0);
88 /*
89 * Deal with TOTP stuff
90 */
91 function rg_ssh_totp($db, $uid, $paras)
92 {
93 rg_prof_start('ssh_totp');
94 rg_log_enter('ssh_totp uid=' . $uid . ' paras=' . rg_array2string($paras));
95
96 $ssh_client = getenv("SSH_CLIENT");
97 $_t = explode(" ", $ssh_client);
98 $ip = $_t[0];
99
100 $cmd = array_shift($paras);
101 switch ($cmd) {
102 case 'enroll':
103 if (empty($paras)) {
104 $secret = rg_totp_base32_generate(16);
105
106 $r = rg_totp_enroll($db, $uid, 'SSH', $secret, $ip, 'f');
107 if ($r !== TRUE) {
108 echo "An internal error occured; please try again later.\n";
109 break;
110 }
111
112 echo "Scan the following code with the mobile application:\n";
113 echo rg_totp_text($secret) . "\n";
114 echo "Or manually enter the following code: " . $secret . "\n";
115 echo "To finish the enrollment you will have to confirm";
116 echo " it by running the following command:";
117 echo " ssh ... enroll <6_digits_code_generated_by_device>\n";
118 break;
119 }
120
121 $confirm = array_shift($paras);
122
123 $lt = rg_totp_list($db, $uid);
124 if ($lt['ok'] != 1) {
125 echo "An internal error occured; please try again later.\n";
126 break;
127 }
128
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 }
141
142 $done = TRUE;
143 break;
144 }
145 }
146
147 if ($ierror)
148 break;
149
150 if ($done === FALSE)
151 echo "Invalid confirmation token; try to re-enroll\n";
152 else
153 echo "Success!\n";
154 break;
155
156 case 'val': break;
157 default:
158 echo "Posible TOTP commands:\n";
159 echo " enroll\n";
160 echo " val\n";
161 echo " inval - Invalidate IP address\n";
162 break;
163 }
164
165 rg_log_exit();
166 rg_prof_end('ssh_totp');
91 167 } }
92 168
93 169 function rg_ssh_dispatch($db, $uid, $cmd) function rg_ssh_dispatch($db, $uid, $cmd)
94 170 { {
95 $paras = explode(" ", $cmd);
171 $paras = explode(' ', $cmd);
96 172 $cmd = array_shift($paras); $cmd = array_shift($paras);
97 173
174 echo "\n== Welcome to RocketGit! ==\n";
175
98 176 switch ($cmd) { switch ($cmd) {
99 177 case 'status': rg_ssh_status($db, $uid); break; case 'status': rg_ssh_status($db, $uid); break;
100 178 case 'repos': rg_ssh_repos($db, $uid); break; case 'repos': rg_ssh_repos($db, $uid); break;
101 179 case 'repo': rg_ssh_repo($db, $uid, $paras); break; case 'repo': rg_ssh_repo($db, $uid, $paras); break;
180 case 'totp': rg_ssh_totp($db, $uid, $paras); break;
102 181 case '': case '':
103 echo "Available commmands: status, repos, repo.\n";
104 exit(0);
182 echo "Available commmands: status, repos, repo, totp.\n";
183 break;
105 184 } }
185
186 exit(0);
106 187 } }
107 188
108 189 ?> ?>
File inc/struct.inc.php changed (mode: 100644) (index 7f4b318..2541bc7)
... ... $rg_sql_struct[33] = array();
419 419 $rg_sql_struct[33]['tables'] = array(); $rg_sql_struct[33]['tables'] = array();
420 420 $rg_sql_struct[33]['other'] = array( $rg_sql_struct[33]['other'] = array(
421 421 "suggestion_itime" => "ALTER TABLE suggestions ADD itime INTEGER NOT NULL DEFAULT 0", "suggestion_itime" => "ALTER TABLE suggestions ADD itime INTEGER NOT NULL DEFAULT 0",
422 "suggestion_email" => "ALTER TABLE suggestions DROP email"
422 "suggestion_email" => "ALTER TABLE suggestions DROP email",
423 "login_tokens" => "CREATE TABLE login_tokens ("
424 . "id SERIAL"
425 . ", uid INT NOT NULL DEFAULT 0"
426 . ", itime INT NOT NULL DEFAULT 0"
427 . ", used INT NOT NULL DEFAULT 0"
428 . ", name TEXT NOT NULL DEFAULT ''"
429 . ", secret TEXT NOT NULL DEFAULT ''"
430 . ", ip TEXT NOT NULL DEFAULT ''"
431 . ", conf BOOLEAN NOT NULL DEFAULT 't')",
432 "login_tokens_i_uid" =>
433 "CREATE INDEX login_tokens_i_uid ON login_tokens(uid)",
423 434 ); );
424 435
425 TODO: do not fill email in suggestions - we have the uid!
426 TODO: "suggestion_drop_email" => "ALTER TABLE suggestions DROP email"
436 TODO: do not fill email in suggestions CODE - we have the uid!
427 437 TODO: change report1 to activate yesterday suggestions! TODO: change report1 to activate yesterday suggestions!
428 438 */ */
429 439
 
... ... function rg_sql_struct_slaves_update($db)
642 652
643 653 // Do we have current month and the next one covered? // Do we have current month and the next one covered?
644 654 if ($current_month_ts < $last_ts) { if ($current_month_ts < $last_ts) {
645 rg_log("\tNo update needed!");
655 rg_log("No update needed!");
646 656 $ret = TRUE; $ret = TRUE;
647 657 break; break;
648 658 } }
File inc/totp.inc.php added (mode: 100644) (index 0000000..c9b0574)
1 <?php
2
3 $rg_totp_error = '';
4
5 function rg_totp_set_error($str)
6 {
7 global $rg_totp_error;
8 $rg_totp_error = $str;
9 rg_log('set_error: ' . $str);
10 }
11
12 function rg_totp_error()
13 {
14 global $rg_totp_error;
15 return $rg_totp_error;
16 }
17
18 /*
19 * Event functions
20 */
21 $rg_totp_functions = array(
22 //2006 => "rg_totp_link_by_name"
23 );
24 rg_event_register_functions($rg_totp_functions);
25
26
27 $rg_totp_base32_tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
28
29 /*
30 * Generates a secret (returned as google base32 string)
31 */
32 function rg_totp_base32_generate($digits)
33 {
34 global $rg_totp_base32_tab;
35
36 $ret = '';
37 for ($i = 0; $i < $digits; $i++)
38 $ret .= $rg_totp_base32_tab[rand(0, 31)];
39
40 return $ret;
41 }
42
43 /*
44 * Transforms a base32 google string into a binary array
45 */
46 function rg_totp_base32_decode($s)
47 {
48 global $rg_totp_base32_tab;
49
50 $s = strtoupper($s);
51 $s_len = strlen($s);
52
53 $ret = '';
54 $buf = 0;
55 $buf_bits = 0;
56 $i = 0;
57 while ($i < $s_len) {
58 while (($i < $s_len) && ($buf_bits < 8)) {
59 $n = strpos($rg_totp_base32_tab, $s[$i++]);
60 $buf = ($buf << 5) | $n;
61 $buf_bits += 5;
62 }
63
64 // less than 8 bits left, pad right with 0
65 if ($buf_bits < 8) {
66 $buf <<= (8 - $buf_bits);
67 $buf_bits = 8;
68 }
69
70 // Now, we have more than 8 bits in buffer, extract
71 // next out char.
72 $buf_bits -= 8;
73 $c = chr($buf >> $buf_bits);
74 $ret .= $c;
75 $buf &= ((1 << $buf_bits) - 1);
76 }
77
78 return $ret;
79 }
80
81 function rg_totp_compute($key, $tc, $digits)
82 {
83 $key_bin = rg_totp_base32_decode($key);
84
85 $tc_bin = hex2bin(sprintf("%016x", $tc));
86
87 $h = hash_hmac('sha1', $tc_bin, $key_bin, TRUE /*bin output*/);
88
89 $o = ord($h[strlen($h) - 1]) & 0x0F;
90 $i = (ord($h[$o]) << 24) | (ord($h[$o + 1]) << 16)
91 | (ord($h[$o + 2]) << 8) | ord($h[$o + 3]);
92 $i &= 0x7FFFFFFF;
93 return sprintf("%0" . $digits . "u", $i % pow(10, $digits));
94 }
95
96 function rg_totp_verify_tc($key, $tc, $token)
97 {
98 $t = rg_totp_compute($key, $tc, 6);
99 if (strcmp($token, $t) == 0)
100 return TRUE;
101
102 return FALSE;
103 }
104
105 /*
106 * Verifies if a login token is valid
107 * We try 2 tcs before currend ts and after current ts
108 */
109 function rg_totp_verify($key, $token)
110 {
111 rg_prof_start('totp_verify');
112
113 $tc = intval(time() / 30);
114 while (1) {
115 $ret = rg_totp_verify_tc($key, $tc, $token);
116 if ($ret === TRUE)
117 break;
118
119 $ret = rg_totp_verify_tc($key, $tc - 1, $token);
120 if ($ret === TRUE)
121 break;
122
123 $ret = rg_totp_verify_tc($key, $tc - 2, $token);
124 if ($ret === TRUE)
125 break;
126
127 $ret = rg_totp_verify_tc($key, $tc + 1, $token);
128 if ($ret === TRUE)
129 break;
130
131 $ret = rg_totp_verify_tc($key, $tc + 2, $token);
132 if ($ret === TRUE)
133 break;
134
135 $ret = FALSE;
136 break;
137 }
138
139 rg_prof_end('totp_verify');
140 return $ret;
141 }
142
143 /*
144 * Returns a PNG encoded QR code
145 */
146 function rg_totp_png($secret)
147 {
148 global $rg_ssh_host;
149
150 $extra = gmdate('Y-m-d H:i');
151 $issuer = $rg_ssh_host;
152 $cmd = "qrencode -o - --level=H --type=PNG 'otpauth://totp/$extra?secret=$secret&issuer=$issuer'";
153 $a = rg_exec($cmd);
154 if ($a['ok'] != 1)
155 return FALSE;
156
157 return $a['data'];
158 }
159
160 /*
161 * Returns a UTF-8 encoded QR code
162 */
163 function rg_totp_text($secret)
164 {
165 global $rg_ssh_host;
166
167 $extra = gmdate('Y-m-d H:i');
168 $issuer = $rg_ssh_host;
169 $cmd = "qrencode -o - --level=M --margin=2 --type=UTF8 'otpauth://totp/$extra?secret=$secret&issuer=$issuer'";
170 $a = rg_exec($cmd);
171 if ($a['ok'] != 1)
172 return FALSE;
173
174 return $a['data'];
175 }
176
177 /*
178 * Cosmetic fixes for a login token row
179 */
180 function rg_totp_cosmetic(&$row)
181 {
182 if (isset($row['itime']))
183 $row['itime_nice'] = gmdate('Y-m-d H:i', $row['itime']);
184
185 if (!isset($row['used']))
186 $row['used'] = 0;
187
188 if ($row['used'] > 0)
189 $row['used_nice'] = gmdate('Y-m-d H:i', $row['used']);
190 else
191 $row['used_nice'] = "n/a";
192
193 if (isset($row['conf'])) {
194 if (strcmp($row['conf'], 't') == 0)
195 $row['conf_nice'] = 'confirmed';
196 else
197 $row['conf_nice'] = 'pending';
198 }
199 }
200
201 /*
202 * Sets when a login token was last used
203 */
204 function rg_totp_set_last_use($db, $uid, $id, $ts)
205 {
206 rg_prof_start('totp_set_last_use');
207 rg_log_enter('totp_set_last_use uid=' . $uid . ' id=' . $id);
208
209 $ret = FALSE;
210 while (1) {
211 $params = array('uid' => $uid,
212 'id' => $id,
213 'used' => $ts);
214 $sql = 'UPDATE login_tokens SET used = @@used@@'
215 . ' WHERE uid = @@uid@@'
216 . ' AND id = @@id@@'
217 . ' AND used != @@used@@';
218 $res = rg_sql_query_params($db, $sql, $params);
219 if ($res === FALSE) {
220 rg_user_set_error('cannot update last used (' . rg_sql_error());
221 break;
222 }
223 rg_sql_free_result($res);
224
225 $key = 'user' . '::' . $uid . '::' . 'login_tokens'
226 . '::' . 'list' . '::' . $id . '::' . 'used';
227 $a = array('used' => $ts);
228 rg_totp_cosmetic($a);
229 rg_cache_merge($key, $a, RG_SOCKET_NO_WAIT);
230
231 $ret = TRUE;
232 break;
233 }
234
235 rg_log_exit();
236 rg_prof_end('totp_set_last_use');
237 return $ret;
238 }
239
240 /*
241 * Add a new secret login token to database
242 */
243 function rg_totp_enroll($db, $uid, $name, $secret, $ip, $conf)
244 {
245 rg_prof_start('totp_enroll');
246 rg_log_enter('totp_enroll name=' . $name);
247
248 $ret = FALSE;
249 while (1) {
250 $params = array('uid' => $uid, 'name' => $name,
251 'secret' => $secret,
252 'itime' => time(), 'ip' => $ip, 'conf' => $conf);
253 $sql = 'INSERT INTO login_tokens (uid, itime, name, secret, ip'
254 . ', conf)'
255 . ' VALUES (@@uid@@, @@itime@@, @@name@@'
256 . ', @@secret@@, @@ip@@, @@conf@@)'
257 . ' RETURNING id';
258 $res = rg_sql_query_params($db, $sql, $params);
259 if ($res === FALSE) {
260 rg_totp_set_error('cannot insert login token; try again later');
261 break;
262 }
263 $row = rg_sql_fetch_array($res);
264 rg_sql_free_result($res);
265
266 $params['id'] = $row['id'];
267 rg_totp_cosmetic($params);
268 $key = 'user' . '::' . $uid . '::' . 'login_tokens'
269 . '::' . 'list' . '::' . $params['id'];
270 rg_cache_set($key, $params, RG_SOCKET_NO_WAIT);
271
272 $ret = TRUE;
273 break;
274 }
275
276 rg_log_exit();
277 rg_prof_end('totp_enroll');
278 return $ret;
279 }
280
281 /*
282 * Confirm a SSH enrollment process
283 */
284 function rg_totp_conf($db, $uid, $id)
285 {
286 rg_prof_start('totp_conf');
287 rg_log_enter('totp_conf id=' . $id);
288
289 $ret = FALSE;
290 while (1) {
291 $params = array('uid' => $uid, 'id' => $id, 'conf' => 't');
292 $sql = 'UPDATE login_tokens SET conf = @@conf@@'
293 . ' WHERE uid = @@uid@@'
294 . ' AND id = @@id@@'
295 . ' AND conf != @@conf@@';
296 $res = rg_sql_query_params($db, $sql, $params);
297 if ($res === FALSE) {
298 rg_totp_set_error('cannot confirm login token; try again later');
299 break;
300 }
301 rg_sql_free_result($res);
302
303 $key = 'user' . '::' . $uid . '::' . 'login_tokens'
304 . '::' . 'list' . '::' . $params['id'];
305 $a = array('conf' => 't');
306 rg_totp_cosmetic($params);
307 rg_cache_merge($key, $a, RG_SOCKET_NO_WAIT);
308
309 $ret = TRUE;
310 break;
311 }
312
313 rg_log_exit();
314 rg_prof_end('totp_conf');
315 return $ret;
316 }
317
318 /*
319 * Returns a list of login tokens from database
320 */
321 function rg_totp_list($db, $uid)
322 {
323 rg_prof_start('totp_list');
324 rg_log_enter('totp_list');
325
326 while (1) {
327 $key = 'user' . '::' . $uid . '::' . 'login_tokens';
328 $ret = rg_cache_get($key);
329 if ($ret !== FALSE) {
330 $ret['ok'] = 1;
331 break;
332 }
333
334 $ret = array();
335 $ret['ok'] = 0;
336
337 $params = array('uid' => $uid);
338 $sql = 'SELECT * FROM login_tokens'
339 . ' WHERE uid = @@uid@@'
340 . ' ORDER BY itime';
341 $res = rg_sql_query_params($db, $sql, $params);
342 if ($res === FALSE) {
343 rg_totp_set_error('cannot load login tokens');
344 break;
345 }
346
347 $ret['list'] = array();
348 while (($row = rg_sql_fetch_array($res))) {
349 $id = $row['id'];
350
351 rg_totp_cosmetic($row);
352
353 $ret['list'][$id] = $row;
354 }
355 rg_sql_free_result($res);
356
357 rg_cache_set($key, $ret, RG_SOCKET_NO_WAIT);
358 $ret['ok'] = 1;
359 break;
360 }
361
362 rg_log_exit();
363 rg_prof_end('totp_list');
364 return $ret;
365 }
366
367 /*
368 * Remove a list of login tokens
369 */
370 function rg_totp_remove($db, $uid, $list)
371 {
372 rg_prof_start('totp_remove');
373 rg_log_enter('totp_remove uid=' . $uid
374 . ' list=' . rg_array2string($list));
375
376 $ret = FALSE;
377 while (1) {
378 if (empty($list)) {
379 rg_totp_set_error('you did not select anything');
380 break;
381 }
382
383 $my_list = array();
384 foreach ($list as $id => $junk)
385 $my_list[] = sprintf("%u", $id);
386
387 $params = array('uid' => $uid);
388 $sql_list = implode(', ', $my_list);
389 $sql = 'DELETE FROM login_tokens'
390 . ' WHERE uid = @@uid@@'
391 . ' AND id IN (' . $sql_list . ')';
392 $res = rg_sql_query_params($db, $sql, $params);
393 if ($res === FALSE) {
394 rg_totp_set_error('cannot remove login token ' . $id
395 . ' (' . rg_sql_error() . ')');
396 break;
397 }
398 rg_sql_free_result($res);
399
400 foreach ($my_list as $junk => $_id) {
401 $key = 'user' . '::' . $uid . '::' . 'login_tokens'
402 . '::' . 'list' . $_id;
403 rg_cache_unset($key, RG_SOCKET_NO_WAIT);
404 }
405
406 $ret = TRUE;
407 break;
408 }
409
410 rg_log_exit();
411 rg_prof_end('totp_remove');
412 return $ret;
413 }
414
415 /*
416 * High-level function for listing tokens
417 */
418 function rg_totp_list_high_level($db, $rg)
419 {
420 $ret = '';
421
422 $del_errmsg = array();
423 $rg['HTML:del_errmsg'] = '';
424 $rg['HTML:del_status'] = '';
425
426 $delete = rg_var_uint('delete');
427 while ($delete == 1) {
428 if (!rg_valid_referer()) {
429 $del_errmsg[] = 'invalid referer; try again';
430 break;
431 }
432
433 if (!rg_token_valid($db, $rg, 'login_tokens_list', FALSE)) {
434 $del_errmsg[] = 'invalid token; try again.';
435 break;
436 }
437
438 $list = rg_var_str("delete_list");
439 $r = rg_totp_remove($db, $rg['login_ui']['uid'], $list);
440 if ($r !== TRUE) {
441 $del_errmsg[] = 'cannot delete: ' . rg_totp_error();
442 break;
443 }
444
445 $rg['HTML:del_status'] = rg_template('user/settings/totp/delete_ok.html',
446 $rg, TRUE /*xss*/);
447 break;
448 }
449
450 $r = rg_totp_list($db, $rg['login_ui']['uid']);
451 if ($r['ok'] !== 1) {
452 $rg['totp_errmsg'] = rg_totp_error();
453 $ret .= rg_template('user/settings/totp/list_err.html',
454 $rg, TRUE /*xss*/);
455 } else {
456 $rg['rg_form_token'] = rg_token_get($db, $rg, 'login_tokens_list');
457 $rg['HTML:del_errmsg'] = rg_template_errmsg($del_errmsg);
458 $ret .= rg_template_table('user/settings/totp/list', $r['list'], $rg);
459 }
460
461 return $ret;
462 }
463
464 /*
465 * Main function for TOTP login token
466 */
467 function rg_totp_high_level($db, $rg)
468 {
469 rg_prof_start('totp_high_level');
470 rg_log_enter('totp_high_level');
471
472 $rg['totp'] = array();
473
474 $ret = '';
475 $errmsg = array();
476
477 $rg['totp']['name'] = rg_var_str('totp::name');
478
479 $enroll = rg_var_uint('enroll');
480 while ($enroll == 1) {
481 $name = rg_var_str('totp::name');
482 $ver = rg_var_str('totp::ver');
483 $secret = rg_var_str('totp::secret');
484
485 if (strlen($name) == 0) {
486 $errmsg[] = "invalid name";
487 break;
488 }
489
490 if (strlen($ver) != 6) {
491 $errmsg[] = "invalid number; you must enter a 6 digit number";
492 break;
493 }
494
495 if (!rg_valid_referer()) {
496 $errmsg[] = "invalid referer; try again";
497 break;
498 }
499
500 if (!rg_token_valid($db, $rg, 'user_totp', FALSE)) {
501 $errmsg[] = "invalid token; try again";
502 break;
503 }
504
505 $r = rg_totp_verify($secret, $ver);
506 if ($r === FALSE) {
507 $errmsg[] = rg_template('user/settings/totp/ver_error.html',
508 $rg, TRUE /*xss*/);
509 break;
510 }
511
512 $ip = $_SERVER['REMOTE_ADDR'];
513 $r = rg_totp_enroll($db, $rg['login_ui']['uid'],
514 $name, $secret, $ip, 't');
515 if ($r !== TRUE) {
516 $errmsg[] = rg_totp_error();
517 break;
518 }
519
520 $ret .= rg_template('user/settings/totp/enroll_ok.html',
521 $rg, TRUE /*xss*/);
522
523 break;
524 }
525
526 $ret .= rg_totp_list_high_level($db, $rg);
527
528 // defaults
529 if ($enroll == 0) {
530 $name = '';
531 $ver = '';
532 $secret = rg_totp_base32_generate(16);
533 }
534
535 $rg['totp']['name'] = $name;
536 $rg['totp']['ver'] = $ver;
537 $rg['totp']['secret'] = $secret;
538
539 $png = rg_totp_png($rg['totp']['secret']);
540 if ($png === FALSE) {
541 $rg['totp']['img'] = 0;
542 } else {
543 $rg['totp']['img'] = 1;
544 $rg['totp']['png'] = base64_encode($png);
545 }
546
547 $rg['HTML:errmsg'] = rg_template_errmsg($errmsg);
548
549 $rg['rg_form_token'] = rg_token_get($db, $rg, 'user_totp');
550 $ret .= rg_template('user/settings/totp/main.html', $rg, TRUE /*xss*/);
551
552 // hints
553 $hints = array();
554 $hints[]['HTML:hint'] = rg_template("user/settings/totp/hints.html", $rg, FALSE /*xss*/);
555 $ret .= rg_template_table("hints/list", $hints, $rg);
556
557 rg_log_exit();
558 rg_prof_end('totp_high_level');
559 return $ret;
560 }
561
562 ?>
File inc/user.inc.php changed (mode: 100644) (index e660e53..975e84f)
... ... require_once($INC . "/rights.inc.php");
8 8 require_once($INC . "/events.inc.php"); require_once($INC . "/events.inc.php");
9 9 require_once($INC . "/cache.inc.php"); require_once($INC . "/cache.inc.php");
10 10 require_once($INC . "/plan.inc.php"); require_once($INC . "/plan.inc.php");
11 require_once($INC . "/totp.inc.php");
11 12
12 13 $rg_user_rights = array( $rg_user_rights = array(
13 14 "C" => "Create repository", "C" => "Create repository",
 
... ... function rg_user_error()
42 43 */ */
43 44 $rg_user_functions = array( $rg_user_functions = array(
44 45 2000 => "rg_user_event_new", 2000 => "rg_user_event_new",
46 2001 => "rg_user_event_login",
45 47 2002 => "rg_user_event_notify_user", 2002 => "rg_user_event_notify_user",
46 48 2005 => "rg_user_event_rename", 2005 => "rg_user_event_rename",
47 49 2006 => "rg_user_link_by_name" 2006 => "rg_user_link_by_name"
 
... ... function rg_user_event_new($db, $event)
57 59
58 60 $event['op'] = "new"; $event['op'] = "new";
59 61 // create link by name // create link by name
60 $ret[] = array_merge($event, array("category" => 2006, "prio" => 200));
62 $ret[] = array_merge($event, array("category" => 2006, "prio" => 500));
61 63 // notify user // notify user
62 $ret[] = array_merge($event, array("category" => 2002, "prio" => 100));
64 $ret[] = array_merge($event, array("category" => 2002, "prio" => 200));
65
66 return $ret;
67 }
68
69 /*
70 * Event for login
71 */
72 function rg_user_event_login($db, $event)
73 {
74 $ret = FALSE;
75 while (1) {
76 $r = rg_user_set_last_seen($db, $event['uid'], $event['ts'],
77 $event['IP']);
78 if ($r !== TRUE)
79 break;
80
81 if ($event['used_login_token_id'] > 0) {
82 $r = rg_totp_set_last_use($db, $event['uid'],
83 $event['used_login_token_id'], $event['ts']);
84 if ($r !== TRUE)
85 break;
86 }
87
88 $ret = array();
89 break;
90 }
63 91
64 92 return $ret; return $ret;
65 93 } }
 
... ... function rg_user_info($db, $uid, $user, $email)
656 684 /* /*
657 685 * Update last_seen field * Update last_seen field
658 686 */ */
659 function rg_user_set_last_seen($db, $uid)
687 function rg_user_set_last_seen($db, $uid, $ts, $ip)
660 688 { {
661 rg_log_enter("user_set_last_seen: uid=$uid");
689 rg_log_enter("user_set_last_seen: uid=$uid ts=$ts");
662 690
663 691 $ret = FALSE; $ret = FALSE;
664 692 while (1) { while (1) {
665 $now = time();
666
667 $IP = $_SERVER['REMOTE_ADDR'];
668
669 $params = array("last_seen" => $now,
670 "last_ip" => $IP,
693 $params = array("last_seen" => $ts,
694 "last_ip" => $ip,
671 695 "uid" => $uid); "uid" => $uid);
672 $sql = "UPDATE users SET last_seen = @@last_seen@@"
673 . ", last_ip = @@last_ip@@"
674 . " WHERE uid = @@uid@@";
696 $sql = 'UPDATE users SET last_seen = @@last_seen@@'
697 . ', last_ip = @@last_ip@@'
698 . ' WHERE uid = @@uid@@'
699 . ' AND last_seen != @@last_seen@@';
675 700 $res = rg_sql_query_params($db, $sql, $params); $res = rg_sql_query_params($db, $sql, $params);
676 701 if ($res === FALSE) { if ($res === FALSE) {
677 702 rg_user_set_error("cannot update last seen (" . rg_sql_error() . ")"); rg_user_set_error("cannot update last seen (" . rg_sql_error() . ")");
 
... ... function rg_user_login_by_sid($db, &$rg)
715 740 break; break;
716 741
717 742 $sess = rg_sess_valid($db, $rg['sid']); $sess = rg_sess_valid($db, $rg['sid']);
718 if ($sess == FALSE) {
719 rg_log("session is not valid");
743 if ($sess == FALSE)
720 744 break; break;
721 }
722 745
723 746 $uid = $sess['uid']; $uid = $sess['uid'];
724 747 $rg['login_ui'] = rg_user_info($db, $uid, "", ""); $rg['login_ui'] = rg_user_info($db, $uid, "", "");
725 748 if ($rg['login_ui']['exists'] != 1) { if ($rg['login_ui']['exists'] != 1) {
726 rg_log("\tUid $uid does not exists (" . rg_user_error() . ")!");
749 rg_log("Uid $uid does not exists (" . rg_user_error() . ")!");
727 750 rg_user_set_error("invalid uid"); rg_user_set_error("invalid uid");
728 751 break; break;
729 752 } }
 
... ... function rg_user_login_by_sid($db, &$rg)
744 767 */ */
745 768 function rg_user_pass_valid($db, $uid, $pass) function rg_user_pass_valid($db, $uid, $pass)
746 769 { {
747 rg_log("user_pass_valid: uid=$uid, pass=$pass...");
770 rg_log_enter("user_pass_valid: uid=$uid, pass=$pass...");
748 771
749 if (empty($pass)) {
750 rg_user_set_error("password is empty");
751 return FALSE;
752 }
772 $ret = FALSE;
773 while (1) {
774 if (empty($pass)) {
775 rg_user_set_error("password is empty");
776 break;
777 }
753 778
754 $ui = rg_user_info($db, $uid, "", "");
755 if ($ui['exists'] != 1) {
756 rg_user_set_error("user does not exists");
757 return FALSE;
758 }
779 $ui = rg_user_info($db, $uid, "", "");
780 if ($ui['exists'] != 1) {
781 rg_user_set_error("user does not exists");
782 break;
783 }
759 784
760 $pass_hash = rg_user_pass($ui['salt'], $pass);
761 if (strcmp($pass_hash, $ui['pass']) != 0) {
762 rg_user_set_error("password is not ok");
763 return FALSE;
785 $pass_hash = rg_user_pass($ui['salt'], $pass);
786 if (strcmp($pass_hash, $ui['pass']) != 0) {
787 rg_user_set_error("password is not ok");
788 break;
789 }
790
791 rg_log("Pass is valid.");
792 $ret = TRUE;
793 break;
764 794 } }
765 795
766 rg_log("\tPass is valid.");
796 rg_log_exit();
767 797 return TRUE; return TRUE;
768 798 } }
769 799
 
... ... function rg_user_auto_login($db, $uid, $lock_ip, &$ui)
823 853 /* /*
824 854 * Test if login is OK * Test if login is OK
825 855 */ */
826 function rg_user_login_by_user_pass($db, $user, $pass, $lock_ip, &$ui)
856 function rg_user_login_by_user_pass($db, $user, $pass, $login_token, $lock_ip,
857 &$ui)
827 858 { {
828 859 rg_prof_start("user_login_by_user_pass"); rg_prof_start("user_login_by_user_pass");
829 860 rg_log_enter("user_login_by_user_pass: user=$user, pass=$pass" rg_log_enter("user_login_by_user_pass: user=$user, pass=$pass"
830 . " lock_ip=$lock_ip");
861 . " login_token=$login_token lock_ip=$lock_ip");
831 862
832 863 $ui = array(); $ui = array();
833 864 $ui['uid'] = 0; $ui['uid'] = 0;
 
... ... function rg_user_login_by_user_pass($db, $user, $pass, $lock_ip, &$ui)
837 868 $ret = FALSE; $ret = FALSE;
838 869 while (1) { while (1) {
839 870 if (empty($user) || empty($pass)) { if (empty($user) || empty($pass)) {
840 rg_user_set_error("invalid user or pass");
871 rg_user_set_error("invalid user, pass or login_token");
841 872 rg_log("user or pass are empty"); rg_log("user or pass are empty");
842 873 break; break;
843 874 } }
 
... ... function rg_user_login_by_user_pass($db, $user, $pass, $lock_ip, &$ui)
846 877 if ($ui0['ok'] != 1) if ($ui0['ok'] != 1)
847 878 break; break;
848 879 if ($ui0['exists'] != 1) { if ($ui0['exists'] != 1) {
849 rg_user_set_error("invalid user or pass");
880 rg_user_set_error("invalid user, pass or login_token");
850 881 rg_log("user doesn't exists"); rg_log("user doesn't exists");
851 882 break; break;
852 883 } }
853 884
854 885 if ($ui0['suspended'] > 0) { if ($ui0['suspended'] > 0) {
855 rg_user_set_error("invalid user or pass");
886 rg_user_set_error("invalid user, pass or login_token");
856 887 rg_log("account is suspended"); rg_log("account is suspended");
857 888 break; break;
858 889 } }
859 890
860 891 if ($ui0['confirmed'] == 0) { if ($ui0['confirmed'] == 0) {
861 rg_user_set_error("invalid user or pass");
892 rg_user_set_error("invalid user, pass or login_token");
862 893 rg_log("account is not confirmed"); rg_log("account is not confirmed");
863 894 break; break;
864 895 } }
865 896
866 897 $pass_hash = rg_user_pass($ui0['salt'], $pass); $pass_hash = rg_user_pass($ui0['salt'], $pass);
867 898 if (strcmp($pass_hash, $ui0['pass']) != 0) { if (strcmp($pass_hash, $ui0['pass']) != 0) {
868 rg_user_set_error("invalid user or pass");
899 rg_user_set_error("invalid user, pass or login token");
869 900 rg_log("pass mismatch db:" . $ui0['pass'] . " computed=$pass_hash"); rg_log("pass mismatch db:" . $ui0['pass'] . " computed=$pass_hash");
870 901 break; break;
871 902 } }
872 903
904 $lt = rg_totp_list($db, $ui0['uid']);
905 if ($lt['ok'] != 1) {
906 rg_user_set_error('login token error: ' . rg_totp_error());
907 break;
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 }
932 }
933
934 $event = array(
935 'category' => 2001,
936 'prio' => 100,
937 'uid' => $ui0['uid'],
938 'used_login_token_id' => $used_login_token_id,
939 'ts' => time());
940 $r = rg_event_add($db, $event);
941 if ($r !== TRUE) {
942 rg_user_set_error('internal error; try again later');
943 break;
944 }
945 rg_event_signal_daemon('', 0);
946
873 947 $ui = $ui0; $ui = $ui0;
874 948 rg_user_auto_login($db, $ui['uid'], $lock_ip, $ui); rg_user_auto_login($db, $ui['uid'], $lock_ip, $ui);
875 949
876 rg_user_set_last_seen($db, $ui['uid']);
877
878 950 $ret = TRUE; $ret = TRUE;
879 951 break; break;
880 952 } }
 
... ... function rg_user_forgot_pass_mail_prepare($db, $email)
1136 1208 while (1) { while (1) {
1137 1209 $r = rg_user_info($db, 0, "", $email); $r = rg_user_info($db, 0, "", $email);
1138 1210 if ($r['ok'] == 0) { if ($r['ok'] == 0) {
1139 rg_log("\tInternal error.");
1211 rg_log("Internal error.");
1140 1212 break; break;
1141 1213 } }
1142 1214 if ($r['exists'] == 0) { if ($r['exists'] == 0) {
1143 rg_log("\tUser does not exists.");
1215 rg_log("User does not exists.");
1144 1216 $ret['ok'] = 1; $ret['ok'] = 1;
1145 1217 break; break;
1146 1218 } }
 
... ... function rg_user_forgot_pass_mail($db, $email)
1185 1257 $ret['ok'] = 0; $ret['ok'] = 0;
1186 1258 $ret['exists'] = 0; $ret['exists'] = 0;
1187 1259
1188 $r = rg_user_forgot_pass_mail_prepare($db, $email);
1189 if ($r['exists'] != 1) {
1190 rg_log("\tUser does not exists.");
1191 return $r;
1192 }
1260 while (1) {
1261 $r = rg_user_forgot_pass_mail_prepare($db, $email);
1262 if ($r['exists'] != 1) {
1263 rg_log("User does not exists.");
1264 $ret = $r;
1265 break;
1266 }
1193 1267
1194 $ret['exists'] = 1;
1268 $ret['exists'] = 1;
1195 1269
1196 $headers = "From: $rg_admin_name <$rg_admin_email>";
1270 $headers = "From: $rg_admin_name <$rg_admin_email>";
1197 1271
1198 $base_url = rg_base_url();
1272 $base_url = rg_base_url();
1199 1273
1200 if (!mail($email,
1201 "Forgot password",
1202 "Hello!\n\n"
1203 . "If you want to reset the password, follow:\n"
1204 . $base_url
1205 . rg_re_url("/op/forgot_link") . "/" . $r['token']
1206 . "\n\nRocketGit team",
1207 $headers,
1208 "-f $rg_admin_email")) {
1209 rg_user_set_error("cannot send mail ($php_errormsg)!");
1210 return $ret;
1211 }
1274 if (!mail($email,
1275 "Forgot password",
1276 "Hello!\n\n"
1277 . "If you want to reset the password, follow:\n"
1278 . $base_url
1279 . rg_re_url("/op/forgot_link") . "/" . $r['token']
1280 . "\n\nRocketGit team",
1281 $headers,
1282 "-f $rg_admin_email")) {
1283 rg_user_set_error("cannot send mail ($php_errormsg)!");
1284 break;
1285 }
1212 1286
1213 $ret['ok'] = 1;
1287 $ret['ok'] = 1;
1288 break;
1289 }
1214 1290
1215 1291 rg_log("DEBUG: user_forgot_pass_mail: ret=" . rg_array2string($ret) . "."); rg_log("DEBUG: user_forgot_pass_mail: ret=" . rg_array2string($ret) . ".");
1292 rg_log_exit();
1216 1293 return $ret; return $ret;
1217 1294 } }
1218 1295
File inc/user/home-page.php changed (mode: 100644) (index d41adc9..cdbe2bb)
1 1 <?php <?php
2 2 rg_log("FILE: /inc/user/home-page"); rg_log("FILE: /inc/user/home-page");
3 3
4 $_home = "";
4 $_home = '';
5
6 $_home .= '<div class="main_title">Home page</div>';
5 7
6 8 $page_ui = rg_user_info($db, 0, $user, ""); $page_ui = rg_user_info($db, 0, $user, "");
7 9 if ($page_ui['exists'] == 0) { if ($page_ui['exists'] == 0) {
File inc/user/keys/keys.php changed (mode: 100644) (index b20dcf2..eb6ec36)
1 1 <?php <?php
2 2 rg_log("FILE: /inc/user/keys/keys"); rg_log("FILE: /inc/user/keys/keys");
3 3
4 $_keys = '';
5
4 6 $add_errmsg = array(); $add_errmsg = array();
5 7 $del_errmsg = array(); $del_errmsg = array();
6 8
7 $_keys = "";
8
9 $key = rg_var_str("key");
10 // TODO: should we accept UTF-8 chars (for comments)?
11 $key = preg_replace("|[^/A-Za-z0-9 @/+_\.\=,-]|", "", $key);
9 $key = trim(rg_var_str('key'));
10 $key = str_replace("\n", ' ', $key);
11 $key = str_replace("\r", ' ', $key);
12 12 $key_id = rg_var_uint("key_id"); $key_id = rg_var_uint("key_id");
13 13 $key_delete_ids = rg_var_str("key_delete_ids"); $key_delete_ids = rg_var_str("key_delete_ids");
14 14
15 $rg['HTML:status'] = "";
15 $rg['HTML:add_status'] = '';
16 $rg['HTML:del_status'] = '';
17
18 while (rg_var_uint("add") == 1) {
19 if (!rg_valid_referer()) {
20 $add_errmsg[] = "invalid referer; try again";
21 break;
22 }
23
24 if (!rg_token_valid($db, $rg, 'keys', FALSE)) {
25 $add_errmsg[] = "Invalid token. Try again.";
26 break;
27 }
28
29 $_r = rg_keys_add($db, $rg['login_ui'], $key);
30 if ($_r === FALSE) {
31 $add_errmsg[] = rg_keys_error();
32 break;
33 }
16 34
17 if (rg_var_uint("add") == 1) {
18 while (1) {
19 if (!rg_valid_referer()) {
20 $add_errmsg[] = "invalid referer; try again";
21 break;
22 }
35 $rg['HTML:add_status'] = rg_template("user/keys/add_ok.html", $rg, TRUE /* xss */);
36 $key = '';
37 break;
38 }
23 39
24 if (!rg_token_valid($db, $rg, 'keys', FALSE)) {
25 $add_errmsg[] = "Invalid token. Try again.";
26 break;
27 }
40 while (rg_var_uint("delete") == 1) {
41 if (!rg_valid_referer()) {
42 $del_errmsg[] = "invalid referer; try again";
43 break;
44 }
28 45
29 $_r = rg_keys_add($db, $rg['login_ui'], $key);
30 if ($_r === FALSE) {
31 $add_errmsg[] = rg_keys_error();
32 break;
33 }
46 if (!rg_token_valid($db, $rg, 'keys', FALSE)) {
47 $del_errmsg[] = "Invalid token. Try again.";
48 break;
49 }
34 50
35 $key = '';
51 if (empty($key_delete_ids)) {
52 $del_errmsg[] = "No key selected.";
36 53 break; break;
37 54 } }
38 } else if (rg_var_uint("delete") == 1) {
39 while (1) {
40 if (!rg_valid_referer()) {
41 $del_errmsg[] = "invalid referer; try again";
42 break;
43 }
44
45 if (!rg_token_valid($db, $rg, 'keys', FALSE)) {
46 $del_errmsg[] = "Invalid token. Try again.";
47 break;
48 }
49
50 if (empty($key_delete_ids)) {
51 $del_errmsg[] = "No key selected.";
52 break;
53 }
54
55 if (rg_keys_remove($db, $rg['login_ui'], $key_delete_ids) !== TRUE) {
56 $del_errmsg[] = rg_keys_error();
57 break;
58 }
59
60 $rg['HTML:status'] = rg_template("user/keys/remove_ok.html", $rg, TRUE /* xss */);
55
56 if (rg_keys_remove($db, $rg['login_ui'], $key_delete_ids) !== TRUE) {
57 $del_errmsg[] = rg_keys_error();
61 58 break; break;
62 59 } }
60
61 $rg['HTML:del_status'] = rg_template("user/keys/remove_ok.html", $rg, TRUE /* xss */);
62 break;
63 63 } }
64 64
65 65 $rg['HTML:add_errmsg'] = rg_template_errmsg($add_errmsg); $rg['HTML:add_errmsg'] = rg_template_errmsg($add_errmsg);
 
... ... $rg['HTML:del_errmsg'] = rg_template_errmsg($del_errmsg);
67 67
68 68 $rg['key'] = $key; $rg['key'] = $key;
69 69 $rg['rg_form_token'] = rg_token_get($db, $rg, 'keys'); $rg['rg_form_token'] = rg_token_get($db, $rg, 'keys');
70 $rg['HTML:add_form'] = rg_template("user/keys/add.html", $rg, TRUE /* xss */);
70 $rg['HTML:add_form'] = rg_template("user/keys/add.html", $rg, TRUE /*xss*/);
71 71
72 72 $keys_list = rg_keys_list($db, $rg['login_ui']); $keys_list = rg_keys_list($db, $rg['login_ui']);
73 73 if ($keys_list === FALSE) if ($keys_list === FALSE)
 
... ... if ($rg_ssh_port != 0)
80 80 $hints[]['HTML:hint'] = rg_template("hints/ssh/key.html", $rg, TRUE /* xss */); $hints[]['HTML:hint'] = rg_template("hints/ssh/key.html", $rg, TRUE /* xss */);
81 81 $rg['HTML:hints'] = rg_template_table("hints/list", $hints, $rg); $rg['HTML:hints'] = rg_template_table("hints/list", $hints, $rg);
82 82
83 $_keys = rg_template("user/keys/main.html", $rg, TRUE /* xss */);
83 $_keys .= rg_template('user/keys/main.html', $rg, TRUE /*xss*/);
84 84 ?> ?>
File inc/user/repo-page.php changed (mode: 100644) (index 1382e1c..71ca65c)
... ... rg_log("FILE: /inc/user/repo-page");
4 4 $_repo_page = ""; $_repo_page = "";
5 5
6 6 if (rg_user_ok($user) !== TRUE) { if (rg_user_ok($user) !== TRUE) {
7 $_repo_page .= rg_warning("Invalid user!");
7 $_repo_page .= rg_error("Invalid user!");
8 8 return; return;
9 9 } }
10 10 $rg['page_ui'] = rg_user_info($db, 0, $user, ""); $rg['page_ui'] = rg_user_info($db, 0, $user, "");
 
... ... if (strcmp($_subop, "history") == 0) {
134 134 $_repo_body .= rg_repo_admin($db, $rg, $paras); $_repo_body .= rg_repo_admin($db, $rg, $paras);
135 135 } else if (strcmp($_subop, "source") == 0) { } else if (strcmp($_subop, "source") == 0) {
136 136 $_subsubop = empty($paras) ? "" : array_shift($paras); $_subsubop = empty($paras) ? "" : array_shift($paras);
137 $rg['source_menu'][$_subsubop] = 1;
137 138
138 139 $type_ref = rg_git_parse_ref($paras); $type_ref = rg_git_parse_ref($paras);
139 140 $ref = $type_ref['ref_path']; $ref = $type_ref['ref_path'];
File inc/user/repo/bug/main.php changed (mode: 100644) (index 25642dd..cde045a)
... ... $_bug_body = "";
6 6 $rg['can_save'] = $rg['login_ui']['uid'] > 0 ? 1 : 0; $rg['can_save'] = $rg['login_ui']['uid'] > 0 ? 1 : 0;
7 7
8 8 $_op = empty($paras) ? "list" : array_shift($paras); $_op = empty($paras) ? "list" : array_shift($paras);
9 $rg['menu']['sub2'][$_op] = 1;
10
9 11 switch ($_op) { switch ($_op) {
10 12 case 'search': case 'search':
11 13 include($INC . "/user/repo/bug/search/search.php"); include($INC . "/user/repo/bug/search/search.php");
File inc/user/settings.php changed (mode: 100644) (index ded67c6..912c88f)
1 1 <?php <?php
2 2 rg_log("FILE: /inc/user/settings"); rg_log("FILE: /inc/user/settings");
3 3
4 $_settings = "";
4 $_settings = '';
5 5
6 6 if ($rg['login_ui']['uid'] == 0) { if ($rg['login_ui']['uid'] == 0) {
7 $_settings .= rg_warning("Error: not logged in.");
7 $_settings .= rg_template('user/login_first.html', $rg, TRUE /*xss*/);
8 8 return; return;
9 9 } }
10 10
 
... ... $rg['target_ui'] = $rg['login_ui'];
13 13 $errmsg = array(); $errmsg = array();
14 14
15 15 $_subop = empty($paras) ? "edit_info" : array_shift($paras); $_subop = empty($paras) ? "edit_info" : array_shift($paras);
16
17 $rg['set_menu'][$_subop] = 1;
18 $_settings = rg_template("user/settings/menu.html", $rg, TRUE /* xss */);
19
16 20 switch ($_subop) { switch ($_subop) {
17 21 case 'edit_info': case 'edit_info':
18 22 $rg['ask_for_pass'] = 0; $rg['ask_for_pass'] = 0;
 
... ... case 'keys':
29 33 include($INC . "/user/keys/keys.php"); include($INC . "/user/keys/keys.php");
30 34 $_settings .= $_keys; $_settings .= $_keys;
31 35 break; break;
32 }
33 36
34 $rg['menu']['sub1'][$_subop] = 1;
35 $rg['HTML:submenu1'] = rg_template("user/settings/menu.html", $rg, TRUE /* xss */);
37 case 'totp':
38 $_settings .= rg_totp_high_level($db, $rg);
39 break;
40 }
36 41
37 42 ?> ?>
File inc/util.inc.php changed (mode: 100644) (index cd8fde2..1671051)
... ... function rg_1024($v)
65 65 } }
66 66
67 67 /* /*
68 * Unique ID generator
68 * Returns a binary string of random bytes
69 69 */ */
70 function rg_id($len)
70 function rg_random_bytes($len)
71 71 { {
72 rg_prof_start("urandom");
72 rg_prof_start('random_bytes');
73 73
74 $id = "";
74 $ret = FALSE;
75 75
76 $f = @fopen("/dev/urandom", "r");
76 $f = @fopen('/dev/urandom', 'r');
77 77 if ($f !== NULL) { if ($f !== NULL) {
78 $buf = @fread($f, 128);
79 if ($buf !== NULL)
80 $id = sha512($buf);
78 $ret = @fread($f, $len);
81 79 fclose($f); fclose($f);
82 80 } }
83 81
84 if (empty($id))
85 $id = sha1(mt_rand() . serialize($_REQUEST));
82 if ($ret === FALSE) {
83 $ret = '';
84 for ($i = 0; $i < $len; $i++)
85 $ret .= rand(0, 255);
86 }
86 87
87 rg_prof_end("urandom");
88 return substr($id, 0, $len);
88 rg_prof_end('random_bytes');
89 return $ret;
90 }
91
92 /*
93 * Unique ID generator
94 */
95 function rg_id($len)
96 {
97 rg_prof_start('id');
98
99 $id = rg_random_bytes(($len + 1) / 2);
100 $id = bin2hex($id);
101 $id = substr($id, 0, $len);
102
103 rg_prof_end('id');
104 return $id;
89 105 } }
90 106
91 107 /* /*
 
... ... function rg_var_bool($name)
321 337 return 0; return 0;
322 338 } }
323 339
340 /*
341 * Allow only @re chars
342 */
324 343 function rg_var_re($name, $re) function rg_var_re($name, $re)
325 344 { {
326 345 $a = rg_var_str($name); $a = rg_var_str($name);
327 return preg_replace($re, '', $a);
346 return preg_replace('/[^' . $re . ']/', '', $a);
328 347 } }
329 348
330 349 /* /*
 
... ... function rg_theme_resolve_path($path)
405 424 global $rg_theme, $rg_theme_dir; global $rg_theme, $rg_theme_dir;
406 425
407 426 $url = "/themes/" . $rg_theme . "/" . $path; $url = "/themes/" . $rg_theme . "/" . $path;
408 $xfile = $rg_theme_dir . "/" . $rg_theme . "/" . $path;
409 if (!is_file($xfile))
410 $url = "/themes/default/" . $path;
427 $xfile = $rg_theme_dir . "/" . $rg_theme . "/" . $path;
428 if (!is_file($xfile))
429 $url = "/themes/default/" . $path;
411 430
412 return $url;
431 return $url;
413 432 } }
414 433
415 434 /* /*
 
... ... function rg_template_string(&$s, $off, &$data, $xss_protection)
674 693 { {
675 694 global $rg_template_functions; global $rg_template_functions;
676 695
677 rg_prof_start("rg_template_string");
696 rg_prof_start('template_string');
678 697 //rg_log_enter("DEBUG: template_string: s+off=[" . substr($s, $off) . "]"); //rg_log_enter("DEBUG: template_string: s+off=[" . substr($s, $off) . "]");
679 698
680 699 $ret = ''; $ret = '';
 
... ... function rg_template_string(&$s, $off, &$data, $xss_protection)
750 769
751 770 //rg_log("DEBUG: ret=[$ret]"); //rg_log("DEBUG: ret=[$ret]");
752 771 //rg_log_exit(); //rg_log_exit();
753 rg_prof_end("rg_template_string");
772 rg_prof_end('template_string');
754 773 return $ret; return $ret;
755 774 } }
756 775
 
... ... function rg_template($file, &$data, $xss_protection)
763 782 global $rg_theme_dir; global $rg_theme_dir;
764 783 global $rg_theme; global $rg_theme;
765 784
766 rg_prof_start("rg_template");
767 rg_log_enter("rg_template: $file");
785 rg_prof_start('template');
786 rg_log_enter('template: ' . $file);
768 787
769 788 $ret = ''; $ret = '';
770 789 while (1) { while (1) {
 
... ... function rg_template($file, &$data, $xss_protection)
789 808
790 809 //rg_log("DEBUG: rg_template returns [$ret]"); //rg_log("DEBUG: rg_template returns [$ret]");
791 810 rg_log_exit(); rg_log_exit();
792 rg_prof_end("rg_template");
811 rg_prof_end('template');
793 812 return $ret; return $ret;
794 813 } }
795 814
 
... ... function rg_template_table($dir, &$data, $more)
802 821 global $rg_theme_dir; global $rg_theme_dir;
803 822 global $rg_theme; global $rg_theme;
804 823
805 rg_log("rg_template_table: $dir");
824 rg_prof_start('template_table');
825 rg_log('template_table: ' . $dir);
806 826
807 827 $xdir = $rg_theme_dir . "/" . $rg_theme . "/" . $dir; $xdir = $rg_theme_dir . "/" . $rg_theme . "/" . $dir;
808 828 if (!is_dir($xdir)) { if (!is_dir($xdir)) {
 
... ... function rg_template_table($dir, &$data, $more)
811 831 rg_log("Using [$xdir]"); rg_log("Using [$xdir]");
812 832 } }
813 833
814 if (!is_array($data) || empty($data))
815 return rg_template($xdir . "/nodata.html", $more, TRUE /* xss */);
834 if (!is_array($data) || empty($data)) {
835 $ret = rg_template($xdir . "/nodata.html", $more, TRUE /* xss */);
836 rg_prof_end('template_table');
837 return $ret;
838 }
816 839
817 840 $head = rg_template($xdir . "/header.html", $more, TRUE /* xss */); $head = rg_template($xdir . "/header.html", $more, TRUE /* xss */);
818 841 $foot = rg_template($xdir . "/footer.html", $more, TRUE /* xss */); $foot = rg_template($xdir . "/footer.html", $more, TRUE /* xss */);
 
... ... function rg_template_table($dir, &$data, $more)
832 855 $body .= rg_template_string($line, 0, $more2, TRUE /* xss */); $body .= rg_template_string($line, 0, $more2, TRUE /* xss */);
833 856 } }
834 857
858 rg_prof_end('template_table');
835 859 return $head . $body . $foot; return $head . $body . $foot;
836 860 } }
837 861
 
... ... function rg_socket_send($socket, $buf)
1398 1422 /* /*
1399 1423 * Connects to a socket, send @buf and returns the answer. * Connects to a socket, send @buf and returns the answer.
1400 1424 * @timeout: NULL=forever, 0=no_wait * @timeout: NULL=forever, 0=no_wait
1401 is 0, we do not wait for an answer. If is NULL, we wait forever.
1402 1425 * @tries - how many time to retry if it fails * @tries - how many time to retry if it fails
1403 1426 */ */
1404 1427 function rg_socket($path, $buf, $timeout, $tries, $flags) function rg_socket($path, $buf, $timeout, $tries, $flags)
 
... ... function rg_valid_referer()
1485 1508 return FALSE; return FALSE;
1486 1509 } }
1487 1510
1511 /*
1512 * Returns the age of an object
1513 */
1514 function rg_age($ts)
1515 {
1516 $diff = time() - $ts;
1517
1518 $ret = ($diff % 60) . 's';
1519 $rest = intval($diff / 60);
1520 if ($rest == 0)
1521 return $ret;
1522
1523 $ret = ($diff % 60) . 'm' . $ret;
1524 $rest = intval($diff / 60);
1525 if ($rest == 0)
1526 return $ret;
1527
1528 $ret = ($diff % 24) . 'h' . $ret;
1529 $rest = intval($diff / 24);
1530 if ($rest == 0)
1531 return $ret;
1532
1533 $ret = ($diff % 12) . 'm' . $ret;
1534 $rest = intval($diff / 12);
1535 if ($rest == 0)
1536 return $ret;
1537
1538 $ret = $rest . 'y' . $ret;
1539
1540 return $ret;
1541 }
1542
1488 1543 ?> ?>
File root/index.php changed (mode: 100644) (index 2c9f130..726cced)
... ... $rg['login_ui'] = array();
49 49 $rg['target_ui'] = array("ok" => 1, "exists" => 0, "uid" => 0); $rg['target_ui'] = array("ok" => 1, "exists" => 0, "uid" => 0);
50 50 $rg['ri'] = array("repo_id" => 0, "uid" => 0); $rg['ri'] = array("repo_id" => 0, "uid" => 0);
51 51 $rg['bug'] = array("bug_id" => 0); $rg['bug'] = array("bug_id" => 0);
52 $rg['HTML:submenu1'] = "";
53 $rg['HTML:submenu2'] = "";
54 52 $rg['debug'] = rg_var_uint('rg_debug'); $rg['debug'] = rg_var_uint('rg_debug');
55 53
56 54 // We have variable 'vv' passed from webserver - build 'op' and rest of paras // We have variable 'vv' passed from webserver - build 'op' and rest of paras
 
... ... if (strcmp($_t, "op") == 0) {
68 66
69 67 $rg['doit'] = rg_var_uint("doit"); $rg['doit'] = rg_var_uint("doit");
70 68 $rg['sid'] = rg_var_cookie_re("sid", "/[^A-Za-z0-9]/"); $rg['sid'] = rg_var_cookie_re("sid", "/[^A-Za-z0-9]/");
71 $rg['token'] = rg_var_re("token", "/[^A-Za-z0-9]/");
69 $rg['token'] = rg_var_re("token", "A-Za-z0-9");
72 70 $user = ""; $repo = ""; $organization = 0; // TODO: those are really used? $user = ""; $repo = ""; $organization = 0; // TODO: those are really used?
73 71
74 72 //rg_log_ml("rg: " . print_r($rg, TRUE)); //rg_log_ml("rg: " . print_r($rg, TRUE));
File root/themes/default/access_denied.html changed (mode: 100644) (index e5e4ea1..96b6b16)
1 <div class="warning">
1 <div class="mess error">
2 2 Access is not allowed! Access is not allowed!
3 3 </div> </div>
File root/themes/default/admin/db_error.html changed (mode: 100644) (index 73148e6..dadf80c)
1 <div class="warning">
1 <div class="mess warning">
2 2 Cannot connect to database. Cannot connect to database.
3 3 </div> </div>
File root/themes/default/admin/invites/invites.html changed (mode: 100644) (index 811d082..0055581)
24 24
25 25 <p> <p>
26 26 <label for="file"> <label for="file">
27 File containing the body of the mail e-mail
27 File containing the body of the e-mail
28 28 ({NAME} will be replaced with the name defined above) ({NAME} will be replaced with the name defined above)
29 29 </label><br /> </label><br />
30 30 <input type="file" name="inv::file" id="file" size="80" /> <input type="file" name="inv::file" id="file" size="80" />
File root/themes/default/admin/invites/sent.html changed (mode: 100644) (index 78faea8..e43a419)
1 <div class="ok">
1 <div class="mess ok">
2 2 The invites were queued for sending. The invites were queued for sending.
3 3 </div> </div>
File root/themes/default/admin/menu.html changed (mode: 100644) (index 5629152..81e245e)
1 <div class="main_title">Admin</div>
2
1 3 <div class="menu menu2"> <div class="menu menu2">
2 4 <ul> <ul>
3 <li@@if(@@menu::sub1::plans@@ == 1){{ class="selected"}}{{}}><a href="/op/admin/plans">Plans</a></li>
4 <li@@if(@@menu::sub1::users@@ == 1){{ class="selected"}}{{}}><a href="/op/admin/users">Users</a></li>
5 <li@@if(@@menu::sub1::repos@@ == 1){{ class="selected"}}{{}}><a href="/op/admin/repos">Repos</a></li>
6 <li@@if(@@menu::sub1::invites@@ == 1){{ class="selected"}}{{}}><a href="/op/admin/invites">Invites</a></li>
5 <li@@if(@@admin_menu::plans@@ == 1){{ class="selected"}}{{}}><a href="/op/admin/plans">Plans</a></li>
6 <li@@if(@@admin_menu::users@@ == 1){{ class="selected"}}{{}}><a href="/op/admin/users">Users</a></li>
7 <li@@if(@@admin_menu::repos@@ == 1){{ class="selected"}}{{}}><a href="/op/admin/repos">Repos</a></li>
8 <li@@if(@@admin_menu::invites@@ == 1){{ class="selected"}}{{}}><a href="/op/admin/invites">Invites</a></li>
7 9 </ul> </ul>
8 10 </div> </div>
File root/themes/default/admin/plans/add_ok.html changed (mode: 100644) (index 870a1b6..b84a9a0)
1 <div class="ok">
1 <div class="mess ok">
2 2 Plan was added/edited with success. Plan was added/edited with success.
3 3 </div> </div>
File root/themes/default/admin/plans/list/nodata.html changed (mode: 100644) (index 760abd1..adc3941)
1 <div class="warning">
1 <div class="mess warning">
2 2 No plans defined yet. No plans defined yet.
3 3 </div> </div>
File root/themes/default/admin/plans/menu.html changed (mode: 100644) (index 8a5a811..831e245)
1 1 <div class="menu menu3"> <div class="menu menu3">
2 2 <ul> <ul>
3 <li@@if(@@menu::sub2::list@@ == 1){{ class="selected"}}{{}}><a href="/op/admin/plans/list">List</a></li>
4 <li@@if(@@menu::sub2::add@@ == 1){{ class="selected"}}{{}}><a href="/op/admin/plans/add">Add</a></li>
3 <li@@if(@@admin_plans_menu::list@@ == 1){{ class="selected"}}{{}}><a href="/op/admin/plans/list">List</a></li>
4 <li@@if(@@admin_plans_menu::add@@ == 1){{ class="selected"}}{{}}><a href="/op/admin/plans/add">Add</a></li>
5 5 </ul> </ul>
6 6 </div> </div>
File root/themes/default/admin/repos/menu.html changed (mode: 100644) (index 18fbfb4..ec39370)
1 1 <div class="menu menu3"> <div class="menu menu3">
2 2 <ul> <ul>
3 <li@@if(@@menu::sub2::list@@ == 1){{ class="selected"}}{{}}><a href="/op/admin/repos/list">List</a></li>
4 <li@@if(@@menu::sub2::add@@ == 1){{ class="selected"}}{{}}><a href="/op/admin/repos/add">Add</a></li>
3 <li@@if(@@admin_repos_menu::list@@ == 1){{ class="selected"}}{{}}><a href="/op/admin/repos/list">List</a></li>
4 <li@@if(@@admin_repos_menu::add@@ == 1){{ class="selected"}}{{}}><a href="/op/admin/repos/add">Add</a></li>
5 5 </ul> </ul>
6 6 </div> </div>
File root/themes/default/admin/users/bad_admin.html changed (mode: 100644) (index f231222..a7695d2)
1 <div class="warning">
1 <div class="mess warning">
2 2 Cannot upgrade account to admin level. Cannot upgrade account to admin level.
3 3 </div> </div>
File root/themes/default/admin/users/bad_remove.html changed (mode: 100644) (index b89abcb..2b795c0)
1 <div class="warning">
1 <div class="mess warning">
2 2 Cannot remove account. Cannot remove account.
3 3 </div> </div>
File root/themes/default/admin/users/bad_suspend.html changed (mode: 100644) (index f4930a2..2d335e2)
1 <div class="warning">
1 <div class="mess warning">
2 2 Cannot suspend account. Cannot suspend account.
3 3 </div> </div>
File root/themes/default/admin/users/bad_unadmin.html changed (mode: 100644) (index 6f67b9d..bca242d)
1 <div class="warning">
1 <div class="mess warning">
2 2 Cannot downgrade account from admin level. Cannot downgrade account from admin level.
3 3 </div> </div>
File root/themes/default/admin/users/bad_unsuspend.html changed (mode: 100644) (index d3d1965..7635684)
1 <div class="warning">
1 <div class="mess warning">
2 2 Cannot un-suspend account. Cannot un-suspend account.
3 3 </div> </div>
File root/themes/default/admin/users/menu.html changed (mode: 100644) (index a10e38c..2b55f10)
1 1 <div class="menu menu3"> <div class="menu menu3">
2 2 <ul> <ul>
3 <li@@if(@@menu::sub2::list@@ == 1){{ class="selected"}}{{}}><a href="/op/admin/users/list">List</a></li>
4 <li@@if(@@menu::sub2::add@@ == 1){{ class="selected"}}{{}}><a href="/op/admin/users/add">Add</a></li>
3 <li@@if(@@admin_users_menu::list@@ == 1){{ class="selected"}}{{}}><a href="/op/admin/users/list">List</a></li>
4 <li@@if(@@admin_users_menu::add@@ == 1){{ class="selected"}}{{}}><a href="/op/admin/users/add">Add</a></li>
5 5 </ul> </ul>
6 6 </div> </div>
File root/themes/default/donate.html changed (mode: 100644) (index 5f740cf..5dec535)
1 <div class="islands">
2 1 <div class="main_title">Donate</div> <div class="main_title">Donate</div>
3 2
3 <div class="islands">
4 4 <div class="island_row"> <div class="island_row">
5 5 <div class="island_cell"> <div class="island_cell">
6 6 <div class="island"> <div class="island">
File root/themes/default/download-vm.html changed (mode: 100644) (index c010e6f..d8d49f8)
1 <div class="islands">
2 1 <div class="main_title">Download - virtual machines</div> <div class="main_title">Download - virtual machines</div>
3 2
3 <div class="islands">
4 4 <div class="island_row"> <div class="island_row">
5 5 <div class="island_cell"> <div class="island_cell">
6 6 <div class="island"> <div class="island">
File root/themes/default/download.html changed (mode: 100644) (index abf99a1..c4a21ed)
1 <div class="islands">
2 1 <div class="main_title">Download</div> <div class="main_title">Download</div>
3 2
3 <div class="islands">
4 4 <div class="island_row"> <div class="island_row">
5 5 <div class="island_cell"> <div class="island_cell">
6 6 <div class="island"> <div class="island">
File root/themes/default/features.html changed (mode: 100644) (index 90d18fc..c5d2ab1)
1 <div class="islands">
2 1 <div class="main_title">Features</div> <div class="main_title">Features</div>
3 2
3 <div class="islands">
4 4 <div class="island_row"> <div class="island_row">
5 5 <div class="island_cell"> <div class="island_cell">
6 6 <div class="island"> <div class="island">
File root/themes/default/hints/repo/bug/add.html changed (mode: 100644) (index f3e5be8..a986adb)
1 TODO: Document here the use of labels.
1 Labels are a powerful way to assign some properties to a bug.<br />
2 When you search for a bug, you can filter also by labels.
File root/themes/default/index.html changed (mode: 100644) (index cdb2bf1..a348d65)
17 17 </div> </div>
18 18
19 19 <div class="main_menu"> <div class="main_menu">
20 @@if(@@login_ui::uid@@ != 0){{
21 <a href="@@login_ui::homepage@@">Me</a>
22 }}
20 23 <a href="/op/features">Features</a> <a href="/op/features">Features</a>
21 24 <a href="/op/discover">Discover</a> <a href="/op/discover">Discover</a>
22 25 <a href="/op/download">Download</a> <a href="/op/download">Download</a>
 
30 33 @@if(@@login_ui::is_admin@@ == 1){{<a href="/op/admin">Admin</a>}} @@if(@@login_ui::is_admin@@ == 1){{<a href="/op/admin">Admin</a>}}
31 34 <a href="/op/logout?token=@@logout_token@@">Logout</a> <a href="/op/logout?token=@@logout_token@@">Logout</a>
32 35 }}{{ }}{{
33 <a href="/op/login">Sign in</a>
34 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>
35 38 }} }}
36 39 </div> </div>
37 40 </div> </div>
38 41 </div> <!-- header --> </div> <!-- header -->
39 42
40 43 <div id="main_container"> <div id="main_container">
41 <div id="main_fake_table">
42 <div class="menus">
43 @@submenu1@@
44 @@submenu2@@
45 </div>
46
47 <div id="main">
48 @@rg_body@@
49 </div>
44 <div id="main">
45 @@rg_body@@
50 46 </div> </div>
51 47 </div> <!-- main_container --> </div> <!-- main_container -->
52 48
File root/themes/default/internal_err.html changed (mode: 100644) (index 826082f..46aeb83)
1 <div class="warning">
1 <div class="mess warning">
2 2 An internal error occurred. Please try again later. An internal error occurred. Please try again later.
3 3 </div> </div>
File root/themes/default/mail/user/key/new.body.txt changed (mode: 100644) (index 85f573e..44ba5f6)
1 1 Hello! Hello!
2 2
3 A new SSH key was added to your account.
4
3 A new SSH key was added to your account:
4 Type: @@ki::type@@
5 Comment: @@ki::comment@@
6 Fingerprint(md5): @@ki::fingerprint_md5@@
7 Fingerprint(sha256): @@ki::fingerprint_sha256@@
5 8 IP: @@IP@@ IP: @@IP@@
9 Key:
10 @@ki::key@@
6 11
7 12 -- --
8 13 RocketGit Team RocketGit Team
File root/themes/default/main.css changed (mode: 100644) (index 216038c..6ded205)
... ... form input[type="radio"] {
61 61 } }
62 62 form select option { padding: 1px 4px 1px 4px; } form select option { padding: 1px 4px 1px 4px; }
63 63 form input[type="submit"] { form input[type="submit"] {
64 color: red;
64 color: #F00;
65 65 display: inline-block; display: inline-block;
66 66 font-weight: bold; font-weight: bold;
67 67 font-size: 11pt; font-size: 11pt;
 
... ... legend { padding: 0px 2pt; }
80 80 width: 100%; width: 100%;
81 81 height: 100%; height: 100%;
82 82 display: table; display: table;
83 xxx-border-collapse: separate;
84 xxx-border-spacing: 10px;
83 85 } }
84 86
85 87 .logo { .logo {
 
... ... legend { padding: 0px 2pt; }
94 96 } }
95 97 .logo a { .logo a {
96 98 text-shadow: 0 0 2px yellow; text-shadow: 0 0 2px yellow;
97 color: red;
99 color: #F00;
98 100 font-size: 20pt; font-size: 20pt;
99 101 font-style: normal; font-style: normal;
100 102 } }
101 103
104
102 105 .main_menu { .main_menu {
103 106 padding: 6pt; padding: 6pt;
104 107 vertical-align: middle; vertical-align: middle;
 
... ... legend { padding: 0px 2pt; }
111 114 text-shadow: 0 0 2px #000; text-shadow: 0 0 2px #000;
112 115 padding: 6px; padding: 6px;
113 116 } }
114 .main_menu a:hover { color: #f00; }
117 .main_menu a:hover { color: #F00; }
115 118
116 119 .menus { .menus {
120 display: table-row;
117 121 } }
118 122
119 123 .menu { .menu {
 
... ... legend { padding: 0px 2pt; }
127 131 } }
128 132 .menu ul li a { .menu ul li a {
129 133 color: #FFF; color: #FFF;
130 font-size: 13pt;
134 font-size: 11pt;
131 135 font-weight: bold; font-weight: bold;
132 136 padding: 2px 15px; padding: 2px 15px;
133 137 text-shadow: 0 0 2px #000; text-shadow: 0 0 2px #000;
134 138 } }
135 .menu ul li a:hover { color: #f00; }
139 .menu ul li a:hover { color: #F00; }
136 140 .menu ul li.selected a { border-bottom: 2px solid #f00; } .menu ul li.selected a { border-bottom: 2px solid #f00; }
137
138 141 .menu2 { background-color: #AAA; } .menu2 { background-color: #AAA; }
139 .menu2 ul li.selected a { border-bottom: 2px solid #f00; }
140 .menu2 ul li.selected a:hover { color: red; }
141
142 142 .menu3 { background-color: #BBB; } .menu3 { background-color: #BBB; }
143 .menu3 ul li.selected a { border-bottom: 2px solid #f00; }
144 .menu3 ul li.selected a:hover { color: red; }
143
145 144
146 145 .main_title { .main_title {
147 146 margin-bottom: 10px; margin-bottom: 10px;
148 color: red;
147 color: #F00;
149 148 font-size: 20pt; font-size: 20pt;
150 149 font-weight: bold; font-weight: bold;
151 150 padding-bottom: 5px; padding-bottom: 5px;
152 border-bottom: 2px solid red;
151 border-bottom: 2px solid #F00;
153 152 } }
154 153
155 154 .junk {} .junk {}
 
... ... legend { padding: 0px 2pt; }
157 156 .branches_and_tags { padding: 3px 0px; margin: 3px 0px; } .branches_and_tags { padding: 3px 0px; margin: 3px 0px; }
158 157 .branches_and_tags a { .branches_and_tags a {
159 158 padding: 3px 3px; padding: 3px 3px;
160 color: black;
159 color: #000;
161 160 border: 1px solid #cccccc; border: 1px solid #cccccc;
162 161 border-radius: 4px 4px 4px 4px; border-radius: 4px 4px 4px 4px;
163 162 font-size: 10pt; font-size: 10pt;
 
... ... legend { padding: 0px 2pt; }
172 171 } }
173 172
174 173 #main { #main {
174 margin-top: 10px;
175 margin-left: auto;
176 margin-right: auto;
175 177 padding: 10px 15px; padding: 10px 15px;
176 178 line-height: 120%; line-height: 120%;
177 display: table-cell;
178 }
179
180 #main_fake_table {
181 179 display: table; display: table;
182 180 } }
183 181
 
... ... legend { padding: 0px 2pt; }
265 263 overflow: hidden; overflow: hidden;
266 264 } }
267 265
268 .error {
269 font-weight: bold;
270 color: red;
271 }
272
273 266 .rg_keys_list { .rg_keys_list {
274 267 margin-top: 20px; margin-top: 20px;
275 268 } }
276 269
277 270 .rg_plans_list {} .rg_plans_list {}
278 271
272 .rg_totp_list {
273 margin-top: 20px;
274 }
275
279 276 .blob_title { .blob_title {
280 277 font-size: 11pt; font-size: 11pt;
281 color: red;
278 color: #F00;
282 279 } }
283 280
284 281 .source { .source {
 
... ... legend { padding: 0px 2pt; }
322 319 background-color: #eee; background-color: #eee;
323 320 } }
324 321
325 .submenu {
326 background-color: #999999;
327 display: block;
328 padding-left: 5px;
329 }
330 .submenu ul li {}
331
332 322 .repo_container { } .repo_container { }
333 323
334 324 .repo_header { } .repo_header { }
 
... ... legend { padding: 0px 2pt; }
365 355 white-space: nowrap; white-space: nowrap;
366 356 } }
367 357
368 .form_error { margin-top: 6pt; color: red; }
358 .form_error { margin-top: 6pt; color: #F00; }
369 359 .form_error b { font-weight: bold; font-size: 11pt; } .form_error b { font-weight: bold; font-size: 11pt; }
370 360 .form_error p { padding-left: 15pt; } .form_error p { padding-left: 15pt; }
371 361
 
... ... legend { padding: 0px 2pt; }
374 364 .labels ul li { .labels ul li {
375 365 display: inline; display: inline;
376 366 padding: 3px 3px; padding: 3px 3px;
377 color: black;
367 color: #000;
378 368 border: 1px solid #cccccc; border: 1px solid #cccccc;
379 369 border-radius: 4px 4px 4px 4px; border-radius: 4px 4px 4px 4px;
380 370 font-size: 10pt; font-size: 10pt;
 
... ... legend { padding: 0px 2pt; }
386 376 .searches ul li { .searches ul li {
387 377 display: inline; display: inline;
388 378 padding: 3px 3px; padding: 3px 3px;
389 color: black;
379 color: #000;
390 380 border: 1px solid #cccccc; border: 1px solid #cccccc;
391 381 border-radius: 4px 4px 4px 4px; border-radius: 4px 4px 4px 4px;
392 382 font-size: 9pt; font-size: 9pt;
 
... ... legend { padding: 0px 2pt; }
403 393 font-size: 9pt; font-size: 9pt;
404 394 box-shadow: 0px 2px 3px #666666; box-shadow: 0px 2px 3px #666666;
405 395 } }
406 .hints ul { list-style-type: none; }
396 .hints ul { list-style-type: square; margin-left: 9pt; }
407 397 .hints ul li { } .hints ul li { }
408 398 .hints ul li a { } .hints ul li a { }
409 399
 
... ... legend { padding: 0px 2pt; }
446 436 margin-top: 3px; margin-top: 3px;
447 437 } }
448 438
449 .warning {
439 .mess {
450 440 margin-top: 5px; margin-top: 5px;
451 background-color: #CCC;
452 441 padding: 5px; padding: 5px;
453 border: 1px solid red;
454 color: red;
455 442 display: table; display: table;
456 443 box-shadow: 0px 2px 3px #666666; box-shadow: 0px 2px 3px #666666;
457 444 } }
458 445
446 .error {
447 background-color: #F00;
448 border: 1px solid #000;
449 color: #000;
450 }
451
452 .warning {
453 background-color: #CCC;
454 border: 1px solid #F00;
455 color: #F00;
456 }
457
459 458 .ok { .ok {
460 margin-top: 5px;
461 padding: 5px;
459 background-color: #8F8;
462 460 border: 1px solid #FFF; border: 1px solid #FFF;
463 461 color: #000; color: #000;
464 display: table;
465 box-shadow: 0px 2px 3px #666666;
466 462 } }
467 463
468 464 .page_title { .page_title {
 
... ... legend { padding: 0px 2pt; }
496 492 } }
497 493
498 494 .island_title { .island_title {
499 color: red;
495 color: #F00;
500 496 font-size: 14pt; font-size: 14pt;
501 497 font-weight: bold; font-weight: bold;
502 498 padding-bottom: 9px; padding-bottom: 9px;
503 499 } }
500
501 .secret_token {
502 font-size: 14pt;
503 font-weight: bold;
504 border: 1px solid #00F;
505 padding: 5pt;
506 margin: 5pt 0pt;
507 }
508
509 .page_description {
510 margin: 5pt 0pt;
511 }
File root/themes/default/main.html changed (mode: 100644) (index 679d243..8263e9a)
1 1 <div class="islands"> <div class="islands">
2
3 2 <div class="island_row"> <div class="island_row">
4 3 <div class="island_cell"> <div class="island_cell">
5 4 <div class="island" style="background-color: #aaa; color: #fff"> <div class="island" style="background-color: #aaa; color: #fff">
File root/themes/default/ok.html changed (mode: 100644) (index 061a39c..81ed918)
1 <div class="ok">@@msg@@</div>
1 <div class="mess ok">@@msg@@</div>
File root/themes/default/pricing.html changed (mode: 100644) (index 0bed3ef..ca36050)
1 <div class="islands">
2 1 <div class="main_title">Pricing</div> <div class="main_title">Pricing</div>
3 2
3 <div class="islands">
4 4 <div class="island_row"> <div class="island_row">
5 5 <div class="island_cell"> <div class="island_cell">
6 6 <div class="island"> <div class="island">
 
21 21 <div class="island_cell"> <div class="island_cell">
22 22 <div class="island"> <div class="island">
23 23 <div class="island_title">Free support</div> <div class="island_title">Free support</div>
24 Contact us at support@rocketgit.com for
25 best-effort (no guaranteed response time) support.
24 Contact us at
25 <a href="mailto:support@rocketgit.com">support@rocketgit.com</a>
26 for best-effort (no guaranteed response time) support.
26 27 In the near future we will also setup a mailing list for support. In the near future we will also setup a mailing list for support.
27 28 </div> </div>
28 29 </div> </div>
 
33 34 <div class="island"> <div class="island">
34 35 <div class="island_title">Paid support</div> <div class="island_title">Paid support</div>
35 36 If you need guaranteed response time or 24/7, If you need guaranteed response time or 24/7,
36 please contact us at paid-support@rocketgit.com
37 please contact us at
38 <a href="mailto:paid-support@rocketgit.com">paid-support@rocketgit.com</a>
37 39 for a personalized offer. for a personalized offer.
38 40 </div> </div>
39 41 </div> </div>
File root/themes/default/repo/add_edit.html changed (mode: 100644) (index f26e973..fcdca7d)
14 14
15 15 <p> <p>
16 16 <label for="name">Name</label><br /> <label for="name">Name</label><br />
17 <input type="text" name="name" id="name" value="@@ri::name@@" />
17 <input type="text" name="name" id="name" value="@@ri::name@@" autocomplete="off" />
18 18 </p> </p>
19 19
20 20 <p> <p>
File root/themes/default/repo/bug/bug_add_edit.html changed (mode: 100644) (index 81771fe..dd8943a)
11 11
12 12 <p> <p>
13 13 <label for="title">Title</label><br /> <label for="title">Title</label><br />
14 <input type="text" name="title" id="title" value="@@bug::title@@" size="80" />
14 <input type="text" name="title" id="title" value="@@bug::title@@" size="80" autocomplete="off" />
15 15 </p> </p>
16 16
17 17 <p> <p>
File root/themes/default/repo/bug/deleted.html changed (mode: 100644) (index 0680a08..cf4b8f4)
1 <div class="error">
1 <div class="mess error">
2 2 This bug was deleted. This bug was deleted.
3 3 </div> </div>
File root/themes/default/repo/bug/deny_close.html changed (mode: 100644) (index 030b690..40c8ea6)
1 <div class="error">
1 <div class="mess error">
2 2 You are not allowed to close bugs. You are not allowed to close bugs.
3 3 </div> </div>
File root/themes/default/repo/bug/deny_delete.html changed (mode: 100644) (index a5b5f33..8d81ad8)
1 <div class="error">
1 <div class="mess error">
2 2 You are not allowed to delete bugs. You are not allowed to delete bugs.
3 3 </div> </div>
File root/themes/default/repo/bug/deny_edit.html changed (mode: 100644) (index 6284a8c..fe31d74)
1 <div class="error">
1 <div class="mess error">
2 2 You are not allowed to edit this bug. You are not allowed to edit this bug.
3 3 </div> </div>
File root/themes/default/repo/bug/deny_reopen.html changed (mode: 100644) (index 1db3cde..52fce09)
1 <div class="error">
1 <div class="mess error">
2 2 You are not allowed to reopen bugs. You are not allowed to reopen bugs.
3 3 </div> </div>
File root/themes/default/repo/bug/list/nodata.html changed (mode: 100644) (index e510296..5a9a182)
1 <div class="ok">
1 <div class="mess ok">
2 2 No bugs found. No bugs found.
3 3 </div> </div>
File root/themes/default/repo/bug/main.html changed (mode: 100644) (index 320e8a7..1804d0a)
1 <div class="menu submenu">
1 <div class="menu menu3">
2 2 <ul> <ul>
3 <li><a href="@@url_repo@@/bug">List</a></li>
4 <li><a href="@@url_repo@@/bug/add">Add</a></li>
5 <li><a href="@@url_repo@@/bug/search">Search</a></li>
3 <li@@if(@@menu::sub2::list@@ == 1){{ class="selected"}}><a href="@@url_repo@@/bug">List</a></li>
4 <li@@if(@@menu::sub2::add@@ == 1){{ class="selected"}}><a href="@@url_repo@@/bug/add">Add</a></li>
5 <li@@if(@@menu::sub2::search@@ == 1){{ class="selected"}}><a href="@@url_repo@@/bug/search">Search</a></li>
6 6 </ul> </ul>
7 7 </div> </div>
8 8
File root/themes/default/repo/bug/not_found.html changed (mode: 100644) (index f794458..709f4bc)
1 <div class="warning">
1 <div class="mess warning">
2 2 Bug <b>@@bug::bug_id@@</b> not found. Bug <b>@@bug::bug_id@@</b> not found.
3 3 </div> </div>
File root/themes/default/repo/create_ok.html changed (mode: 100644) (index 6c59536..716e39d)
1 <div class="ok">
1 <div class="mess ok">
2 2 Repository was created with success. Repository was created with success.
3 3 Click <a href="@@ri::home@@">here</a> to go to the repository home. Click <a href="@@ri::home@@">here</a> to go to the repository home.
4 4 </div> </div>
File root/themes/default/repo/edit_ok.html changed (mode: 100644) (index ad9792e..1872486)
1 <div class="ok">
1 <div class="mess ok">
2 2 Repository was updated with success. Repository was updated with success.
3 3 @@if(@@ri::renamed@@ == 1){{Go to new home <a href="@@ri::home@@">here</a>}}{{}} @@if(@@ri::renamed@@ == 1){{Go to new home <a href="@@ri::home@@">here</a>}}{{}}
4 4 </div> </div>
File root/themes/default/repo/fstat/nodata.html changed (mode: 100644) (index 028c426..0c33f68)
1 <div class="ok">
1 <div class="mess ok">
2 2 No file changed. No file changed.
3 3 </div> </div>
File root/themes/default/repo/history/nodata.html changed (mode: 100644) (index 75b9e0b..04e480c)
1 <div class="ok">
1 <div class="mess ok">
2 2 No history found. No history found.
3 3 </div> </div>
File root/themes/default/repo/invalid.html changed (mode: 100644) (index ca080a3..030c6a9)
1 <div class="warning">
1 <div class="mess warning">
2 2 Invalid repository name. Invalid repository name.
3 3 </div> </div>
File root/themes/default/repo/list/header.html changed (mode: 100644) (index 399854e..d434a3a)
1 <div class="page_title">Repositories</div>
2 1 <table summary="repos list"> <table summary="repos list">
3 2 <tr> <tr>
4 3 <th>User / name</th> <th>User / name</th>
File root/themes/default/repo/list/nodata.html changed (mode: 100644) (index a9cbe64..d752a71)
1 <div class="ok">
1 <div class="mess ok">
2 2 No repositories found. No repositories found.
3 3 </div> </div>
File root/themes/default/repo/log/nodata.html changed (mode: 100644) (index 227cb23..cefc62b)
1 <div class="ok">
1 <div class="mess ok">
2 2 No commit found. No commit found.
3 3 </div> </div>
File root/themes/default/repo/main.html changed (mode: 100644) (index 7174563..f30a8ed)
13 13 @@urls@@ @@urls@@
14 14 </div> </div>
15 15
16 <div class="menu submenu">
16 <div class="menu menu2">
17 17 <ul> <ul>
18 18 <li@@if(@@per_repo_menu::history@@ == 1){{ class="selected"}}{{}}><a href="@@url_repo@@/history">Last events</a></li> <li@@if(@@per_repo_menu::history@@ == 1){{ class="selected"}}{{}}><a href="@@url_repo@@/history">Last events</a></li>
19 19 <li@@if(@@per_repo_menu::source@@ == 1){{ class="selected"}}{{}}><a href="@@url_repo@@/source">Source</a></li> <li@@if(@@per_repo_menu::source@@ == 1){{ class="selected"}}{{}}><a href="@@url_repo@@/source">Source</a></li>
File root/themes/default/repo/menu.html changed (mode: 100644) (index 7d89af9..eea31e0)
1 <div class="main_title">My repositories</div>
2
1 3 <div class="menu menu2"> <div class="menu menu2">
2 4 <ul> <ul>
3 <li@@if(@@menu::sub1::list@@ == 1){{ class="selected"}}{{}}>
5 <li@@if(@@repo_menu::list@@ == 1){{ class="selected"}}>
4 6 <a href="/op/repo/list">List</a> <a href="/op/repo/list">List</a>
5 7 </li> </li>
6 8 @@if(@@login_ui::uid@@ != 0){{ @@if(@@login_ui::uid@@ != 0){{
7 <li@@if(@@menu::sub1::create@@ == 1){{ class="selected"}}{{}}>
9 <li@@if(@@repo_menu::create@@ == 1){{ class="selected"}}>
8 10 <a href="/op/repo/create">Create</a> <a href="/op/repo/create">Create</a>
9 11 </li> </li>
10 }}{{
11 12 }} }}
12 <li@@if(@@menu::sub1::search@@ == 1){{ class="selected"}}{{}}>
13 <li@@if(@@repo_menu::search@@ == 1){{ class="selected"}}>
13 14 <a href="/op/repo/search">Search</a> <a href="/op/repo/search">Search</a>
14 15 </li> </li>
15 16 </ul> </ul>
File root/themes/default/repo/mr/list/nodata.html changed (mode: 100644) (index ba2dc17..e76821a)
1 <div class="ok">
1 <div class="mess ok">
2 2 No merge requests found. No merge requests found.
3 3 </div> </div>
File root/themes/default/repo/no_git_dir.html changed (mode: 100644) (index 6084e41..09ff921)
1 <div class="warning">
1 <div class="mess warning">
2 2 The git dir for this repo was not yet created. Please retry. The git dir for this repo was not yet created. Please retry.
3 3 </div> </div>
File root/themes/default/repo/not_init.html changed (mode: 100644) (index 0e8070c..053a92c)
1 <div class="ok">
1 <div class="mess ok">
2 2 This repo contains no commits. This repo contains no commits.
3 3 </div> </div>
File root/themes/default/repo/source.html changed (mode: 100644) (index e3d9cd4..7274019)
1 1 @@branches_and_tags@@ @@branches_and_tags@@
2 2
3 <div class="menu submenu">
3 <div class="menu menu3">
4 4 <ul> <ul>
5 <li><a href="@@url_repo@@/source/log@@ref_url@@">Log</a></li>
6 <li><a href="@@url_repo@@/source/tree@@ref_url@@">Tree</a></li>
5 <li@@if(@@source_menu::log@@ == 1){{ class="selected"}}><a href="@@url_repo@@/source/log@@ref_url@@">Log</a></li>
6 <li@@if(@@source_menu::tree@@ == 1){{ class="selected"}}><a href="@@url_repo@@/source/tree@@ref_url@@">Tree</a></li>
7 7 </ul> </ul>
8 8 </div> </div>
File root/themes/default/repo/tree/nodata.html changed (mode: 100644) (index 056eb0c..3d2cd5d)
1 <div class="ok">
1 <div class="mess ok">
2 2 Tree is empty or an error occurred. Tree is empty or an error occurred.
3 3 </div> </div>
File root/themes/default/suggestion_sent.html changed (mode: 100644) (index 8881c85..a70dd7a)
1 <div class="ok">Suggestion sent. Thank you very much!</div>
1 <div class="mess ok">Suggestion sent. Thank you very much!</div>
File root/themes/default/tos.html changed (mode: 100644) (index 6bf4d0d..34f31b4)
1 <div class="islands">
2 1 <div class="main_title">Terms of service</div> <div class="main_title">Terms of service</div>
3 2
3 <div class="islands">
4 4 <div class="island_row"> <div class="island_row">
5 5 <div class="island_cell"> <div class="island_cell">
6 6 <div class="island"> <div class="island">
 
19 19 - You must understand that we cannot review all content hosted here, - You must understand that we cannot review all content hosted here,
20 20 therefore you agree to be exposed to any type of content. therefore you agree to be exposed to any type of content.
21 21 Do note that we do not endorse any illegal content hosted on our Do note that we do not endorse any illegal content hosted on our
22 servers and we encourages you to report it to us.<br />
22 servers and we encourage you to report it to us.<br />
23 23
24 24 - There is no warranty for this service to the extent permitted by - There is no warranty for this service to the extent permitted by
25 25 applicable law. Except when otherwise stated in writing we provide applicable law. Except when otherwise stated in writing we provide
26 26 the service "as is" without warranty of any kind, either expressed the service "as is" without warranty of any kind, either expressed
27 or implied, including bu not limited to, the implied warranties of
27 or implied, including but not limited to, the implied warranties of
28 28 merchantability and fitness for a particular purpose. The entire merchantability and fitness for a particular purpose. The entire
29 29 risk as to the quality and performance of the service is with you. risk as to the quality and performance of the service is with you.
30 30 Should the service prove defective, you assume the cost of all Should the service prove defective, you assume the cost of all
 
58 58 - You must not harass or bully other users.<br /> - You must not harass or bully other users.<br />
59 59
60 60 - Note that our site may be visited also by children, therefore - Note that our site may be visited also by children, therefore
61 you must adapt you attitude and language.<br />
61 you must adapt your attitude and language.<br />
62 62
63 63 - You must keep your account secure; you are fully responsible for - You must keep your account secure; you are fully responsible for
64 64 all the activities made under your account.<br /> all the activities made under your account.<br />
File root/themes/default/user/add_edit.html changed (mode: 100644) (index 4334981..6a6f951)
58 58 <input type="text" name="session_time" id="session_time" value="@@session_time@@" /> <input type="text" name="session_time" id="session_time" value="@@session_time@@" />
59 59 </p> </p>
60 60
61 @@if(@@no_tos@@ == 0){{
61 62 <fieldset> <fieldset>
62 63 <legend>Do you agree with our <a href="/op/tos" target="_blank">Terms of service</a>?</legend> <legend>Do you agree with our <a href="/op/tos" target="_blank">Terms of service</a>?</legend>
63 64 <input type="radio" name="tos" id="tos_yes" value="1"@@if(@@tos@@ == 1){{checked="checked"}}{{}} /> <input type="radio" name="tos" id="tos_yes" value="1"@@if(@@tos@@ == 1){{checked="checked"}}{{}} />
 
66 67 <input type="radio" name="tos" id="tos_no" value="0" @@if(@@tos@@ == 0){{checked="checked"}}{{}}/> <input type="radio" name="tos" id="tos_no" value="0" @@if(@@tos@@ == 0){{checked="checked"}}{{}}/>
67 68 <label for="tos_no">I do NOT agree</label> <label for="tos_no">I do NOT agree</label>
68 69 </fieldset> </fieldset>
70 }}
69 71
70 72 <input type="submit" value="@@if(@@create_mode@@ == 1){{Create}}{{Edit}}" /> <input type="submit" value="@@if(@@create_mode@@ == 1){{Create}}{{Edit}}" />
71 73 </form> </form>
File root/themes/default/user/bad_token.html changed (mode: 100644) (index 2bc6b10..f6135f9)
1 <div class="warning">
1 <div class="mess warning">
2 2 Invalid token. Invalid token.
3 3 </div> </div>
File root/themes/default/user/create_na.html changed (mode: 100644) (index fe39c81..e566b99)
1 <div class="warning">
1 <div class="mess warning">
2 2 This site does not allow account creation. Talk with the Admin. This site does not allow account creation. Talk with the Admin.
3 3 </div> </div>
File root/themes/default/user/create_ok.html changed (mode: 100644) (index 650cefb..d443be1)
1 <div class="ok">
1 <div class="mess ok">
2 2 Your account was created. Your account was created.
3 3 @@if(@@rg_account_email_confirm@@ == 1){{ @@if(@@rg_account_email_confirm@@ == 1){{
4 4 <br />You must confirm the account before you can login. <br />You must confirm the account before you can login.
File root/themes/default/user/edit_ok.html changed (mode: 100644) (index 76ab87e..22b3311)
1 <div class="ok">
1 <div class="mess ok">
2 2 Information was updated with success. Information was updated with success.
3 3 </div> </div>
File root/themes/default/user/email_conf.html changed (mode: 100644) (index 3aa3083..52e6d34)
1 <div class="ok">
1 <div class="mess ok">
2 2 Check your e-mail and follow the link inside it. Check your e-mail and follow the link inside it.
3 3 </div> </div>
File root/themes/default/user/invalid.html changed (mode: 100644) (index 8d1424e..0977b5a)
1 <div class="warning">
1 <div class="mess error">
2 2 Invalid user. Invalid user.
3 3 </div> </div>
File root/themes/default/user/keys/add.html changed (mode: 100644) (index 21a2d1d..0907d92)
9 9 <input type="hidden" name="token" value="@@rg_form_token@@" /> <input type="hidden" name="token" value="@@rg_form_token@@" />
10 10
11 11 <p> <p>
12 <label for="key">Key string (starts with ssh-...)</label><br />
12 <label for="key">Key string (starts with ssh- or with ecdsa-)</label><br />
13 13 <textarea name="key" id="key" rows="6" cols="80">@@key@@</textarea> <textarea name="key" id="key" rows="6" cols="80">@@key@@</textarea>
14 14 </p> </p>
15 15
File root/themes/default/user/keys/add_ok.html added (mode: 100644) (index 0000000..f066e8c)
1 <div class="mess ok">
2 Key added with success.
3 </div>
File root/themes/default/user/keys/list/header.html changed (mode: 100644) (index f5056b9..4a9921a)
1 1 <div class="rg_keys_list"> <div class="rg_keys_list">
2 2
3 3 @@del_errmsg@@ @@del_errmsg@@
4 @@status@@
4 @@del_status@@
5 5
6 6 <form method="post" action="/op/settings/keys"> <form method="post" action="/op/settings/keys">
7 7 <input type="hidden" name="delete" value="1" /> <input type="hidden" name="delete" value="1" />
File root/themes/default/user/keys/list/line.html changed (mode: 100644) (index b740ba2..1cd93b8)
1 1 <tr> <tr>
2 2 <td><input type="checkbox" name="key_delete_ids[@@key_id@@]" /></td> <td><input type="checkbox" name="key_delete_ids[@@key_id@@]" /></td>
3 3 <td>@@itime@@</td> <td>@@itime@@</td>
4 <td><small>MD5:@@fingerprint_md5@@<br />SHA256:@@fingerprint_sha256@@</small></td>
4 <td><small>SHA256:@@fingerprint_sha256@@<br />MD5:@@fingerprint_md5@@</small></td>
5 5 <td>@@comment@@</td> <td>@@comment@@</td>
6 6 <td>@@first_use@@</td> <td>@@first_use@@</td>
7 7 <td>@@last_use@@</td> <td>@@last_use@@</td>
File root/themes/default/user/keys/list/nodata.html changed (mode: 100644) (index 6e176db..75cc0d8)
1 <div class="ok">
1 <div class="mess ok">
2 2 No keys uploaded yet. No keys uploaded yet.
3 3 </div> </div>
File root/themes/default/user/keys/main.html changed (mode: 100644) (index 6668ca1..aa18d41)
1 @@status@@
1 @@add_status@@
2 2 @@add_form@@ @@add_form@@
3 3
4 4 @@keys@@ @@keys@@
File root/themes/default/user/keys/remove_ok.html changed (mode: 100644) (index d3d98d1..d886742)
1 <div class="ok">
1 <div class="mess ok">
2 2 Selected keys were removed with success. Selected keys were removed with success.
3 3 </div> </div>
File root/themes/default/user/login.html changed (mode: 100644) (index f265cf1..b4fd388)
18 18 <input type="password" name="pass" id="password" value="@@pass@@" /> <input type="password" name="pass" id="password" value="@@pass@@" />
19 19 </p> </p>
20 20
21 <p>
22 <label for="login_token">Login token (leave empty if you did not enrolled)</label><br />
23 <input type="text" name="login_token" id="login_token" value="@@login_token@@" autocomplete="off" />
24 </p>
25
21 26 <fieldset> <fieldset>
22 27 <legend>Lock login from current IP</legend> <legend>Lock login from current IP</legend>
23 28 <input type="radio" name="lock_ip" id="lock_ip_yes" value="1" checked="checked" /> <input type="radio" name="lock_ip" id="lock_ip_yes" value="1" checked="checked" />
File root/themes/default/user/login_first.html added (mode: 100644) (index 0000000..80000cc)
1 <div class="mess error">
2 Please sign in first.
3 </div>
File root/themes/default/user/logout.html changed (mode: 100644) (index 1e71fc6..680d293)
1 <div class="ok">
1 <div class="mess ok">
2 2 You are now logged out. You are now logged out.
3 3 </div> </div>
File root/themes/default/user/logout_err.html changed (mode: 100644) (index 8f74e6f..ba6e96f)
1 <div class="warning">
1 <div class="mess warning">
2 2 Cannot log you out. Please clean all cookies and restart the browser. Cannot log you out. Please clean all cookies and restart the browser.
3 3 </div> </div>
File root/themes/default/user/pass_changed.html changed (mode: 100644) (index d446b2e..ec8f8ed)
1 <div class="ok">
1 <div class="mess ok">
2 2 Password was updated with success. Password was updated with success.
3 3 </div> </div>
File root/themes/default/user/repo/delete/deny.html changed (mode: 100644) (index 3bc641a..9cf362f)
1 <div class="error">
1 <div class="mess error">
2 2 You are not allowed to delete this repo. You are not allowed to delete this repo.
3 3 </div> </div>
File root/themes/default/user/repo/delete/done.html changed (mode: 100644) (index fc296c0..778dd45)
1 <div class="ok">
1 <div class="mess ok">
2 2 The repository was deleted. The repository was deleted.
3 3 </div> </div>
File root/themes/default/user/repo/delete/no.html changed (mode: 100644) (index 57302d4..2df3e72)
1 <div class="ok">
1 <div class="mess ok">
2 2 We are happy you changed your mind! We are happy you changed your mind!
3 3 </div> </div>
File root/themes/default/user/repo/deny.html changed (mode: 100644) (index 4dd0d6f..f0ba670)
1 <div class="error">
1 <div class="mess error">
2 2 Cannot access non-existing or private repository. Cannot access non-existing or private repository.
3 3 </div> </div>
File root/themes/default/user/repo/deny_create.html changed (mode: 100644) (index 6ecf740..771e286)
1 <div class="error">
2 You are not allowed to create an anonymous repo. Please login first.
1 <div class="mess error">
2 You are not allowed to create an anonymous repo. Please sign in first.
3 3 </div> </div>
File root/themes/default/user/repo/deny_edit.html changed (mode: 100644) (index 82c7199..faae5e2)
1 <div class="error">
1 <div class="mess error">
2 2 You are not allowed to edit this repo. You are not allowed to edit this repo.
3 3 </div> </div>
File root/themes/default/user/repo/menu.html changed (mode: 100644) (index 13c4a2c..453d8be)
1 <div class="menu submenu">
1 <div class="menu menu3">
2 2 <ul> <ul>
3 <li@@if(@@menu::repo::edit@@ == 1){{ class="selected"}}{{}}><a href="@@url_repo@@/admin/edit">Edit</a></li>
4 <li@@if(@@menu::repo::repo_rights@@ == 1){{ class="selected"}}{{}}><a href="@@url_repo@@/admin/repo_rights">Repo rights</a></li>
5 <li@@if(@@menu::repo::refs_rights@@ == 1){{ class="selected"}}{{}}><a href="@@url_repo@@/admin/refs_rights">Refs rights</a></li>
6 <li@@if(@@menu::repo::path_rights@@ == 1){{ class="selected"}}{{}}><a href="@@url_repo@@/admin/path_rights">Path rights</a></li>
7 <li@@if(@@menu::repo::delete@@ == 1){{ class="selected"}}{{}}><a href="@@url_repo@@/admin/delete">Delete</a></li>
3 <li@@if(@@menu::repo::edit@@ == 1){{ class="selected"}}><a href="@@url_repo@@/admin/edit">Edit</a></li>
4 <li@@if(@@menu::repo::repo_rights@@ == 1){{ class="selected"}}><a href="@@url_repo@@/admin/repo_rights">Repo rights</a></li>
5 <li@@if(@@menu::repo::refs_rights@@ == 1){{ class="selected"}}><a href="@@url_repo@@/admin/refs_rights">Refs rights</a></li>
6 <li@@if(@@menu::repo::path_rights@@ == 1){{ class="selected"}}><a href="@@url_repo@@/admin/path_rights">Path rights</a></li>
7 <li@@if(@@menu::repo::delete@@ == 1){{ class="selected"}}><a href="@@url_repo@@/admin/delete">Delete</a></li>
8 8 </ul> </ul>
9 9 </div> </div>
File root/themes/default/user/repo/rights/delete_ok.html changed (mode: 100644) (index c9cd4c6..0a0b3dd)
1 <div class="ok">
1 <div class="mess ok">
2 2 Rights deleted with success. Rights deleted with success.
3 3 </div> </div>
File root/themes/default/user/repo/rights/deny.html changed (mode: 100644) (index cde12b4..b905a4c)
1 <div class="error">
1 <div class="mess error">
2 2 You are not allowed to grant rights. You are not allowed to grant rights.
3 3 </div> </div>
File root/themes/default/user/repo/rights/grant_ok.html changed (mode: 100644) (index d8a4857..0569574)
1 <div class="ok">
1 <div class="mess ok">
2 2 Rights granted with success. Rights granted with success.
3 3 </div> </div>
File root/themes/default/user/settings/menu.html changed (mode: 100644) (index 668ed7c..3766aea)
1 <div class="main_title">Settings</div>
2
1 3 <div class="menu menu2"> <div class="menu menu2">
2 4 <ul> <ul>
3 <li@@if(@@menu::sub1::edit_info@@ == 1){{ class="selected"}}{{}}><a href="/op/settings/edit_info">Edit info</a></li>
4 <li@@if(@@menu::sub1::change_pass@@ == 1){{ class="selected"}}{{}}><a href="/op/settings/change_pass">Change password</a></li>
5 <li@@if(@@menu::sub1::keys@@ == 1){{ class="selected"}}{{}}><a href="/op/settings/keys">SSH keys</a></li>
5 <li@@if(@@set_menu::edit_info@@ == 1){{ class="selected"}}{{}}><a href="/op/settings/edit_info">Edit info</a></li>
6 <li@@if(@@set_menu::change_pass@@ == 1){{ class="selected"}}{{}}><a href="/op/settings/change_pass">Change password</a></li>
7 <li@@if(@@set_menu::keys@@ == 1){{ class="selected"}}{{}}><a href="/op/settings/keys">SSH keys</a></li>
8 <li@@if(@@set_menu::totp@@ == 1){{ class="selected"}}{{}}><a href="/op/settings/totp">Login token</a></li>
6 9 </ul> </ul>
7 10 </div> </div>
File root/themes/default/user/settings/totp/delete_ok.html added (mode: 100644) (index 0000000..03b636e)
1 <div class="mess ok">
2 Login token deleted with success.
3 </div>
File root/themes/default/user/settings/totp/enroll_ok.html added (mode: 100644) (index 0000000..23c5418)
1 <div class="mess ok">
2 You enrolled your new device with success.
3 At next login, you will be asked for the 6 digits number.
4 </div>
File root/themes/default/user/settings/totp/hints.html added (mode: 100644) (index 0000000..c0395a6)
1 Login token feature implements
2 <a href="https://en.wikipedia.org/wiki/Time-based_One-time_Password_Algorithm" target="_blank">
3 TOTP (Time-based One-time Password Algorithm)
4 </a> and will add an extra protection to your login process.<br />
5 <br />
6 How it works:<br />
7 <ul>
8 <li>
9 Install a TOTP application on your mobile phone (we recommend
10 <i>FreeOTP</i> or <i>Google Authenticator</i> for
11 Android/iPhone/Blackberry and
12 <i>Authenticator</i> for Windows Phone).
13 </li>
14
15 <li>
16 Using the just installed application, scan the QR Code (if shown)
17 or the secret provided on screen.
18 </li>
19
20 <li>
21 The application will generate a 6 digit number that must be
22 entered in the form above.
23 </li>
24
25 <li>
26 At next login, you will be asked for the password and for
27 a 6 digit number; you will have to open the mobile application
28 and enter the 6 digit number shown on the device screen.
29 </li>
30 </ul>
31 <br />
32 You may enroll multiple devices if needed. Use the 'name' field to distinguish
33 between them.
File root/themes/default/user/settings/totp/list/footer.html added (mode: 100644) (index 0000000..6b7fafd)
1 </table>
2
3 <input type="submit" name="button" value="Delete selected" />
4 </form>
5 </div>
File root/themes/default/user/settings/totp/list/header.html added (mode: 100644) (index 0000000..fde6509)
1 <div class="rg_totp_list">
2
3 @@del_status@@
4 @@del_errmsg@@
5
6 <form method="post" action="/op/settings/totp">
7 <input type="hidden" name="delete" value="1" />
8 <input type="hidden" name="token" value="@@rg_form_token@@" />
9
10 <table summary="login tokens">
11 <tr>
12 <th>Select</th>
13 <th>Name</th>
14 <th>Date (UTC)</th>
15 <th>Enroll IP</th>
16 <th>Confirmed?</th>
17 <th>Last time used (UTC)</th>
18 </tr>
File root/themes/default/user/settings/totp/list/line.html added (mode: 100644) (index 0000000..c64fdba)
1 <tr>
2 <td><input type="checkbox" name="delete_list[@@id@@]" /></td>
3 <td>@@name@@</td>
4 <td>@@itime_nice@@</td>
5 <td>@@ip@@</td>
6 <td>@@conf_nice@@</td>
7 <td>@@used_nice@@</td>
8 </tr>
9
File root/themes/default/user/settings/totp/list/nodata.html added (mode: 100644) (index 0000000..5c1aea8)
1 @@del_status@@
2
3 <div class="mess ok">
4 No login tokens found.
5 </div>
File root/themes/default/user/settings/totp/list_err.html added (mode: 100644) (index 0000000..fdcd1fb)
1 <div class="mess error">
2 Could not load login tokens (@@totp_errmsg@@). Please try again later.
3 </div>
File root/themes/default/user/settings/totp/main.html added (mode: 100644) (index 0000000..dfd8054)
1 <div class="formarea">
2
3 <div class="formarea_title">Enroll a new phone</div>
4
5 @@errmsg@@
6
7 <form method="post" action="/op/settings/totp">
8 <input type="hidden" name="enroll" value="1" />
9 <input type="hidden" name="token" value="@@rg_form_token@@" />
10 <input type="hidden" name="totp::secret" value="@@totp::secret@@" />
11
12 <p>
13 <label for="name">Name (for example, <i>My work phone</i>)</label><br />
14 <input type="text" name="totp::name" id="name" value="@@totp::name@@" />
15 </p>
16
17 <p>
18 @@if(@@totp::img@@ == 1){{
19 Scan the following QR Code using the mobile application:<br />
20 <img class="secret_token" src="data:image/png;base64,@@totp::png@@" />
21 <br />
22 If you cannot scan the code above, manually enter the following key
23 into the mobile application:<br />
24 <div class="secret_token">@@totp::secret@@</div>
25 }}{{
26 Manually enter the following key into the mobile application:<br />
27 <div class="secret_token">@@totp::secret@@</div>
28 }}
29 </p>
30
31 <p>
32 <label for="ver">Enter the 6 digit number shown on the mobile phone</label><br />
33 <input type="text" name="totp::ver" id="ver" value="@@totp::ver@@" />
34 </p>
35
36 <input type="submit" name="button" value="Enroll" />
37
38 </form>
39 </div>
File root/themes/default/user/settings/totp/ver_error.html added (mode: 100644) (index 0000000..eb29e41)
1 The code could not be validated. Make sure the clock is in sync on your phone.
2 Also, you may mistyped the code if you entered it manually. Please try again.
File root/themes/default/warning.html changed (mode: 100644) (index 539b431..58130bf)
1 <div class="warning">
1 <div class="mess warning">
2 2 @@msg@@ @@msg@@
3 3 </div> </div>
File scripts/events.php changed (mode: 100644) (index aeaa0a4..7d7671e)
... ... do {
106 106 // check machine load - if too big we will delay // check machine load - if too big we will delay
107 107 $load = rg_load(); $load = rg_load();
108 108 if ($load > 10) { if ($load > 10) {
109 rg_log("\tLoad too big! Skip queue processing.");
109 rg_log("Load too big! Skip queue processing.");
110 110 break; break;
111 111 } }
112 112
File scripts/remote.php changed (mode: 100644) (index 0174c0b..abcc609)
... ... if (isset($_SERVER['SSH_CONNECTION'])) {
73 73 $login_uid = isset($_SERVER['argv'][1]) ? $_SERVER['argv'][1] : 0; $login_uid = isset($_SERVER['argv'][1]) ? $_SERVER['argv'][1] : 0;
74 74 if ($login_uid == 0) if ($login_uid == 0)
75 75 fatal("uid not provided!"); fatal("uid not provided!");
76 rg_log("\tuid is $login_uid.");
76 rg_log("uid is $login_uid.");
77 77
78 78 // second parameter must be the ssh key id // second parameter must be the ssh key id
79 79 $key_id = isset($_SERVER['argv'][2]) ? $_SERVER['argv'][2] : 0; $key_id = isset($_SERVER['argv'][2]) ? $_SERVER['argv'][2] : 0;
80 80 if ($key_id == 0) if ($key_id == 0)
81 81 fatal("key_id not provided!"); fatal("key_id not provided!");
82 rg_log("\tkey_id is $key_id.");
82 rg_log("key_id is $key_id.");
83 83
84 84 if (!isset($_SERVER['SSH_ORIGINAL_COMMAND'])) if (!isset($_SERVER['SSH_ORIGINAL_COMMAND']))
85 85 $cmd_repo = ""; $cmd_repo = "";
 
... ... if (isset($_SERVER['SSH_CONNECTION'])) {
104 104
105 105 $f = @fopen("php://stdin", "r"); $f = @fopen("php://stdin", "r");
106 106 if ($f === FALSE) if ($f === FALSE)
107 fatal("\tCannot open stdin!");
107 fatal("Cannot open stdin!");
108 108 $line = @fread($f, 8000); $line = @fread($f, 8000);
109 109 if ($line === FALSE) if ($line === FALSE)
110 fatal("\tCannot read!");
110 fatal("Cannot read!");
111 111 fclose($f); fclose($f);
112 112 $line_len = strlen($line); $line_len = strlen($line);
113 113
114 114 rg_log("line=[$line]"); rg_log("line=[$line]");
115 115 if ($line_len < 4) if ($line_len < 4)
116 fatal("\tLine is too short!");
116 fatal("Line is too short!");
117 117 $len = @hexdec(substr($line, 0, 4)); $len = @hexdec(substr($line, 0, 4));
118 118 if ($line_len < $len) if ($line_len < $len)
119 119 fatal("Too less data ($line_len/$len) received!"); fatal("Too less data ($line_len/$len) received!");
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