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 408ea6e114460b413daca5e96d1551ef04080a04

Checkpoint

Author: Catalin(ux) M. BOIE
Author date (UTC): 2014-12-09 17:18
Committer: Catalin(ux) M. BOIE
Commit date (UTC): 2014-12-09 17:18
Tree: 1dd0a96da748e9272b63611def7c878f397ac259
Parents: 70b59e41caa4a49a3f6580e104da0c8e6cec8658
File Lines added Lines deleted
Compare.txt 20 10
README 10 5
TODO 75 7
inc/cache.inc.php 5 5
inc/events.inc.php 7 4
inc/init.inc.php 7 1
inc/log.inc.php 1 1
inc/repo.inc.php 29 14
inc/rights.inc.php 5 6
inc/state.inc.php 4 1
inc/token.inc.php 101 82
inc/user.inc.php 27 16
inc/util.inc.php 9 5
root/index.php 8 4
root/themes/default/main.css 1 1
root/themes/default/repo/main.html 1 0
root/themes/default/user/add_edit.html 1 1
root/themes/default/user/repo/rights/form_repo.html 1 1
root/themes/default/user/repo/rights/form_repo_path.html 1 1
root/themes/default/user/repo/rights/form_repo_refs.html 1 1
samples/config.php 2 0
scripts/wake.php 1 1
tests/Makefile 7 7
tests/bug.php 5 5
tests/config.php 4 1
tests/event.php 15 5
tests/hook_update.sh 70 1
tests/hook_update_anon.sh 0 73
tests/hook_update_anon_nm.sh 0 80
tests/http.inc.php 76 0
tests/http_login.php 47 0
tests/keys.php 4 0
tests/repo.php 6 2
tests/rights.php 8 2
tests/token.php 52 0
tests/user.php 3 0

File Compare.txt changed (mode: 100644) (index d4c2057..920b851)
1 Gitlab RocketGit GitHub Gitorious unfuddle.com gitolite
1 RocketGit Gitlab GitHub Gitorious unfuddle.com gitolite
2 2
3 License ? GPLv3 Prop. ? ? ?
3 License GPLv3 ? Proprietary ? ? ?
4 4
5 5 [Features] [Features]
6 Easy instalation No Yes Yes No! ? Yes
7 SELinux friendly ? Yes ? ? ? ?
8 Distro friendly No Yes No No
9 Bug tracker Yes Yes Yes No
10 CLI commands (SSH) ? Yes ? ?
11 API ? ? Yes ?
6 Easy instalation Yes No Yes No! ? Yes
7 SELinux friendly Yes ? ? ? ? ?
8 Distro friendly Yes No No No ? Yes
9 Bug tracker Yes Yes Yes No ? No
10 CLI commands (SSH) Yes ? ? ? ? ?
11 API ? ? Yes ? ? ?
12 Anonymous push Yes ? ? ? ? ?
13 Languages 1 ? ? ? ? ?
14 IPv6 Yes ? ? ? ? ?
15
16
17 [Rights]
18 Path control Yes ? ? ? ? ?
19 Refs control Yes ? ? ? ? ?
20 IP control Yes ? ? ? ? ?
21
12 22
13 23 [Details] [Details]
14 Language Ruby+Perl PHP Ruby Ruby
15 Cache Redis ? ? ?
24 Language PHP Ruby+Perl Ruby Ruby ? Perl
25 Cache custom Redis ? ? ? No

File README changed (mode: 100644) (index bac3d29..bf6fa82)
2 2 . Website: http://kernel.embedromix.ro/us/ . Website: http://kernel.embedromix.ro/us/
3 3 . Author: Catalin(ux) M. BOIE . Author: Catalin(ux) M. BOIE
4 4 . Description: Light and fast Git hosting solution . Description: Light and fast Git hosting solution
5 . Language: PHP
5 . License: GPLv3
6 . Language: PHP (plans to rewrite in C)
6 7 . Database: PostgreSQL . Database: PostgreSQL
7 8
8 9
9 10 == Features == == Features ==
11 . Free software
10 12 . No Java . No Java
11 13 . No Javascript . No Javascript
14 . Upgrades with the standard tools of the distributions
12 15 . Very little dependencies, all packaged in main-stream distributions . Very little dependencies, all packaged in main-stream distributions
13 16 . SELinux friendly . SELinux friendly
14 17 . Very small . Very small
 
28 31 . Edit /etc/rocketgit/config.php . Edit /etc/rocketgit/config.php
29 32 . Edit /etc/httpd/conf.d/rocketgit.conf . Edit /etc/httpd/conf.d/rocketgit.conf
30 33
31 . Configure Apache
34 . Activate web server
32 35 # systemctl enable httpd.service # systemctl enable httpd.service
33 36 # systemctl start httpd.service # systemctl start httpd.service
34 37
 
73 76 . Run instalation script . Run instalation script
74 77 # php /usr/share/rocketgit/admin/init.php # php /usr/share/rocketgit/admin/init.php
75 78
76 . Edit firewall to permit port ssh, git, http and https
79 . Edit firewall to permit ssh, git, http and https ports
77 80 In /etc/sysconfig/iptables (IPv4) or ip6tables (IPv6), add something In /etc/sysconfig/iptables (IPv4) or ip6tables (IPv6), add something
78 81 like this: like this:
79 82 -A INPUT -m tcp -p tcp --dport ssh -j ACCEPT -A INPUT -m tcp -p tcp --dport ssh -j ACCEPT
 
82 85 -A INPUT -m tcp -p tcp --dport https -j ACCEPT -A INPUT -m tcp -p tcp --dport https -j ACCEPT
83 86
84 87 . PHP . PHP
85 Adjust php.ini to allow enough RAM and execution time.
88 Adjust php.ini to:
89 - allow enough RAM and execution time
90 - fix timezone
86 91
87 92
88 93 == Thanks == == Thanks ==
 
92 97 . Special thanks to a lot of people that came with suggestions. . Special thanks to a lot of people that came with suggestions.
93 98 . Special thanks to gitosys, Gitorious and other projects from where I learned . Special thanks to gitosys, Gitorious and other projects from where I learned
94 99 things. things.
95 . See AUTHORS file for all people contributed to this project.
100 . See AUTHORS file for all the people who contributed to this project.

File TODO changed (mode: 100644) (index 4b379bb..ce9e129)
1 1 == Where I stopped last time == == Where I stopped last time ==
2 [ ] Not clear why I do not have rights to push a file: it fails on repo_path
3 tests. I did not inject anything there. What should I inject?!
4 We have injection only for owner. Keep in mind is a private repo.
5 [ ] Integrate anonymous push. remove old sh file.
6 [ ] Run unit tests
7 [ ] git url is not ok.
8 [ ]
2 [ ] Seems I have to generate a sid, even if user is not logged in yet.
3 Else, create_account op is not working: no sid -> no token.
4 [ ] Creating an account is not working. We test for 'E' right and is not
5 present. We should not check for 'E' if uid is 0?
6 [ ] Decide what rights to inject for 'refs'.
7 [ ] Friends will need a way to register an account with a full account type.
8 Find a way to distribute this code and a way to support it in rg.
9
10 CSRF login:
11 atacator fraiereste user-ul sa mearga pe o pagina controlata de el.
12 Acolo se face post automat la site-ul adevarat, cu datele atacatorului.
13 Se trimite cookie-ul?
14
15 Asta e form-ul de pe pagina atacatorului:
16
17 <body onload="document.getElementById('fm1').submit()">
18 <form id="fm1" action="http://yoursite/UserProfile/SubmitUpdate" method="post">
19 <input name="email" value="hacker@somewhere.evil" />
20 <input name="hobby" value="Defacing websites" />
21 </form>
22 </body>
23
24 Deci, se trimite cookie-ul. Ce nu se trimite este token-ul asociat cu sesiunea!
25 Atacatorul nu are acces la sesiune si nici la un token asociat cu sesiunea.
26
27 O solutie e sa ai si cookie si token si sa le verifici.
28
29 Cum pot valida token-urile fara sa le stochez in baza de date?
30 As putea sa trimit token1=random, sid, token2=hmac(token1,sid).
31 Cind user-ul face post, va trimite cele 3 chestii. fac hmac(token1,sid) si asa
32 validez token2-ul.
33 Daca atacatorul incearca sa schimbe token1 => token2 nu se mai verifica.
34 Atacatorulului cred ca ii este greu sa gaseasca un token1b astfel incit
35 hmac(token1b,sid) sa fie token2.
36 Hm. Se pare ca trebuie sa am un secret key care sa-l folosesc in hmac, altfel
37 atacatorul poate genera token2 din token1 si sid.
38 De fapt ce vreau eu? Sa demonstrez ca token1 este asociat cu sid-ul.
39 ???
40
41 Ar trebui sa validez si referer-ul. Si sa loghez pagina de pe care s-a facut
42 request-ul.
43
44 Acum, verific ca token-ul e asociat cu sesiunea.
45 De ce?
46 Ca sa impiedic CSRF-ul: js-ul de mai sus ma va forta sa trimit cookie-ul corect
47 dar nu va stii token1. va fi fortat sa puna unul gresit, eu verific in baza
48 de date si nu se pupa => eroare.
49
50 Dar, atacatorul se poate lega direct si sa forteze un cookie, token1 si token2.
51 Dar, server-ul le poate genera pentru el, deci, inutil.
9 52
10 53 == BEFORE NEXT RELEASE == == BEFORE NEXT RELEASE ==
54 [ ] Add User-Agent to session (tokens?).
55 [ ] Check "Content security policy"
56 [ ] htmlspcialchars does not escape '/'. It may be dangerous:
57 https://www.owasp.org/index.php/XSS_%28Cross_Site_Scripting%29_Prevention_Cheat_Sheet
58 [ ] Ar fi fain ca si sesiunile sa nu fie in baza de date. Daca pun uid-ul si
59 expirarea in ele, as putea sa scap de stocarea in baza de date.
60 Sa vedem ce stoches in tabela: uid, expire, session_time, ip.
61 Deci, as putea stoca uid-ul pe 4 bytes, expire pe 4 bytes, session_time
62 pe 2 bytes, si ip-ul doar pe un bit in cimpul de flag-uri.
63 As putea sa fac lock si pe user agent daca user-ul vrea asta.
64 ip-ul si user agent-ul intra in hmac, dar nu se stocheaza in cookie.
65 [ ] Still, a lot of things from
66 https://www.owasp.org/index.php/Session_Management_Cheat_Sheet
67 needs to be implemented.
68 [ ] Add "Secure" cookie para when using HTTPS.
69 [ ] Warning if user has not enabled cookies?
70 [ ] Seems that Etag is not working for main.css!!! At least.
71 [ ] X-Frame-Options: DENY
72 [ ] bad_token.html must not be in user/
73 [ ] On create_account page, submenu1 and submenu2 are with @@...@@!
74 [ ] The merge request name is not so good. Maybe include also the user?
75 [ ] I do at least two times a request to database for uid 22 in hook_update.log
76 [ ] git update-ref supports "ref:" to update a ref. Should we?
77 [ ] Document a little bit how a merge request will show up on a repo.
78 [ ] Limit recursion for regex matches.
11 79 [ ] Delete anonymous push must take uid in consideration. Maybe also other ops. [ ] Delete anonymous push must take uid in consideration. Maybe also other ops.
12 80 [ ] Add unit test also for paths. [ ] Add unit test also for paths.
13 81 [ ] cache: we may have data with \x0 embedded. Check. [ ] cache: we may have data with \x0 embedded. Check.

File inc/cache.inc.php changed (mode: 100644) (index df332b9..5c1557c)
... ... function rg_cache_get($ns_var)
298 298 break; break;
299 299
300 300 $c = rg_socket($rg_cache_socket, $c = rg_socket($rg_cache_socket,
301 "GET " . $ns_var . "\n", $rg_cache_timeout);
301 "GET " . $ns_var . "\n", $rg_cache_timeout, 1);
302 302 if ($c === FALSE) { if ($c === FALSE) {
303 303 // Give up for the rest of the session // Give up for the rest of the session
304 304 $rg_cache_enable = FALSE; $rg_cache_enable = FALSE;
 
... ... function rg_cache_set($ns_var, $value)
358 358 break; break;
359 359
360 360 $c = rg_socket($rg_cache_socket, "SET " . $ns_var . "=" $c = rg_socket($rg_cache_socket, "SET " . $ns_var . "="
361 . rg_cache_prepare($value) . "\n", $rg_cache_timeout);
361 . rg_cache_prepare($value) . "\n", $rg_cache_timeout, 1);
362 362 if ($c === FALSE) { if ($c === FALSE) {
363 363 // Give up for the rest of the session // Give up for the rest of the session
364 364 $rg_cache_enable = FALSE; $rg_cache_enable = FALSE;
 
... ... function rg_cache_inc($ns_var)
397 397 break; break;
398 398
399 399 $c = rg_socket($rg_cache_socket, $c = rg_socket($rg_cache_socket,
400 "INC " . $ns_var . "\n", $rg_cache_timeout);
400 "INC " . $ns_var . "\n", $rg_cache_timeout, 1);
401 401 if ($c === FALSE) { if ($c === FALSE) {
402 402 // Give up for the rest of the session // Give up for the rest of the session
403 403 $rg_cache_enable = FALSE; $rg_cache_enable = FALSE;
 
... ... function rg_cache_unset($ns_var)
440 440 break; break;
441 441
442 442 $ret = rg_socket($rg_cache_socket, $ret = rg_socket($rg_cache_socket,
443 "UNSET " . $ns_var . "\n", $rg_cache_timeout);
443 "UNSET " . $ns_var . "\n", $rg_cache_timeout, 1);
444 444 if ($ret === FALSE) { if ($ret === FALSE) {
445 445 // Give up for the rest of the session // Give up for the rest of the session
446 446 $rg_cache_enable = FALSE; $rg_cache_enable = FALSE;
 
... ... function rg_cache_merge($ns_var, $list)
480 480 break; break;
481 481
482 482 $c = rg_socket($rg_cache_socket, "MERGE " . $ns_var . "=" $c = rg_socket($rg_cache_socket, "MERGE " . $ns_var . "="
483 . rg_cache_prepare($list) . "\n", $rg_cache_timeout);
483 . rg_cache_prepare($list) . "\n", $rg_cache_timeout, 1);
484 484 if ($c === FALSE) { if ($c === FALSE) {
485 485 // Give up for the rest of the session // Give up for the rest of the session
486 486 $rg_cache_enable = FALSE; $rg_cache_enable = FALSE;

File inc/events.inc.php changed (mode: 100644) (index 3c797cb..8e645a6)
... ... function rg_event_signal_daemon($ev_id, $timeout)
65 65 $s_timeout = $timeout . "ms"; $s_timeout = $timeout . "ms";
66 66
67 67 rg_prof_start("event_signal_daemon"); rg_prof_start("event_signal_daemon");
68 rg_log("event_signal_daemon: event_id=[$ev_id] timeout=$s_timeout");
68 rg_log_enter("event_signal_daemon: event_id=[$ev_id] timeout=$s_timeout");
69 69
70 70 if (empty($ev_id)) if (empty($ev_id))
71 71 $buf = "W"; $buf = "W";
72 72 else else
73 73 $buf = "NOTIFY " . $ev_id; $buf = "NOTIFY " . $ev_id;
74 74
75 return rg_socket($rg_event_socket, $buf, $timeout);
75 $r = rg_socket($rg_event_socket, $buf, $timeout, 1);
76
77 rg_log_exit();
78 return $r;
76 79 } }
77 80
78 81 /* /*
 
... ... function rg_event_add($db, $event)
100 103 } }
101 104 rg_sql_free_result($res); rg_sql_free_result($res);
102 105
103 rg_event_signal_daemon("", NULL);
106 rg_event_signal_daemon("", 0);
104 107
105 108 $ret = TRUE; $ret = TRUE;
106 109 break; break;
 
... ... function rg_event_process($db, $event)
127 130 unset($event['category']); unset($event['category']);
128 131
129 132 if (!isset($rg_event_split_functions[$category])) { if (!isset($rg_event_split_functions[$category])) {
130 rg_event_set_error("Cannot find event function [$category]!");
133 rg_event_set_error("Cannot find event function [cat=$category]!");
131 134 rg_log("DEBUG: rg_event_split_functions=" . rg_array2string($rg_event_split_functions)); rg_log("DEBUG: rg_event_split_functions=" . rg_array2string($rg_event_split_functions));
132 135 break; break;
133 136 } }

File inc/init.inc.php changed (mode: 100644) (index 1919431..68b1a7a)
... ... if (empty($rg_ssh_host)) {
12 12 $rg_ssh_host = php_uname("n"); $rg_ssh_host = php_uname("n");
13 13 $rg_ssh_port = 22; $rg_ssh_port = 22;
14 14 } }
15
16 15 $rg['rg_ssh_host'] = $rg_ssh_host; $rg['rg_ssh_host'] = $rg_ssh_host;
17 16 $rg['rg_ssh_port'] = $rg_ssh_port; $rg['rg_ssh_port'] = $rg_ssh_port;
18 17
18 if (empty($rg_git_host)) {
19 $rg_git_host = php_uname("n");
20 $rg_git_port = 9418;
21 }
22 $rg['rg_git_host'] = $rg_git_host;
23 $rg['rg_git_port'] = $rg_git_port;
24
19 25 $rg['rg_version'] = $rocketgit_version; $rg['rg_version'] = $rocketgit_version;
20 26
21 27 if (!isset($rg_scripts)) if (!isset($rg_scripts))

File inc/log.inc.php changed (mode: 100644) (index 098c2e6..dbf1c3d)
... ... function rg_log_enter($a)
235 235 { {
236 236 global $rg_log_level; global $rg_log_level;
237 237
238 $rg_log_level++;
239 238 rg_log($a); rg_log($a);
239 $rg_log_level++;
240 240 } }
241 241
242 242 function rg_log_ml_enter($a) function rg_log_ml_enter($a)

File inc/repo.inc.php changed (mode: 100644) (index 62b1dea..908a40c)
... ... function rg_repo_rights_inject($db, $obj_id, $type, $owner, $uid)
63 63
64 64 $ret = array(); $ret = array();
65 65 while (1) { while (1) {
66 $ui = rg_user_info($db, $uid, "", "");
67 if ($ui['exists'] != 1)
68 break;
69
70 66 $a = array(); $a = array();
71 67 $a['type'] = $type; $a['type'] = $type;
72 68 $a['obj_id'] = $obj_id; $a['obj_id'] = $obj_id;
 
... ... function rg_repo_rights_inject($db, $obj_id, $type, $owner, $uid)
80 76 $a['can_be_deleted'] = 0; $a['can_be_deleted'] = 0;
81 77 $a['description'] = "Autogenerated"; $a['description'] = "Autogenerated";
82 78
83 if ($ui['is_admin'] == 1) {
84 $a['rights'] = rg_rights_all($type);
85 $ret[] = $a;
79 if ($uid > 0) {
80 $ui = rg_user_info($db, $uid, "", "");
81 if ($ui['exists'] != 1)
82 break;
83
84 if ($ui['is_admin'] == 1) {
85 $a['rights'] = rg_rights_all($type);
86 $ret[] = $a;
87 }
86 88 } }
87 89
88 90 $ri = rg_repo_info($db, $obj_id, 0, ""); $ri = rg_repo_info($db, $obj_id, 0, "");
89 if ($ri['exists'] != 1)
91 if ($ri['exists'] != 1) {
92 rg_log("repo $obj_id does not exists");
90 93 break; break;
94 }
95
96 // Here, rights to inject, even if repo is not public
97 if (strcmp($type, "repo_path") == 0) {
98 $a['prio'] = 30001;
99 $a['rights'] = "PW"; // push + whitespace
100 $ret[] = $a;
101 }
91 102
92 103 // No rights to inject if is not public // No rights to inject if is not public
93 104 if ($ri['public'] != 1) if ($ri['public'] != 1)
94 105 break; break;
95 106
96 if (strcmp($type, "repo") == 0)
97 $a['rights'] = "A"; // access
98 else if (strcmp($type, "repo_refs") == 0)
99 $a['rights'] = "F"; // fetch
100 else
107 if (strcmp($type, "repo") == 0) {
108 $a['rights'] = "AB"; // access repo + add bugs
109 $ret[] = $a;
110 } else if (strcmp($type, "repo_refs") == 0) {
111 $a['rights'] = "F"; // Fetch
112 $ret[] = $a;
113 } else if (strcmp($type, "repo_path") == 0) {
114 } else {
115 rg_log("type $type not used. bug?");
101 116 break; break;
117 }
102 118
103 $ret[] = $a;
104 119 break; break;
105 120 } }
106 121

File inc/rights.inc.php changed (mode: 100644) (index c478ed8..63b09c3)
... ... function rg_rights_get($db, $obj_id, $type, $owner, $uid, $right_id)
298 298 $a['description'] = "Autogenerated"; $a['description'] = "Autogenerated";
299 299 rg_rights_cosmetic($db, $a); rg_rights_cosmetic($db, $a);
300 300
301 rg_log_ml("rights_get: inject right for owner: " . print_r($a, TRUE));
302 301 $r[] = $a; $r[] = $a;
302 rg_log_ml("rights_get: inject all rights for owner");
303 303 } }
304 304
305 305 // Inject specific rights // Inject specific rights
306 306 if (isset($rg_rights_inject[$type])) { if (isset($rg_rights_inject[$type])) {
307 307 $f = $rg_rights_inject[$type]; $f = $rg_rights_inject[$type];
308 308 $rows = $f($db, $obj_id, $type, $owner, $uid); $rows = $f($db, $obj_id, $type, $owner, $uid);
309 rg_log_ml("CHECK: inject function for '$type' [$f] returned: " . print_r($rows, TRUE));
309 310 foreach ($rows as $row) { foreach ($rows as $row) {
310 311 rg_rights_cosmetic($db, $row); rg_rights_cosmetic($db, $row);
311 312 rg_log_ml("rights_get: inject specific rights: " . print_r($row, TRUE)); rg_log_ml("rights_get: inject specific rights: " . print_r($row, TRUE));
312 313 $r[] = $row; $r[] = $row;
313 314 } }
314 } else {
315 rg_log("rights_get: no inject function for type [$type]");
316 315 } }
317 316
318 317 $x = rg_rights_load($db, $obj_id, $type); $x = rg_rights_load($db, $obj_id, $type);
 
... ... function rg_rights_set($db, $type, $a)
357 356
358 357 $ret = FALSE; $ret = FALSE;
359 358 while (1) { while (1) {
360 if ($a['prio'] < 10) {
361 rg_rights_set_error("prio must be at least 10");
359 if (($a['prio'] < 10) || ($a['prio'] > 30000)) {
360 rg_rights_set_error("prio must be between 10 and 30000");
362 361 break; break;
363 362 } }
364 363
 
... ... function rg_rights_test($list, $needed_rights, $ip, $misc)
652 651 continue; continue;
653 652 } }
654 653
654 // Test rights
655 655 foreach ($needed as $needed1) { foreach ($needed as $needed1) {
656 656 $r = rg_rights_mask($v['rights'], $needed1); $r = rg_rights_mask($v['rights'], $needed1);
657 657 if (strcmp($r, $needed1) != 0) { if (strcmp($r, $needed1) != 0) {
 
... ... function rg_rights_test($list, $needed_rights, $ip, $misc)
662 662 $ret = TRUE; $ret = TRUE;
663 663 break; break;
664 664 } }
665
666 665 if ($ret === FALSE) if ($ret === FALSE)
667 666 continue; continue;
668 667

File inc/state.inc.php changed (mode: 100644) (index 1127eac..e3f7fa8)
... ... function rg_state_get($db, $var)
49 49 } else { } else {
50 50 $row = rg_sql_fetch_array($res); $row = rg_sql_fetch_array($res);
51 51 $ret = $row['value']; $ret = $row['value'];
52 rg_cache_set("state::" . $var, $ret);
53 52 } }
54 53 rg_sql_free_result($res); rg_sql_free_result($res);
54
55 // We cache it even if is not found
56 rg_cache_set("state::" . $var, $ret);
57
55 58 break; break;
56 59 } }
57 60

File inc/token.inc.php changed (mode: 100644) (index c943ccd..1cdf917)
1 1 <?php <?php
2 2 require_once($INC . "/util.inc.php"); require_once($INC . "/util.inc.php");
3 3 require_once($INC . "/log.inc.php"); require_once($INC . "/log.inc.php");
4 require_once($INC . "/sql.inc.php");
4 require_once($INC . "/prof.inc.php");
5 require_once($INC . "/state.inc.php");
6
7 // The token is split in two parts: one is a random value and the second
8 // one is the HMAC(session, secret_key, first part of token).
9 // Partea aleatoare va fi de 16 caractere, hmac-ul cred ca ar fi mai bine
10 // sa nu-l trunchez.
11 // Problema mare e ca nu pot detecta double-post-uri!
5 12
6 13 $rg_token_error = ""; $rg_token_error = "";
7 14
 
... ... function rg_token_error()
19 26 } }
20 27
21 28 /* /*
22 * Delete a token
29 * Generate master key if not present in db
23 30 */ */
24 function rg_token_delete($db, $sid, $token)
31 function rg_token_get_master($db)
25 32 { {
26 rg_log("rg_token_delete: sid=$sid token=$token");
27
28 $ret = array();
29 $ret['ok'] = 0;
30
31 $params = array("sid" => $sid, "token" => $token);
32 $add_token = "";
33 if (!empty($token))
34 $add_token = " AND token = @@token@@";
35
36 $sql = "DELETE FROM tokens"
37 . " WHERE sid = @@sid@@"
38 . $add_token;
39 $res = rg_sql_query_params($db, $sql, $params);
40 if ($res === FALSE) {
41 rg_token_set_error("cannot delete token (" . rg_sql_error() . ")");
42 return $ret;
33 rg_prof_start("token_get_master");
34 rg_log_enter("token_get_master");
35
36 $ret = FALSE;
37 while (1) {
38 $key = rg_state_get($db, "token_key");
39 if ($key === FALSE) {
40 rg_token_set_error("cannot get token_key:"
41 . " " . rg_state_error());
42 break;
43 }
44
45 if (empty($key)) {
46 $key = rg_id(32);
47 $r = rg_state_set($db, "token_key", $key);
48 if ($r === FALSE) {
49 rg_token_set_error("cannot set state:"
50 . " " . rg_state_error());
51 break;
52 }
53 }
54
55 $ret = $key;
56 break;
43 57 } }
44 rg_sql_free_result($res);
45
46 $ret['ok'] = 1;
47 58
59 rg_log_exit();
60 rg_prof_end("token_get_master");
48 61 return $ret; return $ret;
49 62 } }
50 63
51 64 /* /*
52 * Returns TRUE if the token is valid
65 * Returns a token to be used on a form/url
66 * We generate only one per session.
53 67 */ */
54 function rg_token_valid($db, $sid, $token)
68 $rg_token = FALSE;
69 function rg_token_get($db, $sid)
55 70 { {
56 rg_log("rg_token_get: sid=$sid token=$token");
57
58 $params = array("sid" => $sid, "token" => $token);
59 $sql = "SELECT 1 AS junk FROM tokens"
60 . " WHERE token = @@token@@"
61 . " AND sid = @@sid@@";
62 $res = rg_sql_query_params($db, $sql, $params);
63 if ($res === FALSE) {
64 rg_token_set_error("cannot get token (" . rg_sql_error() . ")");
65 return FALSE;
66 }
67
68 $ret['ok'] = 1;
69 $ret['exists'] = 0;
70 $rows = rg_sql_num_rows($res);
71 rg_sql_free_result($res);
72 if ($rows == 0)
73 return FALSE;
74
75 return TRUE;
76 }
71 global $rg_token;
77 72
78 /*
79 * Insert a token
80 */
81 function rg_token_insert($db, $sid, $token)
82 {
83 rg_log("rg_token_insert: sid=$sid token=$token");
84
85 $ret = array();
86 $ret['ok'] = 0;
87
88 $now = time();
89
90 $params = array("sid" => $sid,
91 "token" => $token,
92 "expire" => $now + 24 * 3600);
93 $sql = "INSERT INTO tokens (sid, token, expire)"
94 . " VALUES (@@sid@@, @@token@@, @@expire@@)";
95 $res = rg_sql_query_params($db, $sql, $params);
96 if ($res === FALSE) {
97 rg_token_set_error("cannot insert token (" . rg_sql_error() . ")!");
98 return $ret;
73 $ret = FALSE;
74 while (1) {
75 if (empty($sid))
76 break;
77
78 if ($rg_token !== FALSE) {
79 $ret = $rg_token;
80 break;
81 }
82
83 $key = rg_token_get_master($db);
84 if ($key === FALSE)
85 break;
86
87 $rand = rg_id(16);
88 $sign = hash_hmac("sha1", $rand, $key);
89 rg_log("rand=$rand (" . strlen($rand) . ") sign=$sign(" . strlen($sign) . ")");
90 $rg_token = rg_id(16) . $sign;
91 rg_log("token_get: strlen(rg_token)=" . strlen($rg_token));
92 $ret = $rg_token;
93 break;
99 94 } }
100 95
101 $ret['ok'] = 1;
102 96 return $ret; return $ret;
103 97 } }
104 98
105 99 /* /*
106 * Returns a token to be used on a form/url
107 * We generate only one per session.
100 * Returns TRUE if the token is valid
108 101 */ */
109 $rg_token = FALSE;
110 function rg_token_get($db, $sid)
102 function rg_token_valid($db, $sid, $token)
111 103 { {
112 global $rg_token;
113
114 if (empty($sid))
115 return "";
116
117 if ($rg_token === FALSE) {
118 $rg_token = rg_id(16);
119
120 rg_token_insert($db, $sid, $rg_token);
104 rg_prof_start("token_valid");
105 rg_log_enter("rg_token_valid: sid=$sid token=$token");
106
107 $ret = FALSE;
108 while (1) {
109 if (empty($sid))
110 break;
111
112 $len = strlen($token);
113 if ($len != 16 + 40) {
114 rg_token_set_error("token length != 16 + 40 ($len)");
115 break;
116 }
117
118 $key = rg_token_get_master($db);
119 if ($key === FALSE)
120 break;
121
122 $rand = substr($token, 0, 16);
123 $sign = substr($token, 16);
124
125 $hash = hash_hmac("sha1", $rand, $key);
126 if ($hash === FALSE) {
127 rg_token_set_error("cannot compute hash");
128 break;
129 }
130
131 if (strcmp($hash, $sign) != 0) {
132 rg_log("Sign does not match: $hash != $sign");
133 break;
134 }
135
136 $ret = TRUE;
137 break;
121 138 } }
122 139
123 return $rg_token;
140 rg_log_exit();
141 rg_prof_end("token_valid");
142 return $ret;
124 143 } }
125 144
126 145 ?> ?>

File inc/user.inc.php changed (mode: 100644) (index 1e05acb..718a525)
... ... function rg_user_edit($db, $d)
510 510 ); );
511 511 $r = rg_event_add($db, $event); $r = rg_event_add($db, $event);
512 512 if ($r === FALSE) { if ($r === FALSE) {
513 rg_user_set_error("Canot add event!");
513 rg_user_set_error("Cannot add event!");
514 514 break; break;
515 515 } }
516 516 } }
 
... ... function rg_user_login_by_sid($db, &$rg)
661 661
662 662 $ret = FALSE; $ret = FALSE;
663 663 while (1) { while (1) {
664 if (empty($rg['sid'])) {
665 rg_log("\tNo sid!");
664 if (empty($rg['sid']))
666 665 break; break;
667 }
668 666
669 667 $sess = rg_sess_valid($db, $rg['sid']); $sess = rg_sess_valid($db, $rg['sid']);
670 668 if ($sess == FALSE) { if ($sess == FALSE) {
 
... ... function rg_user_pass_valid($db, $uid, $pass)
722 720 } }
723 721
724 722 /* /*
723 * Set session cookie
724 */
725 function rg_user_set_session_cookie($db, $uid, $sess_time, $lock_ip)
726 {
727 $secure = FALSE;
728 if (isset($_SERVER['HTTPS']))
729 $secure = TRUE;
730
731 $sid = rg_id(40);
732 rg_sess_add($db, $uid, $sid, $sess_time, $lock_ip);
733 setcookie("sid", $sid, 0, "/", $_SERVER['SERVER_NAME'],
734 $secure, TRUE /* httponly */);
735
736 return $sid;
737 }
738
739 /*
725 740 * Auto login the user * Auto login the user
726 741 */ */
727 742 function rg_user_auto_login($db, $uid, $lock_ip, &$ui) function rg_user_auto_login($db, $uid, $lock_ip, &$ui)
 
... ... function rg_user_auto_login($db, $uid, $lock_ip, &$ui)
740 755 break; break;
741 756 } }
742 757
743 $secure = FALSE;
744 if (isset($_SERVER['HTTPS']))
745 $secure = TRUE;
746
747 $sid = rg_id(40);
748 rg_sess_add($db, $uid, $sid, $ui['session_time'], $lock_ip);
749 setcookie("sid", $sid, 0, "/", $_SERVER['SERVER_NAME'],
750 $secure, TRUE /* httponly */);
758 rg_user_set_session_cookie($db, $uid, $ui['session_time'], $lock_ip);
751 759
752 760 $ret = TRUE; $ret = TRUE;
753 761 break; break;
 
... ... function rg_user_over_limit($db, $ui, &$max)
1352 1360 function rg_user_edit_high_level($db, &$rg) function rg_user_edit_high_level($db, &$rg)
1353 1361 { {
1354 1362 rg_log("user_edit_high_level"); rg_log("user_edit_high_level");
1363 rg_log_ml("user_edit_high_level:rg:" . print_r($rg, TRUE));
1355 1364
1356 1365 $ret = ""; $ret = "";
1357 1366
 
... ... function rg_user_edit_high_level($db, &$rg)
1362 1371 } }
1363 1372
1364 1373 $owner = $rg['target_ui']['uid']; $owner = $rg['target_ui']['uid'];
1365 if (!rg_rights_allow($db, $rg['target_ui']['uid'], "user", $owner,
1366 $rg['login_ui']['uid'], "E", $rg['ip'], "")) {
1367 $ret .= rg_template("access_denied.html", $rg);
1368 return $ret;
1374 if ($owner > 0) {
1375 if (!rg_rights_allow($db, $rg['target_ui']['uid'], "user", $owner,
1376 $rg['login_ui']['uid'], "E", $rg['ip'], "")) {
1377 $ret .= rg_template("access_denied.html", $rg);
1378 return $ret;
1379 }
1369 1380 } }
1370 1381
1371 1382 if ($rg['target_ui']['uid'] > 0) if ($rg['target_ui']['uid'] > 0)

File inc/util.inc.php changed (mode: 100644) (index 9931874..57643d2)
... ... function rg_re_repo_ssh($organization, $user, $repo)
229 229
230 230 function rg_re_repo_git($organization, $user, $repo) function rg_re_repo_git($organization, $user, $repo)
231 231 { {
232 global $rg_git_host;
232 233 global $rg_git_port; global $rg_git_port;
233 234
234 235 if ($rg_git_port == 9418) if ($rg_git_port == 9418)
 
... ... function rg_re_repo_git($organization, $user, $repo)
240 241 if ($organization == 0) if ($organization == 0)
241 242 $prefix = "/user"; $prefix = "/user";
242 243
243 return "git://" . $_SERVER['SERVER_NAME'] . $port
244 return "git://" . $rg_git_host . $port
244 245 . $prefix . "/" . $user . "/" . $repo; . $prefix . "/" . $user . "/" . $repo;
245 246 } }
246 247
 
... ... function rg_replace_conditionals($block, &$data)
634 635 */ */
635 636 function rg_file_get_contents($f) function rg_file_get_contents($f)
636 637 { {
637 if (!file_exists($f))
638 if (!file_exists($f)) {
639 rg_log("CHECK: file $f does not exists. cwd=" . getcwd());
638 640 return ""; return "";
641 }
639 642
640 643 $c = file_get_contents($f); $c = file_get_contents($f);
641 644 if ($c === FALSE) { if ($c === FALSE) {
 
... ... function rg_dir_load_deep($dir)
1029 1032 */ */
1030 1033 function rg_copy_tree($src, $dst, $mask) function rg_copy_tree($src, $dst, $mask)
1031 1034 { {
1035 rg_log("rg_copy_tree($src, $dst, $mask)");
1036
1032 1037 if (!is_dir($dst)) { if (!is_dir($dst)) {
1033 1038 $r = @mkdir($dst, $mask); $r = @mkdir($dst, $mask);
1034 1039 if ($r !== TRUE) { if ($r !== TRUE) {
 
... ... function rg_socket_send($socket, $buf)
1296 1301 * Connects to a socket, send @buf and returns the answer. * Connects to a socket, send @buf and returns the answer.
1297 1302 * @timeout: NULL=forever, 0=no_wait * @timeout: NULL=forever, 0=no_wait
1298 1303 is 0, we do not wait for an answer. If is NULL, we wait forever. is 0, we do not wait for an answer. If is NULL, we wait forever.
1304 * @tries - how many time to retry if it fails
1299 1305 */ */
1300 function rg_socket($path, $buf, $timeout)
1306 function rg_socket($path, $buf, $timeout, $tries)
1301 1307 { {
1302 1308 global $rg_socket_cache; global $rg_socket_cache;
1303 1309
 
... ... function rg_socket($path, $buf, $timeout)
1314 1320 break; break;
1315 1321 } }
1316 1322
1317 // try 3 times
1318 $tries = 3;
1319 1323 while ($tries > 0) { while ($tries > 0) {
1320 1324 $r = socket_connect($socket, $path); $r = socket_connect($socket, $path);
1321 1325 if ($r === FALSE) { if ($r === FALSE) {

File root/index.php changed (mode: 100644) (index c9805d6..808ef8f)
... ... rg_prof_start("MAIN");
25 25
26 26 rg_log_set_file($rg_web_log_dir . "/main.log"); rg_log_set_file($rg_web_log_dir . "/main.log");
27 27
28 // database connection
29 rg_sql_app("rg-web");
30 $db = rg_sql_open($rg_sql);
31
28 32 // Store configuration into 'rg' // Store configuration into 'rg'
29 33 if (!isset($rg_account_email_confirm)) if (!isset($rg_account_email_confirm))
30 34 $rg_account_email_confirm = 1; $rg_account_email_confirm = 1;
 
... ... if (strcmp($_t, "op") == 0) {
58 62
59 63 $rg['doit'] = rg_var_uint("doit"); $rg['doit'] = rg_var_uint("doit");
60 64 $rg['sid'] = rg_var_re("sid", "/[^A-Za-z0-9]/"); $rg['sid'] = rg_var_re("sid", "/[^A-Za-z0-9]/");
65 if (empty($rg['sid']))
66 $rg['sid'] = rg_user_set_session_cookie($db, 0, 600, FALSE);
61 67 $rg['token'] = rg_var_re("token", "/[^A-Za-z0-9]/"); $rg['token'] = rg_var_re("token", "/[^A-Za-z0-9]/");
62 68 $user = ""; $repo = ""; $organization = 0; // TODO: those are really used? $user = ""; $repo = ""; $organization = 0; // TODO: those are really used?
63 69
70 rg_log_ml("rg: " . print_r($rg, TRUE));
71
64 72 $rg['ip'] = isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : ""; $rg['ip'] = isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : "";
65 73 rg_log("IP: " . $rg['ip']); rg_log("IP: " . $rg['ip']);
66 74 rg_log("_REQUEST: " . rg_array2string($_REQUEST)); rg_log("_REQUEST: " . rg_array2string($_REQUEST));
 
... ... rg_log("_COOKIE: " . rg_array2string($_COOKIE));
68 76 rg_log("Start! ver=$rocketgit_version"); rg_log("Start! ver=$rocketgit_version");
69 77
70 78
71 // database connection
72 rg_sql_app("rg-web");
73 $db = rg_sql_open($rg_sql);
74
75 79 $good = 0; $good = 0;
76 80 $tries = 10; $tries = 10;
77 81 while ($tries > 0) { while ($tries > 0) {

File root/themes/default/main.css changed (mode: 100644) (index 562db34..c37097c)
... ... form input[type="submit"] {
244 244 .repo_title { .repo_title {
245 245 font-size: 15pt; font-size: 15pt;
246 246 font-weight: bold; font-weight: bold;
247 color: red;
247 color: #bbbbbb;
248 248 } }
249 249 .repo_title a { .repo_title a {
250 250 text-decoration: none; text-decoration: none;

File root/themes/default/repo/main.html changed (mode: 100644) (index ce0dc59..d8dd3fa)
3 3 <div> <div>
4 4 <div class="repo_title"> <div class="repo_title">
5 5 <a href="@@url_user@@">@@page_ui.username@@</a> / <a href="@@url_repo@@">@@ri.name@@</a> <a href="@@url_user@@">@@page_ui.username@@</a> / <a href="@@url_repo@@">@@ri.name@@</a>
6 (@@if(@@ri.public@@ == 1){{public}}{{private}})
6 7 </div> </div>
7 8 <div class="repo_desc"> <div class="repo_desc">
8 9 @@ri.description_nice@@ @@ri.description_nice@@

File root/themes/default/user/add_edit.html changed (mode: 100644) (index 139d15d..c7d1dac)
4 4
5 5 @@errmsg@@ @@errmsg@@
6 6
7 <form method="post" action="/op/settings/edit_info">
7 <form method="post" action="/op/@@if(@@create_mode@@ == 1){{create_account}}{{settings/edit_info}}">
8 8 <input type="hidden" name="uid" value="@@uid@@" /> <input type="hidden" name="uid" value="@@uid@@" />
9 9 <input type="hidden" name="doit" value="1" /> <input type="hidden" name="doit" value="1" />
10 10 <input type="hidden" name="token" value="@@rg_form_token@@" /> <input type="hidden" name="token" value="@@rg_form_token@@" />

File root/themes/default/user/repo/rights/form_repo.html changed (mode: 100644) (index 8655cd5..14241a1)
28 28 <br /> <br />
29 29 <br /> <br />
30 30
31 <label class="form_item_title" for="prio">Priority (at least 10)</label><br />
31 <label class="form_item_title" for="prio">Priority (10 - 30000)</label><br />
32 32 <input type="text" name="prio" value="@@prio@@" /> <input type="text" name="prio" value="@@prio@@" />
33 33 <br /> <br />
34 34 <br /> <br />

File root/themes/default/user/repo/rights/form_repo_path.html changed (mode: 100644) (index 55f9a6e..b21f2f9)
33 33 <br /> <br />
34 34 <br /> <br />
35 35
36 <label class="form_item_title" for="prio">Priority (at least 10)</label><br />
36 <label class="form_item_title" for="prio">Priority (10 - 30000)</label><br />
37 37 <input type="text" name="prio" value="@@prio@@" /> <input type="text" name="prio" value="@@prio@@" />
38 38 <br /> <br />
39 39 <br /> <br />

File root/themes/default/user/repo/rights/form_repo_refs.html changed (mode: 100644) (index 5771ef5..c3ebe9d)
33 33 <br /> <br />
34 34 <br /> <br />
35 35
36 <label class="form_item_title" for="prio">Priority (at least 10)</label><br />
36 <label class="form_item_title" for="prio">Priority (10 - 30000)</label><br />
37 37 <input type="text" name="prio" value="@@prio@@" /> <input type="text" name="prio" value="@@prio@@" />
38 38 <br /> <br />
39 39 <br /> <br />

File samples/config.php changed (mode: 100644) (index 0e20126..9ed16d4)
... ... $rg_ssh_host = "x.company.tld";
76 76 // SSH port - put 0 to disable // SSH port - put 0 to disable
77 77 $rg_ssh_port = 22; $rg_ssh_port = 22;
78 78
79 // git host - leave empty to autodetect
80 $rg_git_host = "x.company.tld";
79 81 // Git port - put 0 to disable (standard is 9418) // Git port - put 0 to disable (standard is 9418)
80 82 $rg_git_port = 9418; $rg_git_port = 9418;
81 83

File scripts/wake.php changed (mode: 100644) (index 42f815d..04e15e6)
... ... require_once($INC . "/fixes.inc.php");
25 25 rg_log_set_file($rg_log_dir . "/wake.log"); rg_log_set_file($rg_log_dir . "/wake.log");
26 26 rg_log_set_sid("000000"); // to spread the logs rg_log_set_sid("000000"); // to spread the logs
27 27
28 rg_event_signal_daemon("", NULL);
28 rg_event_signal_daemon("", 0);
29 29
30 30 ?> ?>

File tests/Makefile changed (mode: 100644) (index 779eddb..af4d9db)
1 tests := util log state cache prof db event rights keys user repo git bug \
2 hook_update hook_update_anon hook_update_anon_nm
1 tests := token util log state cache prof db event rights keys user repo git bug \
2 hook_update http_create_account
3 3 .PHONY: $(tests) .PHONY: $(tests)
4 4
5 5 all: $(tests) all: $(tests)
6 6
7 token:
8 php token.php
9
7 10 util: util:
8 11 php util.php php util.php
9 12
 
... ... cache:
46 49 hook_update: hook_update:
47 50 ./hook_update.sh ./hook_update.sh
48 51
49 hook_update_anon:
50 ./hook_update_anon.sh
51
52 hook_update_anon_nm:
53 ./hook_update_anon_nm.sh
52 http_create_account:
53 php http_create_account.php
54 54
55 55 .PHONY: clean .PHONY: clean
56 56 clean: clean:

File tests/bug.php changed (mode: 100644) (index 39e7701..a80f5b4)
... ... require_once("common.php");
17 17 // defaults // defaults
18 18 $uid = 1; $uid = 1;
19 19 $ui = array("uid" => $uid, "username" => "userX", "organization" => 0, "email" => "test@embedromix.ro"); $ui = array("uid" => $uid, "username" => "userX", "organization" => 0, "email" => "test@embedromix.ro");
20 $repo_name = "A";
20 $repo_name = "bug-A";
21 21
22 22 rg_log("Creating a repo"); rg_log("Creating a repo");
23 23 $new = array(); $new = array();
 
... ... if (strcmp($r[2], "label3") != 0) {
64 64
65 65 // add user // add user
66 66 $_u['uid'] = 0; $_u['uid'] = 0;
67 $_u['realname'] = "userA real name";
68 $_u['username'] = "userA";
67 $_u['realname'] = "user-bug-A real name";
68 $_u['username'] = "user-bug-A";
69 69 $_u['email'] = "rg@localhost"; $_u['email'] = "rg@localhost";
70 70 $_u['pass'] = "pass1"; $_u['pass'] = "pass1";
71 71 $_u['pass2'] = "pass1"; $_u['pass2'] = "pass1";
 
... ... if ($r['exists'] != 0) {
101 101 } }
102 102
103 103 // Search bugs // Search bugs
104 $q = array("reported_by" => "userA",
105 "assigned_to" => "userA",
104 $q = array("reported_by" => "user-bug-A",
105 "assigned_to" => "user-bug-A",
106 106 "state" => "1", "state" => "1",
107 107 "start" => "2000-01-01", "start" => "2000-01-01",
108 108 "end" => "2001-01-01", "end" => "2001-01-01",

File tests/config.php changed (mode: 100644) (index 6a2ce3a..48971f8)
... ... $rg_web_log_dir = dirname(__FILE__);
24 24 $rg_state_dir = dirname(__FILE__); $rg_state_dir = dirname(__FILE__);
25 25 $rg_lock_dir = dirname(__FILE__); $rg_lock_dir = dirname(__FILE__);
26 26 $rg_repos = "base"; $rg_repos = "base";
27 $rg_theme_dir = "themes";
27 $rg_theme_dir = $rg_base . "/themes";
28 28 $rg_theme = "util"; $rg_theme = "util";
29 29 $rg_lang = "en"; $rg_lang = "en";
30 30 $rg_cache_enable = FALSE; $rg_cache_enable = FALSE;
31 31 $rg_event_socket = ""; $rg_event_socket = "";
32 32
33 // For http testing
34 $test_url = "http://r1i:9000";
35
33 36 ?> ?>

File tests/event.php changed (mode: 100644) (index 2336628..009fc29)
... ... require_once("common.php");
19 19
20 20 $rg_sql_debug = 1; $rg_sql_debug = 1;
21 21
22 $sql = "DELETE FROM events";
23 $res = rg_sql_query($db, $sql);
24 rg_sql_free_result($res);
25
22 26 /* /*
23 27 * This function will generate an array of sub-events * This function will generate an array of sub-events
24 28 */ */
 
... ... function notif_new_repo($db, $ev)
28 32
29 33 $ret = array(); $ret = array();
30 34
31 // Send mail to the owner
32 $ret[] = array_merge($ev, array("category" => 1, "prio" => 1));
33
34 // Send mail to admin
35 // Action 1
35 36 $ret[] = array_merge($ev, array("category" => 2, "prio" => 1)); $ret[] = array_merge($ev, array("category" => 2, "prio" => 1));
36 37
37 // Other junk
38 // Action 2
38 39 $ret[] = array_merge($ev, array("category" => 3, "prio" => 1)); $ret[] = array_merge($ev, array("category" => 3, "prio" => 1));
39 40
40 41 return $ret; return $ret;
41 42 } }
42 43
44 function func2and3($db, $ev)
45 {
46 rg_log_ml("ev=" . print_r($ev, TRUE));
47
48 return array();
49 }
50
43 51 // Register an event function // Register an event function
44 52 $functions = array(); $functions = array();
45 53 $functions[1] = "notif_new_repo"; $functions[1] = "notif_new_repo";
54 $functions[2] = "func2and3";
55 $functions[3] = "func2and3";
46 56 $r = rg_event_register_functions($functions); $r = rg_event_register_functions($functions);
47 57 if ($r !== TRUE) { if ($r !== TRUE) {
48 58 echo "Cannot register functions!\n"; echo "Cannot register functions!\n";

File tests/hook_update.sh changed (mode: 100755) (index fc009b9..ec53c82)
... ... git init --bare
17 17 ) )
18 18 cp -v ../hooks/update hook_update_dest.git/hooks/ cp -v ../hooks/update hook_update_dest.git/hooks/
19 19
20 ln -sf ../../root/themes/default themes/
21
20 22 git clone hook_update_dest.git hook_update_src.git git clone hook_update_dest.git hook_update_src.git
21 23
22 24 cd hook_update_src.git cd hook_update_src.git
 
... ... fi
215 217
216 218 echo echo
217 219 echo "=== Preparing for anonymous push..." echo "=== Preparing for anonymous push..."
220 # We should allow only W? TODO
221 export ROCKETGIT_REPO_RIGHTS="W"
222 php ${tests}/hook_update_help.php refs
218 223 export GIT_NAMESPACE="hook_update_ns1" export GIT_NAMESPACE="hook_update_ns1"
219 git commit --amend -m "new"
224 echo "xx" > b; git add b
225 git commit -m "preparing for anonymous push" b
226 # We need to do this because it is done in remote.php that we do not call here
227 X="../hook_update_dest.git/refs/namespaces/${GIT_NAMESPACE}/refs/heads"
228 mkdir -p ${X}
229 cp -a ../hook_update_dest.git/refs/heads/* "${X}/"
220 230 echo "=== Testing anonymous push without rights..." echo "=== Testing anonymous push without rights..."
231 #strace -s200 -ff -o ${tests}/hook_update.strace \
221 232 git push origin master git push origin master
222 233 if [ "${?}" != "1" ]; then if [ "${?}" != "1" ]; then
223 234 echo "Should not work!" echo "Should not work!"
 
... ... if [ "${?}" != "0" ]; then
231 242 echo "Should work!" echo "Should work!"
232 243 exit 1 exit 1
233 244 fi fi
245 # Test if the namespace was updated instead of main namespace
246 A=`diff ../hook_update_dest.git/refs/namespaces/${GIT_NAMESPACE}/refs/heads/master \
247 .git/refs/heads/master`
248 if [ "${?}" != 0 ]; then
249 echo "Cannot do the diff for anonymous push"
250 exit 1
251 fi
252 if [ "${A}" != "" ]; then
253 echo "We did not update the namespace!"
254 exit 1
255 fi
256 A=`diff ../hook_update_dest.git/refs/heads/master \
257 .git/refs/heads/master`
258 if [ "${A}" = "" ]; then
259 echo "Seems we updated also main namespace!"
260 exit 1
261 fi
262
263 # TODO: we should not allow force pushes on anonymous branches?
264
265
266 echo "=== Preparing for branch anonymous push without rights..."
267 echo "*** Creating a branch..."
268 git checkout -b branch_anon1
269 echo "=== Testing branch anonymous push without rights..."
270 export ROCKETGIT_REPO_RIGHTS=""
271 php ${tests}/hook_update_help.php refs
272 git push origin branch_anon1:branch_anon1
273 if [ "${?}" = "0" ]; then
274 echo "Should not work!"
275 exit 1
276 fi
277 echo "=== Testing branch anonymous push with rights..."
278 export ROCKETGIT_REPO_RIGHTS="H"
279 php ${tests}/hook_update_help.php refs
280 git push origin branch_anon1:branch_anon1
281 if [ "${?}" != "0" ]; then
282 echo "Should work!"
283 exit 1
284 fi
285 # Test if the namespace was updated instead of the namespace
286 if [ "${?}" != 0 ]; then
287 echo "Cannot do the diff for anonymous push"
288 exit 1
289 fi
290 A=`diff ../hook_update_dest.git/refs/namespaces/${GIT_NAMESPACE}/refs/heads/branch_anon1 \
291 .git/refs/heads/branch_anon1`
292 if [ "${A}" != "" ]; then
293 echo "We did not update the namespace but main refs (anon+branch)!"
294 exit 1
295 fi
296 A=`diff ../hook_update_dest.git/refs/heads/master \
297 .git/refs/heads/branch_anon1`
298 if [ "${A}" = "" ]; then
299 echo "Seems we updated also main refs (anon+branch)!"
300 exit 1
301 fi
302
234 303
235 304 cd .. cd ..
236 305

File tests/hook_update_anon.sh deleted (index 9b3885e..0000000)
1 #!/bin/bash
2
3 # Test anonymous push
4
5 export ROCKETGIT_CONF_FILE="`pwd`/common.php"
6
7 C=`pwd`
8
9 rm -rf hook_update_anon_*.git
10 mkdir hook_update_anon_dest.git
11 (
12 cd hook_update_anon_dest.git
13 git init --bare
14 )
15 cp ../hooks/* hook_update_anon_dest.git/hooks/
16
17 git clone hook_update_anon_dest.git hook_update_anon_src.git
18
19 cd hook_update_anon_src.git
20
21 mkdir -p "${C}/mr_queue"
22
23 export ROCKETGIT_REPO_ID=2000000000
24 export ROCKETGIT_IP="IP"
25 export GIT_NAMESPACE="abcdefgh" # we have to set it manually
26 export ROCKETGIT_MR_QUEUE="${C}/mr_queue"
27
28 rm -f ../mr_queue/mr-${ROCKETGIT_REPO_ID}-*
29
30 echo "=== Preparing repo..."
31 echo "bbb" > a
32 git add a
33 git commit -m "b" a
34
35 echo "=== Testing anon push without rights..."
36 export ROCKETGIT_REPO_RIGHTS=""
37 git push origin master
38 if [ "${?}" = "0" ]; then
39 echo "Should not work!"
40 exit 1
41 fi
42
43 set -e
44 echo "=== Testing anon push with rights..."
45 export ROCKETGIT_REPO_RIGHTS="H"
46 git push origin master
47 if [ "${?}" != "0" ]; then
48 echo "Should work!"
49 exit 1
50 fi
51 # Test if the namespace was updated instead of main namespace
52 diff ../hook_update_anon_dest.git/refs/namespaces/${GIT_NAMESPACE}/refs/heads/master \
53 .git/refs/heads/master
54 if [ "${?}" != "0" ]; then
55 echo "We did not update the namespace!"
56 exit 1
57 fi
58 if [ -r ../hook_update_anon_dest.git/refs/heads/master ]; then
59 echo "Seems we updated also main namespace!"
60 exit 1
61 fi
62 if [ "`ls ../mr_queue/mr-${ROCKETGIT_REPO_ID}-*`" = "" ]; then
63 echo "Seems that the merge queue file was not created!"
64 exit 1
65 fi
66
67 # TODO: we should not allow force pushes on anon branches
68
69 cd ..
70
71 rm -rf hook_update_anon_*.git
72
73 echo "hook_update_anon: OK!"

File tests/hook_update_anon_nm.sh deleted (index 8949310..0000000)
1 #!/bin/bash
2
3 # Test anonymous push with a custom branch
4 # nm = non-master
5
6 export ROCKETGIT_CONF_FILE="`pwd`/common.php"
7
8 C=`pwd`
9 P="hook_update_anon_nm"
10
11 rm -rf ${P}_*.git
12 mkdir ${P}_dest.git
13 (
14 cd ${P}_dest.git
15 git init --bare
16 )
17 cp ../hooks/* ${P}_dest.git/hooks/
18
19 git clone ${P}_dest.git ${P}_src.git
20
21 cd ${P}_src.git
22
23 mkdir -p "${C}/mr_queue"
24
25 export ROCKETGIT_REPO_ID=2000000001
26 export ROCKETGIT_IP="IP"
27 export GIT_NAMESPACE="abcdefgh" # we have to set it manually
28 export ROCKETGIT_MR_QUEUE="${C}/mr_queue"
29
30 rm -f ../mr_queue/mr-${ROCKETGIT_REPO_ID}-*
31
32 echo "=== Preparing repo..."
33 echo "bbb" > a
34 git add a
35 git commit -m "b" a
36
37 echo "*** Creating a branch..."
38 export ROCKETGIT_REPO_RIGHTS="CP"
39 git checkout -b branch1
40 git push origin branch1
41
42 echo "=== Testing anon push without rights..."
43 export ROCKETGIT_REPO_RIGHTS=""
44 git push origin master
45 if [ "${?}" = "0" ]; then
46 echo "Should not work!"
47 exit 1
48 fi
49
50 set -e
51 echo "=== Testing anon push with rights..."
52 export ROCKETGIT_REPO_RIGHTS="H"
53 git push origin master
54 if [ "${?}" != "0" ]; then
55 echo "Should work!"
56 exit 1
57 fi
58 # Test if the namespace was updated instead of main namespace
59 diff ../${P}_dest.git/refs/namespaces/${GIT_NAMESPACE}/refs/heads/master \
60 .git/refs/heads/master
61 if [ "${?}" != "0" ]; then
62 echo "We did not update the namespace!"
63 exit 1
64 fi
65 if [ -r ../${P}_dest.git/refs/heads/master ]; then
66 echo "Seems we updated also main namespace!"
67 exit 1
68 fi
69 if [ "`ls ../mr_queue/mr-${ROCKETGIT_REPO_ID}-*`" = "" ]; then
70 echo "Seems that the merge queue file was not created!"
71 exit 1
72 fi
73
74 # TODO: we should not allow force pushes on anon branches
75
76 cd ..
77
78 rm -rf ${P}_*.git
79
80 echo "hook_update_anon_nm: OK!"

File tests/http.inc.php added (mode: 100644) (index 0000000..4e7c1d8)
1 <?php
2
3 /*
4 * Data is an array
5 */
6 function do_req($url, $data, $headers)
7 {
8 rg_log_ml("do_req url[$url] data=" . print_r($data, TRUE)
9 . "headers=" . print_r($headers, TRUE));
10
11 //$sdata = http_build_query($data);
12
13 $c = curl_init($url);
14 if (count($data) > 0) {
15 curl_setopt($c, CURLOPT_POST, 1);
16 curl_setopt($c, CURLOPT_POSTFIELDS, $data);
17 }
18 curl_setopt($c, CURLOPT_RETURNTRANSFER, TRUE);
19 // We cannot use this because we will not have a
20 // chanse to capture the sid.
21 //curl_setopt($c, CURLOPT_FOLLOWLOCATION, 1);
22 curl_setopt($c, CURLOPT_HEADER, 1);
23 curl_setopt($c, CURLOPT_HTTPHEADER, $headers);
24
25 $r = curl_exec($c);
26 if ($r === FALSE) {
27 rg_log("Cannot exec (url=$url), data: " . print_r($data, TRUE));
28 return FALSE;
29 }
30
31 $ret = array();
32 $header_size = curl_getinfo($c, CURLINFO_HEADER_SIZE);
33 $ret['header'] = substr($r, 0, $header_size);
34 $ret['body'] = substr($r, $header_size);
35 curl_close($c);
36
37 // find sid
38 $x = preg_match('/Set-Cookie: sid=([a-zA-Z0-9]*)/', $ret['header'], $matches);
39 if (($x === FALSE) || (!isset($matches[1]))) {
40 $ret['sid'] = "";
41 } else {
42 $ret['sid'] = $matches[1];
43 if (strlen($ret['sid']) != 40)
44 $ret['sid'] = "";
45 }
46
47 // find token
48 $x = preg_match('/ name="token" value="([a-zA-Z0-9]*)"/', $ret['body'], $matches);
49 if (($x === FALSE) || (!isset($matches[1]))) {
50 $ret['token'] = "";
51 } else {
52 $ret['token'] = $matches[1];
53 if (strlen($ret['token']) != 16)
54 $ret['token'] = "";
55 }
56
57 $x = preg_match('/Location: (.*)\s/', $ret['header'], $matches);
58 if ($x > 0) {
59 if (strncmp($url, "http://", 7) == 0)
60 $url = substr($url, 7);
61 rg_log("url=$url");
62 $t = explode("/", $url, 2);
63 $new = "http://" . $t[0] . $matches[1];
64 rg_log("Redirecting to $new...");
65 $data = array();
66 $headers = array("Cookie: sid=" . $ret['sid']);
67 $f = do_req($new, $data, $headers);
68 if (empty($f['sid']))
69 $f['sid'] = $ret['sid'];
70 return $f;
71 }
72
73 return $ret;
74 }
75
76 ?>

File tests/http_login.php added (mode: 100644) (index 0000000..34308a6)
1 <?php
2 error_reporting(E_ALL | E_STRICT);
3 ini_set("track_errors", "On");
4
5 $INC = dirname(__FILE__) . "/../inc";
6 require_once(dirname(__FILE__) . "/config.php");
7 require_once($INC . "/init.inc.php");
8 require_once($INC . "/util.inc.php");
9 require_once("http.inc.php");
10
11 rg_log_set_file("http_login.log");
12
13 $rg_no_db = TRUE;
14 require_once("common.php");
15
16 rg_log("Test login operation");
17 // First we need to load the form so we can get the token
18 $data = array();
19 $headers = array();
20 $r = do_req($test_url . "/op/login", $data, $headers);
21 if ($r === FALSE) {
22 echo "Cannot load login form.\n";
23 exit(1);
24 }
25 rg_log_ml("After loading login form, r: " . print_r($r, TRUE));
26
27 // Second, do the request
28 $data = array(
29 "doit" => 1,
30 "token" => $r['token'],
31 "user" => "catab",
32 "pass" => "aaaa",
33 "lock_ip" => 1
34 );
35 $headers = array("Cookie: sid=" . $r['sid']);
36 $r = do_req($test_url . "/op/login", $data, $headers);
37 if ($r === FALSE) {
38 rg_log_ml("Cannot login: " . print_r($r, TRUE));
39 exit(1);
40 }
41 rg_log_ml("After doing login, r: " . print_r($r, TRUE));
42 if (strstr($r['body'], "invalid user or pass")) {
43 rg_log("Login invalid: " . print_r($r, TRUE));
44 exit(1);
45 }
46
47 ?>

File tests/keys.php changed (mode: 100644) (index 9dc8b13..7836276)
... ... $rg_admin_email = "rg@embedromix.ro";
22 22
23 23 $rg_ui = array("uid" => 1, "is_admin" => 0, "email" => "test@embedromix.ro"); $rg_ui = array("uid" => 1, "is_admin" => 0, "email" => "test@embedromix.ro");
24 24
25 $sql = "DELETE FROM keys";
26 $res = rg_sql_query($db, $sql);
27 rg_sql_free_result($res);
28
25 29 // insert a key 1 // insert a key 1
26 30 $key = "aaa 'bbb' first_key"; $key = "aaa 'bbb' first_key";
27 31 $key_id1 = rg_keys_add($db, $rg_ui, $key); $key_id1 = rg_keys_add($db, $rg_ui, $key);

File tests/repo.php changed (mode: 100644) (index 44b983b..c3d876d)
... ... require_once("common.php");
20 20
21 21 $rg_sql_debug = 1; $rg_sql_debug = 1;
22 22
23 $sql = "DELETE FROM repos";
24 $res = rg_sql_query($db, $sql);
25 rg_sql_free_result($res);
26
23 27 rg_log("rg_repo_path 1"); rg_log("rg_repo_path 1");
24 28 $e = $rg_repos . "/by_id/11/22/33/44/11223344/repos/by_id/55.git"; $e = $rg_repos . "/by_id/11/22/33/44/11223344/repos/by_id/55.git";
25 29 $c = rg_repo_path_by_id(0x11223344, 55); $c = rg_repo_path_by_id(0x11223344, 55);
 
... ... if ($v === FALSE) {
169 173 exit(1); exit(1);
170 174 } }
171 175
172 rg_log("non-owner gets correct rights: A gets from injected rights.");
176 rg_log("non-owner gets correct rights: 'A' is from injected rights.");
173 177 $a = array(); $a = array();
174 178 $a['right_id'] = 0; $a['right_id'] = 0;
175 179 $a['obj_id'] = $ri['repo_id']; $a['obj_id'] = $ri['repo_id'];
 
... ... if ($r !== TRUE) {
185 189 rg_log("Cannot set rights (" . rg_rights_error() . ")!"); rg_log("Cannot set rights (" . rg_rights_error() . ")!");
186 190 exit(1); exit(1);
187 191 } }
188 $e = "A"; // will not match the above right but the one injected
192 $e = "AB"; // will not match the above right but the one injected
189 193 $r = rg_rights_get($db, $ri['repo_id'], "repo", $uid, $a['uid'], 0); $r = rg_rights_get($db, $ri['repo_id'], "repo", $uid, $a['uid'], 0);
190 194 $c = isset($r['list'][0]['rights']) ? $r['list'][0]['rights'] : "_BAD_"; $c = isset($r['list'][0]['rights']) ? $r['list'][0]['rights'] : "_BAD_";
191 195 if (strcmp($c, $e) != 0) { if (strcmp($c, $e) != 0) {

File tests/rights.php changed (mode: 100644) (index 2ebf8cd..349438c)
... ... $rg_sql_debug = 1;
17 17 $rg_admin_email = "rg@embedromix.ro"; $rg_admin_email = "rg@embedromix.ro";
18 18
19 19
20 $sql = "DELETE FROM rights";
21 $res = rg_sql_query($db, $sql);
22 rg_sql_free_result($res);
23
20 24 rg_log("test if combine works correctly (1)"); rg_log("test if combine works correctly (1)");
21 25 $a = "AF"; $b = "AD"; $e = "AFD"; $a = "AF"; $b = "AD"; $e = "AFD";
22 26 $r = rg_rights_combine($a, $b); $r = rg_rights_combine($a, $b);
 
... ... if (($r['ok'] !== 1) || (strcmp($r['list'][1]['rights'], "d") != 0)) {
106 110 } }
107 111
108 112 rg_log("Testing delete_list..."); rg_log("Testing delete_list...");
109 $list = array(1, 2);
113 $list = array();
114 foreach ($r['list'] as $junk => $i)
115 $list[] = $i['right_id'];
110 116 $r = rg_rights_delete_list($db, "type1", $a['obj_id'], $list); $r = rg_rights_delete_list($db, "type1", $a['obj_id'], $list);
111 117 if ($r !== TRUE) { if ($r !== TRUE) {
112 118 echo "We should be able to delete rights!\n"; echo "We should be able to delete rights!\n";
 
... ... if ($r !== TRUE) {
115 121 $right_id = 0; $right_id = 0;
116 122 $r = rg_rights_get($db, $a['obj_id'], "type1", $a['who'], $a['uid'], $right_id); $r = rg_rights_get($db, $a['obj_id'], "type1", $a['who'], $a['uid'], $right_id);
117 123 if (($r['ok'] !== 1) || (count($r['list']) > 0)) { if (($r['ok'] !== 1) || (count($r['list']) > 0)) {
118 echo "We should not have anymore type1 objects, after a delete.\n";
119 124 print_r($r); print_r($r);
125 echo "We should not have anymore type1 objects, after a delete.\n";
120 126 exit (1); exit (1);
121 127 } }
122 128

File tests/token.php added (mode: 100644) (index 0000000..2d72466)
1 <?php
2 error_reporting(E_ALL | E_STRICT);
3 ini_set("track_errors", "On");
4
5 $INC = dirname(__FILE__) . "/../inc";
6 require_once(dirname(__FILE__) . "/config.php");
7 require_once($INC . "/init.inc.php");
8 require_once($INC . "/util.inc.php");
9 require_once($INC . "/log.inc.php");
10 require_once($INC . "/token.inc.php");
11
12 rg_log_set_file("token.log");
13
14 $rg_no_db = TRUE;
15 require_once("common.php");
16
17 $sid = "session1";
18 $token = rg_token_get($db, $sid);
19 if ($token === FALSE) {
20 rg_log("Generating a token should not fail (" . rg_token_error() . ")!");
21 exit(1);
22 }
23 rg_log("Correct token: $token");
24
25 $bad_len = substr($token, 0, 16 + 40 - 1) . "invalidlen";
26 $r = rg_token_valid($db, $sid, $bad_len);
27 if ($r !== FALSE) {
28 rg_log("Invalid length token must return error!");
29 exit(1);
30 }
31
32 $copy = substr($token, 0, 16 + 40 - 1) . "z";
33 $r = rg_token_valid($db, $sid, $copy);
34 if ($r !== FALSE) {
35 rg_log("Altering a token must return error!");
36 exit(1);
37 }
38
39 $r = rg_token_valid($db, $sid . "Z", $token);
40 if ($r !== FALSE) {
41 rg_log("Altering a sid must return error!");
42 exit(1);
43 }
44
45 $r = rg_token_valid($db, $sid, $token);
46 if ($r === FALSE) {
47 rg_log("Validating a correct token must work (" . rg_token_error() . ")!");
48 exit(1);
49 }
50
51 echo "token: OK!\n";
52 ?>

File tests/user.php changed (mode: 100644) (index 5ce58ca..56c7d4c)
... ... if ($r['ok'] != 1) {
33 33 exit(1); exit(1);
34 34 } }
35 35
36 $sql = "DELETE FROM users";
37 $res = rg_sql_query($db, $sql);
38 rg_sql_free_result($res);
36 39
37 40 // Test if empty uid/user/email returns error // Test if empty uid/user/email returns error
38 41 $_ui = rg_user_info($db, 0, "", ""); $_ui = rg_user_info($db, 0, "", "");
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