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 e503666df79ef1553d0bb7ffd1d12a6b62748b1c

Big commit of a lot of unrelated changes. Shame on me!
First working version of continuous integration build system.
Added first round of API access.
Unit testing for forgot password.
Author: Catalin(ux) M. BOIE
Author date (UTC): 2016-07-06 04:44
Committer name: Catalin(ux) M. BOIE
Committer date (UTC): 2016-07-06 04:47
Parent(s): 57baca81e9087a00a8e2e1807c932de2fb9769c4
Signing key:
Tree: eeacbf4e74388026d051f45b9d2538a14e0f70fa
File Lines added Lines deleted
README 11 4
TODO 106 25
inc/admin.inc.php 12 3
inc/admin/admin.php 12 1
inc/admin/plans/plans.php 1 1
inc/admin/repos/repos.php 1 1
inc/admin/users/users.php 1 1
inc/api.inc.php 49 0
inc/apikeys.inc.php 578 0
inc/builder.inc.php 17 9
inc/cache.inc.php 22 0
inc/conn.inc.php 40 7
inc/dispatch/dispatch.php 17 0
inc/git.inc.php 10 6
inc/init.inc.php 1 1
inc/keys.inc.php 35 5
inc/mail.inc.php 9 2
inc/repo.inc.php 154 5
inc/rights.inc.php 2 0
inc/sql.inc.php 12 4
inc/ssh.inc.php 42 1
inc/struct.inc.php 39 1
inc/totp.inc.php 1 1
inc/user.inc.php 100 20
inc/user/forgot_send.php 6 5
inc/user/keys/keys.php 17 17
inc/user/settings.php 12 2
inc/util.inc.php 26 1
inc/webhooks.inc.php 2 2
inc/wh/amazon.inc.php 1 1
inc/wh/build.inc.php 111 20
inc/wh/cloud.inc.php 1 1
inc/wh/core.inc.php 2 2
inc/wh/http.inc.php 7 4
inc/wh/lambda.inc.php 1 1
inc/workers.inc.php 675 0
rocketgit.spec.in 2 2
root/index.php 63 4
root/themes/default/admin/menu.html 2 1
root/themes/default/admin/plans/list/footer.html 0 1
root/themes/default/admin/plans/list/header.html 1 3
root/themes/default/doc/api.html 313 0
root/themes/default/doc/worker.html 65 0
root/themes/default/features.html 26 26
root/themes/default/hints/ssh/cmds.html 2 1
root/themes/default/index.html 6 1
root/themes/default/mail/user/ak/del.body.txt 1 1
root/themes/default/mail/user/ak/del.head.txt 0 0
root/themes/default/mail/user/ak/del.subj.txt 1 0
root/themes/default/mail/user/ak/new.body.txt 9 0
root/themes/default/mail/user/ak/new.head.txt 0 0
root/themes/default/mail/user/ak/new.subj.txt 1 0
root/themes/default/mail/user/forgot/recover.body.txt 8 0
root/themes/default/mail/user/forgot/recover.head.txt 0 0
root/themes/default/mail/user/forgot/recover.subj.txt 1 0
root/themes/default/mail/user/key/del.body.txt 1 1
root/themes/default/mail/user/key/del.subj.txt 1 1
root/themes/default/main.css 32 29
root/themes/default/pricing.html 8 8
root/themes/default/repo/list/line.html 1 1
root/themes/default/repo/mr/merge_in_progress.html 1 1
root/themes/default/tos.html 2 2
root/themes/default/user/keys/add_ok.html 1 1
root/themes/default/user/keys/list/footer.html 0 1
root/themes/default/user/keys/list/header.html 0 2
root/themes/default/user/keys/remove_ok.html 1 1
root/themes/default/user/repo/rights/delete_ok.html 1 1
root/themes/default/user/repo/rights/grant_ok.html 1 1
root/themes/default/user/repo/rights/list_repo/footer.html 0 1
root/themes/default/user/repo/rights/list_repo/header.html 1 3
root/themes/default/user/repo/rights/list_repo_path/footer.html 0 1
root/themes/default/user/repo/rights/list_repo_path/header.html 1 3
root/themes/default/user/repo/rights/list_repo_refs/footer.html 0 1
root/themes/default/user/repo/rights/list_repo_refs/header.html 1 3
root/themes/default/user/settings/apikeys/add.html 24 0
root/themes/default/user/settings/apikeys/add_ok.html 5 0
root/themes/default/user/settings/apikeys/delete_ok.html 3 0
root/themes/default/user/settings/apikeys/hints.html 10 0
root/themes/default/user/settings/apikeys/list/footer.html 0 1
root/themes/default/user/settings/apikeys/list/header.html 6 9
root/themes/default/user/settings/apikeys/list/line.html 11 0
root/themes/default/user/settings/apikeys/list/nodata.html 1 1
root/themes/default/user/settings/apikeys/list_err.html 3 0
root/themes/default/user/settings/apikeys/menu.html 6 0
root/themes/default/user/settings/menu.html 3 1
root/themes/default/user/settings/totp/delete_ok.html 1 1
root/themes/default/user/settings/totp/enroll.html 1 1
root/themes/default/user/settings/totp/list/footer.html 0 1
root/themes/default/user/settings/totp/list/header.html 1 3
root/themes/default/user/settings/totp/sc/delete_ok.html 1 1
root/themes/default/user/settings/totp/sc/gen_ok.html 2 1
root/themes/default/user/settings/totp/sc/list/footer.html 0 1
root/themes/default/user/settings/totp/sc/list/header.html 1 3
root/themes/default/user/settings/wh/build/env_show_one.html 3 0
root/themes/default/user/settings/wh/build/form.html 10 0
root/themes/default/user/settings/wh/build/form_env.html 3 0
root/themes/default/user/settings/wh/build/inv_env.txt 1 0
root/themes/default/user/settings/wh/build/show.html 13 1
root/themes/default/user/settings/wh/delete_ok.html 1 1
root/themes/default/user/settings/wh/edit_ok.html 1 1
root/themes/default/user/settings/wh/list/footer.html 0 1
root/themes/default/user/settings/wh/list/header.html 1 3
root/themes/default/user/settings/workers/add.html 36 0
root/themes/default/user/settings/workers/add_ok.html 3 0
root/themes/default/user/settings/workers/delete_ok.html 3 0
root/themes/default/user/settings/workers/hints.html 12 0
root/themes/default/user/settings/workers/list/footer.html 0 1
root/themes/default/user/settings/workers/list/header.html 22 0
root/themes/default/user/settings/workers/list/line.html 14 0
root/themes/default/user/settings/workers/list/nodata.html 1 1
root/themes/default/user/settings/workers/list_err.html 3 0
root/themes/default/user/settings/workers/menu.html 6 0
samples/config.php 1 0
samples/cron 3 0
samples/worker.conf.sample 46 0
scripts/builder.php 197 55
scripts/cron.php 2 2
scripts/remote.php 31 13
scripts/worker.php 177 64
techdocs/slack.txt 12 0
tests/.gitignore 1 0
tests/Makefile 9 2
tests/api.sh 8 0
tests/email.php 0 2
tests/export.php 56 0
tests/helpers.inc.php 80 1
tests/http_forgot.php 134 0
File README changed (mode: 100644) (index f6624be..95543a1)
65 65 . Configure PostgreSQL server . Configure PostgreSQL server
66 66 Fedora: Fedora:
67 67 # systemctl enable postgresql.service # systemctl enable postgresql.service
68 # postgresql-setup --initdb (TAKE CARE! YOU MAY DESTROY ALL YOUR DATA!)
69 68 # export PGSETUP_INITDB_OPTIONS="--data-checksums" # recommended # export PGSETUP_INITDB_OPTIONS="--data-checksums" # recommended
69 # postgresql-setup --initdb # (TAKE CARE! YOU MAY DESTROY ALL YOUR DATA!)
70 70 # systemctl start postgresql.service # systemctl start postgresql.service
71 71 RedHat/CentOS/Oracle RedHat/CentOS/Oracle
72 72 # chkconfig postgresql on # chkconfig postgresql on
 
85 85 host rocketgit rocketgit 127.0.0.1/32 trust host rocketgit rocketgit 127.0.0.1/32 trust
86 86 host rocketgit rocketgit ::1/128 trust host rocketgit rocketgit ::1/128 trust
87 87
88 systemctl reload postgresql.service
88 systemd based distributions:
89 # systemctl reload postgresql.service
90 RedHat/CentOS/Oracle
91 # service postgresql reload
89 92
90 93 Notes: Notes:
91 94 - Check also the config file (/etc/rocketgit/config.php) and set - Check also the config file (/etc/rocketgit/config.php) and set
 
98 101 . Mail . Mail
99 102 To be able to generate e-mails as other user, you have to: To be able to generate e-mails as other user, you have to:
100 103 For sendmail: For sendmail:
101 - Enable daemon: systemctl enable sendmail.service
104 - Enable daemon:
105 systemd based distributions: systemctl enable sendmail.service
106 RedHat/CentOS/Oracle: chkconfig sendmail on
102 107 - Edit /etc/mail/trusted-users and add 'rocketgit' and 'apache'. - Edit /etc/mail/trusted-users and add 'rocketgit' and 'apache'.
103 - Restart daemon: 'systemctl restart sendmail.service' (Fedora)
108 - Restart daemon:
109 systemd based distributions: systemctl restart sendmail.service
110 RedHat/CentOS/Oracle: service sendmail restart
104 111
105 112 . Edit firewall to permit ssh, git, http and https ports . Edit firewall to permit ssh, git, http and https ports
106 113 In /etc/sysconfig/iptables (IPv4) and ip6tables (IPv6), add something In /etc/sysconfig/iptables (IPv4) and ip6tables (IPv6), add something
File TODO changed (mode: 100644) (index 19ede7c..a8bfdcf)
1 1 == Where I stopped last time == == Where I stopped last time ==
2 [ ] unit testing for forgot_link - seems is not working!
3 [ ] Visit all functions in git.int to not pass unescaped references to bash.
2
3 == BEFORE NEXT RELEASE ==
4 [ ] build: Document how to start builder.sh (from cron or let it read the conf
5 file). Or, never install worker.conf and let an admin to rename
6 worker.conf.sample into worker.conf
7 [ ] build: for admin, we can access "Workers" two ways:
8 - Settings -> Workers
9 - Admin -> Workers
10 [ ] worker: allow a custom virsh command (to be able to connect to other host)
11 [ ] git diff does not execute arbitrary commands from .gitattributes?!
12 --no-ext-diff, --no-textconv
13 [ ] When we build for multiple architectures, we may reuse the initial image...
14 [ ] build: when we should fallback to global workers? Maybe the user
15 does not want to use the global ones!
16 [ ] build: try to rebuild the master image with all the packages a user needs,
17 so, the start-up cost will be smaller.
18 [ ] build: we must add an event when a job is done.
19 [ ] build: What if I tunnel everything using SSH?
20 Take care to not allow a worker to fetch any repo. The server must
21 provide a key that will allow only a repo/head to be cloned.
22 Probably the best way is to use the socket for notifications and
23 use the API to get the job and post the job.
24 [ ] debian: deal with config files (do not overwrite them)
25 [ ] build: Ask softiron to donate an "Overdrive 1000" for builds on 64bit ARM.
26 [ ] build: document colors (/color=fff)
27 [ ] build: provide real link to the repo for cloning.
28 Done, but if ssh is disabled, allow https!
29 [ ] build: we must be able to specify a color for labels.
30 [ ] build: when listing workers, add some info about what they are doing?
31 Pay attention to security issues: we do not want to list private repos!
32 [ ] build: allow meta rocketgit tags in commit message to trigger some hooks.
33 [ ] build: warn user about the unprotected channel with the master process.
34 [ ] build: add a "Download" button for worker configuration.
35 [ ] build: if a worker losts conectivity, at reconnect may send DON jobs
36 to the server. But in the mean time the server may already
37 redistributed the job to other worker. Just ignore the DON.
38 But, a worker must ask the server if the job is still needed before
39 starting to work.
40 [ ] build: what happens if worker process crashes? We loose all state (pids,
41 virtual machines etc.). We must save this info to be able recover!
42 [ ] build: do load testing (Cosmin R)
43 [ ] We may want to cut the network access for user 'build' inside the worker.
44 [ ] If user is using firewalld:
45 firewall-cmd --permanent --add-port=19999/tcp
46 firewall-cmd --reload
47 [ ] Register with freecode.club
48 [ ] build: give error if we cannot install one of the packages.
49 [ ] build: allow user to install some dependencies.
50 Or maybe try to detect from the spec file?
51 We also must specify how to install packages.
52 [ ] wh: we do not have the time of last run!
53 [ ] build: allow adding environment variables for a job.
54 [ ] Somehow, warn the user that no environments are available and instruct
55 she/him to add workers.
56 [ ] css: 'mess' class has a 5px top margin. it is not ok (check edit webhook).
57 [ ] Filter environment (allow only a-zA-Z0-9_.)
58 [ ] Join builders.inc.php and workers.inc.php?
59 [ ] build: builder.php: we should wait for a notification instead to poll
60 the database.
61 [ ] build: enforce a max build time; use cost; use max_workers.
62 [ ] build: If a user has own workers, do not use global ones (of course,
63 arch is taken in consideration).
64 [ ] build: show user the status of the workers. Also, how much time they
65 were used and what builds they did.
66 [ ] build: find a way to reuse machines, so we avoid the startup cost.
67 Take care also about package instalation.
68 [ ] build: avoid starting a lot of services. We do not need them!
69 [ ] Some daemon to synchronize two instances (master standby or just
70 load balancing)?
71 [ ] build: Use 'type' field!
72 [ ] build: 'key' is still used?
73 I think yes. It will be presented when a user validates the worker.
74 [ ] build: Reload worker config somehow.
75 [ ] log2listing: seems I do not add labels per commit but only at the end!
4 76 [ ] The verification of user-provided CSRF crumbs with the expected value did [ ] The verification of user-provided CSRF crumbs with the expected value did
5 77 not use a constant-time comparison algorithm, potentially allowing not use a constant-time comparison algorithm, potentially allowing
6 78 attackers to use statistical methods to determine valid CSRF crumbs attackers to use statistical methods to determine valid CSRF crumbs
7 79 using brute-force methods. using brute-force methods.
8 80 [ ] clone seems to be done by git and not by ssh! [ ] clone seems to be done by git and not by ssh!
9 [ ] build: environment lists must be with checkboxes
10 [ ] build: when a client connects, add the environments to the env table.
11 Allow to expire? or allow the admin to do it?
12 [ ] log2listing: seems I do not add labels per commit but only at the end!
13 [ ] Oracle: libsepol.print_missing_requirements: rocketgit's global
14 requirements were
15 not met: type/attribute passwd_file_t (No such file or directory).
16 libsemanage.semanage_link_sandbox: Link packages failed (No such file
17 or directory). /usr/sbin/semodule: Failed!
18 [ ] Document how to start builder.sh (from cron or let it read the conf file)
19 [ ] Forgot password does not redirect - no message!
20 [ ]
21
22 ++
23 Allow workes to connect, but admin must validate them before being able
24 to build something. At the same time, also set the auth key?
25 Also, client must generate a ssh key and the public part must be sent to
26 the server. After validation, the user can clone by ssh!
27 I think is better to create an archive of the repo and transfer it by
28 the same protocol. Not clear if I should use "git clone" or "git archive".
29 ++
30
31 == BEFORE NEXT RELEASE ==
81 [ ] About SSH/API keys and rights: there is some interference between these
82 and granting rights. Seems, as we grant users some rights, we also
83 grant API keys some rights. Maybe add the key in rights?!
84 Which rights?! It is not clear how should I link the api key
85 with a right. What sense makes the 'user' field next to the api key?!
86 And how do I show the api key? As the short name or as the id?
87 OK, but this makes sense only for repos! What about users, webhooks
88 etc.? Maybe repo 'rights' makes sense from cloning.
89 API makes sense for API manipulation. What about cloning using an
90 APIKEY?
91 So, the API keys is just another authentication method.
92 This means that the 'rights' tabs should be moved in settings?!
93 Probably no. But we will need also rights in Settings to control
94 !repo stuff.
95 [ ] Unit testing for API keys
96 [ ] Probably, also ssh keys must have some actions allowed attached to them.
97 How it will work?! By default, all rights.
98 Use case: allow a key only to push on some repos (regex)
99 Use case: allow a key to only access repo APIs.
100 [ ] Scan SSH/API keys and notify user whey were used too long ago, and ask
101 the user to remove them?
102 [ ] From time to time, regenerate the passwords with other salt to protect
103 against stolen db and brute force attacks.
104 [ ] Respect .gitattributes file
105 [ ] Get rid of "Please login first"! Just show the login form!
106 [ ] Sometimes we send cosmetic data to cache! Not good! At least in totp.inc.php!
107 [ ] LIST_LOADED/LOADED etc. is not used: at least on totp.inc.php!
108 [ ] A difference between paid accounts and free ones: how much time we keep the
109 logs.
110 [ ] Add an API layer to be able to use other git hosting scripts to connect to me
111 [ ] Sign some contract with Nitrokey.com to provide keys to the users.
112 [ ] build: allow user to specify some packages to be installed first?
32 113 [ ] Get rid of php-mbstring! It is not in main repo on Oracle Linux! [ ] Get rid of php-mbstring! It is not in main repo on Oracle Linux!
33 114 [ ] Destroy storage for 'build' machines [ ] Destroy storage for 'build' machines
34 115 [ ] If a user types a wrong e-mail at registration phase, and without [ ] If a user types a wrong e-mail at registration phase, and without
File inc/admin.inc.php changed (mode: 100644) (index 552eabe..3967fae)
1 1 <?php <?php
2 2 $INC = isset($INC) ? $INC : dirname(__FILE__); $INC = isset($INC) ? $INC : dirname(__FILE__);
3 3 require_once($INC . "/user.inc.php"); require_once($INC . "/user.inc.php");
4 require_once($INC . "/workers.inc.php");
4 5
5 6 /* /*
6 7 * Event functions * Event functions
 
... ... function rg_admin_invite_one($db, $event)
72 73 */ */
73 74 function rg_admin_invites_high_level($db, $rg) function rg_admin_invites_high_level($db, $rg)
74 75 { {
75 rg_log_enter("rg_admin_invites_high_level");
76 rg_log_enter("admin_invites_high_level");
76 77
77 78 $ret = ""; $ret = "";
78 79
 
... ... function rg_admin_report1_suggestions($db, $from, $to)
320 321 function rg_admin_report1($db, $rg) function rg_admin_report1($db, $rg)
321 322 { {
322 323 global $rg_admin_email; global $rg_admin_email;
324 global $rg_web_url;
323 325
324 326 $body = ''; $body = '';
325 327
 
... ... function rg_admin_report1($db, $rg)
328 330
329 331 $body .= "Report between " . gmdate('Y-m-d H:i:s', $y_start) $body .= "Report between " . gmdate('Y-m-d H:i:s', $y_start)
330 332 . " and " . gmdate('Y-m-d H:i:s', $y_end) . " UTC\n"; . " and " . gmdate('Y-m-d H:i:s', $y_end) . " UTC\n";
333 $body .= 'For site ' . $rg_web_url . "\n";
331 334
332 335 $list = array( $list = array(
333 336 'users' => 'users', 'users' => 'users',
 
... ... function rg_admin_report1($db, $rg)
342 345 'webhooks' => 'webhooks', 'webhooks' => 'webhooks',
343 346 'rights' => 'rights', 'rights' => 'rights',
344 347 'events' => 'events', 'events' => 'events',
345 'build_jobs' => 'build jobs');
348 'build_jobs' => 'build jobs',
349 'apikeys' => 'api keys',
350 'workers' => 'workers');
346 351 $total_yesterday_changes = 0; $total_yesterday_changes = 0;
347 352 foreach ($list as $table => $text) { foreach ($list as $table => $text) {
348 353 // Yesterday // Yesterday
 
... ... function rg_admin_report1($db, $rg)
387 392 while (($row = rg_sql_fetch_array($res))) { while (($row = rg_sql_fetch_array($res))) {
388 393 $users++; $users++;
389 394 $list .= "\t" . $row['username'] $list .= "\t" . $row['username']
390 . "\t" . $row['realname'] . "\n";
395 . "\t" . $row['realname']
396 . "\t" . $row['email']
397 . "\n";
391 398 } }
392 399 if ($users) if ($users)
393 400 $body .= "\nYesterday users (" . $users . "):\n" $body .= "\nYesterday users (" . $users . "):\n"
 
... ... function rg_admin_report1($db, $rg)
425 432 . ' [' . $users . 'u]' . ' [' . $users . 'u]'
426 433 . ' [' . $repos . 'r]' . ' [' . $repos . 'r]'
427 434 . ' [' . $total_yesterday_changes . 'c]'; . ' [' . $total_yesterday_changes . 'c]';
435 if (!empty($rg_web_url))
436 $rg['mail']['subject'] .= ' (' . $rg_web_url . ')';
428 437 $rg['mail']['body'] = $body; $rg['mail']['body'] = $body;
429 438 rg_mail_template("mail/admin/report1", $rg); rg_mail_template("mail/admin/report1", $rg);
430 439 } }
File inc/admin/admin.php changed (mode: 100644) (index dea3ded..83e68f1)
... ... if ($rg['login_ui']['is_admin'] != 1) {
11 11 $_subop = empty($paras) ? 'plans' : array_shift($paras); $_subop = empty($paras) ? 'plans' : array_shift($paras);
12 12
13 13 $rg['admin_menu'][$_subop] = 1; $rg['admin_menu'][$_subop] = 1;
14 $rg['HTML:menu_admin_level2'] = '';
14 $rg['HTML:menu_level2'] = '';
15 15
16 $rg['url_up'] = $rg['url'];
17 $rg['url'] .= '/' . $_subop;
16 18 switch ($_subop) { switch ($_subop) {
17 19 case 'plans': case 'plans':
18 20 include($INC . "/admin/plans/plans.php"); include($INC . "/admin/plans/plans.php");
 
... ... case 'repos': // repos
29 31 $_admin_body = $_admin_repos; $_admin_body = $_admin_repos;
30 32 break; break;
31 33
34 case 'workers':
35 $_admin_body = rg_worker_high_level($db, $rg, $paras);
36 break;
37
32 38 case 'invites': // invites case 'invites': // invites
33 39 $_admin_body = rg_admin_invites_high_level($db, $rg); $_admin_body = rg_admin_invites_high_level($db, $rg);
34 40 break; break;
41
42 default:
43 $_admin_body = rg_warning('invalid operation');
44 break;
35 45 } }
46 $rg['url'] = $rg['url_up'];
36 47
37 48 $_admin .= rg_template("admin/menu.html", $rg, TRUE /* xss */); $_admin .= rg_template("admin/menu.html", $rg, TRUE /* xss */);
38 49 $_admin .= '<div class="generic_body">' . "\n"; $_admin .= '<div class="generic_body">' . "\n";
File inc/admin/plans/plans.php changed (mode: 100644) (index 0871cd3..c3c8a87)
... ... $_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 8
9 9 $rg['admin_plans_menu'][$_op] = 1; $rg['admin_plans_menu'][$_op] = 1;
10 $rg['HTML:menu_admin_level2'] = rg_template("admin/plans/menu.html", $rg, TRUE /* xss */);
10 $rg['HTML:menu_level2'] = rg_template("admin/plans/menu.html", $rg, TRUE /* xss */);
11 11
12 12 switch ($_op) { switch ($_op) {
13 13 case 'list': // list case 'list': // list
File inc/admin/repos/repos.php changed (mode: 100644) (index ef8d969..f0edbe3)
... ... $_admin_repos = "";
6 6 $_op = empty($paras) ? "list" : array_shift($paras); $_op = empty($paras) ? "list" : array_shift($paras);
7 7
8 8 $rg['admin_repos_menu'][$_op] = 1; $rg['admin_repos_menu'][$_op] = 1;
9 $rg['HTML:menu_admin_level2'] = rg_template("admin/repos/menu.html", $rg, TRUE /* xss */);
9 $rg['HTML:menu_level2'] = rg_template("admin/repos/menu.html", $rg, TRUE /* xss */);
10 10
11 11 switch ($_op) { switch ($_op) {
12 12 case 'add': case 'add':
File inc/admin/users/users.php changed (mode: 100644) (index e0abc7b..45cf33a)
... ... $target_ui = rg_user_info($db, 0, $target, "");
11 11 $_show_list = 1; $_show_list = 1;
12 12
13 13 $rg['admin_users_menu'][$_op] = 1; $rg['admin_users_menu'][$_op] = 1;
14 $rg['HTML:menu_admin_level2'] = rg_template("admin/users/menu.html", $rg, TRUE /* xss */);
14 $rg['HTML:menu_level2'] = rg_template("admin/users/menu.html", $rg, TRUE /* xss */);
15 15
16 16 switch ($_op) { switch ($_op) {
17 17 case 'add': // add case 'add': // add
File inc/api.inc.php added (mode: 100644) (index 0000000..af3f3f5)
1 <?php
2 require_once($INC . "/util.inc.php");
3 require_once($INC . "/log.inc.php");
4 require_once($INC . "/sql.inc.php");
5 require_once($INC . "/user.inc.php");
6 require_once($INC . "/repo.inc.php");
7 require_once($INC . "/bug.inc.php");
8 require_once($INC . "/keys.inc.php");
9 require_once($INC . "/prof.inc.php");
10 require_once($INC . "/watch.inc.php");
11
12 /*
13 * Main entry point
14 */
15 function rg_api($db, $a)
16 {
17 rg_prof_start('api');
18 rg_log_enter('api: a=' . rg_array2string($a));
19
20 $ret = array();
21 while (1) {
22 $a['cui'] = rg_user_info($db, $a['connect_uid'], '', '');
23 if ($a['cui']['exists'] != 1) {
24 $ret = array('error' => 'internal error');
25 break;
26 }
27
28 if (strncmp($a['cmd'], 'user', 4) == 0) {
29 $ret = rg_user_api($db, $a);
30 break;
31 }
32
33 if (strncmp($a['cmd'], 'repo', 4) == 0) {
34 $ret = rg_repo_api($db, $a);
35 break;
36 }
37
38 $ret['error'] = 'invalid command';
39 break;
40 }
41
42 $ret = json_encode($ret, JSON_PRETTY_PRINT) . "\n";
43
44 rg_log_exit();
45 rg_prof_end('api');
46 return $ret;
47 }
48
49 ?>
File inc/apikeys.inc.php added (mode: 100644) (index 0000000..49f213a)
1 <?php
2 // This files deals with keys used to call the API (over HTTPS)
3 require_once($INC . '/sql.inc.php');
4 require_once($INC . '/state.inc.php');
5 require_once($INC . '/prof.inc.php');
6 require_once($INC . '/events.inc.php');
7 require_once($INC . '/cache.inc.php');
8
9 $rg_ak_error = '';
10
11 function rg_ak_set_error($str)
12 {
13 global $rg_ak_error;
14 $rg_ak_error = $str;
15 rg_log($str);
16 }
17
18 function rg_ak_error()
19 {
20 global $rg_ak_error;
21 return $rg_ak_error;
22 }
23
24 /*
25 * Events functions
26 */
27 $rg_ak_functions = array(
28 'ak_event_new' => 'rg_ak_event_new',
29 'ak_event_del' => 'rg_ak_event_del',
30 'ak_event_notify_user' => 'rg_ak_event_notify_user'
31 );
32 rg_event_register_functions($rg_ak_functions);
33
34 /*
35 * Event for adding a new api key
36 */
37 function rg_ak_event_new($db, $event)
38 {
39 $ret = array();
40
41 $event['op'] = 'new';
42
43 // notify user
44 $a = array('category' => 'ak_event_notify_user', 'prio' => 100);
45 $ret[] = array_merge($event, $a);
46
47 return $ret;
48 }
49
50 /*
51 * Event for deleting a key
52 */
53 function rg_ak_event_del($db, $event)
54 {
55 $ret = array();
56 $event['op'] = 'del';
57
58 // notify user
59 $a = array('category' => 'ak_event_notify_user', 'prio' => 100);
60 $ret[] = array_merge($event, $a);
61
62 return $ret;
63 }
64
65 /*
66 * Notify user that a new key was added to the keyring
67 */
68 function rg_ak_event_notify_user($db, $event)
69 {
70 rg_prof_start('ak_event_notify_user');
71 rg_log('ak_event_notify_user: event=' . rg_array2string($event));
72
73 $ret = FALSE;
74 while (1) {
75 $r = rg_mail_template('mail/user/ak/' . $event['op'], $event);
76 if ($r === FALSE)
77 break;
78
79 $ret = array();
80 break;
81 }
82
83 rg_prof_end('ak_event_notify_user');
84 return $ret;
85 }
86
87 /*
88 * Remove api keys from database for user 'ui'
89 */
90 function rg_ak_remove($db, $uid, $list)
91 {
92 rg_prof_start('ak_remove');
93 rg_log_enter('ak_remove: list=' . rg_array2string($list));
94
95 $ret = FALSE;
96 while (1) {
97 $my_list = array();
98 foreach ($list as $key_id => $junk)
99 $my_list[] = sprintf('%u', $key_id);
100
101 $params = array('uid' => $uid);
102 $sql_list = implode(', ', $my_list);
103 $sql = 'DELETE FROM apikeys'
104 . ' WHERE uid = @@uid@@'
105 . ' AND key_id IN (' . $sql_list . ')';
106 $res = rg_sql_query_params($db, $sql, $params);
107 if ($res === FALSE) {
108 rg_ak_set_error('cannot delete api keys');
109 break;
110 }
111 rg_sql_free_result($res);
112
113 $event = array(
114 'category' => 'rg_ak_event_del',
115 'prio' => 50,
116 'ui' => array('uid' => $uid),
117 'keys' => implode(',', $my_list));
118 $r = rg_event_add($db, $event);
119 if ($r !== TRUE) {
120 rg_ak_set_error('cannot add event'
121 . ' (' . rg_event_error() . ')');
122 break;
123 }
124
125 $key = 'user' . '::' . $uid . '::' . 'apikeys' . '::' . 'list';
126 foreach ($my_list as $_key_id)
127 rg_cache_unset($key . '::' . $_key_id,
128 RG_SOCKET_NO_WAIT);
129
130 rg_event_signal_daemon('', 0);
131 $ret = TRUE;
132 break;
133 }
134
135 rg_log_exit();
136 rg_prof_end('ak_remove');
137 return $ret;
138 }
139
140 /*
141 * Adds an apikey
142 * Returns the key_id of the key.
143 */
144 function rg_ak_add($db, $uid, $key, $name)
145 {
146 rg_prof_start('ak_add');
147 rg_log_enter('ak_add: key=' . $key . ' name=' . $name);
148
149 $ret = FALSE;
150 $do_rollback = 0;
151 while (1) {
152 $itime = time();
153
154 $r = rg_sql_begin($db);
155 if ($r !== TRUE) {
156 rg_ak_set_error('cannot start transaction');
157 break;
158 }
159 $do_rollback = 1;
160
161 $params = array(
162 'itime' => $itime,
163 'uid' => $uid,
164 'key' => $key,
165 'name' => $name,
166 'count' => 0,
167 'first_use' => 0);
168 $sql = 'INSERT INTO apikeys (itime, uid, key, name)'
169 . ' VALUES (@@itime@@, @@uid@@, @@key@@, @@name@@)'
170 . ' RETURNING key_id';
171 $res = rg_sql_query_params($db, $sql, $params);
172 if ($res === FALSE) {
173 rg_ak_set_error('cannot insert key');
174 break;
175 }
176 $row = rg_sql_fetch_array($res);
177 $key_id = $row['key_id'];
178 rg_sql_free_result($res);
179
180 $event = array(
181 'category' => 'ak_event_new',
182 'prio' => 50,
183 'ui' => array('uid' => $uid),
184 'key' => $key,
185 'name' => $name,
186 'key_id' => $key_id);
187 $r = rg_event_add($db, $event);
188 if ($r !== TRUE) {
189 rg_ak_set_error('cannot add event'
190 . ' (' . rg_event_error() . ')');
191 break;
192 }
193
194 $r = rg_sql_commit($db);
195 if ($r !== TRUE) {
196 rg_ak_set_error('cannot commit transaction');
197 break;
198 }
199 $do_rollback = 0;
200
201 $_key = 'user' . '::' . $uid . '::'
202 . 'apikeys' . '::' . 'list' . '::' . $key_id;
203 rg_cache_merge($_key, $params, RG_SOCKET_NO_WAIT);
204
205 rg_event_signal_daemon('', 0);
206
207 $ret = $key_id;
208 break;
209 }
210
211 if ($do_rollback == 1)
212 rg_sql_rollback($db);
213
214 rg_log_exit();
215 rg_prof_end('ak_add');
216 return $ret;
217 }
218
219 /*
220 * Update first_use, last_use, last_ip and count
221 */
222 function rg_ak_update_use($db, $uid, $key_id, $ip, $cmd)
223 {
224 rg_prof_start('ak_update_use');
225 rg_log_enter('ak_update_use: uid=' . $uid . ' key_id=' . $key_id
226 . ', ip=' . $ip . ', cmd=' . $cmd);
227
228 $ret = FALSE;
229 while (1) {
230 $now = time();
231
232 $update_first_use = TRUE;
233 $update_last_use = TRUE;
234
235 $key = 'user' . '::' . $uid . '::' . 'apikeys'
236 . ' ::' . 'list' . '::' . $key_id;
237 $c = rg_cache_get($key);
238 if ($c !== FALSE) {
239 if (isset($c['first_use']) && ($c['first_use'] > 0))
240 $update_first_use = FALSE;
241
242 // We will not update the field if is too soon
243 if (isset($c['last_use'])
244 && (strcmp($ip, $c['last_ip']) == 0)
245 && (strcmp($cmd, $c['last_cmd']) == 0)
246 && ($now - $c['last_use'] < 60))
247 $update_last_use = FALSE;
248 }
249
250 $params = array(
251 'now' => $now,
252 'key_id' => $key_id,
253 'ip' => $ip,
254 'last_cmd' => $cmd);
255
256 if ($update_first_use) {
257 $sql = 'UPDATE apikeys SET first_use = @@now@@'
258 . ' WHERE first_use = 0'
259 . ' AND key_id = @@key_id@@';
260 $res = rg_sql_query_params($db, $sql, $params);
261 if ($res === FALSE) {
262 rg_ak_set_error('cannot update apikey\'s first use');
263 break;
264 }
265 rg_sql_free_result($res);
266
267 rg_cache_set($key . '::' . 'first_use', $now,
268 RG_SOCKET_NO_WAIT);
269 }
270
271 if ($update_last_use) {
272 $sql = 'UPDATE apikeys SET last_use = @@now@@'
273 . ', last_ip = @@ip@@'
274 . ', last_cmd = @@last_cmd@@'
275 . ', count = count + 1'
276 . ' WHERE key_id = @@key_id@@';
277 $res = rg_sql_query_params($db, $sql, $params);
278 if ($res === FALSE) {
279 rg_ak_set_error('cannot update key');
280 break;
281 }
282 rg_sql_free_result($res);
283
284 $a = array(
285 'last_use' => $now,
286 'last_ip' => $ip,
287 'last_cmd' => $cmd);
288 rg_cache_merge($key, $a, RG_SOCKET_NO_WAIT);
289 }
290
291 $ret = TRUE;
292 break;
293 }
294
295 rg_log_exit();
296 rg_prof_end('ak_update_use');
297 return $ret;
298 }
299
300 /*
301 * Cosmetic changes for a key
302 */
303 function rg_ak_cosmetic(&$row)
304 {
305 if ($row['itime'] == 0)
306 $row['itime_nice'] = 'N/A';
307 else
308 $row['itime_nice'] = gmdate('Y-m-d H:i', $row['itime']);
309
310 if ($row['first_use'] == 0)
311 $row['first_use_nice'] = 'N/A';
312 else
313 $row['first_use_nice'] = gmdate('Y-m-d H:i', $row['first_use']);
314
315 if (empty($row['last_ip']))
316 $row['last_ip'] = 'N/A';
317
318 if ($row['last_use'] == 0)
319 $row['last_use_nice'] = 'N/A';
320 else
321 $row['last_use_nice'] = gmdate('Y-m-d H:i', $row['last_use']);
322
323 if (empty($row['last_cmd']))
324 $row['last_cmd'] = 'N/A';
325 }
326
327 /*
328 * List keys
329 */
330 function rg_ak_list($db, $uid)
331 {
332 rg_prof_start('ak_list');
333 rg_log_enter('ak_list: uid=' . $uid);
334
335 $ret = FALSE;
336 while (1) {
337 $key = 'user' . '::' . $uid . '::' . 'apikeys';
338 $c = rg_cache_get($key);
339 //rg_log_ml('DEBUG: cache: ' . print_r($c, TRUE));
340 if (($c !== FALSE) && isset($c['LOADED'])) {
341 $ret = $c['list'];
342
343 foreach ($ret as $key_id => &$i)
344 rg_ak_cosmetic($i);
345 break;
346 }
347
348 $params = array('uid' => $uid);
349 $sql = 'SELECT * FROM apikeys WHERE uid = @@uid@@'
350 . ' ORDER BY itime DESC';
351 $res = rg_sql_query_params($db, $sql, $params);
352 if ($res === FALSE) {
353 rg_ak_set_error('cannot query');
354 break;
355 }
356
357 $ret = array();
358 while (($row = rg_sql_fetch_array($res))) {
359 $key_id = $row['key_id'];
360 $ret[$key_id] = $row;
361 }
362 rg_sql_free_result($res);
363
364 $a = array('LOADED' => 1, 'list' => $ret);
365 rg_cache_set($key, $a, RG_SOCKET_NO_WAIT);
366
367 foreach ($ret as $key_id => &$i)
368 rg_ak_cosmetic($i);
369 break;
370 }
371
372 rg_log_exit();
373 rg_prof_end('ak_list');
374 return $ret;
375 }
376
377 /*
378 * Validates a api keys
379 * Returns the key_id of the matching key or FALSE
380 */
381 function rg_ak_valid($db, $uid, $apikey)
382 {
383 rg_prof_start('ak_valid');
384 rg_log_enter('ak_valid');
385
386 $ret = FALSE;
387 while (1) {
388 $key = 'user' . '::' . $uid . '::' . 'apikeys';
389 $c = rg_cache_get($key);
390 if (($c === FALSE) || !isset($c['LOADED'])) {
391 $params = array('uid' => $uid);
392 $sql = 'SELECT * FROM apikeys WHERE uid = @@uid@@';
393 $res = rg_sql_query_params($db, $sql, $params);
394 if ($res === FALSE) {
395 rg_ak_set_error('canno load list');
396 break;
397 }
398
399 $list = array();
400 while (($row = rg_sql_fetch_array($res))) {
401 $key_id = intval($row['key_id']);
402 unset($row['key_id']);
403 $list[$key_id] = $row;
404 }
405 rg_sql_free_result($res);
406
407 $a = array('LOADED' => 1, 'list' => $list);
408 rg_cache_set($key, $a, RG_SOCKET_NO_WAIT);
409 } else {
410 $list = $c['list'];
411 }
412
413 foreach ($list as $key_id => $info) {
414 if (strcmp($info['key'], $apikey) == 0) {
415 $ret = $key_id;
416 break;
417 }
418 }
419
420 break;
421 }
422
423 rg_log_exit();
424 rg_prof_end('ak_valid');
425 return $ret;
426 }
427
428 /*
429 * High-level function for listing api keys
430 */
431 function rg_ak_list_high_level($db, $rg, $paras)
432 {
433 rg_prof_start('ak_list_high_level');
434 rg_log_enter('ak_list_high_level');
435
436 $ret = '';
437
438 $errmsg = array();
439 $rg['HTML:status'] = '';
440
441 $doit = rg_var_uint('doit');
442 while ($doit == 1) {
443 if (!rg_valid_referer()) {
444 $errmsg[] = 'invalid referer; try again';
445 break;
446 }
447
448 if (!rg_token_valid($db, $rg, 'ak_list', FALSE)) {
449 $errmsg[] = 'invalid token; try again.';
450 break;
451 }
452
453 $list = rg_var_str('key_delete_ids');
454 $r = rg_ak_remove($db, $rg['login_ui']['uid'], $list);
455 if ($r !== TRUE) {
456 $errmsg[] = 'cannot delete: ' . rg_ak_error();
457 break;
458 }
459
460 $rg['HTML:status'] = rg_template(
461 'user/settings/apikeys/delete_ok.html',
462 $rg, TRUE /*xss*/);
463 break;
464 }
465
466 $r = rg_ak_list($db, $rg['login_ui']['uid']);
467 if ($r === FALSE) {
468 $rg['errmsg'] = rg_ak_error();
469 $ret .= rg_template('user/settings/apikeys/list_err.html',
470 $rg, TRUE /*xss*/);
471 } else {
472 $rg['rg_form_token'] = rg_token_get($db, $rg, 'ak_list');
473 $rg['HTML:errmsg'] = rg_template_errmsg($errmsg);
474 $ret .= rg_template_table('user/settings/apikeys/list', $r, $rg);
475 }
476
477 rg_log_exit();
478 rg_prof_end('ak_list_high_level');
479 return $ret;
480 }
481
482 /*
483 * Enroll function for adding a api key
484 */
485 function rg_ak_add_high_level($db, $rg, $paras)
486 {
487 rg_prof_start('ak_add_high_level');
488 rg_log_enter('ak_add_high_level');
489
490 $ret = '';
491 $errmsg = array();
492
493 $rg['ak'] = array();
494 $rg['ak']['name'] = '';
495 $rg['ak']['key'] = rg_id(32);;
496
497 $doit = rg_var_uint('doit');
498 rg_log('DEBUG: doit=' . $doit);
499 while ($doit == 1) {
500 $rg['ak']['name'] = rg_var_str('ak::name');
501 $rg['ak']['key'] = rg_var_str('ak::key');
502
503 if (strlen($rg['ak']['name']) == 0) {
504 $errmsg[] = 'invalid name';
505 break;
506 }
507
508 if (!rg_valid_referer()) {
509 $errmsg[] = 'invalid referer; try again';
510 break;
511 }
512
513 if (!rg_token_valid($db, $rg, 'ak_add', FALSE)) {
514 $errmsg[] = 'invalid token; try again';
515 break;
516 }
517
518 $r = rg_ak_add($db, $rg['login_ui']['uid'], $rg['ak']['key'],
519 $rg['ak']['name']);
520 if ($r === FALSE) {
521 $errmsg[] = rg_ak_error();
522 break;
523 }
524
525 $ret .= rg_template('user/settings/apikeys/add_ok.html',
526 $rg, TRUE /*xss*/);
527
528 $rg['ak']['name'] = '';
529 $rg['ak']['key'] = rg_id(32);
530 break;
531 }
532
533 $rg['HTML:errmsg'] = rg_template_errmsg($errmsg);
534 $rg['rg_form_token'] = rg_token_get($db, $rg, 'ak_add');
535 $ret .= rg_template('user/settings/apikeys/add.html', $rg, TRUE /*xss*/);
536
537 rg_log_exit();
538 rg_prof_end('ak_add_high_level');
539 return $ret;
540 }
541
542 /*
543 * Main HL function for api keys
544 */
545 function rg_ak_high_level($db, &$rg, $paras)
546 {
547 rg_prof_start('ak_high_level');
548 rg_log_enter('ak_high_level paras: ' . rg_array2string($paras));
549
550 $ret = '';
551
552 $op = empty($paras) ? 'list' : array_shift($paras);
553 $rg['menu']['ak'][$op] = 1;
554
555 $rg['HTML:menu_level2'] =
556 rg_template('user/settings/apikeys/menu.html', $rg, TRUE /*xss*/);
557
558 switch ($op) {
559 case 'add':
560 $ret .= rg_ak_add_high_level($db, $rg, $paras);
561 break;
562
563 default:
564 $ret .= rg_ak_list_high_level($db, $rg, $paras);
565 break;
566 }
567
568 $hints = array();
569 $hints[]['HTML:hint'] = rg_template('user/settings/apikeys/hints.html',
570 $rg, TRUE /*xss*/);
571 $ret .= rg_template_table('hints/list', $hints, $rg);
572
573 rg_log_exit();
574 rg_prof_end('ak_high_level');
575 return $ret;
576 }
577
578 ?>
File inc/builder.inc.php changed (mode: 100644) (index c5a5b88..86c445b)
1 1 <?php <?php
2 2 $INC = isset($INC) ? $INC : dirname(__FILE__); $INC = isset($INC) ? $INC : dirname(__FILE__);
3 require_once($INC . '/workers.inc.php');
3 4
4 5 /* /*
5 6 * Function to load job list * Function to load job list
 
... ... function rg_builder_done($db, $job, $s)
164 165 break; break;
165 166 rg_sql_free_result($res); rg_sql_free_result($res);
166 167
168 $ev = array(
169 'category' => 'wh_build_job_done',
170 'prio' => 100,
171 'ui' => array('uid' => $job['uid']),
172 'job' => $job,
173 'status' => $s
174 );
175 $r = rg_event_add($db, $ev);
176 if ($r !== TRUE) {
177 rg_repo_set_error('cannot add event'
178 . ' (' . rg_event_error() . ')');
179 break;
180 }
181
167 182 $res = rg_sql_commit($db); $res = rg_sql_commit($db);
168 183 if ($res === FALSE) if ($res === FALSE)
169 184 break; break;
170 185
171 186 $rollback = FALSE; $rollback = FALSE;
172 187
188 rg_event_signal_daemon('', 0);
189
173 190 $ret = TRUE; $ret = TRUE;
174 191 break; break;
175 192 } }
 
... ... function rg_builder_done($db, $job, $s)
180 197 rg_log_exit(); rg_log_exit();
181 198 } }
182 199
183 /*
184 * Returns a list of possible environments
185 * TODO: think about a lot of architecures, bits, OSes!
186 */
187 function rg_builder_env_list($db)
188 {
189 return array('fedora23-server-x86_64');
190 }
191
192 200 ?> ?>
File inc/cache.inc.php changed (mode: 100644) (index 8510000..5e8197d)
... ... function rg_cache_error()
41 41 return $rg_cache_error; return $rg_cache_error;
42 42 } }
43 43
44 /*
45 * Clears all core cache
46 */
47 function rg_cache_core_destroy()
48 {
49 global $rg_cache;
50 global $rg_cache_core_enable;
51
52 if (!$rg_cache_core_enable)
53 return;
54
55 $rg_cache = array();
56 }
57
44 58 /* /*
45 59 * Dump all tables * Dump all tables
46 60 */ */
 
... ... function rg_cache_core_get($ns_var)
181 195 */ */
182 196 function rg_cache_core_unset($ns_var) function rg_cache_core_unset($ns_var)
183 197 { {
198 global $rg_cache_debug;
184 199 global $rg_cache; global $rg_cache;
185 200 global $rg_cache_core_enable; global $rg_cache_core_enable;
186 201
 
... ... function rg_cache_core_unset($ns_var)
200 215 } }
201 216
202 217 if (isset($tree[$var])) { if (isset($tree[$var])) {
218 if ($rg_cache_debug)
219 rg_log('cache_core_unset(' . $ns_var . ')');
203 220 unset($tree[$var]); unset($tree[$var]);
204 221 return TRUE; return TRUE;
205 222 } }
 
... ... function rg_cache_inc($ns_var)
485 502 */ */
486 503 function rg_cache_unset($ns_var, $flags) function rg_cache_unset($ns_var, $flags)
487 504 { {
505 global $rg_cache_debug;
506
488 507 rg_prof_start('cache_unset'); rg_prof_start('cache_unset');
489 508
490 509 rg_cache_core_unset($ns_var); rg_cache_core_unset($ns_var);
491 510 $ret = rg_cache_send('UNSET', $ns_var, $flags); $ret = rg_cache_send('UNSET', $ns_var, $flags);
492 511
512 if ($rg_cache_debug)
513 rg_log('cache_unset(' . $ns_var . ')');
514
493 515 rg_prof_end('cache_unset'); rg_prof_end('cache_unset');
494 516 return $ret; return $ret;
495 517 } }
File inc/conn.inc.php changed (mode: 100644) (index ecb8c94..0887a04)
... ... function rg_conn_prepare($s)
14 14 return addcslashes($s, "\n\r\\"); return addcslashes($s, "\n\r\\");
15 15 } }
16 16
17 /*
18 * Shutts down a connection
19 */
20 function rg_conn_shutdown($key, $what)
21 {
22 global $rg_conns;
23
24 if (!isset($rg_conns[$key]['socket']))
25 return;
26
27 if (!is_resource($rg_conns[$key]['socket']))
28 return;
29
30 @socket_shutdown($rg_conns[$key]['socket'], $what);
31 rg_log($key . ': shutdown ' . $what);
32 }
33
17 34 /* /*
18 35 * Destroys a connection * Destroys a connection
19 36 */ */
 
... ... function rg_conn_destroy($key)
28 45 if ($rg_conns[$key]['exit_on_close']) if ($rg_conns[$key]['exit_on_close'])
29 46 exit(1); exit(1);
30 47
48 if (isset($rg_conns[$key]['func_destroy']))
49 $rg_conns[$key]['func_destroy']($key);
50
31 51 if (isset($rg_events['r'][$key])) if (isset($rg_events['r'][$key]))
32 52 unset($rg_events['r'][$key]); unset($rg_events['r'][$key]);
33 53 if (isset($rg_events['w'][$key])) if (isset($rg_events['w'][$key]))
 
... ... function rg_conn_new($key, $socket)
46 66 global $rg_conns; global $rg_conns;
47 67 global $rg_events; global $rg_events;
48 68
69 $ip = '?';
70 $port ='?';
71 if (strcmp($key, 'master') != 0)
72 @socket_getpeername($socket, $ip, $port);
73
49 74 $rg_conns[$key] = array( $rg_conns[$key] = array(
50 75 'socket' => $socket, 'socket' => $socket,
51 76 'recv' => '', 'recv' => '',
 
... ... function rg_conn_new($key, $socket)
53 78 'itime' => time(), 'itime' => time(),
54 79 'exit_on_close' => 0, 'exit_on_close' => 0,
55 80 'func_error' => 'rg_conn_func_error', 'func_error' => 'rg_conn_func_error',
56 'func_close' => 'rg_conn_func_close'
81 'func_close' => 'rg_conn_func_close',
82 'ip' => $ip,
83 'port' => $port
57 84 ); );
58 85
59 86 $rg_events['r'][$key] = $socket; $rg_events['r'][$key] = $socket;
 
... ... function rg_conn_send($key)
85 112 rg_log('SEND: ' . $s['send']); rg_log('SEND: ' . $s['send']);
86 113 $r = @socket_send($s['socket'], $s['send'], strlen($s['send']), 0); $r = @socket_send($s['socket'], $s['send'], strlen($s['send']), 0);
87 114 if ($r === FALSE) { if ($r === FALSE) {
88 rg_log('Cannot receive!');
115 rg_log('Cannot send: ' . socket_strerror(socket_last_error()));
89 116 $s['func_error']($key); $s['func_error']($key);
90 117 rg_conn_destroy($key); rg_conn_destroy($key);
91 118 return FALSE; return FALSE;
 
... ... function rg_conn_recv($key)
111 138 if (isset($s['func_new'])) { if (isset($s['func_new'])) {
112 139 $client = @socket_accept($s['socket']); $client = @socket_accept($s['socket']);
113 140 if ($client === FALSE) { if ($client === FALSE) {
114 rg_log('Cannot accept!');
141 rg_log($key . ':Cannot accept!');
115 142 return; return;
116 143 } }
117 144
 
... ... function rg_conn_recv($key)
129 156
130 157 $r = @socket_recv($s['socket'], $buf, 4096, 0); $r = @socket_recv($s['socket'], $buf, 4096, 0);
131 158 if ($r === FALSE) { if ($r === FALSE) {
132 rg_log('Cannot receive!');
159 rg_log($key . ':Cannot receive (err): ' . socket_strerror(socket_last_error()));
133 160 $s['func_error']($key); $s['func_error']($key);
134 161 rg_conn_destroy($key); rg_conn_destroy($key);
135 162 return FALSE; return FALSE;
136 163 } }
137 164 if ($r === 0) { if ($r === 0) {
138 rg_log('Cannot receive!');
165 rg_log($key . ':Cannot receive (0): ' . socket_strerror(socket_last_error()));
139 166 $s['func_close']($key); $s['func_close']($key);
140 167 rg_conn_destroy($key); rg_conn_destroy($key);
141 168 return FALSE; return FALSE;
 
... ... function rg_conn_recv($key)
150 177 } }
151 178
152 179 if (!isset($s['func_cmd'])) { if (!isset($s['func_cmd'])) {
153 rg_log_ml('key=' . $key . '; s: ' . print_r($s, TRUE));
154 rg_log('Neithter func_data nor func_cmd present!');
180 rg_log_ml($key . ': s: ' . print_r($s, TRUE));
181 rg_log($key . ':Neither func_data nor func_cmd present!');
155 182 return; return;
156 183 } }
157 184
 
... ... function rg_conn_wait($timeout)
186 213 if ($r === 0) if ($r === 0)
187 214 return; return;
188 215
216 if (!empty($r2))
217 rg_log_ml('read events: ' . print_r($r2, TRUE));
189 218 foreach ($r2 as $key => $sock) foreach ($r2 as $key => $sock)
190 219 rg_conn_recv($key); rg_conn_recv($key);
191 220
221 if (!empty($w2))
222 rg_log_ml('write events: ' . print_r($w2, TRUE));
192 223 foreach ($w2 as $key => $sock) foreach ($w2 as $key => $sock)
193 224 rg_conn_send($key); rg_conn_send($key);
194 225
226 if (!empty($e2))
227 rg_log_ml('error events: ' . print_r($e2, TRUE));
195 228 foreach ($e2 as $key => $sock) foreach ($e2 as $key => $sock)
196 229 rg_conn_destroy($key); rg_conn_destroy($key);
197 230 } }
File inc/dispatch/dispatch.php changed (mode: 100644) (index a6519b0..98b3869)
... ... rg_log("FILE: /inc/dispatch/dispatch");
3 3
4 4 $rg['menu'][$_op] = 1; $rg['menu'][$_op] = 1;
5 5
6 $rg['url_up'] = $rg['url'];
7 $rg['url'] .= '/' . $_op;
6 8 switch ($_op) { switch ($_op) {
7 9 case 'login': case 'login':
8 10 include($INC . "/login/login.php"); include($INC . "/login/login.php");
 
... ... case 'discover':
105 107 $body .= rg_repo_discover($db, $_op, $rg, $_ui); $body .= rg_repo_discover($db, $_op, $rg, $_ui);
106 108 break; break;
107 109
110 case 'doc':
111 $sec = array_shift($paras);
112 switch ($sec) {
113 case 'api':
114 $body .= rg_template('doc/api.html', $rg,
115 TRUE /* xss */);
116 break;
117 case 'worker':
118 $body .= rg_template('doc/worker.html', $rg,
119 TRUE /* xss */);
120 break;
121 }
122 break;
123
108 124 default: // can be the main page or user page or repo page default: // can be the main page or user page or repo page
109 125 rg_log("DEBUG:paras=" . rg_array2string($paras)); rg_log("DEBUG:paras=" . rg_array2string($paras));
110 126 $type = empty($paras) ? "" : $paras[0]; $type = empty($paras) ? "" : $paras[0];
 
... ... default: // can be the main page or user page or repo page
137 153
138 154 break; break;
139 155 } }
156 $rg['url'] = $rg['url_up'];
140 157
141 158 ?> ?>
File inc/git.inc.php changed (mode: 100644) (index 6dbb650..0443ad6)
... ... function rg_git_type($obj)
226 226 break; break;
227 227 } }
228 228
229 $cmd = "git cat-file -t '" . $obj . "'";
229 $cmd = "git cat-file -t '" . escapeshellarg($obj) . "'";
230 230 $a = rg_exec($cmd); $a = rg_exec($cmd);
231 231 if ($a['ok'] != 1) { if ($a['ok'] != 1) {
232 232 rg_git_set_error("error on cat-file (" . $a['errmsg'] . ")"); rg_git_set_error("error on cat-file (" . $a['errmsg'] . ")");
 
... ... function rg_git_content($obj)
252 252
253 253 $ret = FALSE; $ret = FALSE;
254 254 while (1) { while (1) {
255 $cmd = "git cat-file -p '" . $obj . "'";
255 $cmd = "git cat-file -p '" . escapeshellarg($obj) . "'";
256 256 $a = rg_exec($cmd); $a = rg_exec($cmd);
257 257 if ($a['ok'] != 1) { if ($a['ok'] != 1) {
258 258 rg_git_set_error("error on cat-file (" . $a['errmsg'] . ")"); rg_git_set_error("error on cat-file (" . $a['errmsg'] . ")");
 
... ... function rg_git_merge_base($repo_path, $a, $b)
432 432 $key = 'git' $key = 'git'
433 433 . '::' . sha1($repo_path) . '::' . sha1($repo_path)
434 434 . '::' . 'merge-base' . '::' . 'merge-base'
435 . '::' . $head . '::' . $b;
435 . '::' . escapeshellarg($head)
436 . '::' . escapeshellarg($b);
436 437 $r = rg_cache_get($key); $r = rg_cache_get($key);
437 438 if ($r !== FALSE) { if ($r !== FALSE) {
438 439 $ret = $r; $ret = $r;
 
... ... function rg_git_update_ref($repo_path, $ref, $old, $new, $reason)
486 487 if (empty($new)) if (empty($new))
487 488 $cmd .= " -d " . escapeshellarg($ref); $cmd .= " -d " . escapeshellarg($ref);
488 489 else else
489 $cmd .= " " . escapeshellarg($ref) . " " . escapeshellarg($new);
490 $cmd .= " " . escapeshellarg($ref)
491 . " " . escapeshellarg($new);
490 492
491 493 if (!empty($old)) if (!empty($old))
492 494 $cmd .= " " . escapeshellarg($old); $cmd .= " " . escapeshellarg($old);
 
... ... function rg_git_shortlog($repo_path, $a, $b)
518 520 while (1) { while (1) {
519 521 $cmd = 'git shortlog' $cmd = 'git shortlog'
520 522 . ' --git-dir=' . escapeshellarg($repo_path) . ' --git-dir=' . escapeshellarg($repo_path)
521 . ' ' . escapeshellarg($a) . '..' . escapeshellarg($b);
523 . ' ' . escapeshellarg($a)
524 . '..' . escapeshellarg($b);
522 525 $r = rg_exec($cmd); $r = rg_exec($cmd);
523 526 if ($r['ok'] != 1) { if ($r['ok'] != 1) {
524 527 rg_git_set_error('error on shortlog (' . $r['errmsg'] . ')'); rg_git_set_error('error on shortlog (' . $r['errmsg'] . ')');
 
... ... function rg_git_ls_tree($repo_path, $tree, $path)
552 555 } }
553 556
554 557 $cmd = "git --git-dir=" . escapeshellarg($repo_path) $cmd = "git --git-dir=" . escapeshellarg($repo_path)
555 . " ls-tree --long" . $op . $tree;
558 . " ls-tree --long" . $op
559 . escapeshellarg($tree);
556 560 if (!empty($path)) if (!empty($path))
557 561 $cmd .= ' ' . escapeshellarg($path); $cmd .= ' ' . escapeshellarg($path);
558 562 $a = rg_exec($cmd); $a = rg_exec($cmd);
File inc/init.inc.php changed (mode: 100644) (index 03eacd3..0e96a58)
... ... if (!isset($rg_builder_bind))
51 51 $rg_builder_bind = '0.0.0.0'; $rg_builder_bind = '0.0.0.0';
52 52
53 53 if (!isset($rg_builder_port)) if (!isset($rg_builder_port))
54 $rg_builder_port = 65000;
54 $rg_builder_port = 0;
55 55
56 56 ?> ?>
File inc/keys.inc.php changed (mode: 100644) (index 8d00ffc..669da99)
... ... function rg_keys_count($db, $uid)
375 375 } }
376 376
377 377 /* /*
378 * Add a key
378 * Adds a key
379 379 * Returns the key_id of the key. * Returns the key_id of the key.
380 380 */ */
381 381 function rg_keys_add($db, $ui, $key) function rg_keys_add($db, $ui, $key)
 
... ... function rg_keys_add($db, $ui, $key)
481 481 */ */
482 482 function rg_keys_update_use($db, $uid, $key_id, $ip, $cmd) function rg_keys_update_use($db, $uid, $key_id, $ip, $cmd)
483 483 { {
484 // The build system will not update table 'keys'
485 if ($key_id == 0)
486 return TRUE;
487
484 488 rg_prof_start("keys_update_use"); rg_prof_start("keys_update_use");
485 489 rg_log_enter("keys_update_use: uid=$uid key_id=$key_id" rg_log_enter("keys_update_use: uid=$uid key_id=$key_id"
486 490 . ", ip=$ip, cmd=$cmd"); . ", ip=$ip, cmd=$cmd");
 
... ... function rg_keys_regen($db)
598 602 chown($tmp, "rocketgit"); chown($tmp, "rocketgit");
599 603 chgrp($tmp, "rocketgit"); chgrp($tmp, "rocketgit");
600 604
605 $list = array();
606
601 607 $sql = "SELECT key_id, uid, key FROM keys ORDER BY count DESC"; $sql = "SELECT key_id, uid, key FROM keys ORDER BY count DESC";
602 608 $res = rg_sql_query($db, $sql); $res = rg_sql_query($db, $sql);
603 609 if ($res === FALSE) { if ($res === FALSE) {
604 rg_keys_set_error("cannot query (" . rg_sql_error() . ")");
610 rg_keys_set_error('cannot query keys table');
611 break;
612 }
613 while (($row = rg_sql_fetch_array($res))) {
614 $row['flags'] = 'N';
615 $list[] = $row;
616 }
617 rg_sql_free_result($res);
618
619 $sql = 'SELECT id, who, ssh_key FROM workers';
620 $res = rg_sql_query($db, $sql);
621 if ($res === FALSE) {
622 rg_keys_set_error('cannot query workers table');
605 623 break; break;
606 624 } }
607 $errors = 0;
608 625 while (($row = rg_sql_fetch_array($res))) { while (($row = rg_sql_fetch_array($res))) {
626 $a = array(
627 'key_id' => $row['id'],
628 'uid' => $row['who'],
629 'key' => $row['ssh_key'],
630 'flags' => 'W'
631 );
632 $list[] = $a;
633 }
634 rg_sql_free_result($res);
635
636 $errors = 0;
637 foreach ($list as $row) {
609 638 //rg_log("Writing key [" . $row['key'] . "] for uid " . $row['uid']); //rg_log("Writing key [" . $row['key'] . "] for uid " . $row['uid']);
610 639 $buf = "command=\"" $buf = "command=\""
611 640 . $rg_scripts . "/scripts/remote.sh" . $rg_scripts . "/scripts/remote.sh"
612 641 . " " . $row['uid'] . " " . $row['uid']
613 . " " . $row['key_id'] . "\""
642 . " " . $row['key_id']
643 . " " . $row['flags']
644 . "\""
614 645 . "," . $rg_ssh_paras . "," . $rg_ssh_paras
615 646 . " " . $row['key'] . "\n"; . " " . $row['key'] . "\n";
616 647 if (@fwrite($f, $buf) === FALSE) { if (@fwrite($f, $buf) === FALSE) {
 
... ... function rg_keys_regen($db)
619 650 break; break;
620 651 } }
621 652 } }
622 rg_sql_free_result($res);
623 653
624 654 fclose($f); fclose($f);
625 655 if ($errors == 1) { if ($errors == 1) {
File inc/mail.inc.php changed (mode: 100644) (index f37bc03..7189cf7)
... ... function rg_mail_template($template, $more)
31 31
32 32 // Account was not confirmed, so do not send mail // Account was not confirmed, so do not send mail
33 33 // BUT, first time, when we ask for confirmation?! // BUT, first time, when we ask for confirmation?!
34 if (empty($more['ui']['email']))
34 if (empty($more['ui']['email'])) {
35 rg_log('BUG! ui::email is not set in @more!');
35 36 return TRUE; return TRUE;
37 }
36 38
37 39 if (!isset($more['debug'])) if (!isset($more['debug']))
38 40 $more['debug'] = 0; $more['debug'] = 0;
 
... ... function rg_mail_template($template, $more)
57 59 rg_log("CHECK: mail_template(" . $more['ui']['email'] . ", rg_log("CHECK: mail_template(" . $more['ui']['email'] . ",
58 60 $subject, $body, $header, -f $rg_admin_email"); $subject, $body, $header, -f $rg_admin_email");
59 61 if ($more['debug'] == 1) { if ($more['debug'] == 1) {
60 rg_cache_set('DEBUG::' . $more['ui']['uid'] . '::mail',
62 if (!isset($more['ui']['uid']))
63 $k = 'nouid';
64 else
65 $k = $more['ui']['uid'];
66
67 rg_cache_set('DEBUG::' . $k . '::mail',
61 68 array( array(
62 69 'header' => $header, 'header' => $header,
63 70 'subject' => $subject, 'subject' => $subject,
File inc/repo.inc.php changed (mode: 100644) (index 93f20df..ce5f443)
... ... function rg_repo_cosmetic($db, &$row)
138 138 $row['clone_url'] = $row['clone_url_git']; $row['clone_url'] = $row['clone_url_git'];
139 139 } }
140 140
141 $master_repo = '-';
141 $row['master_name'] = '-';
142 142 if ($row['master'] > 0) { if ($row['master'] > 0) {
143 $master_repo = '?';
144 143 $_mi = rg_repo_info($db, $row['master'], 0, ''); $_mi = rg_repo_info($db, $row['master'], 0, '');
145 144 if ($_mi['exists'] = 1) if ($_mi['exists'] = 1)
146 $master_repo = $_mi['name'];
145 $row['master_name'] = $_mi['name'];
147 146 } }
148 $row['clone_of'] = $master_repo;
149 147
150 148 if (isset($row['disk_used_mb'])) if (isset($row['disk_used_mb']))
151 149 $row['disk_used'] = rg_1024($row['disk_used_mb'] * 1024 * 1024); $row['disk_used'] = rg_1024($row['disk_used_mb'] * 1024 * 1024);
 
... ... function rg_repo_edit_high_level($db, &$rg)
1813 1811 $x['owner'] = $rg['ri']['uid']; $x['owner'] = $rg['ri']['uid'];
1814 1812 $x['uid'] = $rg['login_ui']['uid']; $x['uid'] = $rg['login_ui']['uid'];
1815 1813 $x['username'] = $rg['login_ui']['username']; $x['username'] = $rg['login_ui']['username'];
1816 $x['needed_rights'] = 'E';
1814 $x['needed_rights'] = 'E'; // E = create/edit
1817 1815 $x['ip'] = $rg['ip']; $x['ip'] = $rg['ip'];
1818 1816 $x['misc'] = ""; $x['misc'] = "";
1819 1817 if (rg_rights_allow($db, $x) !== TRUE) { if (rg_rights_allow($db, $x) !== TRUE) {
 
... ... function rg_repo_commit_labels_html($db, $repo_id, $commit)
2254 2252 return $ret; return $ret;
2255 2253 } }
2256 2254
2255 /*
2256 * API dispatch function
2257 */
2258 function rg_repo_api($db, $a)
2259 {
2260 rg_prof_start('repo_api');
2261 rg_log_enter('repo_api');
2262
2263 $cmd = $a['cmd'];
2264
2265 $ret = array();
2266 while (1) {
2267 if (isset($a['name'])) {
2268 $ri = rg_repo_info($db, 0, $a['connect_uid'],
2269 $a['name']);
2270 } else if (isset($a['repo_id'])) {
2271 $repo_id = intval($a['repo_id']);
2272 $ri = rg_repo_info($db, $repo_id, '', '');
2273 } else {
2274 $ri = FALSE;
2275 }
2276
2277 if (strcmp($cmd, 'repo_list') == 0) {
2278 $params = array('uid' => $a['cui']['uid']);
2279 $sql = 'SELECT name FROM repos'
2280 . ' WHERE uid = @@uid@@';
2281 $res = rg_sql_query_params($db, $sql, $params);
2282 if ($res === FALSE) {
2283 $ret['error'] = 'internal error';
2284 break;
2285 }
2286 $ret = array();
2287 while (($row = rg_sql_fetch_array($res))) {
2288 $ret[] = $row['name'];
2289 }
2290 rg_sql_free_result($res);
2291 break;
2292 }
2293
2294 // From this point below, we have a repo
2295
2296 if ($ri === FALSE) {
2297 $ret['error'] = 'no repo_id=/name= specified';
2298 break;
2299 }
2300
2301 if ($ri['exists'] != 1) {
2302 $ret['error'] = 'invalid user or no rights';
2303 break;
2304 }
2305
2306 $x = array();
2307 $x['obj_id'] = $ri['repo_id'];
2308 $x['type'] = 'repo';
2309 $x['owner'] = $ri['uid'];
2310 $x['uid'] = $a['cui']['uid'];
2311 $x['username'] = $a['cui']['username'];
2312 $x['needed_rights'] = 'A'; // A = Access repo; E = create/edit
2313 $x['ip'] = $a['ip'];
2314 $x['misc'] = '';
2315
2316 if (strcmp($cmd, 'repo_info') == 0) {
2317 if (rg_rights_allow($db, $x) !== TRUE) {
2318 $ret['error'] = 'invalid user or no rights';
2319 break;
2320 }
2321
2322 $ret = $ri;
2323 break;
2324 }
2325
2326 if (strcmp($cmd, 'repo_pr_list') == 0) {
2327 if (rg_rights_allow($db, $x) !== TRUE) {
2328 $ret['error'] = 'invalid user or no rights';
2329 break;
2330 }
2331
2332 $params = array('repo_id' => $ri['repo_id']);
2333 $sql = 'SELECT * FROM merge_requests'
2334 . ' WHERE repo_id = @@repo_id@@';
2335 $res = rg_sql_query_params($db, $sql, $params);
2336 if ($res === FALSE) {
2337 $ret['error'] = 'internal error';
2338 break;
2339 }
2340 $ret = array();
2341 while (($row = rg_sql_fetch_array($res))) {
2342 $ret[] = $row;
2343 }
2344 rg_sql_free_result($res);
2345 break;
2346 }
2347
2348 if (strcmp($cmd, 'repo_bug_list') == 0) {
2349 $y = $x;
2350 $y['needed_rights'] = 'a'; // a = Access bug repo
2351 if (rg_rights_allow($db, $y) !== TRUE) {
2352 $ret['error'] = 'invalid user or no rights';
2353 break;
2354 }
2355
2356 $params = array('repo_id' => $ri['repo_id']);
2357 $sql = 'SELECT bug_id FROM bugs'
2358 . ' WHERE repo_id = @@repo_id@@';
2359 $res = rg_sql_query_params($db, $sql, $params);
2360 if ($res === FALSE) {
2361 $ret['error'] = 'internal error';
2362 break;
2363 }
2364 $ret = array();
2365 while (($row = rg_sql_fetch_array($res))) {
2366 $ret[] = $row['bug_id'];
2367 }
2368 rg_sql_free_result($res);
2369 break;
2370 }
2371
2372 // TODO: for bugs, we do layer violation here!
2373 if (strcmp($cmd, 'repo_bug_info') == 0) {
2374 if (!isset($a['bug_id'])) {
2375 $ret['error'] = 'bug_id= para not specified';
2376 break;
2377 }
2378 $bug_id = intval($a['bug_id']);
2379
2380 $y = $x;
2381 $y['needed_rights'] = 'a'; // a = Access bug repo
2382 if (rg_rights_allow($db, $y) !== TRUE) {
2383 $ret['error'] = 'invalid user or no rights';
2384 break;
2385 }
2386
2387 $bi = rg_bug_info($db, $ri['repo_id'], $bug_id);
2388 if ($bi['exists'] != 1) {
2389 $ret['error'] = 'bug does not exists';
2390 break;
2391 }
2392
2393 $ret = $bi;
2394 break;
2395 }
2396
2397 $ret['error'] = 'invalid command';
2398 break;
2399 }
2400
2401 rg_log_exit();
2402 rg_prof_end('repo_api');
2403 return $ret;
2404 }
2405
2257 2406 ?> ?>
File inc/rights.inc.php changed (mode: 100644) (index 6ade197..b237123)
... ... function rg_rights_load($db, $obj_id, $type)
245 245 rg_prof_start("rights_load"); rg_prof_start("rights_load");
246 246 rg_log_enter("rights_load: obj_id=$obj_id type=$type"); rg_log_enter("rights_load: obj_id=$obj_id type=$type");
247 247
248 $type = rg_force_alpha($type);
249
248 250 $ret = FALSE; $ret = FALSE;
249 251 while (1) { while (1) {
250 252 $key = "rights_by_obj_id::$obj_id::$type"; $key = "rights_by_obj_id::$obj_id::$type";
File inc/sql.inc.php changed (mode: 100644) (index e14bd31..e7fb0f5)
... ... function rg_sql_open_nodelay($h)
72 72 while (1) { while (1) {
73 73 $db = @pg_pconnect($str); $db = @pg_pconnect($str);
74 74 if ($db !== FALSE) { if ($db !== FALSE) {
75 $x = pg_ping($db);
75 // reconnect if needed
76 $x = @pg_ping($db);
76 77 if ($x === TRUE) if ($x === TRUE)
77 78 break; break;
78 79 } }
 
... ... function rg_sql_open_nodelay($h)
89 90 $diff = intval((microtime(TRUE) - $_s) * 1000); $diff = intval((microtime(TRUE) - $_s) * 1000);
90 91 rg_prof_set(array("db_c_ms" => $diff)); rg_prof_set(array("db_c_ms" => $diff));
91 92 if ($db === FALSE) { if ($db === FALSE) {
92 rg_sql_set_error('cannot connect to database');
93 $err = 'cannot connect to database';
94 rg_sql_set_error($err);
95 rg_internal_error($err);
93 96 rg_prof_set(array('db_conn_errors' => 1)); rg_prof_set(array('db_conn_errors' => 1));
94 97 break; break;
95 98 } }
 
... ... function rg_sql_query0($db, $sql, $res, $_s)
142 145
143 146 while (1) { while (1) {
144 147 if ($res === FALSE) { if ($res === FALSE) {
145 rg_sql_set_error("$sql: " . @pg_last_error($db));
146 rg_prof_set(array("qerrors" => 1));
148 $err = "$sql: " . @pg_last_error($db);
149 rg_sql_set_error($err);
150 rg_internal_error($err);
151 rg_prof_set(array('qerrors' => 1));
152 // reconnect if needed
153 @pg_ping($db);
147 154 break; break;
148 155 } }
149 156
 
... ... function rg_sql_query_params($h, $sql, $params)
248 255 */ */
249 256 function rg_sql_close($h) function rg_sql_close($h)
250 257 { {
258 // TODO: why should I connect before close?!
251 259 $db = rg_sql_open_nodelay($h); $db = rg_sql_open_nodelay($h);
252 260 if ($db === FALSE) if ($db === FALSE)
253 261 return FALSE; return FALSE;
File inc/ssh.inc.php changed (mode: 100644) (index 06f3e93..f5c2f6d)
... ... 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 9 require_once($INC . '/totp.inc.php'); require_once($INC . '/totp.inc.php');
10 require_once($INC . '/api.inc.php');
10 11
11 12 function rg_ssh_status($db, $uid) function rg_ssh_status($db, $uid)
12 13 { {
 
... ... function rg_ssh_totp($db, $ip, $uid, $paras)
313 314 rg_prof_end('ssh_totp'); rg_prof_end('ssh_totp');
314 315 } }
315 316
317 /*
318 * Deal with API
319 */
320 function rg_ssh_api($db, $ip, $uid, $paras)
321 {
322 rg_prof_start('ssh_api');
323 rg_log_enter('ssh_api paras=' . rg_array2string($paras));
324
325 $cmd = array_shift($paras);
326 while (1) {
327 $a = array();
328 foreach ($paras as $t) {
329 $v = explode('=', $t, 2);
330 if (count($v) != 2) {
331 $a['error'] = 'invalid para (no =)';
332 $ret = json_encode($a, JSON_PRETTY_PRINT) . "\n";
333 break;
334 }
335
336 $k = trim($v[0]);
337 $a[$k] = trim($v[1]);
338 }
339 if (isset($a['error']))
340 break;
341
342 $a['cmd'] = $cmd;
343 $a['connect_uid'] = $uid;
344 $a['ip'] = $ip;
345 $ret = rg_api($db, $a);
346 break;
347 }
348
349 rg_log_exit();
350 rg_prof_start('ssh_api');
351 rg_log_ml('ret: ' . print_r($ret, TRUE));
352 echo $ret;
353 }
354
316 355 /* /*
317 356 * Returns TRUE if we need to stop execution * Returns TRUE if we need to stop execution
318 357 */ */
 
... ... function rg_ssh_dispatch($db, $ip, $uid, $orig_cmd)
349 388 case 'repos': rg_ssh_repos($db, $uid); return TRUE; case 'repos': rg_ssh_repos($db, $uid); return TRUE;
350 389 case 'repo': rg_ssh_repo($db, $uid, $paras); return TRUE; case 'repo': rg_ssh_repo($db, $uid, $paras); return TRUE;
351 390 case 'totp': rg_ssh_totp($db, $ip, $uid, $paras); return TRUE; case 'totp': rg_ssh_totp($db, $ip, $uid, $paras); return TRUE;
391 case 'api': rg_ssh_api($db, $ip, $uid, $paras); return TRUE;
352 392 case '': case '':
353 393 echo "Available commmands:\n" echo "Available commmands:\n"
354 394 . " status - show some status about the user\n" . " status - show some status about the user\n"
355 395 . " repos - list repos and information about them\n" . " repos - list repos and information about them\n"
356 396 . " repo - list info about a repo\n" . " repo - list info about a repo\n"
357 . " totp - two-factor authentication commands\n";
397 . " totp - two-factor authentication commands\n"
398 . " api - API calls\n";
358 399 return TRUE; return TRUE;
359 400 } }
360 401
File inc/struct.inc.php changed (mode: 100644) (index 267c376..0da9f8e)
... ... $rg_sql_struct[39]['tables'] = array(
535 535 . ", labels TEXT NOT NULL)" . ", labels TEXT NOT NULL)"
536 536 ); );
537 537
538
538 $rg_sql_struct[40]['tables'] = array(
539 'ak' =>
540 "CREATE TABLE apikeys"
541 . " (key_id SERIAL PRIMARY KEY"
542 . ", itime INTEGER NOT NULL"
543 . ", uid INTEGER NOT NULL"
544 . ", name TEXT NOT NULL DEFAULT ''"
545 . ", key TEXT NOT NULL"
546 . ", last_use INTEGER NOT NULL DEFAULT 0"
547 . ", last_ip TEXT NOT NULL DEFAULT ''"
548 . ", count INTEGER NOT NULL DEFAULT 0"
549 . ", first_use INTEGER NOT NULL DEFAULT 0"
550 . ", last_cmd TEXT NOT NULL DEFAULT '')",
551 'workers' =>
552 "CREATE TABLE workers"
553 . " (id SERIAL PRIMARY KEY"
554 . ", name TEXT NOT NULL"
555 . ", key TEXT NOT NULL"
556 . ", itime INTEGER NOT NULL"
557 . ", uid INTEGER NOT NULL"
558 . ", last_connect INTEGER DEFAULT 0"
559 . ", last_ip TEXT DEFAULT ''"
560 . ", uname TEXT DEFAULT ''"
561 . ", host TEXT DEFAULT ''"
562 . ", arch TEXT DEFAULT ''"
563 . ", env TEXT DEFAULT ''"
564 . ", ssh_key TEXT DEFAULT ''"
565 . ", cost INTEGER DEFAULT 0"
566 . ", workers TEXT DEFAULT 1"
567 . ", who INTEGER DEFAULT 0)"
568 );
569 $rg_sql_struct[40]['other'] = array(
570 'api_keys_i_uid' =>
571 "CREATE INDEX apikeys_i_uid ON apikeys(uid)",
572 'workers_i_uid' =>
573 "CREATE INDEX workers_i_uid ON workers(uid)"
574 );
575
576 // Do not forget to add the new tables to statistics
539 577 // This must be the last line // This must be the last line
540 578 $rg_sql_schema_ver = count($rg_sql_struct); $rg_sql_schema_ver = count($rg_sql_struct);
541 579
File inc/totp.inc.php changed (mode: 100644) (index 23a1338..8971fc8)
... ... function rg_totp_high_level($db, &$rg, $paras)
1348 1348 $op = empty($paras) ? 'info' : array_shift($paras); $op = empty($paras) ? 'info' : array_shift($paras);
1349 1349 $rg['menu']['totp'][$op] = 1; $rg['menu']['totp'][$op] = 1;
1350 1350
1351 $rg['HTML:menu_set_level2'] =
1351 $rg['HTML:menu_level2'] =
1352 1352 rg_template('user/settings/totp/menu.html', $rg, TRUE /*xss*/); rg_template('user/settings/totp/menu.html', $rg, TRUE /*xss*/);
1353 1353
1354 1354 switch ($op) { switch ($op) {
File inc/user.inc.php changed (mode: 100644) (index ff1c4cd..36975b5)
... ... function rg_user_edit($db, $d)
528 528
529 529 if ($d['uid'] == 0) { // add if ($d['uid'] == 0) { // add
530 530 $d['uid'] = $row['uid']; $d['uid'] = $row['uid'];
531 rg_cache_set('user' . '::' . $d['uid'] . '::' . ':info',
531 rg_cache_set('user' . '::' . $d['uid'] . '::' . 'info',
532 532 $d, RG_SOCKET_NO_WAIT); $d, RG_SOCKET_NO_WAIT);
533 533
534 534 $event = array('category' => 2000, 'prio' => 50, $event = array('category' => 2000, 'prio' => 50,
 
... ... function rg_user_remove($db, $rg, $uid)
594 594 rg_sql_free_result($res); rg_sql_free_result($res);
595 595
596 596 // invalidate cache // invalidate cache
597 rg_cache_unset('user' . '::' . $uid . 'info', RG_SOCKET_NO_WAIT);
597 rg_cache_unset('user' . '::' . $uid, RG_SOCKET_NO_WAIT);
598 598
599 599 $ret = TRUE; $ret = TRUE;
600 600 break; break;
 
... ... function rg_user_forgot_pass_uid($db, $token)
1160 1160 rg_prof_start("user_forgot_pass_uid"); rg_prof_start("user_forgot_pass_uid");
1161 1161 rg_log_enter("user_forgot_pass_uid: token=$token"); rg_log_enter("user_forgot_pass_uid: token=$token");
1162 1162
1163 if (strlen($token) > 20)
1164 $token = substr($token, 0, 20);
1165
1163 1166 $ret = array(); $ret = array();
1164 1167 $ret['ok'] = 0; $ret['ok'] = 0;
1165 1168 $ret['uid'] = 0; $ret['uid'] = 0;
 
... ... function rg_user_forgot_pass_uid($db, $token)
1172 1175 . " AND expire > @@now@@"; . " AND expire > @@now@@";
1173 1176 $res = rg_sql_query_params($db, $sql, $params); $res = rg_sql_query_params($db, $sql, $params);
1174 1177 if ($res === FALSE) { if ($res === FALSE) {
1175 rg_user_set_error("cannot lookup token (" . rg_sql_error() . ")");
1178 rg_user_set_error('cannot lookup token');
1176 1179 break; break;
1177 1180 } }
1178 1181
 
... ... function rg_user_forgot_pass_uid($db, $token)
1182 1185 if ($rows > 0) if ($rows > 0)
1183 1186 $row = rg_sql_fetch_array($res); $row = rg_sql_fetch_array($res);
1184 1187 rg_sql_free_result($res); rg_sql_free_result($res);
1185 if ($rows == 0)
1188 if ($rows == 0) {
1189 rg_user_set_error('invalid token');
1186 1190 break; break;
1191 }
1187 1192
1188 1193 $ret['uid'] = $row['uid']; $ret['uid'] = $row['uid'];
1189 1194 break; break;
 
... ... function rg_user_forgot_pass_mail_prepare($db, $email)
1250 1255
1251 1256 /* /*
1252 1257 * Reset password function (send mail) * Reset password function (send mail)
1253 * TODO: Convert to rg_mail_template! Maybe also other functions!
1254 1258 */ */
1255 function rg_user_forgot_pass_mail($db, $email)
1259 function rg_user_forgot_pass_mail($db, $rg, $email)
1256 1260 { {
1257 1261 global $php_errormsg; global $php_errormsg;
1258 1262 global $rg_admin_name, $rg_admin_email; global $rg_admin_name, $rg_admin_email;
 
... ... function rg_user_forgot_pass_mail($db, $email)
1274 1278
1275 1279 $ret['exists'] = 1; $ret['exists'] = 1;
1276 1280
1277 $headers = "From: $rg_admin_name <$rg_admin_email>";
1278
1279 $base_url = rg_base_url();
1281 $rg['ui'] = array('email' => $email);
1282 $rg['forgot_token'] = $r['token'];
1280 1283
1281 if (!mail($email,
1282 "Forgot password",
1283 "Hello!\n\n"
1284 . "If you want to reset the password, follow:\n"
1285 . $base_url
1286 . rg_re_url("/op/forgot_link") . "/" . $r['token']
1287 . "\n\nRocketGit team",
1288 $headers,
1289 "-f $rg_admin_email")) {
1290 rg_user_set_error("cannot send mail ($php_errormsg)!");
1284 $r = rg_mail_template('mail/user/forgot/recover', $rg);
1285 if ($r === FALSE) {
1286 rg_user_set_error(rg_mail_error());
1291 1287 break; break;
1292 1288 } }
1293 1289
 
... ... function rg_user_forgot_pass_mail($db, $email)
1295 1291 break; break;
1296 1292 } }
1297 1293
1298 rg_log("DEBUG: user_forgot_pass_mail: ret=" . rg_array2string($ret) . ".");
1294 //rg_log("DEBUG: user_forgot_pass_mail: ret=" . rg_array2string($ret) . ".");
1299 1295 rg_log_exit(); rg_log_exit();
1300 1296 rg_prof_end('user_forgot_pass_mail'); rg_prof_end('user_forgot_pass_mail');
1301 1297 return $ret; return $ret;
 
... ... function rg_user_edit_high_level($db, &$rg)
1640 1636 return $ret; return $ret;
1641 1637 } }
1642 1638
1639 /*
1640 * API dispatch function
1641 */
1642 function rg_user_api($db, $a)
1643 {
1644 rg_prof_start('user_api');
1645 rg_log_enter('user_api');
1646
1647 $cmd = $a['cmd'];
1648
1649 $ret = array();
1650 while (1) {
1651 if (isset($a['user'])) {
1652 $ui = rg_user_info($db, 0, $a['user'], '');
1653 } else if (isset($a['uid'])) {
1654 $ui = rg_user_info($db, $a['uid'], '', '');
1655 } else {
1656 $ret['error'] = 'no uid=/user= specified';
1657 break;
1658 }
1659 if ($ui['exists'] != 1) {
1660 $ret['error'] = 'invalid user or no rights';
1661 break;
1662 }
1663
1664 // TODO: allow also a master user to access user info
1665 if (($a['cui']['is_admin'] != 1)
1666 && ($ui['uid'] != $a['cui']['uid'])) {
1667 $ret['error'] = 'invalid user or no rights';
1668 rg_log('user has no rights');
1669 break;
1670 }
1671
1672 if (strcmp($cmd, 'user_info') == 0) {
1673 $ret = $ui;
1674 break;
1675 }
1676
1677 if (strcmp($cmd, 'user_ssh_keys_list') == 0) {
1678 $ret = rg_keys_list($db, $a['cui']);
1679 break;
1680 }
1681
1682 if (strcmp($cmd, 'user_rights_list') == 0) {
1683 $params = array('who' => $ui['uid']);
1684 $sql = 'SELECT * FROM rights'
1685 . ' WHERE who = @@who@@';
1686 $res = rg_sql_query_params($db, $sql, $params);
1687 if ($res === FALSE) {
1688 $ret['error'] = 'internal error';
1689 break;
1690 }
1691 $ret = array();
1692 while (($row = rg_sql_fetch_array($res))) {
1693 rg_rights_cosmetic($db, $row);
1694 $ret[] = $row;
1695 }
1696 rg_sql_free_result($res);
1697 break;
1698 }
1699
1700 if (strcmp($cmd, 'user_wh_list') == 0) {
1701 $r = rg_wh_list($db, $ui['uid']);
1702 if ($r['ok'] !== 1) {
1703 $ret['error'] = rg_wh_error();
1704 break;
1705 }
1706 rg_wh_cosmetic($r['list']);
1707 // list is indexed by hook_id, remove this
1708 $ret = array();
1709 foreach ($r['list'] as $index => $d)
1710 $ret[] = $d;
1711 break;
1712 }
1713
1714 $ret['error'] = 'invalid command';
1715 break;
1716 }
1717
1718 rg_log_exit();
1719 rg_prof_end('user_api');
1720 return $ret;
1721 }
1722
1643 1723 ?> ?>
File inc/user/forgot_send.php changed (mode: 100644) (index cc33275..c31ffd5)
... ... $errmsg = array();
9 9
10 10 $_show_form = 1; $_show_form = 1;
11 11 if ($rg['doit'] == 1) { if ($rg['doit'] == 1) {
12 $r = rg_user_forgot_pass_mail($db, $email);
12 $r = rg_user_forgot_pass_mail($db, $rg, $email);
13 13 if ($r['ok'] == 0) { if ($r['ok'] == 0) {
14 $errmsg[] = "Internal error! Try again later.";
15 } else if ($r['exists'] == 0) {
16 $errmsg[] = "E-mail does not exists.";
14 $errmsg[] = "internal error; try again later";
17 15 } else { } else {
18 $_forgot .= rg_ok("Check your inbox and follow the instructions!");
16 // Security: we will not tell to an attacker if a user has
17 // an account here!
18 $_forgot .= rg_ok('If you confirmed your e-mail in the past,'
19 . ' check your inbox and follow the instructions.');
19 20 $_show_form = 0; $_show_form = 0;
20 21 } }
21 22 } else { } else {
File inc/user/keys/keys.php changed (mode: 100644) (index 2c9c6f2..dfd7d1e)
1 1 <?php <?php
2 rg_log("FILE: /inc/user/keys/keys");
2 rg_log('FILE: /inc/user/keys/keys');
3 3
4 4 $_keys = ''; $_keys = '';
5 5
 
... ... $del_errmsg = array();
9 9 $key = trim(rg_var_str('key')); $key = trim(rg_var_str('key'));
10 10 $key = str_replace("\n", ' ', $key); $key = str_replace("\n", ' ', $key);
11 11 $key = str_replace("\r", ' ', $key); $key = str_replace("\r", ' ', $key);
12 $key_id = rg_var_uint("key_id");
13 $key_delete_ids = rg_var_str("key_delete_ids");
12 $key_id = rg_var_uint('key_id');
13 $key_delete_ids = rg_var_str('key_delete_ids');
14 14
15 15 $rg['HTML:add_status'] = ''; $rg['HTML:add_status'] = '';
16 16 $rg['HTML:del_status'] = ''; $rg['HTML:del_status'] = '';
17 17
18 while (rg_var_uint("add") == 1) {
18 while (rg_var_uint('add') == 1) {
19 19 if (!rg_valid_referer()) { if (!rg_valid_referer()) {
20 $add_errmsg[] = "invalid referer; try again";
20 $add_errmsg[] = 'invalid referer; try again';
21 21 break; break;
22 22 } }
23 23
24 24 if (!rg_token_valid($db, $rg, 'keys', FALSE)) { if (!rg_token_valid($db, $rg, 'keys', FALSE)) {
25 $add_errmsg[] = "Invalid token. Try again.";
25 $add_errmsg[] = 'invalid token; try again';
26 26 break; break;
27 27 } }
28 28
 
... ... while (rg_var_uint("add") == 1) {
32 32 break; break;
33 33 } }
34 34
35 $rg['HTML:add_status'] = rg_template("user/keys/add_ok.html", $rg, TRUE /* xss */);
35 $rg['HTML:add_status'] = rg_template('user/keys/add_ok.html', $rg, TRUE /* xss */);
36 36 $key = ''; $key = '';
37 37 break; break;
38 38 } }
39 39
40 while (rg_var_uint("delete") == 1) {
40 while (rg_var_uint('delete') == 1) {
41 41 if (!rg_valid_referer()) { if (!rg_valid_referer()) {
42 $del_errmsg[] = "invalid referer; try again";
42 $del_errmsg[] = 'invalid referer; try again';
43 43 break; break;
44 44 } }
45 45
46 46 if (!rg_token_valid($db, $rg, 'keys', FALSE)) { if (!rg_token_valid($db, $rg, 'keys', FALSE)) {
47 $del_errmsg[] = "Invalid token. Try again.";
47 $del_errmsg[] = 'invalid token; try again';
48 48 break; break;
49 49 } }
50 50
51 51 if (empty($key_delete_ids)) { if (empty($key_delete_ids)) {
52 $del_errmsg[] = "No keys selected.";
52 $del_errmsg[] = 'no keys selected';
53 53 break; break;
54 54 } }
55 55
 
... ... while (rg_var_uint("delete") == 1) {
58 58 break; break;
59 59 } }
60 60
61 $rg['HTML:del_status'] = rg_template("user/keys/remove_ok.html", $rg, TRUE /* xss */);
61 $rg['HTML:del_status'] = rg_template('user/keys/remove_ok.html', $rg, TRUE /* xss */);
62 62 break; break;
63 63 } }
64 64
 
... ... $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)
74 $rg['HTML:keys'] = rg_warning("Could not load keys. Try later."); // TODO
74 $rg['HTML:keys'] = rg_warning('Could not load keys. Try later.'); // TODO
75 75 else else
76 $rg['HTML:keys'] = rg_template_table("user/keys/list", $keys_list, $rg);
76 $rg['HTML:keys'] = rg_template_table('user/keys/list', $keys_list, $rg);
77 77
78 78 $hints = array(); $hints = array();
79 79 if ($rg_ssh_port != 0) if ($rg_ssh_port != 0)
80 $hints[]['HTML:hint'] = rg_template("hints/ssh/key.html", $rg, TRUE /* xss */);
81 $rg['HTML:hints'] = rg_template_table("hints/list", $hints, $rg);
80 $hints[]['HTML:hint'] = rg_template('hints/ssh/key.html', $rg, TRUE /* xss */);
81 $rg['HTML:hints'] = rg_template_table('hints/list', $hints, $rg);
82 82
83 83 $_keys .= rg_template('user/keys/main.html', $rg, TRUE /*xss*/); $_keys .= rg_template('user/keys/main.html', $rg, TRUE /*xss*/);
84 84 ?> ?>
File inc/user/settings.php changed (mode: 100644) (index 76c7313..7c2d3af)
1 1 <?php <?php
2 2 rg_log("FILE: /inc/user/settings"); rg_log("FILE: /inc/user/settings");
3 require_once($INC . '/webhooks.inc.php');
4 3
5 4 $_settings = ''; $_settings = '';
6 5
 
... ... $errmsg = array();
15 14
16 15 $_subop = empty($paras) ? "edit_info" : array_shift($paras); $_subop = empty($paras) ? "edit_info" : array_shift($paras);
17 16
18 $rg['HTML:menu_set_level2'] = '';
17 $rg['HTML:menu_level2'] = '';
19 18
19 $rg['url_up'] = $rg['url'];
20 $rg['url'] .= '/' . $_subop;
20 21 switch ($_subop) { switch ($_subop) {
21 22 case 'change_pass': case 'change_pass':
22 23 include($INC . "/user/pass/pass.php"); include($INC . "/user/pass/pass.php");
 
... ... case 'keys':
28 29 $_settings_body = $_keys; $_settings_body = $_keys;
29 30 break; break;
30 31
32 case 'apikeys':
33 $_settings_body = rg_ak_high_level($db, $rg, $paras);
34 break;
35
31 36 case 'totp': case 'totp':
32 37 $_settings_body = rg_totp_high_level($db, $rg, $paras); $_settings_body = rg_totp_high_level($db, $rg, $paras);
33 38 break; break;
 
... ... case 'wh':
36 41 $_settings_body = rg_wh_high_level($db, $rg, $paras); $_settings_body = rg_wh_high_level($db, $rg, $paras);
37 42 break; break;
38 43
44 case 'workers':
45 $_settings_body = rg_worker_high_level($db, $rg, $paras);
46 break;
47
39 48 default: default:
40 49 $rg['ask_for_pass'] = 0; $rg['ask_for_pass'] = 0;
41 50 $rg['no_tos'] = 1; // we ask for only for account creation $rg['no_tos'] = 1; // we ask for only for account creation
42 51 $_settings_body = rg_user_edit_high_level($db, $rg); $_settings_body = rg_user_edit_high_level($db, $rg);
43 52 break; break;
44 53 } }
54 $rg['url'] = $rg['url_up'];
45 55
46 56 $rg['set_menu'][$_subop] = 1; $rg['set_menu'][$_subop] = 1;
47 57 $_settings = rg_template("user/settings/menu.html", $rg, TRUE /* xss */); $_settings = rg_template("user/settings/menu.html", $rg, TRUE /* xss */);
File inc/util.inc.php changed (mode: 100644) (index 27e7eb4..70c91af)
... ... function rg_fix_ip($ip)
1652 1652 */ */
1653 1653 function rg_json_escape($s) function rg_json_escape($s)
1654 1654 { {
1655 return $s;
1655 return json_encode($s);
1656 }
1657
1658 /*
1659 * Escapes texts inside XML tags
1660 * Example: <a>&</a> -> <a>&amp;</a>
1661 */
1662 function fn_xml_escape($s)
1663 {
1664 return strtr($s,
1665 array(
1666 '<' => '&lt;',
1667 '>' => '&gt;',
1668 '"' => '&quot;',
1669 '\'' => '&apos;',
1670 '&' => '&amp;',
1671 )
1672 );
1673 }
1674
1675 /*
1676 * Removes from a string all non-alpha characters
1677 */
1678 function rg_force_alpha($s)
1679 {
1680 return preg_replace('/[^A-Za-z]/', '', $s);
1656 1681 } }
1657 1682
1658 1683 ?> ?>
File inc/webhooks.inc.php changed (mode: 100644) (index d8e0dba..02bc8e8)
... ... function rg_wh_add_high_level($db, $rg, $op, $paras)
187 187 } }
188 188 } }
189 189
190 rg_wh_add_form($rg);
190 rg_wh_add_form($db, $rg);
191 191
192 192 $hints[]['HTML:hint'] = rg_template('user/settings/wh/hints_htype.html', $hints[]['HTML:hint'] = rg_template('user/settings/wh/hints_htype.html',
193 193 $rg, TRUE /*xss*/); $rg, TRUE /*xss*/);
 
... ... function rg_wh_high_level($db, &$rg, $paras)
222 222 $op = empty($paras) ? 'list' : array_shift($paras); $op = empty($paras) ? 'list' : array_shift($paras);
223 223 $rg['menu']['wh'][$op] = 1; $rg['menu']['wh'][$op] = 1;
224 224
225 $rg['HTML:menu_set_level2'] =
225 $rg['HTML:menu_level2'] =
226 226 rg_template('user/settings/wh/menu.html', $rg, TRUE /*xss*/); rg_template('user/settings/wh/menu.html', $rg, TRUE /*xss*/);
227 227
228 228 switch ($op) { switch ($op) {
File inc/wh/amazon.inc.php changed (mode: 100644) (index 049f76b..720cdc9)
... ... function rg_amazon_req($a)
146 146 $xerr = @fread($err, 16 * 4096); $xerr = @fread($err, 16 * 4096);
147 147 fclose($err); fclose($err);
148 148 $ret['debug'] = $xerr; $ret['debug'] = $xerr;
149 rg_log_ml('xerr=' . $xerr);
149 rg_log_ml('DEBUG: xerr=' . $xerr);
150 150 } }
151 151
152 152 if ($r === FALSE) { if ($r === FALSE) {
File inc/wh/build.inc.php changed (mode: 100644) (index f694916..decb485)
... ... require_once($INC . "/wh/core.inc.php");
9 9
10 10 $rg_wh_build_functions = array( $rg_wh_build_functions = array(
11 11 'wh_build_send' => 'rg_wh_build_send', 'wh_build_send' => 'rg_wh_build_send',
12 'wh_build_send_one' => 'rg_wh_build_send_one'
12 'wh_build_send_one' => 'rg_wh_build_send_one',
13 'wh_build_job_done' => 'rg_wh_build_job_done'
13 14 ); );
14 15 rg_event_register_functions($rg_wh_build_functions); rg_event_register_functions($rg_wh_build_functions);
15 16
16 17
18 /*
19 * This is called when a job is done
20 */
21 function rg_wh_build_job_done($db, $ev)
22 {
23 rg_prof_start('wh_build_job_done');
24 rg_log_ml('wh_build_job_done: ev: ' . print_r($ev, TRUE));
25
26 $ret = FALSE;
27 while (1) {
28 $s = $ev['status'];
29 $out = 'Worker: ' . $ev['job']['worker_name'] . "\n";
30 $out .= 'Date (UTC): '
31 . gmdate('Y-m-d H:i', $ev['job']['done']) . "\n";
32 $out .= 'Elapsed time: '
33 . ($ev['job']['done'] - $ev['job']['worker_started'])
34 . 's' . "\n";
35 $out .= "\n";
36 $out .= 'Packages:' . "\n" . $s['packages'];
37 foreach ($s['cmds'] as $index => $i) {
38 if (empty($ev['job']['cmds'][$index]['cmd']))
39 continue;
40
41 $out .= "\n\n" . 'Command['
42 . $ev['job']['cmds'][$index]['cmd'] . ']: '
43 . "\n" . $i['log'];
44 }
45
46 rg_wh_set_last_output($db, $ev['ui']['uid'],
47 $ev['job']['hook_id'], $out);
48 $ret = array();
49 break;
50 }
51
52 rg_prof_end('wh_build_job_done');
53 return $ret;
54 }
55
17 56 /* /*
18 57 * Helper for rg_wh_build_send * Helper for rg_wh_build_send
19 58 */ */
 
... ... function rg_wh_build_send_one($db, $event)
31 70 // replace ##tags## // replace ##tags##
32 71 rg_wh_replace_tags($event); rg_wh_replace_tags($event);
33 72
34 // we need to copy 'flags'/'url' because we pass idata
35 $wh['idata']['flags'] = $wh['flags'];
36 $wh['idata']['url'] = $event['ri']['clone_url'];
37 $wh['idata']['head'] = $event['new_rev'];
38
39 // TODO: still have to pass env
40 // TODO: also, e-mail notification
41 $wh['idata']['env'] = 'fedora23-server-x86_64';
73 $a = $wh['idata'];
74 $a['hook_id'] = $wh['id'];
75 $a['uid'] = $event['ui']['uid'];
76 $a['flags'] = $wh['flags'];
77 $a['url'] = $event['ri']['clone_url'];
78 $a['head'] = $event['new_rev'];
79 $a['env'] = $event['env'];
80 $a['packages'] = $event['packages'];
81 // TODO: pass e-mail notification
42 82
43 83 // Call the function // Call the function
44 $r = rg_builder_add($db, $event['ri']['repo_id'], $wh['idata']);
84 $r = rg_builder_add($db, $event['ri']['repo_id'], $a);
45 85 if ($r['ok'] != 1) { if ($r['ok'] != 1) {
46 86 $last_output .= $r['error']; $last_output .= $r['error'];
47 87 break; break;
 
... ... function rg_wh_build_send_one($db, $event)
51 91 break; break;
52 92 } }
53 93
54 rg_wh_set_last_output($db, $event['ui']['uid'], $wh['id'],
55 substr($last_output, 0, 4096));
94 if (!empty($last_output))
95 rg_wh_set_last_output($db, $event['ui']['uid'], $wh['id'],
96 substr($last_output, 0, 4096));
56 97
57 98 rg_prof_end('wh_build_send_one'); rg_prof_end('wh_build_send_one');
58 99 return $ret; return $ret;
 
... ... function rg_wh_build_send($db, $event)
96 137
97 138 $x = $event; $x = $event;
98 139 $x['category'] = 'wh_build_send_one'; $x['category'] = 'wh_build_send_one';
99 $x['wh'] = $wh;
100 140 $x['debug'] = $wh['idata']['debug']; $x['debug'] = $wh['idata']['debug'];
101 $ret[] = $x;
141 $x['packages'] = $wh['idata']['packages'];
142 $envs = $wh['idata']['envs']; unset($wh['idata']['envs']);
143 $x['wh'] = $wh;
144 foreach ($envs as $env => $junk) {
145 $y = $x;
146 $y['env'] = $env;
147 $ret[] = $y;
148 }
102 149 } }
103 150
104 151 rg_prof_end('wh_build_send'); rg_prof_end('wh_build_send');
 
... ... function rg_wh_build_cosmetic(&$row)
112 159 { {
113 160 $f = rg_template('user/settings/wh/build/show_one.html', $f = rg_template('user/settings/wh/build/show_one.html',
114 161 $rg, TRUE/*xss*/); $rg, TRUE/*xss*/);
115
116 162 $list = ''; $list = '';
117 163 foreach ($row['idata']['cmds'] as $i => &$info) { foreach ($row['idata']['cmds'] as $i => &$info) {
118 164 if (empty($info['cmd'])) if (empty($info['cmd']))
 
... ... function rg_wh_build_cosmetic(&$row)
125 171 $row['idata']['HTML:wh_list'] = $row['idata']['HTML:wh_list'] =
126 172 rg_template_string($list, 0 /*off*/, $row['idata'], TRUE /*xss*/); rg_template_string($list, 0 /*off*/, $row['idata'], TRUE /*xss*/);
127 173
174 $f = rg_template('user/settings/wh/build/env_show_one.html',
175 $rg, TRUE/*xss*/);
176 $list = '';
177 //rg_log_ml('DEBUG: envs: ' . print_r($row['idata']['envs'], TRUE));
178 foreach ($row['idata']['envs'] as $env => $junk) {
179 $list .= str_replace('##env##', $env, $f);
180 }
181 $row['idata']['HTML:envs_list'] =
182 rg_template_string($list, 0 /*off*/, $row['idata'], TRUE /*xss*/);
183
128 184 $row['idata']['HTML:private'] = rg_template( $row['idata']['HTML:private'] = rg_template(
129 185 'user/settings/wh/build/show.html', $row['idata'], TRUE /*xss*/); 'user/settings/wh/build/show.html', $row['idata'], TRUE /*xss*/);
130 186 } }
 
... ... function rg_wh_build_fill_vars(&$rg)
159 215 $a['cmds'][$i]['abort'] = strcasecmp($x, 'on') == 0 ? 1 : 0; $a['cmds'][$i]['abort'] = strcasecmp($x, 'on') == 0 ? 1 : 0;
160 216 } }
161 217
218 $a['envs'] = array();
219 $envs = rg_var_str('wh::idata::envs');
220 //rg_log_ml('envs: ' . print_r($envs, TRUE));
221 foreach ($envs as $env => $on)
222 $a['envs'][$env] = strcasecmp($on, 'on') == 0 ? 1 : 0;
223
224 $a['packages'] = trim(rg_var_str('wh::idata::packages'));
225 $a['packages'] = str_replace(';', ' ', $a['packages']);
226 $a['packages'] = str_replace(',', ' ', $a['packages']);
227 $a['packages'] = str_replace('\r', ' ', $a['packages']);
228 $a['packages'] = str_replace('\n', ' ', $a['packages']);
229 $a['packages'] = str_replace('\t', ' ', $a['packages']);
230
162 231 //rg_log_ml('DEBUG: after fill_vars: ' . print_r($a, TRUE)); //rg_log_ml('DEBUG: after fill_vars: ' . print_r($a, TRUE));
163 232 } }
164 233
 
... ... function rg_wh_build_validate_vars($rg, &$errmsg)
175 244 while (1) { while (1) {
176 245 $all_empty = TRUE; $all_empty = TRUE;
177 246
178 rg_log_ml('DEBUG: cmds:' . print_r($a['idata']['cmds'], TRUE));
247 //rg_log_ml('DEBUG: cmds:' . print_r($a['idata']['cmds'], TRUE));
179 248 if (empty($a['idata']['cmds'])) { if (empty($a['idata']['cmds'])) {
180 249 $errmsg[] = rg_template('user/settings/wh/build/inv_cmd.txt', $errmsg[] = rg_template('user/settings/wh/build/inv_cmd.txt',
181 250 $rg, TRUE /*xss*/); $rg, TRUE /*xss*/);
182 251 break; break;
183 252 } }
184 253
254 //rg_log_ml('DEBUG: envs:' . print_r($a['idata']['envs'], TRUE));
255 if (empty($a['idata']['envs'])) {
256 $errmsg[] = rg_template('user/settings/wh/build/inv_env.txt',
257 $rg, TRUE /*xss*/);
258 break;
259 }
260
185 261 $ret = TRUE; $ret = TRUE;
186 262 break; break;
187 263 } }
 
... ... function rg_wh_build_validate_vars($rg, &$errmsg)
192 268 /* /*
193 269 * Transfers to $rg the custom parameters - used when showing the form * Transfers to $rg the custom parameters - used when showing the form
194 270 */ */
195 function rg_wh_build_add_form(&$rg)
271 function rg_wh_build_add_form($db, &$rg)
196 272 { {
197 273 $f = rg_template_blind('user/settings/wh/build/form_cmd.html'); $f = rg_template_blind('user/settings/wh/build/form_cmd.html');
198
199 274 $cmds = ''; $cmds = '';
200 275 for ($i = 1; $i <= 5; $i++) for ($i = 1; $i <= 5; $i++)
201 276 $cmds .= str_replace('##i##', $i, $f); $cmds .= str_replace('##i##', $i, $f);
202
203 277 //rg_log_ml('DEBUG: cmds=' . $cmds); //rg_log_ml('DEBUG: cmds=' . $cmds);
204
205 278 $rg['HTML:cmds'] = $rg['HTML:cmds'] =
206 279 rg_template_string($cmds, 0 /*off*/, $rg, TRUE /*xss*/); rg_template_string($cmds, 0 /*off*/, $rg, TRUE /*xss*/);
207 280
281 $envs = rg_worker_environments($db, $rg['login_ui']['uid']);
282 $f = rg_template_blind('user/settings/wh/build/form_env.html');
283 $_s = '';
284 foreach ($envs as $env)
285 $_s .= str_replace('##env##', $env, $f);
286 rg_log_ml('envs: ' . $_s);
287 $rg['HTML:envs'] =
288 rg_template_string($_s, 0 /*off*/, $rg, TRUE /*xss*/);
289
290 // 'packages' was added later
291 if (!isset($rg['wh']['idata']['packages']))
292 $rg['wh']['idata']['packages'] = '';
293
294 //rg_log_ml('DEBUG:rg: ' . print_r($rg, TRUE));
295
208 296 $rg['HTML:custom_form'] = rg_template('user/settings/wh/build/form.html', $rg['HTML:custom_form'] = rg_template('user/settings/wh/build/form.html',
209 297 $rg, TRUE /*xss*/); $rg, TRUE /*xss*/);
210 298 } }
 
... ... function rg_wh_build_default_paras(&$rg)
235 323 for ($i = 1; $i <= 5; $i++) for ($i = 1; $i <= 5; $i++)
236 324 $a['cmds'][$i] = $t; $a['cmds'][$i] = $t;
237 325
326 $a['envs'] = array();
327 $a['packages'] = '';
328
238 329 $a['events'] = 'P'; $a['events'] = 'P';
239 330 } }
240 331
File inc/wh/cloud.inc.php changed (mode: 100644) (index a92e2d9..d3fec88)
... ... function rg_wh_cloud_validate_vars($rg, &$errmsg)
209 209 /* /*
210 210 * Transfers to $rg the custom parameters - used when showing the form * Transfers to $rg the custom parameters - used when showing the form
211 211 */ */
212 function rg_wh_cloud_add_form(&$rg)
212 function rg_wh_cloud_add_form($db, &$rg)
213 213 { {
214 214 $rg['HTML:custom_form'] = rg_template('user/settings/wh/cloud/form.html', $rg['HTML:custom_form'] = rg_template('user/settings/wh/cloud/form.html',
215 215 $rg, TRUE /*xss*/); $rg, TRUE /*xss*/);
File inc/wh/core.inc.php changed (mode: 100644) (index 718ff0f..06d18b8)
... ... function rg_wh_validate_vars($rg, &$errmsg)
480 480 /* /*
481 481 * Generic add_form function * Generic add_form function
482 482 */ */
483 function rg_wh_add_form(&$rg)
483 function rg_wh_add_form($db, &$rg)
484 484 { {
485 485 global $rg_wh_plugins; global $rg_wh_plugins;
486 486
 
... ... function rg_wh_add_form(&$rg)
499 499 rg_wh_check_events($rg['wh']['idata']['events']); rg_wh_check_events($rg['wh']['idata']['events']);
500 500
501 501 if (isset($rg_wh_plugins[$t]['add_form'])) { if (isset($rg_wh_plugins[$t]['add_form'])) {
502 $rg_wh_plugins[$t]['add_form']($rg);
502 $rg_wh_plugins[$t]['add_form']($db, $rg);
503 503 break; break;
504 504 } }
505 505
File inc/wh/http.inc.php changed (mode: 100644) (index 5da8bfd..90091f1)
... ... function rg_wh_http_send_one($db, $event)
92 92 curl_setopt($c, CURLOPT_CAINFO, $ca_file); curl_setopt($c, CURLOPT_CAINFO, $ca_file);
93 93 } }
94 94
95 $xerr = 'Date (UTC): '
96 . gmdate('Y-m-d H:i') . "\n";
97 $xerr .= "\n";
98
95 99 $r = @curl_exec($c); $r = @curl_exec($c);
96 100
97 101 if ($err !== FALSE) { if ($err !== FALSE) {
98 102 rewind($err); rewind($err);
99 $xerr = @fread($err, 16 * 4096);
103 $xerr .= @fread($err, 16 * 4096);
100 104 fclose($err); fclose($err);
101 105 rg_log_ml('xerr: ' . $xerr); rg_log_ml('xerr: ' . $xerr);
102 106 } }
 
... ... function rg_wh_http_send_one($db, $event)
134 138 if ($ca_file !== FALSE) if ($ca_file !== FALSE)
135 139 @unlink($ca_file); @unlink($ca_file);
136 140
137 rg_wh_set_last_output($db, $event['ui']['uid'], $wh['id'],
138 substr($xerr, 0, 4096));
141 rg_wh_set_last_output($db, $event['ui']['uid'], $wh['id'], $xerr);
139 142
140 143 rg_prof_end('wh_http_send_helper'); rg_prof_end('wh_http_send_helper');
141 144 return $ret; return $ret;
 
... ... function rg_wh_http_validate_vars($rg, &$errmsg)
339 342 /* /*
340 343 * Transfers to $rg the custom parameters - used when showing the form * Transfers to $rg the custom parameters - used when showing the form
341 344 */ */
342 function rg_wh_http_add_form(&$rg)
345 function rg_wh_http_add_form($db, &$rg)
343 346 { {
344 347 $rg['HTML:select_itype'] = rg_wh_http_select_itype($rg['wh']['idata']['itype']); $rg['HTML:select_itype'] = rg_wh_http_select_itype($rg['wh']['idata']['itype']);
345 348
File inc/wh/lambda.inc.php changed (mode: 100644) (index ea72912..8dc3396)
... ... function rg_wh_lambda_validate_vars($rg, &$errmsg)
154 154 /* /*
155 155 * Transfers to $rg the custom parameters - used when showing the form * Transfers to $rg the custom parameters - used when showing the form
156 156 */ */
157 function rg_wh_lambda_add_form(&$rg)
157 function rg_wh_lambda_add_form($db, &$rg)
158 158 { {
159 159 $rg['HTML:custom_form'] = rg_template('user/settings/wh/lambda/form.html', $rg['HTML:custom_form'] = rg_template('user/settings/wh/lambda/form.html',
160 160 $rg, TRUE /*xss*/); $rg, TRUE /*xss*/);
File inc/workers.inc.php added (mode: 100644) (index 0000000..7e77f17)
1 <?php
2 $INC = isset($INC) ? $INC : dirname(__FILE__);
3 require_once($INC . '/events.inc.php');
4
5 $rg_worker_error = '';
6
7 function rg_worker_set_error($str)
8 {
9 global $rg_worker_error;
10 $rg_worker_error = $str;
11 rg_log($str);
12 }
13
14 function rg_worker_error()
15 {
16 global $rg_worker_error;
17 return $rg_worker_error;
18 }
19
20 /*
21 * Event functions
22 */
23 $rg_worker_functions = array(
24 'worker_event_add' => 'rg_worker_event_add',
25 'worker_event_del' => 'rg_worker_event_del'
26 );
27 rg_event_register_functions($rg_worker_functions);
28
29 /*
30 * Event for adding a worker
31 */
32 function rg_worker_event_add($db, $ev)
33 {
34 $ret = array();
35
36 $ret[] = array_merge($ev, array('category' => 1002, 'prio' => 10));
37
38 return $ret;
39 }
40
41 /*
42 * Event for deleting a worker
43 */
44 function rg_worker_event_del($db, $ev)
45 {
46 $ret = array();
47
48 $ret[] = array_merge($ev, array('category' => 1002, 'prio' => 10));
49
50 return $ret;
51 }
52
53 /*
54 * Helper for sorting by time
55 */
56 function rg_worker_sort_time_desc($a, $b)
57 {
58 if ($a['itime'] > $b['itime'])
59 return 1;
60 if ($a['itime'] < $b['itime'])
61 return -1;
62 return 0;
63 }
64
65 /*
66 * Cosmetic function (one element)
67 */
68 function rg_worker_cosmetic_one(&$row)
69 {
70 $row['itime_nice'] = gmdate('Y-m-d H:i', $row['itime']);
71 if ($row['last_connect'] == 0)
72 $row['last_connect_nice'] = 'n/a';
73 else
74 $row['last_connect_nice'] = gmdate('Y-m-d H:i',
75 $row['last_connect']);
76
77 if (empty($row['env'])) {
78 $row['HTML:envs_nice'] = 'n/a';
79 } else {
80 $list = @unserialize($row['env']);
81 $t = array();
82 foreach ($list as $env => $env_info)
83 $t[] = rg_xss_safe($env);
84 sort($t);
85 $row['HTML:envs_nice'] = implode('<br />', $t);
86 }
87 }
88
89 /*
90 * Cosmetic function (array)
91 */
92 function rg_worker_cosmetic(&$a)
93 {
94 foreach ($a as &$row)
95 rg_worker_cosmetic_one($row);
96 uasort($a, 'rg_worker_sort_time_desc');
97 }
98
99 /*
100 * Sorts the list of workers.
101 * It is used when selecting a server to send the job.
102 */
103 function rg_worker_sort($a, $b)
104 {
105 if ($a['cost'] > $b['cost'])
106 return 1;
107 if ($a['cost'] < $b['cost'])
108 return -1;
109 return 0;
110 }
111
112 /*
113 * Sorts the list of workers by name.
114 */
115 function rg_worker_sort_alpha($a, $b)
116 {
117 return strcmp($a, $b);
118 }
119
120 /*
121 * Loads info about a worker
122 */
123 function rg_worker_list($db, $uid)
124 {
125 rg_prof_start('worker_list');
126 rg_log_enter('worker_list uid=' . $uid);
127
128 $ret = FALSE;
129 while (1) {
130 $key = 'workers' . '::' . $uid;
131 $c = rg_cache_get($key);
132 if (($c !== FALSE) && isset($c['LOADED'])) {
133 $ret = $c['list'];
134 rg_worker_cosmetic($ret);
135 break;
136 }
137
138 $params = array('uid' => $uid);
139 $sql = 'SELECT * FROM workers'
140 . ' WHERE uid = @@uid@@';
141 $res = rg_sql_query_params($db, $sql, $params);
142 if ($res === FALSE) {
143 rg_worker_set_error('cannot load list');
144 break;
145 }
146
147 $ret = array();
148 while (($row = rg_sql_fetch_array($res))) {
149 $id = $row['id'];
150 $ret[$id] = $row;
151 }
152 rg_sql_free_result($res);
153
154 $a = array('LOADED' => 1, 'list' => $ret);
155 rg_cache_set($key, $a, RG_SOCKET_NO_WAIT);
156
157 rg_worker_cosmetic($ret);
158 break;
159 }
160
161 rg_log_exit();
162 rg_prof_end('worker_list');
163 return $ret;
164 }
165
166 /*
167 * Returns a list of workers, including the global ones
168 */
169 function rg_worker_list_all($db, $uid)
170 {
171 $l1 = rg_worker_list($db, $uid);
172 if ($l1 === FALSE)
173 return FALSE;
174
175 $l2 = rg_worker_list($db, 0);
176 if ($l2 === FALSE)
177 return FALSE;
178
179 $ret = array();
180 foreach ($l1 as $id => $i)
181 $ret[$id] = $i;
182 foreach ($l2 as $id => $i)
183 $ret[$id] = $i;
184
185 uasort($ret, 'rg_worker_sort');
186 return $ret;
187 }
188
189 /*
190 * Searches for a worker, by name
191 * Returns -1 on error, 0 if not found or the info if found
192 */
193 function rg_worker_find_by_id($db, $uid, $id)
194 {
195 rg_log_enter('worker_find_by_uid uid=' . $uid . ' id=' . $id);
196
197 $ret = -1;
198 while (1) {
199 $wi = rg_worker_list($db, $uid);
200 if ($wi === FALSE)
201 break;
202
203 $ret = 0;
204
205 foreach ($wi as $_id => $i) {
206 if ($_id == $id) {
207 $ret = $i;
208 break;
209 }
210 }
211 break;
212 }
213
214 rg_log_exit();
215 return $ret;
216 }
217
218 /*
219 * Searches for a worker, by name
220 * Returns -1 on error, 0 if not found or the info if found
221 */
222 function rg_worker_find_by_name($db, $uid, $name)
223 {
224 rg_log_enter('worker_find_by_name uid=' . $uid . ' name=' . $name);
225
226 $ret = -1;
227 while (1) {
228 $wi = rg_worker_list($db, $uid);
229 if ($wi === FALSE)
230 break;
231
232 $ret = 0;
233
234 foreach ($wi as $id => $i) {
235 rg_log('DEBUG: comparing with [' . $i['name'] . ']...');
236 if (strcasecmp($i['name'], $name) == 0) {
237 $ret = $i;
238 break;
239 }
240 }
241 break;
242 }
243
244 rg_log_exit();
245 return $ret;
246 }
247
248 /*
249 * Adds a new worker
250 */
251 function rg_worker_add($db, $uid, $a)
252 {
253 rg_prof_start('worker_add');
254 rg_log_enter('worker_add');
255
256 //rg_log_ml('DEBUG: a: ' . print_r($a, TRUE));
257
258 $ret = FALSE;
259 while (1) {
260 $params = array();
261 $params['uid'] = $uid;
262 $params['id'] = $a['id'];
263 $params['name'] = $a['name'];
264 $params['cost'] = $a['cost'];
265 $params['workers'] = $a['workers'];
266
267 if ($a['id'] == 0) {
268 $params['itime'] = time();
269 $params['uname'] = '';
270 $params['host'] = '';
271 $params['arch'] = '';
272 $params['last_connect'] = '';
273 $params['last_ip'] = '';
274
275 $sql = 'INSERT INTO workers (itime, uid, name'
276 . ', key, who, cost, workers)'
277 . ' VALUES (@@itime@@, @@uid@@, @@name@@'
278 . ', @@key@@, @@who@@, @@cost@@, @@workers@@)'
279 . ' RETURNING id';
280 } else {
281 $sql = 'UPDATE workers SET name = @@name@@'
282 . ', cost = @@cost@@'
283 . ', workers = @@workers@@'
284 . ' WHERE uid = @@uid@@ AND id = @@id@@';
285 }
286
287 $res = rg_sql_query_params($db, $sql, $params);
288 if ($res === FALSE) {
289 rg_worker_set_error('cannot insert/update');
290 break;
291 }
292 $row = rg_sql_fetch_array($res);
293 rg_sql_free_result($res);
294
295 if ($a['id'] == 0)
296 $id = $row['id'];
297 else
298 $id = $a['id'];
299
300 $event = array(
301 'category' => 'worker_event_add',
302 'prio' => 50,
303 'ui' => array('uid' => $uid),
304 'add' => $a['id'] == 0 ? 1 : 0,
305 'id' => $id);
306 $r = rg_event_add($db, $event);
307 if ($r !== TRUE) {
308 rg_worker_set_error('cannot add event'
309 . ' (' . rg_event_error() . ')');
310 break;
311 }
312
313 $key = 'workers' . '::' . $uid . '::' . 'list' . '::' . $id;
314 unset($params['uid']);
315 $params['id'] = $id;
316 rg_cache_merge($key, $params, RG_SOCKET_NO_WAIT);
317
318 rg_event_signal_daemon('', 0);
319
320 $ret = TRUE;
321 break;
322 }
323
324 rg_log_exit();
325 rg_prof_end('worker_add');
326
327 return $ret;
328 }
329
330 /*
331 * Updates 'last_connect' and 'last_ip', 'uname', 'host', 'arch', 'env'
332 */
333 function rg_worker_update($db, $uid, $id, $a)
334 {
335 rg_prof_start('worker_update');
336 rg_log_enter('worker_update');
337
338 rg_log_ml('DEBUG: a: ' . print_r($a, TRUE));
339
340 $ret = FALSE;
341 while (1) {
342 $params = $a;
343 $params['uid'] = $uid;
344 $params['id'] = $id;
345 $params['last_connect'] = time();
346 $params['env'] = serialize($a['env']);
347
348 $sql = 'UPDATE workers SET'
349 . ' name = @@name@@'
350 . ', last_connect = @@last_connect@@'
351 . ', last_ip = @@ip@@'
352 . ', uname = @@uname@@'
353 . ', host = @@host@@'
354 . ', arch = @@arch@@'
355 . ', env = @@env@@'
356 . ', ssh_key = @@ssh_key@@'
357 . ' WHERE uid = @@uid@@'
358 . ' AND id = @@id@@';
359 $res = rg_sql_query_params($db, $sql, $params);
360 if ($res === FALSE) {
361 rg_worker_set_error('cannot update fields');
362 break;
363 }
364 rg_sql_free_result($res);
365
366 $key = 'workers' . '::' . $uid . '::' . 'list' . '::' . $id;
367 unset($params['uid']);
368 rg_cache_merge($key, $params, RG_SOCKET_NO_WAIT);
369
370 $ret = TRUE;
371 break;
372 }
373
374 rg_log_exit();
375 rg_prof_end('worker_update');
376
377 return $ret;
378 }
379
380 /*
381 * Returns a list of available environments
382 * It also order by cost.
383 */
384 function rg_worker_environments($db, $uid)
385 {
386 rg_prof_start('worker_environments');
387 rg_log_enter('worker_environments');
388
389 $ret = FALSE;
390 while (1) {
391 $user_envs = array();
392 if ($uid > 0) {
393 $r = rg_worker_list($db, $uid);
394 if ($r === FALSE)
395 break;
396 }
397
398 $global_envs = rg_worker_list($db, 0);
399 if ($global_envs === FALSE)
400 break;
401
402 $r = array_merge($user_envs, $global_envs);
403 $ret = array();
404 foreach ($r as $id => $i) {
405 $list = @unserialize($i['env']);
406 if ($list === FALSE)
407 continue;
408
409 foreach ($list as $env => $junk)
410 $ret[$env] = $env;
411 }
412
413 uksort($ret, 'rg_worker_sort_alpha');
414 //rg_log_ml('DEBUG: workers_environments: ret=' . print_r($ret, TRUE));
415 break;
416 }
417
418 rg_log_exit();
419 rg_prof_end('worker_environments');
420 return $ret;
421 }
422
423 /*
424 * Remove workers from database
425 */
426 function rg_worker_remove($db, $uid, $list)
427 {
428 rg_prof_start('workers_remove');
429 rg_log_enter('workers_remove: list=' . rg_array2string($list));
430
431 $ret = FALSE;
432 while (1) {
433 $my_list = array();
434 foreach ($list as $key_id => $junk)
435 $my_list[] = sprintf('%u', $key_id);
436
437 $params = array('uid' => $uid);
438 $sql_list = implode(', ', $my_list);
439 $sql = 'DELETE FROM workers'
440 . ' WHERE uid = @@uid@@'
441 . ' AND id IN (' . $sql_list . ')';
442 $res = rg_sql_query_params($db, $sql, $params);
443 if ($res === FALSE) {
444 rg_worker_set_error('cannot delete api keys');
445 break;
446 }
447 rg_sql_free_result($res);
448
449 $event = array(
450 'category' => 'worker_event_del',
451 'prio' => 50,
452 'ui' => array('uid' => $uid),
453 'keys' => implode(',', $my_list));
454 $r = rg_event_add($db, $event);
455 if ($r !== TRUE) {
456 rg_worker_set_error('cannot add event'
457 . ' (' . rg_event_error() . ')');
458 break;
459 }
460
461 $key = 'workers' . '::' . $uid . '::' . 'list';
462 foreach ($my_list as $_key_id)
463 rg_cache_unset($key . '::' . $_key_id,
464 RG_SOCKET_NO_WAIT);
465
466 rg_event_signal_daemon('', 0);
467 $ret = TRUE;
468 break;
469 }
470
471 rg_log_exit();
472 rg_prof_end('workers_remove');
473 return $ret;
474 }
475
476
477 /*
478 * Workers - add
479 */
480 function rg_worker_add_high_level($db, $rg, $op, $paras)
481 {
482 rg_prof_start('worker_add_high_level');
483 rg_log_enter('worker_add_high_level op=' . $op);
484
485 $ret = '';
486 $errmsg = array();
487
488 $rg['worker'] = array();
489 if (strcmp($op, 'add') == 0) {
490 $rg['worker']['id'] = 0;
491 $rg['worker']['name'] = '';
492 $rg['worker']['key'] = rg_id(32);
493 $rg['worker']['cost'] = 10;
494 $rg['worker']['workers'] = 1;
495 } else {
496 if (isset($paras[0])) {
497 $id = intval($paras[0]);
498 $r = rg_worker_find_by_id($db, $rg['login_ui']['uid'],
499 $id);
500 if ($r === -1)
501 $errmsg[] = 'error loading list; try again later';
502 else if ($r === 0)
503 $errmsg[] = 'invalid id for edit';
504 else
505 $rg['worker'] = $r;
506 } else {
507 $errmsg[] = 'no worker id received';
508 }
509 }
510 rg_log_ml('DEBUG: rg[worker]: ' . print_r($rg['worker'], TRUE));
511
512 $doit = rg_var_uint('doit');
513 while ($doit == 1) {
514 if ($rg['worker']['id'] == 0) {
515 $rg['worker']['id'] = rg_var_uint('worker::id');
516 $rg['worker']['key'] = rg_var_str('worker::key');
517 }
518 $rg['worker']['name'] = rg_var_str('worker::name');
519 $rg['worker']['cost'] = rg_var_uint('worker::cost');
520 $rg['worker']['workers'] = rg_var_uint('worker::workers');
521
522 if ($rg['worker']['id'] == 0) {
523 $len = strlen($rg['worker']['key']);
524 if ($len < 32) {
525 $errmsg[] = 'invalid key (len = ' . $len . ')';
526 break;
527 }
528 }
529
530 if (empty($rg['worker']['name'])) {
531 $errmsg[] = 'invalid name';
532 break;
533 }
534
535 if (!rg_valid_referer()) {
536 $errmsg[] = 'invalid referer; try again';
537 break;
538 }
539
540 if (!rg_token_valid($db, $rg, 'worker_add', FALSE)) {
541 $errmsg[] = 'invalid token; try again';
542 break;
543 }
544
545 if ($rg['login_ui']['is_admin'] == 1) {
546 $rg['worker']['who'] = 0;
547 $target_uid = 0;
548 } else {
549 $rg['worker']['who'] = $rg['login_ui']['uid'];
550 $target_uid = $rg['login_ui']['uid'];
551 }
552 $r = rg_worker_add($db, $target_uid, $rg['worker']);
553 if ($r === FALSE) {
554 $errmsg[] = rg_worker_error();
555 break;
556 }
557
558 $ret .= rg_template('user/settings/workers/add_ok.html',
559 $rg, TRUE /*xss*/);
560
561 $rg['worker']['id'] = 0;
562 $rg['worker']['name'] = '';
563 $rg['worker']['key'] = rg_id(32);
564 $rg['worker']['cost'] = 10;
565 $rg['worker']['workers'] = 1;
566 break;
567 }
568
569 $rg['HTML:errmsg'] = rg_template_errmsg($errmsg);
570 $rg['rg_form_token'] = rg_token_get($db, $rg, 'worker_add');
571 $ret .= rg_template('user/settings/workers/add.html',
572 $rg, TRUE /*xss*/);
573
574 rg_log_exit();
575 rg_prof_end('worker_add_high_level');
576 return $ret;
577 }
578
579 /*
580 * Workers - list
581 */
582 function rg_worker_list_high_level($db, $rg, $paras)
583 {
584 rg_prof_start('worker_list_high_level');
585 rg_log_enter('worker_list_high_level');
586
587 $ret = '';
588
589 $errmsg = array();
590 $rg['HTML:status'] = '';
591
592 if ($rg['login_ui']['is_admin'] == 1)
593 $target_uid = 0;
594 else
595 $target_uid = $rg['login_ui']['uid'];
596
597 $doit = rg_var_uint('doit');
598 while ($doit == 1) {
599 if (!rg_valid_referer()) {
600 $errmsg[] = 'invalid referer; try again';
601 break;
602 }
603
604 if (!rg_token_valid($db, $rg, 'workers_list', FALSE)) {
605 $errmsg[] = 'invalid token; try again.';
606 break;
607 }
608
609 $list = rg_var_str('delete_ids');
610 $r = rg_worker_remove($db, $target_uid, $list);
611 if ($r !== TRUE) {
612 $errmsg[] = 'cannot delete: ' . rg_worker_error();
613 break;
614 }
615
616 $rg['HTML:status'] = rg_template(
617 'user/settings/workers/delete_ok.html',
618 $rg, TRUE /*xss*/);
619 break;
620 }
621
622 $r = rg_worker_list($db, $target_uid);
623 if ($r === FALSE) {
624 $rg['errmsg'] = rg_worker_error();
625 $ret .= rg_template('user/settings/workers/list_err.html',
626 $rg, TRUE /*xss*/);
627 } else {
628 $rg['rg_form_token'] = rg_token_get($db, $rg, 'workers_list');
629 $rg['HTML:errmsg'] = rg_template_errmsg($errmsg);
630 $ret .= rg_template_table('user/settings/workers/list', $r, $rg);
631 }
632
633 rg_log_exit();
634 rg_prof_end('worker_list_high_level');
635 return $ret;
636 }
637
638 /*
639 * Deals with workers
640 */
641 function rg_worker_high_level($db, &$rg, $paras)
642 {
643 rg_prof_start('worker_high_level');
644 rg_log_enter('worker_high_level');
645
646 $ret = '';
647
648 $op = empty($paras) ? 'list' : array_shift($paras);
649 $rg['menu']['worker'][$op] = 1;
650
651 $rg['HTML:menu_level2'] =
652 rg_template('user/settings/workers/menu.html', $rg, TRUE /*xss*/);
653
654 switch ($op) {
655 case 'edit':
656 case 'add':
657 $ret .= rg_worker_add_high_level($db, $rg, $op, $paras);
658 break;
659
660 default:
661 $ret .= rg_worker_list_high_level($db, $rg, $paras);
662 break;
663 }
664
665 $hints = array();
666 $hints[]['HTML:hint'] = rg_template('user/settings/workers/hints.html',
667 $rg, TRUE /*xss*/);
668 $ret .= rg_template_table('hints/list', $hints, $rg);
669
670 rg_log_exit();
671 rg_prof_end('worker_high_level');
672 return $ret;
673 }
674
675 ?>
File rocketgit.spec.in changed (mode: 100644) (index c13763d..8486d6d)
... ... rm -rf ${RPM_BUILD_ROOT}
82 82 %dir @USR_SHARE@/@PRJ@ %dir @USR_SHARE@/@PRJ@
83 83 %doc README LICENSE Changelog TODO selinux/@PRJ@.* %doc README LICENSE Changelog TODO selinux/@PRJ@.*
84 84 %dir @ETC@/@PRJ@ %dir @ETC@/@PRJ@
85 %config(noreplace) @ETC@/@PRJ@/config.php
86 85 @ETC@/@PRJ@/config.php.sample @ETC@/@PRJ@/config.php.sample
87 @ETC@/cron.d/rocketgit
88 86 @ETC@/logrotate.d/rocketgit @ETC@/logrotate.d/rocketgit
87 %config(noreplace) @ETC@/@PRJ@/config.php
88 %config(noreplace) @ETC@/cron.d/rocketgit
89 89 %config(noreplace) @ETC@/xinetd.d/rocketgit %config(noreplace) @ETC@/xinetd.d/rocketgit
90 90 %config(noreplace) @ETC@/httpd/conf.d/rocketgit.conf %config(noreplace) @ETC@/httpd/conf.d/rocketgit.conf
91 91 %attr(0755,rocketgit,rocketgit) %dir @VAR_LOG@/@PRJ@ %attr(0755,rocketgit,rocketgit) %dir @VAR_LOG@/@PRJ@
File root/index.php changed (mode: 100644) (index 53ef7a8..07e7eee)
... ... include_once($INC . "/bug.inc.php");
23 23 include_once($INC . "/fixes.inc.php"); include_once($INC . "/fixes.inc.php");
24 24 include_once($INC . "/plan.inc.php"); include_once($INC . "/plan.inc.php");
25 25 include_once($INC . "/admin.inc.php"); include_once($INC . "/admin.inc.php");
26 include_once($INC . "/api.inc.php");
27 include_once($INC . "/apikeys.inc.php");
26 28 include_once($INC . "/ver.php"); include_once($INC . "/ver.php");
27 29
28 30 rg_prof_start("MAIN"); rg_prof_start("MAIN");
 
... ... $rg['target_ui'] = array("ok" => 1, "exists" => 0, "uid" => 0);
52 54 $rg['ri'] = array("repo_id" => 0, "uid" => 0); $rg['ri'] = array("repo_id" => 0, "uid" => 0);
53 55 $rg['bug'] = array("bug_id" => 0); $rg['bug'] = array("bug_id" => 0);
54 56 $rg['debug'] = rg_var_uint('rg_debug'); $rg['debug'] = rg_var_uint('rg_debug');
57 $rg['base_url'] = rg_base_url();
55 58
56 59 // 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
57 60 $sparas = rg_var_str("vv"); $sparas = rg_var_str("vv");
58 61 rg_log("DEBUG: sparas=$sparas"); rg_log("DEBUG: sparas=$sparas");
59 62 $rg['current_url'] = rawurlencode($sparas); $rg['current_url'] = rawurlencode($sparas);
60 $rg['url'] = "/op";
63 $rg['url'] = '/op';
61 64 $paras = explode("/", trim($sparas, "/")); $paras = explode("/", trim($sparas, "/"));
62 65 $_t = empty($paras) ? "" : $paras[0]; $_t = empty($paras) ? "" : $paras[0];
63 66 if (strcmp($_t, "op") == 0) { if (strcmp($_t, "op") == 0) {
64 67 array_shift($paras); array_shift($paras);
65 $_op = empty($paras) ? "" : array_shift($paras);
68 $_op = empty($paras) ? '' : array_shift($paras);
66 69 } else { } else {
67 $_op = "";
70 $_op = '';
68 71 } }
69 72
70 73 $rg['doit'] = rg_var_uint("doit"); $rg['doit'] = rg_var_uint("doit");
 
... ... if ($good == 0) {
118 121 exit(0); exit(0);
119 122 } }
120 123
121 if (strcmp($service, "git-upload-packXXX") == 0) {
124 if (0 && strcmp($service, "git-upload-packXXX") == 0) {
122 125 rg_log("We have a fetch by http!"); rg_log("We have a fetch by http!");
123 126 // TODO: settimelimit to a resonable value // TODO: settimelimit to a resonable value
124 127 putenv("GIT_HTTP_EXPORT_ALL=1"); putenv("GIT_HTTP_EXPORT_ALL=1");
 
... ... if (strcmp($service, "git-upload-packXXX") == 0) {
129 132 exit(0); exit(0);
130 133 } }
131 134
135 // API dispatch
136 if (strcmp($_op, 'api') == 0) {
137 $_auth = isset($_SERVER['HTTP_AUTHORIZATION']) ? $_SERVER['HTTP_AUTHORIZATION'] : '';
138 $_t = explode(' ', $_auth, 2);
139 $_user = trim($_t[0]);
140 $_key = trim($_t[1]);
141 rg_log('api user=[' . $_user . '] key=[' . $_key . ']!');
142 $body = '';
143 while (1) {
144 $ui = rg_user_info($db, 0, $_user, '');
145 if ($ui['ok'] != 1) {
146 $body = array('error' => rg_user_error());
147 echo json_encode($body, JSON_PRETTY_PRINT) . "\n";
148 break;
149 }
150 if ($ui['exists'] != 1) {
151 $body = array('error' => 'invalid user or apikey');
152 echo json_encode($body, JSON_PRETTY_PRINT) . "\n";
153 break;
154 }
155
156 $key_id = rg_ak_valid($db, $ui['uid'], $_key);
157 if ($key_id === FALSE) {
158 $body = array('error' => 'invalid user or apikey');
159 echo json_encode($body, JSON_PRETTY_PRINT) . "\n";
160 break;
161 }
162
163 $post = @file_get_contents("php://input");
164 rg_log('post=' . $post);
165
166 $d = @json_decode($post);
167 if ($d === NULL) {
168 rg_log('error parsing!');
169 $body = array('error' => json_last_error_msg());
170 echo json_encode($body, JSON_PRETTY_PRINT) . "\n";
171 break;
172 }
173
174 rg_ak_update_use($db, $ui['uid'], $key_id, $rg['ip'], $post);
175
176 // we need to transform the object 'd' into an array
177 $d2 = array();
178 foreach ($d as $k => $v)
179 $d2[$k] = $v;
180 $d2['connect_uid'] = $ui['uid'];
181 $d2['ip'] = $rg['ip'];
182 echo rg_api($db, $d2);
183 break;
184 }
185
186 rg_prof_end("MAIN");
187 rg_prof_log();
188 exit(0);
189 }
190
132 191 rg_user_login_by_sid($db, $rg); rg_user_login_by_sid($db, $rg);
133 192 rg_log("After login_by_sid, login_ui=" . rg_array2string($rg['login_ui'])); rg_log("After login_by_sid, login_ui=" . rg_array2string($rg['login_ui']));
134 193 // If user provided an old/expired sid, we generate a new one, pre-login // If user provided an old/expired sid, we generate a new one, pre-login
File root/themes/default/admin/menu.html changed (mode: 100644) (index 4778560..83dccef)
5 5 <li@@if(@@admin_menu::plans@@ == 1){{ class="selected"}}{{}}><a href="/op/admin/plans">Plans</a></li> <li@@if(@@admin_menu::plans@@ == 1){{ class="selected"}}{{}}><a href="/op/admin/plans">Plans</a></li>
6 6 <li@@if(@@admin_menu::users@@ == 1){{ class="selected"}}{{}}><a href="/op/admin/users">Users</a></li> <li@@if(@@admin_menu::users@@ == 1){{ class="selected"}}{{}}><a href="/op/admin/users">Users</a></li>
7 7 <li@@if(@@admin_menu::repos@@ == 1){{ class="selected"}}{{}}><a href="/op/admin/repos">Repos</a></li> <li@@if(@@admin_menu::repos@@ == 1){{ class="selected"}}{{}}><a href="/op/admin/repos">Repos</a></li>
8 <li@@if(@@admin_menu::workers@@ == 1){{ class="selected"}}{{}}><a href="/op/admin/workers">Workers</a></li>
8 9 <li@@if(@@admin_menu::invites@@ == 1){{ class="selected"}}{{}}><a href="/op/admin/invites">Invites</a></li> <li@@if(@@admin_menu::invites@@ == 1){{ class="selected"}}{{}}><a href="/op/admin/invites">Invites</a></li>
9 10 </ul> </ul>
10 11 </div> </div>
11 @@menu_admin_level2@@
12 @@menu_level2@@
File root/themes/default/admin/plans/list/footer.html changed (mode: 100644) (index 29fad9a..4759628)
2 2
3 3 <input type="submit" name="button" value="Delete selected plans" /> <input type="submit" name="button" value="Delete selected plans" />
4 4 </form> </form>
5 </div>
File root/themes/default/admin/plans/list/header.html changed (mode: 100644) (index 0418109..d82908c)
1 <div class="rg_plans_list">
2
3 1 @@del_errmsg@@ @@del_errmsg@@
4 2
5 <form method="post" action="/op/admin/plans/list">
3 <form method="post" action="/op/admin/plans/list" class="form_table">
6 4 <input type="hidden" name="delete" value="1" /> <input type="hidden" name="delete" value="1" />
7 5 <input type="hidden" name="token" value="@@rg_form_token@@" /> <input type="hidden" name="token" value="@@rg_form_token@@" />
8 6
File root/themes/default/doc/api.html added (mode: 100644) (index 0000000..6558691)
1 <div class="main_title">API documentation</div>
2
3 <div class="islands">
4 <div class="island_row">
5 <div class="island_cell">
6 <div class="island">
7 <div class="island_title">Calling API by SSH or by CURL</div>
8 Possible commands:<br />
9 <a href="#user_info">user_info<a/><br />
10 <a href="#user_rights_list">user_rights_list</a><br />
11 <a href="#user_ssh_keys_list">user_ssh_keys_list</a><br />
12 <a href="#user_wh_list">user_wh_list</a><br />
13 <a href="#repo_bug_info">repo_bug_info</a><br />
14 <a href="#repo_bug_list">repo_bug_list</a><br />
15 <a href="#repo_list">repo_list</a><br />
16 <a href="#repo_info">repo_info</a><br />
17 <a href="#repo_pr_list">repo_pr_list</a><br />
18 <br />
19
20 <a name="user_info"><b>user_info</b></a><br />
21 <b>Description</b>: List information abot a user<br />
22 <b>Parameters</b>: user, uid<br />
23 Example:
24 <div class="term">
25 $ curl --header 'Authorization: bla this_is_bla_api_key' \
26 --data '{"cmd": "user_info", "user": "bla"}' \
27 @@base_url@@/op/api
28 $ ssh rocketgit@rocketgit.com api user_info user=bla
29 {
30 "ok": 1,
31 "exists": 1,
32 "uid": "846",
33 "is_admin": "0",
34 "rights": "C",
35 "homepage": "\/user\/bla",
36 "username": "bla",
37 "salt": "3f786850e387550fdab836ed7e6dc881de23001b",
38 "pass": "162b0b32f024...01cc7884a635be",
39 "email": "bla@example.com",
40 "itime": "1440834245",
41 "suspended": null,
42 "session_time": "3600",
43 "last_seen": "1464805192",
44 "disk_used_mb": null,
45 "confirmed": "1",
46 "confirm_token": "c215e946b2b15d66d14b",
47 "organization": "0",
48 "realname": "my real name",
49 "plan_id": "0",
50 "last_ip": "192.168.79.154",
51 "itime_nice": "2015-08-29",
52 "email_md5": "60b725f10c9c85c70d97880dfe8191b3",
53 "HTML:gravatar": "&lt;img src=\"https:\/\/www.gravatar.com\/avatar\/60...b3?s=64&amp;r=g\" alt=\"avatar\" width=\"64\" height=\"64\" \/&gt;"
54 }
55 </div>
56 <br />
57
58 <a name="user_rights_list"><b>user_rights_list</b></a><br />
59 <b>Description</b>: Lists user defined rights<br />
60 <b>Parameters</b>: user<br />
61 Example:
62 <div class="term">
63 $ curl --header 'Authorization: bla this_is_bla_api_key' \
64 --data '{"cmd": "user_rights_list", "user": "bla"}' \
65 @@base_url@@/op/api
66 $ ssh rocketgit@rocketgit.com api user_rights_list user=bla
67 [
68 {
69 "type": "repo_path",
70 "obj_id": "831",
71 "uid": "0",
72 "rights": "P",
73 "itime": "1450417938",
74 "misc": "",
75 "prio": "100",
76 "who": "846",
77 "right_id": "79",
78 "ip": "",
79 "misc2": "",
80 "<b>Description</b>": "dfdsfds",
81 "username": "*",
82 "who_name": "catab",
83 "rights_text": "Push",
84 "itime_text": "2015-12-18 05:52",
85 "ip_nice": "Any",
86 "HTML:<b>Description</b>_nlbr": "dfdsfds",
87 "can_be_deleted": 1
88 },
89 ...
90 ]
91 </div>
92 <br />
93
94 <a name="user_ssh_keys_list"><b>user_ssh_keys_list</b></a><br />
95 <b>Description</b>: Lists SSH keys of a user<br />
96 <b>Parameters</b>: user<br />
97 Example:
98 <div class="term">
99 $ curl --header 'Authorization: bla this_is_bla_api_key' \
100 --data '{"cmd": "user_ssh_keys_list", "user": "bla"}' \
101 @@base_url@@/op/api
102 $ ssh rocketgit@rocketgit.com api user_ssh_keys_list user=bla
103 [
104 {
105 "ok": 1,
106 "type": "ssh-rsa",
107 "comment": "Key for rocketgit - r1i",
108 "key": "AAAAB3NzaC1yc2...yTRiD8gFdg9UT1bw==",
109 "bits": 4096,
110 "fingerprint_md5": "b1:fd:5f:f0:53:f5:9c:31:b2:de:ff:00:1c:f1:c5:61",
111 "fingerprint_sha256": "SNPwFw0Snaz7pdUAFV4Lrf8LFHqx93I7VmW5LsjTlLS0",
112 "key_id": "438",
113 "itime": "2016-01-27 21:11",
114 "first_use": "2016-01-27 21:13",
115 "last_ip": "192.168.79.154",
116 "last_use": "2016-01-29 18:27",
117 "last_cmd": "git-receive-pack '\/user\/catab\/delme10'",
118 "count": "27"
119 },
120 ...
121 ]
122 </div>
123 <br />
124
125 <a name="user_wh_list"><b>user_wh_list</b></a><br />
126 <b>Description</b>: Lists webhooks of a user<br />
127 <b>Parameters</b>: user<br />
128 Example:
129 <div class="term">
130 $ curl --header 'Authorization: bla this_is_bla_api_key' \
131 --data '{"cmd": "user_wh_list", "user": "bla"}' \
132 @@base_url@@/op/api
133 $ ssh rocketgit@rocketgit.com api user_wh_list user=bla
134 [
135 {
136 "id": "648",
137 "uid": "846",
138 "itime": "1454001110",
139 "<b>Description</b>": "Test Slack integration",
140 "add_ip": "192.168.79.154",
141 "last_output": "* Trying ...H5pQ==\r\n\r\nok",
142 "idata": {
143 "debug": "0",
144 "events": "P",
145 "url": "https:\/\/hooks.slack.com\/services\/T...D\/B...N\/j...E",
146 "itype": "2",
147 "client_cert": "",
148 "client_ca_cert": "",
149 "opaque": "",
150 "key": "",
151 "custom_body": "{\n \"cha...host:\"\n}",
152 "events_text": "Push",
153 "itype_text": "Custom (use custom body field)",
154 "HTML:client_cert_short": "n\/a",
155 "HTML:client_ca_cert_short": "n\/a",
156 "HTML:custom_body_nlbr": "{&lt;br \/&gt;... \/&gt;\n}",
157 "HTML:private": "&lt;table ...&lt;\/table&gt;\n"
158 },
159 "htype": "http",
160 "flags": "",
161 "refname": "(test1|master)",
162 "repo": ".*10",
163 "itime_nice": "2016-01-28 17:11",
164 "HTML:flags_text": "",
165 "HTML:<b>Description</b>_nice": "Test Slack integration",
166 "HTML:last_output_nice": "* Try...\r\nok"
167 },
168 ...
169 ]
170 </div>
171 <br />
172
173 <a name="repo_bug_info"><b>repo_bug_info</b></a><br />
174 <b>Description</b>: Shows information about a bug<br />
175 <b>Parameters</b>: name/repo_id, bug_id<br />
176 Example:
177 <div class="term">
178 $ curl --header 'Authorization: bla this_is_bla_api_key' \
179 --data '{"cmd": "repo_bug_info", "name": "repo1", "bug_id": 2}' \
180 @@base_url@@/op/api
181 $ ssh rocketgit@rocketgit.com api repo_bug_info name=repo1 bug_id=2
182 {
183 "bug_id": "2",
184 "title": "dsdasds",
185 "body": "OS type(s) and version(s)?",
186 "state": "1",
187 "labels": "",
188 "assigned_to": "bla",
189 "assigned_uid": "846",
190 "itime": 1464812804,
191 "utime": 1464812804,
192 "ip": "192.168.79.154",
193 "repo_id": "1088",
194 "uid": "846",
195 "deleted": 0,
196 "ok": 1,
197 "exists": 1,
198 "owner": "catab",
199 "HTML:body_nlbr": "OS type(s) and version(s)?",
200 "creation": "2016-06-01 20:26",
201 "updated": "2016-06-01 20:26",
202 "deleted_text": "",
203 "deleted_who_name": "",
204 "state_text": "Open"
205 }
206 </div>
207 <br />
208
209 <a name="repo_bug_list"><b>repo_bug_list</b></a><br />
210 <b>Description</b>: Lists the bugs<br />
211 <b>Parameters</b>: name, repo_id<br />
212 Example:
213 <div class="term">
214 $ curl --header 'Authorization: bla this_is_bla_api_key' \
215 --data '{"cmd": "repo_bug_list", "name": "repo1"}' \
216 @@base_url@@/op/api
217 $ ssh rocketgit@rocketgit.com api repo_bug_list name=repo1
218 [
219 "1",
220 "2",
221 "3"
222 ]
223 </div>
224 <br />
225
226 <a name="repo_list"><b>repo_list</b></a><br />
227 <b>Parameters</b>: none<br />
228 Example:
229 <div class="term">
230 $ curl --header 'Authorization: bla this_is_bla_api_key' \
231 --data '{"cmd": "repo_list"}' \
232 @@base_url@@/op/api
233 $ ssh rocketgit@rocketgit.com api repo_list
234 [
235 "repo1",
236 "repo2",
237 "repo3"
238 ]
239 </div>
240 <br />
241
242 <a name="repo_info"><b>repo_info</b></a><br />
243 <b>Description</b>: Shows info about a repository<br />
244 <b>Parameters</b>: name, repo_id<br />
245 Example:
246 <div class="term">
247 $ curl --header 'Authorization: bla this_is_bla_api_key' \
248 --data '{"cmd": "repo_info", "name": "repo1"}' \
249 @@base_url@@/op/api
250 $ ssh rocketgit@rocketgit.com api repo_info name=repo1
251 {
252 "repo_id": "769",
253 "name": "repo1",
254 "uid": "846",
255 "itime": "1447874006",
256 "disk_quota_mb": null,
257 "max_commit_size": "0",
258 "master": "0",
259 "<b>Description</b>": "here is a <b>Description</b>",
260 "git_dir_done": "1",
261 "deleted": "0",
262 "disk_used_mb": "0",
263 "public": "1",
264 "last_bug_id": "1",
265 "license": "GPLv3",
266 "template": "",
267 "last_mr_id": "0",
268 "ok": 1,
269 "exists": 1,
270 "clone_url": "ssh:\/\/rocketgit@rg.embedromix.ro:2222\/user\/bla\/repo1",
271 "HTML:<b>Description</b>_nlbr": "here is a <b>Description</b>",
272 "HTML:itime_nice": "2015-11-18",
273 "owner": "bla",
274 "url_user": "http:\/\/r1i:9000\/user\/bla",
275 "url_repo": "http:\/\/r1i:9000\/user\/bla\/repo1",
276 "clone_url_ssh": "ssh:\/\/rocketgit@rg.embedromix.ro:2222\/user\/bla\/repo1",
277 "clone_url_git": "git:\/\/rg.embedromix.ro\/user\/bla\/repo1",
278 "master_name": "-",
279 "disk_used": "0B"
280 }
281 </div>
282 <br />
283
284 <a name="repo_pr_list"><b>repo_pr_list</b></a><br />
285 <b>Description</b>: Lists the pull requests<br />
286 <b>Parameters</b>: name, repo_id<br />
287 Example:
288 <div class="term">
289 $ curl --header 'Authorization: bla this_is_bla_api_key' \
290 --data '{"cmd": "repo_pr_list", "name": "repo1"}' \
291 @@base_url@@/op/api
292 $ ssh rocketgit@rocketgit.com api repo_pr_list name=repo1
293 [
294 {
295 "repo_id": "769",
296 "itime": "1330296541",
297 "namespace": "rg_b21751c3",
298 "refname": "refs\/heads\/master",
299 "old_rev": "afd1df2940fe440cde9b8ede988ff24c051a10d6",
300 "new_rev": "f919c9bf863471aeb97da6aa2380319a1bee6eda",
301 "done": "0",
302 "ip": "2002:2e66:5950::1",
303 "id": "5",
304 "who": "0"
305 },
306 ...
307 ]
308 </div>
309 </div>
310 </div>
311 </div>
312
313 </div>
File root/themes/default/doc/worker.html added (mode: 100644) (index 0000000..55b20a1)
1 <div class="main_title">How to prepare a worker to build/test your projects</div>
2
3 <div class="islands">
4 <div class="island_row">
5 <div class="island_cell">
6 <div class="island">
7 <div class="island_title">Preparing a virtual machine</div>
8 - Install an operating system into a virtual machine.<br />
9 - Inside the virtual machine, edit /etc/rc.d/rc.local like this:
10 <div class="term">
11 #!/bin/bash
12
13 id build > /dev/null
14 if [ "${?}" != "0" ]; then
15 adduser build
16 fi
17
18 while [ 1 ]; do
19 mount LABEL=RG /mnt
20 if [ "${?}" != "0" ]; then
21 sleep 1
22 continue
23 fi
24
25 /mnt/rg.sh >/mnt/rg.log 2>&amp;1
26 break
27 done 1>/dev/null 2>&amp;1 < /dev/null &amp;
28 </div>
29 and make it executable:
30 <div class="term">
31 chmod a+x /etc/rc.d/rc.local
32 </div>
33 </div>
34 </div>
35
36 <div class="island_cell">
37 <div class="island">
38 <div class="island_title">Preparing the worker machine</div>
39 - Install rocketgit <a href="/op/download" target="_blank">software</a> on a machine<br />
40 - Add a worker (Settings / Worker or Admin / Worker)<br />
41 - Edit /etc/rocketgit/worker.conf (start with .sample file)<br />
42 - Edit /etc/cron.d/rocketgit: uncomment the worker.sh line<br />
43 Sample worker.conf:<br />
44 <div class="term">
45 type = user
46 user = my_rocketgit.com_user
47 name = Builder 1
48 master = r1.example.net
49 port = 65000
50 state = /var/lib/rocketgit/worker
51 key = this_is_the_key_used_when_the_worker_was_added
52
53 env = fedora-server-24-x86_64
54 type = libvirt
55 arch = x86_64
56 image = /var/lib/libvirt/images/rgw/fedora-server-24-x86_64.qcow2
57 pkg_cmd = dnf -y install
58 os-variant = fedora22
59 </div>
60 To debug the problems with the worker, check /var/log/rocketgit/worker-*.log
61 </div>
62 </div>
63 </div>
64
65 </div>
File root/themes/default/features.html changed (mode: 100644) (index cb6c2cf..4b7c407)
2 2
3 3 <div class="islands"> <div class="islands">
4 4 <div class="island_row"> <div class="island_row">
5 <div class="island_cell">
6 <div class="island">
5 <div class="island_cell">
6 <div class="island">
7 7 <div class="island_title">FLOS (Free, Libre and Open-Source) software</div> <div class="island_title">FLOS (Free, Libre and Open-Source) software</div>
8 8 RocketGit is licensed under RocketGit is licensed under
9 9 the GNU Affero General Public License v3+, therefore you have the freedom the GNU Affero General Public License v3+, therefore you have the freedom
 
16 16 </div> </div>
17 17 </div> </div>
18 18
19 <div class="island_cell">
20 <div class="island">
19 <div class="island_cell">
20 <div class="island">
21 21 <div class="island_title">Fastest</div> <div class="island_title">Fastest</div>
22 22 RocketGit is extremely fast as it doesn't contain any Java, RocketGit is extremely fast as it doesn't contain any Java,
23 23 Javascript or Flash. And we plan to rewrite it in C for maximum speed. Javascript or Flash. And we plan to rewrite it in C for maximum speed.
24 24 </div> </div>
25 25 </div> </div>
26 26
27 <div class="island_cell">
28 <div class="island">
27 <div class="island_cell">
28 <div class="island">
29 29 <div class="island_title">Lightest</div> <div class="island_title">Lightest</div>
30 30 RocketGit is really compact, therefore even if you choose to RocketGit is really compact, therefore even if you choose to
31 31 install it on your machine instead of using it in your web install it on your machine instead of using it in your web
 
36 36 </div> </div>
37 37
38 38 <div class="island_row"> <div class="island_row">
39 <div class="island_cell">
40 <div class="island">
39 <div class="island_cell">
40 <div class="island">
41 41 <div class="island_title">Ready to use</div> <div class="island_title">Ready to use</div>
42 42 You can just open your web browser and start using You can just open your web browser and start using
43 43 RocketGit, but even if you choose to install RocketGit on your RocketGit, but even if you choose to install RocketGit on your
 
46 46 </div> </div>
47 47 </div> </div>
48 48
49 <div class="island_cell">
50 <div class="island">
49 <div class="island_cell">
50 <div class="island">
51 51 <div class="island_title">Very easy to maintain</div> <div class="island_title">Very easy to maintain</div>
52 52 RocketGit has very few dependencies, all packed RocketGit has very few dependencies, all packed
53 53 in the main-stream distributions, therefore you just upgrade your in the main-stream distributions, therefore you just upgrade your
 
55 55 </div> </div>
56 56 </div> </div>
57 57
58 <div class="island_cell">
59 <div class="island">
58 <div class="island_cell">
59 <div class="island">
60 60 <div class="island_title">Corporate friendly</div> <div class="island_title">Corporate friendly</div>
61 61 RocketGit is SELinux protected, RocketGit is SELinux protected,
62 62 therefore you can keep your system secure while using it. therefore you can keep your system secure while using it.
 
67 67 </div> </div>
68 68
69 69 <div class="island_row"> <div class="island_row">
70 <div class="island_cell">
71 <div class="island">
70 <div class="island_cell">
71 <div class="island">
72 72 <div class="island_title">Platform independent</div> <div class="island_title">Platform independent</div>
73 73 You can use RocketGit in your web browser (no matter what You can use RocketGit in your web browser (no matter what
74 74 operating system is running on your machine) or you can choose to operating system is running on your machine) or you can choose to
 
77 77 </div> </div>
78 78 </div> </div>
79 79
80 <div class="island_cell">
81 <div class="island">
80 <div class="island_cell">
81 <div class="island">
82 82 <div class="island_title">Integrated bug tracker</div> <div class="island_title">Integrated bug tracker</div>
83 83 RocketGit provides the simplest and the most powerful bug tracker: RocketGit provides the simplest and the most powerful bug tracker:
84 84 minimal input fields, flexible label based tagging minimal input fields, flexible label based tagging
 
86 86 </div> </div>
87 87 </div> </div>
88 88
89 <div class="island_cell">
90 <div class="island">
89 <div class="island_cell">
90 <div class="island">
91 91 <div class="island_title">Easy to contribute</div> <div class="island_title">Easy to contribute</div>
92 92 With the anonymous push feature, it becomes very easy to contribute With the anonymous push feature, it becomes very easy to contribute
93 93 to a project: a clone and a push. You do not even need an account on to a project: a clone and a push. You do not even need an account on
 
97 97 </div> </div>
98 98
99 99 <div class="island_row"> <div class="island_row">
100 <div class="island_cell">
101 <div class="island">
100 <div class="island_cell">
101 <div class="island">
102 102 <div class="island_title">Powerful rights management</div> <div class="island_title">Powerful rights management</div>
103 103 You have a wide range of possibilities to block access to a repository. You have a wide range of possibilities to block access to a repository.
104 104 You can filter by IPv4/IPv6 addresses (including prefix length), You can filter by IPv4/IPv6 addresses (including prefix length),
 
109 109 </div> </div>
110 110 </div> </div>
111 111
112 <div class="island_cell">
113 <div class="island">
112 <div class="island_cell">
113 <div class="island">
114 114 <div class="island_title">Web hooks</div> <div class="island_title">Web hooks</div>
115 115 We provide flexible web hooks allowing you to automate your tasks. We provide flexible web hooks allowing you to automate your tasks.
116 116 You can easily store a repository archive in You can easily store a repository archive in
 
125 125 </div> </div>
126 126 </div> </div>
127 127
128 <div class="island_cell">
129 <div class="island">
128 <div class="island_cell">
129 <div class="island">
130 130 <div class="island_title">Built on top of top software</div> <div class="island_title">Built on top of top software</div>
131 131 RocketGit has been created by using the best products to build upon: RocketGit has been created by using the best products to build upon:
132 132 Linux, Git, OpenSSH, PostgreSQL, Apache, PHP and SELinux. Linux, Git, OpenSSH, PostgreSQL, Apache, PHP and SELinux.
 
135 135 </div> </div>
136 136
137 137 <div class="island_row"> <div class="island_row">
138 <div class="island_cell">
139 <div class="island">
138 <div class="island_cell">
139 <div class="island">
140 140 <div class="island_title">Are there features that you need and they are not here?</div> <div class="island_title">Are there features that you need and they are not here?</div>
141 141 Do not worry! Let us know by leaving a Do not worry! Let us know by leaving a
142 142 <a href="/op/suggestion">suggestion</a> (you must be logged in) <a href="/op/suggestion">suggestion</a> (you must be logged in)
File root/themes/default/hints/ssh/cmds.html changed (mode: 100644) (index 667e755..07f3252)
... ... You can use ssh to quickly find information about your RocketGit account.<br />
3 3 Commands:<br /> Commands:<br />
4 4 <ul> <ul>
5 5 <li>status - several stuff</li> <li>status - several stuff</li>
6 <li>repos - will give a list of repos, the creation date and size</li>
6 <li>repos - will give a list of repos, the creation date and size</li>
7 7 <li>repo here_put_name_of_the_repo - information about a specific repo</li> <li>repo here_put_name_of_the_repo - information about a specific repo</li>
8 <li>api - retrieve information as JSON (<a href="/op/doc/api">more info</a></li>
8 9 </ul> </ul>
File root/themes/default/index.html changed (mode: 100644) (index 1210df9..74b2778)
54 54 </div> </div>
55 55 </div> </div>
56 56
57 <div id="footer_info">
57 <div class="footer_info">
58 58 For any information, please contact us at For any information, please contact us at
59 59 <a href="mailto:in@rocketgit.com">in@rocketgit.com</a>.<br /> <a href="mailto:in@rocketgit.com">in@rocketgit.com</a>.<br />
60 60 Copyright: <a href="http://kernel.embedromix.ro/" target="_blank">Catalin(ux) M. BOIE</a><br /> Copyright: <a href="http://kernel.embedromix.ro/" target="_blank">Catalin(ux) M. BOIE</a><br />
 
65 65 RO13505234, J08/979/2000, Brasov, Romania.<br /> RO13505234, J08/979/2000, Brasov, Romania.<br />
66 66 All data is stored in Germany only. All data is stored in Germany only.
67 67 </div> </div>
68
69 <div class="footer_info">
70 Documentation:<br />
71 <a href="/op/doc/api">API</a>
72 </div>
68 73 </div> <!-- footer --> </div> <!-- footer -->
69 74
70 75 </div> <!-- container --> </div> <!-- container -->
File root/themes/default/mail/user/ak/del.body.txt copied from file root/themes/default/mail/user/key/del.body.txt (similarity 54%) (mode: 100644) (index 90be092..1f212f7)
1 1 Hello! Hello!
2 2
3 Some SSH keys were removed from your account.
3 Some API keys have been removed from your account.
4 4
5 5 IP: @@ip@@ IP: @@ip@@
6 6
File root/themes/default/mail/user/ak/del.head.txt copied from file root/themes/default/mail/user/key/del.head.txt (similarity 100%)
File root/themes/default/mail/user/ak/del.subj.txt added (mode: 100644) (index 0000000..0e6e320)
1 Some API keys have been removed
File root/themes/default/mail/user/ak/new.body.txt added (mode: 100644) (index 0000000..10ea590)
1 Hello!
2
3 A new API key has been added to your account:
4 Comment: @@ki::comment@@
5 IP: @@ip@@
6
7 --
8 RocketGit Team
9 http://rocketgit.com/
File root/themes/default/mail/user/ak/new.head.txt copied from file root/themes/default/mail/user/key/new.head.txt (similarity 100%)
File root/themes/default/mail/user/ak/new.subj.txt added (mode: 100644) (index 0000000..cbc6870)
1 New API key added
File root/themes/default/mail/user/forgot/recover.body.txt added (mode: 100644) (index 0000000..c95fd0d)
1 Hello!
2
3 If you requested a password reset, follow:
4 @@base_url@@/op/forgot_link/@@forgot_token@@
5
6 --
7 RocketGit Team
8 http://rocketgit.com/
File root/themes/default/mail/user/forgot/recover.head.txt copied from file root/themes/default/mail/admin/report1.head.txt (similarity 100%)
File root/themes/default/mail/user/forgot/recover.subj.txt added (mode: 100644) (index 0000000..0df3f5f)
1 Forgot password recovery
File root/themes/default/mail/user/key/del.body.txt changed (mode: 100644) (index 90be092..4548500)
1 1 Hello! Hello!
2 2
3 Some SSH keys were removed from your account.
3 Some SSH keys have been removed from your account.
4 4
5 5 IP: @@ip@@ IP: @@ip@@
6 6
File root/themes/default/mail/user/key/del.subj.txt changed (mode: 100644) (index 433f836..895ca01)
1 SSH keys were removed
1 Some SSH keys have beed removed
File root/themes/default/main.css changed (mode: 100644) (index 08a8388..2286d95)
... ... a {
43 43 line-height: 120%; line-height: 120%;
44 44 } }
45 45
46 .term {
47 background-color: #000;
48 font-family: monospace;
49 font-size: 9pt;
50 color: #0F0;
51 border-left: 4px solid #F00;
52 margin: 5px 0;
53 padding-left: 5px;
54 padding-right: 5px;
55 line-height: 120%;
56 white-space: pre-wrap;
57 }
58
46 59 form { } form { }
47 form p { margin-top: 8pt }
60 form p { margin-top: 6pt }
48 61 form input[type="text"], form input[type="password"], form input[type="text"], form input[type="password"],
49 62 form input[type="radio"], form input[type="checkbox"], form input[type="radio"], form input[type="checkbox"],
50 63 form textarea, form select { form textarea, form select {
 
... ... legend { padding: 0px 2pt; }
217 230 margin-left: auto; margin-left: auto;
218 231 margin-right: auto; margin-right: auto;
219 232 } }
220 #footer_info {
233 .footer_info {
221 234 color: #ffffff; color: #ffffff;
222 235 padding: 10px; padding: 10px;
223 236 font-size: 11pt; font-size: 11pt;
224 237 line-height: 115%; line-height: 115%;
225 238 vertical-align: top; vertical-align: top;
239 border-left: 1px solid #777;
226 240 } }
227 241
228 242 .horizontal_buttons { .horizontal_buttons {
 
... ... legend { padding: 0px 2pt; }
251 265 align-self: center; align-self: center;
252 266 } }
253 267 .formarea:not(:first-child) { .formarea:not(:first-child) {
254 margin-top: 8pt;
268 margin-top: 6pt;
255 269 } }
256 270
257 271 .formarea_title { .formarea_title {
 
... ... legend { padding: 0px 2pt; }
261 275 border-bottom: 2px solid #999998; border-bottom: 2px solid #999998;
262 276 } }
263 277
264 .keys_list {
265 margin-top: 8pt;
266 }
267
268 .rg_plans_list {}
269
270 .totp_list {
271 margin-top: 8pt;
272 }
273
274 .sc_list {
275 margin-top: 8pt;
276 }
277
278 .wh_list {}
279
280 278 .wh_plugins_list {} .wh_plugins_list {}
279 .wh_plugins_list:not(:first-child) {
280 margin-top: 6pt;
281 }
281 282
282 283 .blob_title { .blob_title {
283 284 margin-top: 5pt; margin-top: 5pt;
 
... ... legend { padding: 0px 2pt; }
350 351 } }
351 352
352 353 .repo_body { .repo_body {
353 margin-top: 8pt;
354 margin-top: 6pt;
354 355 display: flex; display: flex;
355 356 flex-flow: column nowrap; flex-flow: column nowrap;
356 357 } }
 
... ... legend { padding: 0px 2pt; }
412 413 box-shadow: 0px 2px 3px #666666; box-shadow: 0px 2px 3px #666666;
413 414 align-self: stretch; align-self: stretch;
414 415 } }
415 .hints:not(:first-child) { margin-top: 8pt }
416 .hints:not(:first-child) { margin-top: 6pt }
416 417 .hints ul { list-style-type: square; margin-left: 9pt; } .hints ul { list-style-type: square; margin-left: 9pt; }
417 418 .hints ul li { } .hints ul li { }
418 419 .hints ul li a { } .hints ul li a { }
 
... ... legend { padding: 0px 2pt; }
461 462 } }
462 463
463 464 .mess { .mess {
464 margin-top: 5px;
465 465 padding: 5px; padding: 5px;
466 466 box-shadow: 0px 2px 3px #666666; box-shadow: 0px 2px 3px #666666;
467 align-self: flex-start;
467 align-self: center;
468 468 border: 1px solid #000; border: 1px solid #000;
469 469 border-radius: 4px; border-radius: 4px;
470 470 } }
 
... ... legend { padding: 0px 2pt; }
556 556 } }
557 557
558 558 .generic_body { .generic_body {
559 margin-top: 8pt;
559 margin-top: 5pt;
560 560 display: flex; display: flex;
561 561 flex-flow: column nowrap; flex-flow: column nowrap;
562 562 align-content: space-between; align-content: space-between;
563 563 align-items: stretch; align-items: stretch;
564 564 } }
565 565
566 .merge_info {
567 }
566 .merge_info {}
568 567
569 568 .merge_status { .merge_status {
570 569 padding: 2pt; padding: 2pt;
 
... ... legend { padding: 0px 2pt; }
579 578 background-color: #fbb; background-color: #fbb;
580 579 } }
581 580
582 .table_log {
583 }
581 .table_log {}
584 582 .table_log:not(:first-child) { .table_log:not(:first-child) {
585 margin-top: 8pt;
583 margin-top: 6pt;
586 584 } }
587 585
588 586 .conflicts { .conflicts {
 
... ... legend { padding: 0px 2pt; }
592 590 align-self: flex-start; align-self: flex-start;
593 591 background-color: #fbb; background-color: #fbb;
594 592 } }
593
594 .form_table {}
595 .form_table:not(:first-child) {
596 margin-top: 6pt;
597 }
File root/themes/default/pricing.html changed (mode: 100644) (index ca36050..a528e69)
2 2
3 3 <div class="islands"> <div class="islands">
4 4 <div class="island_row"> <div class="island_row">
5 <div class="island_cell">
6 <div class="island">
5 <div class="island_cell">
6 <div class="island">
7 7 <div class="island_title">rocketgit.com is free</div> <div class="island_title">rocketgit.com is free</div>
8 8 You can have an unlimited number of both public and private You can have an unlimited number of both public and private
9 9 repositories. Free of charge. repositories. Free of charge.
10 10 </div> </div>
11 11 </div> </div>
12 12
13 <div class="island_cell">
14 <div class="island">
13 <div class="island_cell">
14 <div class="island">
15 15 <div class="island_title">Behind the firewall (on-premise)</div> <div class="island_title">Behind the firewall (on-premise)</div>
16 16 You can have an unlimited behind-the-firewall installations. You can have an unlimited behind-the-firewall installations.
17 17 Free of charge. Free of charge.
18 18 </div> </div>
19 19 </div> </div>
20 20
21 <div class="island_cell">
22 <div class="island">
21 <div class="island_cell">
22 <div class="island">
23 23 <div class="island_title">Free support</div> <div class="island_title">Free support</div>
24 24 Contact us at Contact us at
25 25 <a href="mailto:support@rocketgit.com">support@rocketgit.com</a> <a href="mailto:support@rocketgit.com">support@rocketgit.com</a>
 
30 30 </div> </div>
31 31
32 32 <div class="island_row"> <div class="island_row">
33 <div class="island_cell">
34 <div class="island">
33 <div class="island_cell">
34 <div class="island">
35 35 <div class="island_title">Paid support</div> <div class="island_title">Paid support</div>
36 36 If you need guaranteed response time or 24/7, If you need guaranteed response time or 24/7,
37 37 please contact us at please contact us at
File root/themes/default/repo/list/line.html changed (mode: 100644) (index 2a70ad5..680b1bf)
1 1 <tr> <tr>
2 2 <td><a href="@@url_user@@">@@owner@@</a> / <a href="@@url_repo@@">@@name@@</a> (#@@repo_id@@)</td> <td><a href="@@url_user@@">@@owner@@</a> / <a href="@@url_repo@@">@@name@@</a> (#@@repo_id@@)</td>
3 3 <td><small>@@description_nlbr@@</small></td> <td><small>@@description_nlbr@@</small></td>
4 <td>@@clone_of@@</td>
4 <td>@@master_name@@</td>
5 5 <td>@@itime_nice@@</td> <td>@@itime_nice@@</td>
6 6 <td>@@if(@@public@@ == 1){{Public}}{{Private}}</td> <td>@@if(@@public@@ == 1){{Public}}{{Private}}</td>
7 7 <td>@@if("@@license@@" == ""){{Unspecified}}{{@@license@@}}</td> <td>@@if("@@license@@" == ""){{Unspecified}}{{@@license@@}}</td>
File root/themes/default/repo/mr/merge_in_progress.html changed (mode: 100644) (index 844b7c0..fef89e1)
1 1 <div class="mess ok"> <div class="mess ok">
2 Your merge was queued with success.
2 Your merge has been successfully queued.
3 3 </div> </div>
File root/themes/default/tos.html changed (mode: 100644) (index f6fc669..3a45fac)
2 2
3 3 <div class="islands"> <div class="islands">
4 4 <div class="island_row"> <div class="island_row">
5 <div class="island_cell">
6 <div class="island">
5 <div class="island_cell">
6 <div class="island">
7 7
8 8 The RocketGit code is copyright (c) 2016 Catalin BOIE and it is The RocketGit code is copyright (c) 2016 Catalin BOIE and it is
9 9 covered by the covered by the
File root/themes/default/user/keys/add_ok.html changed (mode: 100644) (index f066e8c..f21148f)
1 1 <div class="mess ok"> <div class="mess ok">
2 Key added with success.
2 The SSH key has been successfully added.
3 3 </div> </div>
File root/themes/default/user/keys/list/footer.html changed (mode: 100644) (index f7b135b..b732d74)
2 2
3 3 <input type="submit" name="button" value="Delete selected keys" /> <input type="submit" name="button" value="Delete selected keys" />
4 4 </form> </form>
5 </div>
File root/themes/default/user/keys/list/header.html changed (mode: 100644) (index f3510eb..092880b)
1 <div class="keys_list">
2
3 1 @@del_errmsg@@ @@del_errmsg@@
4 2
5 3 <form method="post" action="/op/settings/keys"> <form method="post" action="/op/settings/keys">
File root/themes/default/user/keys/remove_ok.html changed (mode: 100644) (index d886742..d693caa)
1 1 <div class="mess ok"> <div class="mess ok">
2 Selected keys were removed with success.
2 Selected keys have been successfully deleted.
3 3 </div> </div>
File root/themes/default/user/repo/rights/delete_ok.html changed (mode: 100644) (index 0a0b3dd..8891bc7)
1 1 <div class="mess ok"> <div class="mess ok">
2 Rights deleted with success.
2 The rights have been successfully deleted.
3 3 </div> </div>
File root/themes/default/user/repo/rights/grant_ok.html changed (mode: 100644) (index 0569574..8170801)
1 1 <div class="mess ok"> <div class="mess ok">
2 Rights granted with success.
2 The rights have been successfully granted.
3 3 </div> </div>
File root/themes/default/user/repo/rights/list_repo/footer.html changed (mode: 100644) (index 6daf5cd..93e7b44)
2 2
3 3 <input type="submit" name="button" value="Delete selected rights" /> <input type="submit" name="button" value="Delete selected rights" />
4 4 </form> </form>
5 </div>
File root/themes/default/user/repo/rights/list_repo/header.html changed (mode: 100644) (index 78d7840..6bc1803)
1 <div class="repo_rights">
2
3 1 @@list_errmsg@@ @@list_errmsg@@
4 2
5 <form method="post" action="@@url_repo@@/admin/repo_rights">
3 <form method="post" action="@@url_repo@@/admin/repo_rights" class="form_table">
6 4 <input type="hidden" name="delete" value="1" /> <input type="hidden" name="delete" value="1" />
7 5 <input type="hidden" name="token" value="@@rg_form_token@@" /> <input type="hidden" name="token" value="@@rg_form_token@@" />
8 6
File root/themes/default/user/repo/rights/list_repo_path/footer.html changed (mode: 100644) (index 6daf5cd..93e7b44)
2 2
3 3 <input type="submit" name="button" value="Delete selected rights" /> <input type="submit" name="button" value="Delete selected rights" />
4 4 </form> </form>
5 </div>
File root/themes/default/user/repo/rights/list_repo_path/header.html changed (mode: 100644) (index 344f7cf..f19c8ec)
1 <div class="repo_rights">
2
3 1 @@list_errmsg@@ @@list_errmsg@@
4 2
5 <form method="post" action="@@url@@">
3 <form method="post" action="@@url@@" class="form_table">
6 4 <input type="hidden" name="delete" value="1" /> <input type="hidden" name="delete" value="1" />
7 5 <input type="hidden" name="token" value="@@rg_form_token@@" /> <input type="hidden" name="token" value="@@rg_form_token@@" />
8 6
File root/themes/default/user/repo/rights/list_repo_refs/footer.html changed (mode: 100644) (index 6daf5cd..93e7b44)
2 2
3 3 <input type="submit" name="button" value="Delete selected rights" /> <input type="submit" name="button" value="Delete selected rights" />
4 4 </form> </form>
5 </div>
File root/themes/default/user/repo/rights/list_repo_refs/header.html changed (mode: 100644) (index 9c1115e..8f72463)
1 <div class="repo_rights">
2
3 1 @@list_errmsg@@ @@list_errmsg@@
4 2
5 <form method="post" action="@@url@@">
3 <form method="post" action="@@url@@" class="form_table">
6 4 <input type="hidden" name="delete" value="1" /> <input type="hidden" name="delete" value="1" />
7 5 <input type="hidden" name="token" value="@@rg_form_token@@" /> <input type="hidden" name="token" value="@@rg_form_token@@" />
8 6
File root/themes/default/user/settings/apikeys/add.html added (mode: 100644) (index 0000000..7044913)
1 <div class="formarea">
2
3 <div class="formarea_title">Add a new API key</div>
4
5 @@errmsg@@
6
7 <form method="post" action="/op/settings/apikeys/add">
8 <input type="hidden" name="doit" value="1" />
9 <input type="hidden" name="token" value="@@rg_form_token@@" />
10
11 <p>
12 <label for="name">Name</label><br />
13 <input type="text" name="ak::name" id="name" value="@@ak::name@@" size="80" />
14 </p>
15
16 <p>
17 <label for="key">Key string (pre-generated, but you may change it)</label><br />
18 <input type="text" name="ak::key" id="key" value="@@ak::key@@" size="80" />
19 </p>
20
21 <input type="submit" name="button" value="Add" />
22
23 </form>
24 </div>
File root/themes/default/user/settings/apikeys/add_ok.html added (mode: 100644) (index 0000000..b89bf31)
1 <div class="mess ok">
2 The API key <b>@@ak::key@@</b> has been successfully added.<br />
3 Please copy it in clipboard because now is the last chance
4 (it will not be shown again after you leave the page).
5 </div>
File root/themes/default/user/settings/apikeys/delete_ok.html added (mode: 100644) (index 0000000..a75ec08)
1 <div class="mess ok">
2 The selected keys have been successfully deleted.
3 </div>
File root/themes/default/user/settings/apikeys/hints.html added (mode: 100644) (index 0000000..9eccb13)
1 <br />
2 API keys are used to access RocketGit's API by HTTPS.<br />
3 Check <a href="/op/doc/api">API documentation</a> for more info.<br />
4 Example:
5 <div class="term">
6 $ curl --header 'Authorization: @@login_ui::username@@ insert_here_the_key' \
7 --data '{"cmd": "user_info", "user": "@@login_ui::username@@"}' \
8 @@base_url@@/op/api
9
10 </div>
File root/themes/default/user/settings/apikeys/list/footer.html copied from file root/themes/default/user/keys/list/footer.html (similarity 92%) (mode: 100644) (index f7b135b..b732d74)
2 2
3 3 <input type="submit" name="button" value="Delete selected keys" /> <input type="submit" name="button" value="Delete selected keys" />
4 4 </form> </form>
5 </div>
File root/themes/default/user/settings/apikeys/list/header.html copied from file root/themes/default/user/keys/list/header.html (similarity 50%) (mode: 100644) (index f3510eb..77d7bc5)
1 <div class="keys_list">
1 @@errmsg@@
2 @@status@@
2 3
3 @@del_errmsg@@
4
5 <form method="post" action="/op/settings/keys">
6 <input type="hidden" name="delete" value="1" />
4 <form method="post" action="/op/settings/apikeys/list" class="form_table">
5 <input type="hidden" name="doit" value="1" />
7 6 <input type="hidden" name="token" value="@@rg_form_token@@" /> <input type="hidden" name="token" value="@@rg_form_token@@" />
8 7
9 <table summary="keys list">
8 <table summary="apikeys list">
10 9 <tr> <tr>
11 10 <th>Select</th> <th>Select</th>
12 11 <th>Upload date (UTC)</th> <th>Upload date (UTC)</th>
13 <th>Type and bits</th>
14 <th>Fingerprint</th>
15 <th>Comment</th>
12 <th>Name</th>
16 13 <th>First use (UTC)</th> <th>First use (UTC)</th>
17 14 <th>Last use (UTC)</th> <th>Last use (UTC)</th>
18 15 <th>Last IP</th> <th>Last IP</th>
File root/themes/default/user/settings/apikeys/list/line.html added (mode: 100644) (index 0000000..1a106ba)
1 <tr>
2 <td><input type="checkbox" name="key_delete_ids[@@key_id@@]" /></td>
3 <td>@@itime_nice@@</td>
4 <td>@@name@@</td>
5 <td>@@first_use_nice@@</td>
6 <td>@@last_use_nice@@</td>
7 <td>@@last_ip@@</td>
8 <td><small>@@last_cmd@@</small></td>
9 <td>@@count@@</td>
10 </tr>
11
File root/themes/default/user/settings/apikeys/list/nodata.html copied from file root/themes/default/repo/cl/list/nodata.html (similarity 51%) (mode: 100644) (index 776abc7..56d34b7)
1 1 <div class="mess ok"> <div class="mess ok">
2 No commit labels found.
2 No API keys uploaded yet.
3 3 </div> </div>
File root/themes/default/user/settings/apikeys/list_err.html added (mode: 100644) (index 0000000..a37f787)
1 <div class="mess error">
2 Could not load API keys (@@errmsg@@). Please try again later.
3 </div>
File root/themes/default/user/settings/apikeys/menu.html added (mode: 100644) (index 0000000..95d8d7e)
1 <div class="menu menu3">
2 <ul>
3 <li@@if(@@menu::ak::list@@ == 1){{ class="selected"}}><a href="/op/settings/apikeys/list">List</a></li>
4 <li@@if(@@menu::ak::add@@ == 1){{ class="selected"}}><a href="/op/settings/apikeys/add">Add</a></li>
5 </ul>
6 </div>
File root/themes/default/user/settings/menu.html changed (mode: 100644) (index 5be23bd..88cd49a)
5 5 <li@@if(@@set_menu::edit_info@@ == 1){{ class="selected"}}{{}}><a href="/op/settings/edit_info">Edit info</a></li> <li@@if(@@set_menu::edit_info@@ == 1){{ class="selected"}}{{}}><a href="/op/settings/edit_info">Edit info</a></li>
6 6 <li@@if(@@set_menu::change_pass@@ == 1){{ class="selected"}}{{}}><a href="/op/settings/change_pass">Change password</a></li> <li@@if(@@set_menu::change_pass@@ == 1){{ class="selected"}}{{}}><a href="/op/settings/change_pass">Change password</a></li>
7 7 <li@@if(@@set_menu::keys@@ == 1){{ class="selected"}}{{}}><a href="/op/settings/keys">SSH keys</a></li> <li@@if(@@set_menu::keys@@ == 1){{ class="selected"}}{{}}><a href="/op/settings/keys">SSH keys</a></li>
8 <li@@if(@@set_menu::apikeys@@ == 1){{ class="selected"}}{{}}><a href="/op/settings/apikeys">API keys</a></li>
8 9 <li@@if(@@set_menu::totp@@ == 1){{ class="selected"}}{{}}><a href="/op/settings/totp">Login tokens</a></li> <li@@if(@@set_menu::totp@@ == 1){{ class="selected"}}{{}}><a href="/op/settings/totp">Login tokens</a></li>
9 10 <li@@if(@@set_menu::wh@@ == 1){{ class="selected"}}{{}}><a href="/op/settings/wh">Webhooks</a></li> <li@@if(@@set_menu::wh@@ == 1){{ class="selected"}}{{}}><a href="/op/settings/wh">Webhooks</a></li>
11 <li@@if(@@set_menu::workers@@ == 1){{ class="selected"}}{{}}><a href="/op/settings/workers">Workers</a></li>
10 12 </ul> </ul>
11 13 </div> </div>
12 @@menu_set_level2@@
14 @@menu_level2@@
File root/themes/default/user/settings/totp/delete_ok.html changed (mode: 100644) (index bb40ba1..a075bf5)
1 1 <div class="mess ok"> <div class="mess ok">
2 Login token(s) deleted with success.
2 The login tokens have been successfully deleted.
3 3 </div> </div>
File root/themes/default/user/settings/totp/enroll.html changed (mode: 100644) (index b1a7238..109d9e5)
18 18 @@if(@@totp::img@@ == 1){{ @@if(@@totp::img@@ == 1){{
19 19 Scan the following QR Code using the mobile application:<br /> Scan the following QR Code using the mobile application:<br />
20 20 <img class="secret_token" src="data:image/png;base64,@@totp::png@@" alt="qr code" /> <img class="secret_token" src="data:image/png;base64,@@totp::png@@" alt="qr code" />
21 <br />
21 <br />
22 22 If you cannot scan the code above, manually enter the following key If you cannot scan the code above, manually enter the following key
23 23 into the mobile application:<br /> into the mobile application:<br />
24 24 }}{{ }}{{
File root/themes/default/user/settings/totp/list/footer.html changed (mode: 100644) (index 6b7fafd..5ff0640)
2 2
3 3 <input type="submit" name="button" value="Delete selected" /> <input type="submit" name="button" value="Delete selected" />
4 4 </form> </form>
5 </div>
File root/themes/default/user/settings/totp/list/header.html changed (mode: 100644) (index 8002697..10b81a1)
1 <div class="totp_list">
2
3 1 @@del_status@@ @@del_status@@
4 2 @@del_errmsg@@ @@del_errmsg@@
5 3
6 <form method="post" action="/op/settings/totp/list">
4 <form method="post" action="/op/settings/totp/list" class="form_table">
7 5 <input type="hidden" name="delete" value="1" /> <input type="hidden" name="delete" value="1" />
8 6 <input type="hidden" name="token" value="@@rg_form_token@@" /> <input type="hidden" name="token" value="@@rg_form_token@@" />
9 7
File root/themes/default/user/settings/totp/sc/delete_ok.html changed (mode: 100644) (index ed04164..21e80b6)
1 1 <div class="mess ok"> <div class="mess ok">
2 Scratch codes deleted with success.
2 The scratch codes have been successfully deleted.
3 3 </div> </div>
File root/themes/default/user/settings/totp/sc/gen_ok.html changed (mode: 100644) (index 911499c..95a138a)
1 1 <div class="mess ok"> <div class="mess ok">
2 Scratch codes generated with success. Please print or save them now
2 The scratch codes has been successfully generated.
3 Please print or save them now
3 4 - after leaving this page they will not be visible anymore.<br /> - after leaving this page they will not be visible anymore.<br />
4 5
5 6 <div class="secret_token"> <div class="secret_token">
File root/themes/default/user/settings/totp/sc/list/footer.html changed (mode: 100644) (index 6b7fafd..5ff0640)
2 2
3 3 <input type="submit" name="button" value="Delete selected" /> <input type="submit" name="button" value="Delete selected" />
4 4 </form> </form>
5 </div>
File root/themes/default/user/settings/totp/sc/list/header.html changed (mode: 100644) (index 20681b9..475edad)
1 <div class="sc_list">
2
3 1 @@del_status@@ @@del_status@@
4 2 @@del_errmsg@@ @@del_errmsg@@
5 3
6 <form method="post" action="/op/settings/totp/sc">
4 <form method="post" action="/op/settings/totp/sc" class="form_table">
7 5 <input type="hidden" name="delete" value="1" /> <input type="hidden" name="delete" value="1" />
8 6 <input type="hidden" name="token" value="@@rg_form_token@@" /> <input type="hidden" name="token" value="@@rg_form_token@@" />
9 7
File root/themes/default/user/settings/wh/build/env_show_one.html added (mode: 100644) (index 0000000..6107a47)
1 <tr>
2 <td>##env##</td>
3 </tr>
File root/themes/default/user/settings/wh/build/form.html changed (mode: 100644) (index 8dfbd16..b2b3e02)
1 1 @@check_events@@ @@check_events@@
2 2
3 <fieldset>
4 <legend>Select build environments</legend>
5 @@envs@@
6 </fieldset>
7
8 <p>
9 <label for="packages">Packages to install</label><br />
10 <textarea name="wh::idata::packages" id="packages" cols="80" rows="2">@@wh::idata::packages@@</textarea>
11 </p>
12
3 13 @@cmds@@ @@cmds@@
File root/themes/default/user/settings/wh/build/form_env.html added (mode: 100644) (index 0000000..b97d6c7)
1 <p>
2 <input type="checkbox" name="wh::idata::envs[##env##]" @@if(@@wh::idata::envs::##env##@@ == 1){{checked="checked"}} /> ##env##
3 </p>
File root/themes/default/user/settings/wh/build/inv_env.txt added (mode: 100644) (index 0000000..77fac90)
1 no environments selected
File root/themes/default/user/settings/wh/build/show.html changed (mode: 100644) (index f22dc7a..bd615fd)
1 <table summary="plugin internal info">
1 <table summary="plugin internal info - commands">
2 2 <tr> <tr>
3 3 <th>No.</th> <th>No.</th>
4 4 <th>Command</th> <th>Command</th>
 
9 9
10 10 @@wh_list@@ @@wh_list@@
11 11 </table> </table>
12 <br />
13
14 <table summary="plugin internal info - environments">
15 <tr>
16 <th>Environment(s)</th>
17 </tr>
18
19 @@envs_list@@
20 </table>
21 <br />
22
23 <b>Packages</b>: @@packages@@
File root/themes/default/user/settings/wh/delete_ok.html changed (mode: 100644) (index f001c96..8354e47)
1 1 <div class="mess ok"> <div class="mess ok">
2 Webhook(s) deleted with success.
2 The webhooks have been successfully deleted.
3 3 </div> </div>
File root/themes/default/user/settings/wh/edit_ok.html changed (mode: 100644) (index 0b7043a..63a441e)
1 1 <div class="mess ok"> <div class="mess ok">
2 Webhook added/edited with success.
2 The webhook has been successfully added/edited.
3 3 </div> </div>
File root/themes/default/user/settings/wh/list/footer.html changed (mode: 100644) (index 6b7fafd..5ff0640)
2 2
3 3 <input type="submit" name="button" value="Delete selected" /> <input type="submit" name="button" value="Delete selected" />
4 4 </form> </form>
5 </div>
File root/themes/default/user/settings/wh/list/header.html changed (mode: 100644) (index 68f325b..017c0c3)
1 <div class="wh_list">
2
3 <form method="post" action="/op/settings/wh/list">
1 <form method="post" action="/op/settings/wh/list" class="form_table">
4 2 <input type="hidden" name="delete" value="1" /> <input type="hidden" name="delete" value="1" />
5 3 <input type="hidden" name="token" value="@@rg_form_token@@" /> <input type="hidden" name="token" value="@@rg_form_token@@" />
6 4
File root/themes/default/user/settings/workers/add.html added (mode: 100644) (index 0000000..4a796be)
1 <div class="formarea">
2
3 <div class="formarea_title">@@if(@@worker::id@@ == 0){{Add a new worker}}{{Edit worker}}</div>
4
5 @@errmsg@@
6
7 <form method="post" action="@@url@@/@@if(@@worker::id@@ == 0){{add}}{{edit/@@worker::id@@}}">
8 <input type="hidden" name="doit" value="1" />
9 <input type="hidden" name="token" value="@@rg_form_token@@" />
10
11 <p>
12 <label for="name">Name</label><br />
13 <input type="text" name="worker::name" id="name" value="@@worker::name@@" size="80" />
14 </p>
15
16 @@if(@@worker::id@@ == 0){{
17 <p>
18 <label for="name">Key (please provide at least 32 chars, copy it in clipboard because will not be shown again)</label><br />
19 <input type="text" name="worker::key" id="name" value="@@worker::key@@" size="80" />
20 </p>
21 }}
22
23 <p>
24 <label for="name">Cost</label><br />
25 <input type="text" name="worker::cost" id="name" value="@@worker::cost@@" size="80" />
26 </p>
27
28 <p>
29 <label for="name">Max parallel workers</label><br />
30 <input type="text" name="worker::workers" id="name" value="@@worker::workers@@" size="80" />
31 </p>
32
33 <input type="submit" name="button" value="@@if(@@worker::id@@ == 0){{Add}}{{Edit}}" />
34
35 </form>
36 </div>
File root/themes/default/user/settings/workers/add_ok.html added (mode: 100644) (index 0000000..89dcf2d)
1 <div class="mess ok">
2 The worker has been successfully added/edited.
3 </div>
File root/themes/default/user/settings/workers/delete_ok.html added (mode: 100644) (index 0000000..88ed5b9)
1 <div class="mess ok">
2 The selected workers have been successfully deleted.
3 </div>
File root/themes/default/user/settings/workers/hints.html added (mode: 100644) (index 0000000..b0f9d4e)
1 <br />
2 Workers are used to process build jobs.<br />
3 Global workers are available for building at rocketgit.com, so,
4 just configure a build webhook.<br />
5 Cost - it is used to decide on which worker to send a job; bigger = less
6 chances to choose it.<br />
7 Key - it is used to authenticate the connection from worker.<br />
8 <br />
9 To learn how to configure a build machine, go
10 <a href="/op/doc/worker" target="_blank">here</a>.<br />
11 The worker will connect automatically and will be ready to receive build jobs.
12 <br />
File root/themes/default/user/settings/workers/list/footer.html copied from file root/themes/default/user/keys/list/footer.html (similarity 92%) (mode: 100644) (index f7b135b..b732d74)
2 2
3 3 <input type="submit" name="button" value="Delete selected keys" /> <input type="submit" name="button" value="Delete selected keys" />
4 4 </form> </form>
5 </div>
File root/themes/default/user/settings/workers/list/header.html added (mode: 100644) (index 0000000..6231530)
1 @@errmsg@@
2 @@status@@
3
4 <form method="post" action="@@url@@/list" class="form_table">
5 <input type="hidden" name="doit" value="1" />
6 <input type="hidden" name="token" value="@@rg_form_token@@" />
7
8 <table summary="workers list">
9 <tr>
10 <th>Select</th>
11 <th>Add date (UTC)</th>
12 <th>Name</th>
13 <th>Host</th>
14 <th>Arch</th>
15 <th>Environments</th>
16 <th>Cost</th>
17 <th>Max workers</th>
18 <th>Last connect (UTC)</th>
19 <th>Last IP</th>
20 <th>Operations</th>
21 </tr>
22
File root/themes/default/user/settings/workers/list/line.html added (mode: 100644) (index 0000000..8ae3ac8)
1 <tr>
2 <td><input type="checkbox" name="delete_ids[@@id@@]" /></td>
3 <td>@@itime_nice@@</td>
4 <td>@@name@@</td>
5 <td><small>@@host@@</small></td>
6 <td>@@arch@@</td>
7 <td>@@envs_nice@@</td>
8 <td>@@cost@@</td>
9 <td>@@workers@@</td>
10 <td>@@last_connect_nice@@</td>
11 <td>@@last_ip@@</td>
12 <td><a href="@@url@@/edit/@@id@@">Edit</a></td>
13 </tr>
14
File root/themes/default/user/settings/workers/list/nodata.html copied from file root/themes/default/repo/bug/list/nodata.html (similarity 63%) (mode: 100644) (index 5a9a182..46ad280)
1 1 <div class="mess ok"> <div class="mess ok">
2 No bugs found.
2 No workers yet.
3 3 </div> </div>
File root/themes/default/user/settings/workers/list_err.html added (mode: 100644) (index 0000000..a0c1c24)
1 <div class="mess error">
2 Could not load workers list (@@errmsg@@). Please try again later.
3 </div>
File root/themes/default/user/settings/workers/menu.html added (mode: 100644) (index 0000000..9c0f80a)
1 <div class="menu menu3">
2 <ul>
3 <li@@if(@@menu::worker::list@@ == 1){{ class="selected"}}><a href="@@url@@/list">List</a></li>
4 <li@@if(@@menu::worker::add@@ == 1){{ class="selected"}}><a href="@@url@@/add">Add</a></li>
5 </ul>
6 </div>
File samples/config.php changed (mode: 100644) (index 64f82db..5b85335)
... ... $rg_web_url = '';
89 89 $rg_logs_lifetime = 31; $rg_logs_lifetime = 31;
90 90
91 91 // addr/port to bind/listen for build workers // addr/port to bind/listen for build workers
92 // set port to 0 to disable the builder
92 93 $rg_builder_bind = '0.0.0.0'; $rg_builder_bind = '0.0.0.0';
93 94 $rg_builder_port = 65000; $rg_builder_port = 65000;
94 95
File samples/cron changed (mode: 100644) (index 892a4d6..1a51bc0)
3 3 * * * * * rocketgit /usr/share/rocketgit/scripts/cron.sh rocketgit * * * * * rocketgit /usr/share/rocketgit/scripts/cron.sh rocketgit
4 4 * * * * * rocketgit /usr/share/rocketgit/scripts/events.sh * * * * * rocketgit /usr/share/rocketgit/scripts/events.sh
5 5 * * * * * rocketgit /usr/share/rocketgit/scripts/cache.sh * * * * * rocketgit /usr/share/rocketgit/scripts/cache.sh
6
6 7 #* * * * * rocketgit /usr/share/rocketgit/scripts/builder.sh #* * * * * rocketgit /usr/share/rocketgit/scripts/builder.sh
8
9 #* * * * * root /usr/share/rocketgit/scripts/worker.sh
File samples/worker.conf.sample added (mode: 100644) (index 0000000..98460f0)
1 # Type: is 'global' or 'user'
2 # This will affect the registration process with the server.
3 # If you do not have admin rights, set it to 'user'.
4 # If you have admin rights and you want this worker to be used by all users,
5 # set it to 'global'.
6 type = global
7
8 # If 'type' is 'user', please specify here your user name
9 #user = ...
10
11 # My identification
12 name = Builder 1
13
14 # Where to connect for jobs
15 master = build.example.com
16 port = 65000
17
18 # rocketgit dir
19 state = /var/lib/rocketgit/worker
20
21 # This is used to be able to authenticate with the server
22 key = insert_your_pass_here
23
24 # Available build environments
25 # os-variant can be set by 'osinfo-query os' command; it is used for virtio
26 #env = fedora23-server-x86_64
27 # type = libvirt
28 # arch = x86_64
29 # image = /var/lib/libvirt/images/rgw/fedora23-server-x86_64.qcow2
30 # pkg_cmd = dnf -y install
31 # os-variant = fedora22
32
33 #env = debian-8.2-i386
34 # type = libvirt
35 # arch = i386
36 # image = /var/lib/libvirt/images/rgw/debian-8.2-i386
37 # pkg_cmd = apt-get -y install
38 # os-variant = debian8
39
40 #env = arm-32-fedora-23
41 # type = libvirt
42 # arch = armv7l
43 # image = /var/lib/libvirt/images/rgw/arm-32-fedora-23.qcow2
44 # paras = --boot kernel=/var/lib/libvirt/images/ARM-Server-23/vmlinuz-4.4.6-300.fc23.armv7hl,initrd=/var/lib/libvirt/images/ARM-Server-23/initramfs-4.4.6-300.fc23.armv7hl.img,kernel_args="console=ttyAMA0 rw root=LABEL=_/ rootwait"
45 # pkg_cmd = dnf -y install
46 # os-variant = fedora22
File scripts/builder.php changed (mode: 100644) (index 250ef08..fc8b401)
1 1 <?php <?php
2 2 // This is called by cron, and is persistent. // This is called by cron, and is persistent.
3 3 // It takes care of build jobs. // It takes care of build jobs.
4 // It can be run on the same machine as the webserver.
4 5 error_reporting(E_ALL); error_reporting(E_ALL);
5 6 ini_set("track_errors", "On"); ini_set("track_errors", "On");
6 7 set_time_limit(0); set_time_limit(0);
 
... ... require_once($INC . "/admin.inc.php");
27 28 require_once($INC . "/ver.php"); require_once($INC . "/ver.php");
28 29 require_once($INC . "/builder.inc.php"); require_once($INC . "/builder.inc.php");
29 30 require_once($INC . "/conn.inc.php"); require_once($INC . "/conn.inc.php");
31 require_once($INC . "/workers.inc.php");
32
33 if ($rg_builder_port == 0)
34 exit(0);
35
36 /*
37 * Called when a connection closes
38 */
39 function xdestroy($key)
40 {
41 global $workers;
42 $workers--;
43 }
30 44
31 45 /* /*
32 46 * Called when a new client connects * Called when a new client connects
 
... ... require_once($INC . "/conn.inc.php");
34 48 function xnew($key, $arg) function xnew($key, $arg)
35 49 { {
36 50 global $rg_conns; global $rg_conns;
51 global $workers;
37 52
38 53 $s = &$rg_conns[$key]; $s = &$rg_conns[$key];
39 54 $s['func_cmd'] = 'xdispatch'; $s['func_cmd'] = 'xdispatch';
55 $s['func_destroy'] = 'xdestroy';
40 56 $s['db'] = $arg; $s['db'] = $arg;
41 57 $s['auth'] = 0; $s['auth'] = 0;
58 $s['is_master'] = 0;
59 $workers++;
42 60 } }
43 61
62 /*
63 * Dispatch a command from a worker
64 */
44 65 function xdispatch($key, $line) function xdispatch($key, $line)
45 66 { {
46 67 global $rg_conns; global $rg_conns;
47 68 global $jobs; global $jobs;
48 global $rg_builder_key;
49 69
50 70 rg_log('Dispatch[' . $key . ']'); rg_log('Dispatch[' . $key . ']');
51 71
 
... ... function xdispatch($key, $line)
56 76 $x = stripcslashes($d); $x = stripcslashes($d);
57 77 $u = @unserialize($x); $u = @unserialize($x);
58 78 if ($u === FALSE) { if ($u === FALSE) {
59 rg_conn_destroy($key);
79 rg_conn_enq($key, 'ERR malformed command' . "\n");
80 rg_conn_shutdown($key, 2);
60 81 return; return;
61 82 } }
62 83
 
... ... function xdispatch($key, $line)
64 85
65 86 if (strcmp($cmd, 'ANN ') == 0) { if (strcmp($cmd, 'ANN ') == 0) {
66 87 $now = time(); $now = time();
67 if ($u['boot_time'] < $now - 10) {
88 if (($u['boot_time'] < $now - 30) || ($u['boot_time'] > $now + 30)) {
68 89 rg_log('boot_time is too old; abort'); rg_log('boot_time is too old; abort');
69 rg_conn_destroy($key);
90 rg_conn_enq($key, 'ERR time not in sync between worker'
91 . ' and server' . "\n");
92 rg_conn_shutdown($key, 2);
93 return;
94 }
95
96 // Lookup user first
97 if (!isset($u['type']))
98 $u['type'] = 'global';
99 if (strcasecmp($u['type'], 'global') == 0) {
100 $worker_uid = 0;
101 } else if (!isset($u['user'])) {
102 rg_log('user field is not present; abort');
103 rg_conn_enq($key, 'ERR user not defined in conf file' . "\n");
104 rg_conn_shutdown($key, 2);
105 return;
106 } else {
107 $w_ui = rg_user_info($s['db'], 0, $u['user'], '');
108 if ($w_ui['exists'] !== 1) {
109 rg_log('invalid user; abort');
110 rg_conn_enq($key, 'ERR invalid user' . "\n");
111 rg_conn_shutdown($key, 2);
112 return;
113 }
114
115 $worker_uid = $w_ui['uid'];
116 }
117
118 // Check if worker is registered
119 $wi = rg_worker_find_by_name($s['db'], $worker_uid, $u['name']);
120 if ($wi === -1) {
121 rg_log('cannot load worker info: '
122 . rg_worker_error() . '; abort');
123 rg_conn_enq($key, 'ERR internal error' . "\n");
124 rg_conn_shutdown($key, 2);
70 125 return; return;
71 126 } }
72 $sign = hash_hmac('sha512', $u['boot_time'], $rg_builder_key);
127 if ($wi === 0) {
128 rg_log('name [' . $u['name'] . '] not found; abort');
129 $err = 'ERR builder name not found, add it in the web'
130 . ' interface!' . "\n";
131 rg_conn_enq($key, $err);
132 rg_conn_shutdown($key, 2);
133 return;
134 }
135
136 $sign = hash_hmac('sha512', $u['boot_time'], $wi['key']);
73 137 if (strcmp($sign, $u['sign']) != 0) { if (strcmp($sign, $u['sign']) != 0) {
74 138 rg_log('signature is not ok [' . $sign . ']' rg_log('signature is not ok [' . $sign . ']'
75 139 . ' != [' . $u['sign'] . ']'); . ' != [' . $u['sign'] . ']');
76 rg_conn_destroy($key);
140 rg_conn_enq($key, 'ERR wrong signature' . "\n");
141 rg_conn_shutdown($key, 2);
77 142 return; return;
78 143 } }
144 $s['worker_id'] = $wi['id'];
145 $s['worker_uid'] = $worker_uid;
79 146 $s['ann'] = $u; $s['ann'] = $u;
80 147 $s['auth'] = 1; $s['auth'] = 1;
81 rg_log('Peer announced itself!');
82 } else if (strcmp($cmd, 'STA ') == 0) {
83 if ($s['auth'] != 1) {
84 rg_log($key . ':Client not authenticated!');
85 $a = array('error' => 'client not authenticated');
86 $cmd = 'ERR ' . rg_conn_prepare($a) . "\n";
87 rg_conn_enq($key, $cmd);
88 return;
89 }
148 $s['active_jobs'] = 0;
149
150 $a = array();
151 $a['name'] = $u['name'];
152 $a['uname'] = $u['uname'];
153 $a['host'] = $u['host'];
154 $a['arch'] = $u['arch'];
155 $a['env'] = $u['env'];
156 $a['ssh_key'] = $u['ssh_key'];
157 $a['ip'] = rg_fix_ip($s['ip']);
158 rg_worker_update($s['db'], $worker_uid, $wi['id'], $a);
159
160 rg_log($key . ':Peer [' . $u['name'] . '] announce');
161 return;
162 }
163
164 if ($s['auth'] != 1) {
165 rg_log($key . ':Client not authenticated!');
166 $a = array('error' => 'client not authenticated');
167 $cmd = 'ERR ' . rg_conn_prepare($a) . "\n";
168 rg_conn_enq($key, $cmd);
169 return;
170 }
171
172 if (strcmp($cmd, 'STA ') == 0) {
90 173 $jid = $u['id']; $jid = $u['id'];
91 174 $jobs[$jid]['worker'] = $key; $jobs[$jid]['worker'] = $key;
175 $jobs[$jid]['worker_name'] = $s['ann']['name'];
92 176 $jobs[$jid]['worker_started'] = time(); $jobs[$jid]['worker_started'] = time();
177 $s['active_jobs'] += 1;
93 178 rg_log('Job started: ' . $jid); rg_log('Job started: ' . $jid);
94 } else if (strcmp($cmd, 'DON ') == 0) {
95 if ($s['auth'] != 1) {
96 rg_log($key . ':Client not authenticated!');
97 $a = array('error' => 'client not authenticated');
98 $cmd = 'ERR ' . rg_conn_prepare($a) . "\n";
99 rg_conn_enq($key, $cmd);
179 return;
180 }
181
182 if (strcmp($cmd, 'DON ') == 0) {
183 $s['active_jobs'] -= 1;
184
185 $jid = $u['id'];
186 if (isset($u['error'])) {
187 rg_log('job failed with error: ' . $u['error']);
188 // Delay job and retry (on another worker)
189 $jobs[$jid]['next_try'] = time() + 60;
190 $k = $s['worker_id'];
191 $jobs[$jid]['avoid'][$k] = 1;
100 192 return; return;
101 193 } }
102 $jid = $u['id'];
194
103 195 $r = rg_builder_done($s['db'], $jobs[$jid], $u['status']); $r = rg_builder_done($s['db'], $jobs[$jid], $u['status']);
104 196 if ($r === TRUE) { if ($r === TRUE) {
105 197 unset($jobs[$jid]); unset($jobs[$jid]);
 
... ... function xdispatch($key, $line)
108 200 $cmd = 'DRE ' . rg_conn_prepare($a) . "\n"; $cmd = 'DRE ' . rg_conn_prepare($a) . "\n";
109 201 rg_conn_enq($key, $cmd); rg_conn_enq($key, $cmd);
110 202 } }
111 } else {
112 rg_log('Unknown command [' . $cmd . ']!');
203 return;
113 204 } }
205
206 rg_log('Unknown command [' . $cmd . ']!');
114 207 } }
115 208
116 function rg_process_queue($db, &$job)
209 function rg_process_job($db, &$job)
117 210 { {
118 211 global $rg_conns; global $rg_conns;
119 212
120 rg_log('process_queue: worker=' . $job['worker']);
213 // Job is already in progress?
121 214 if (!empty($job['worker'])) if (!empty($job['worker']))
122 215 return; return;
123 216
217 // Should we delay because of a previous fail?
218 if (isset($job['next_try']) && ($job['next_try'] < time()))
219 return;
220
124 221 rg_log_ml('Processing job: ' . print_r($job, TRUE)); rg_log_ml('Processing job: ' . print_r($job, TRUE));
125 222
126 // Find a target for this job
223 // Get the worker list, so we can sort it
224 $workers_list = rg_worker_list_all($db, $job['uid']);
225 if ($workers_list === FALSE) {
226 rg_log('cannot load workers list: ' . rg_worker_error());
227 $job['next_try'] = time() + 60;
228 return;
229 }
230 //rg_log_ml('DEBUG: workers list: ' . print_r($workers_list, TRUE));
231
232 // Trying to find a worker in the list of connections
127 233 $found = FALSE; $found = FALSE;
128 234 foreach ($rg_conns as $key => $i) { foreach ($rg_conns as $key => $i) {
129 // Is it a worker?
235 if (strcmp($key, 'master') == 0)
236 continue;
237
130 238 if (!isset($i['ann'])) { if (!isset($i['ann'])) {
131 239 rg_log('Conn ' . $key . ' has no announce.'); rg_log('Conn ' . $key . ' has no announce.');
132 240 // TODO: close after some time? // TODO: close after some time?
 
... ... function rg_process_queue($db, &$job)
138 246 continue; continue;
139 247 } }
140 248
249 if (($i['worker_uid'] > 0) && ($i['worker_uid'] != $job['uid'])) {
250 //rg_log('uid does not match, try next');
251 continue;
252 }
253
254 $k = $i['worker_uid'];
255 if (!isset($workers_list[$k])) {
256 rg_log('Worker ' . $k . ' not found in workers_list! Strange!');
257 continue;
258 }
259 $wi = $workers_list[$k];
260
261 if (isset($job['avoid'][$k])) {
262 rg_log('We must avoid worker ' . $k);
263 continue;
264 }
265
266 rg_log('DEBUG: selected worker ' . $k);
267
268 // If number of active jobs is == max workers, skip it
269 if ($wi['workers'] <= $i['active_jobs']) {
270 rg_log('DEBUG: workers=' . $wi['workers']
271 . ' active_jobs=' . $i['active_jobs']);
272 continue;
273 }
274
141 275 foreach ($i['ann']['env'] as $env => $junk) { foreach ($i['ann']['env'] as $env => $junk) {
142 if (strcmp($job['env'], $env) != 0) {
143 rg_log('job env [' . $job['env'] . ']'
144 . ' != worker [' . $env . ']');
276 if (strcasecmp($job['env'], $env) != 0) {
277 //rg_log('DEBUG job env [' . $job['env'] . ']'
278 // . ' != worker [' . $env . ']');
145 279 continue; continue;
146 280 } }
147 281
148 // Remove some stuff
149 $job2 = $job;
150 unset($job2['worker']);
151 unset($job2['events']);
152 unset($job2['flags']);
282 // Send only what is really needed
283 $job2 = array();
284 $job2['cmds'] = $job['cmds'];
285 $job2['packages'] = $job['packages'];
286 $job2['hook_id'] = $job['hook_id'];
287 $job2['url'] = $job['url'];
288 $job2['head'] = $job['head'];
289 $job2['env'] = $job['env'];
290 $job2['id'] = $job['id'];
153 291
154 292 $cmd = 'BLD ' . rg_conn_prepare($job2) . "\n"; $cmd = 'BLD ' . rg_conn_prepare($job2) . "\n";
155 293 rg_conn_enq($key, $cmd); rg_conn_enq($key, $cmd);
 
... ... function rg_process_queue($db, &$job)
157 295 $job['worker'] = $key; $job['worker'] = $key;
158 296 $job['worker_started'] = 0; $job['worker_started'] = 0;
159 297 $job['worker_sent'] = time(); $job['worker_sent'] = time();
160 rg_log_ml('After sending BLD: ' . print_r($job, TRUE));
298 rg_log_ml('DEBUG: After sending BLD: job: ' . print_r($job, TRUE));
161 299 // TODO: after some time, if worker_started is still 0, // TODO: after some time, if worker_started is still 0,
162 300 // mark the 'worker' as '' to be able to go in other place // mark the 'worker' as '' to be able to go in other place
163 301 // TODO: maybe the client must resync with server to // TODO: maybe the client must resync with server to
 
... ... rg_prof_start("MAIN");
177 315
178 316 rg_log_set_file($rg_log_dir . "/builder.log"); rg_log_set_file($rg_log_dir . "/builder.log");
179 317 rg_log_set_sid("000000"); // to spread the logs rg_log_set_sid("000000"); // to spread the logs
180 // We must disable cache, else, we will not receive the updates because
181 // of the core cache. Do not forget that we are a long live process.
182 $rg_cache_core_enable = FALSE;
183 318
184 319 rg_log("Start (ver=$rocketgit_version)..."); rg_log("Start (ver=$rocketgit_version)...");
185 320
 
... ... rg_conn_new('master', $socket);
225 360 $rg_conns['master']['exit_on_close'] = 1; $rg_conns['master']['exit_on_close'] = 1;
226 361 $rg_conns['master']['func_new'] = 'xnew'; $rg_conns['master']['func_new'] = 'xnew';
227 362 $rg_conns['master']['func_new_arg'] = $db; $rg_conns['master']['func_new_arg'] = $db;
363 $rg_conns['master']['is_master'] = 1;
228 364
229 365 $jobs = array(); $jobs = array();
230 366
367 $workers = 0;
231 368 $original_mtime = @filemtime(__FILE__); $original_mtime = @filemtime(__FILE__);
232 369 do { do {
233 370 rg_log_buffer_clear(); rg_log_buffer_clear();
234 371
372 // We do not want stale entries!
373 rg_cache_core_destroy();
374
235 375 // Check our mtime so we can upgrade the software and this script // Check our mtime so we can upgrade the software and this script
236 376 // will restart. // will restart.
237 377 clearstatcache(); clearstatcache();
 
... ... do {
242 382 break; break;
243 383 } }
244 384
245 $r = rg_builder_load_jobs($db);
246 if ($r['ok'] != 1) {
247 rg_log('Cannot load jobs from database!');
248 sleep(30);
249 continue;
250 }
251
252 foreach ($r['list'] as $jid => $job) {
253 if (!isset($jobs[$jid])) {
254 $job['worker'] = '';
255 $job['url'] = 'git://rg.embedromix.ro/user/catab/delme10'; // TODO
256 $jobs[$jid] = $job;
385 if ($workers > 0) {
386 $r = rg_builder_load_jobs($db);
387 if ($r['ok'] != 1) {
388 rg_log('Cannot load jobs from database! Sleeping 30s...');
389 sleep(30);
390 continue;
257 391 } }
258 392
259 $r = rg_process_queue($db, $jobs[$jid]);
393 foreach ($r['list'] as $jid => $job) {
394 if (!isset($jobs[$jid])) {
395 $job['worker'] = '';
396 $job['avoid'] = array(); // to avoid workers
397 $jobs[$jid] = $job;
398 }
399
400 $r = rg_process_job($db, $jobs[$jid]);
401 if ($r === FALSE)
402 break;
403 }
260 404 if ($r === FALSE) if ($r === FALSE)
261 405 break; break;
262 406 } }
263 if ($r === FALSE)
264 break;
265 407
266 408 rg_log("Waiting for connections..."); rg_log("Waiting for connections...");
267 409 rg_conn_wait(10); rg_conn_wait(10);
File scripts/cron.php changed (mode: 100644) (index 6aaa8fb..a2d78cc)
... ... if (gmdate("Hi") == "0105") {
151 151 if (gmdate("Hi") == "0300") { if (gmdate("Hi") == "0300") {
152 152 rg_log_enter("Clean old forget_pass entries..."); rg_log_enter("Clean old forget_pass entries...");
153 153 $sql = "DELETE FROM forgot_pass WHERE expire < $now"; $sql = "DELETE FROM forgot_pass WHERE expire < $now";
154 $res = rg_sql_query($db, $sql);
154 155 if ($res !== FALSE) if ($res !== FALSE)
155 $res = rg_sql_query($db, $sql);
156 rg_sql_free_result($res);
156 rg_sql_free_result($res);
157 157 rg_log_exit(); rg_log_exit();
158 158 } }
159 159
File scripts/remote.php changed (mode: 100644) (index c9a2684..5379e0d)
... ... if (isset($_SERVER['SSH_CONNECTION'])) {
85 85
86 86 // first parameter must be uid of the user // first parameter must be uid of the user
87 87 $login_uid = isset($_SERVER['argv'][1]) ? $_SERVER['argv'][1] : 0; $login_uid = isset($_SERVER['argv'][1]) ? $_SERVER['argv'][1] : 0;
88 if ($login_uid == 0)
89 fatal("uid not provided!");
90 88 rg_log("uid is $login_uid."); rg_log("uid is $login_uid.");
91 89
92 90 // second parameter must be the ssh key id // second parameter must be the ssh key id
93 91 $key_id = isset($_SERVER['argv'][2]) ? $_SERVER['argv'][2] : 0; $key_id = isset($_SERVER['argv'][2]) ? $_SERVER['argv'][2] : 0;
94 if ($key_id == 0)
95 fatal("key_id not provided!");
92 // TODO: because of build system, 0 may be valid.
93 //if ($key_id == 0)
94 // fatal("key_id not provided!");
96 95 rg_log("key_id is $key_id."); rg_log("key_id is $key_id.");
97 96
97 // Third para is 'flags'
98 $flags = isset($_SERVER['argv'][3]) ? $_SERVER['argv'][3] : '';
99 rg_log('flags=' . $flags);
100
98 101 if (!isset($_SERVER['SSH_ORIGINAL_COMMAND'])) if (!isset($_SERVER['SSH_ORIGINAL_COMMAND']))
99 102 $cmd_repo = ""; $cmd_repo = "";
100 103 else else
 
... ... if (isset($_SERVER['SSH_CONNECTION'])) {
114 117
115 118 putenv('ROCKETGIT_INFO_SHOW=1'); putenv('ROCKETGIT_INFO_SHOW=1');
116 119
117 $must_exit = rg_ssh_dispatch($db, $ip, $login_uid, $cmd_repo);
118
119 // We do this operation after dispatch to not impact the latency.
120 // TODO: This should be put in a queue for performance reasons
121 // At the same time, update stats? events?
122 $_r = rg_keys_update_use($db, $conn_ui['uid'], $key_id, $ip, $cmd_repo);
123 if ($_r !== TRUE)
124 rg_internal_error("Cannot update key last_use!");
120 // Only normal keys can execute some commands
121 if (strstr($flags, 'N'))
122 $must_exit = rg_ssh_dispatch($db, $ip, $login_uid, $cmd_repo);
123 else
124 $must_exit = FALSE;
125
126 // Only normal keys can update stats
127 if (strstr($flags, 'N')) {
128 // We do this operation after dispatch to not impact the latency.
129 // TODO: This should be put in a queue for performance reasons
130 // At the same time, update stats? events?
131 $_r = rg_keys_update_use($db, $conn_ui['uid'], $key_id, $ip,
132 $cmd_repo);
133 if ($_r !== TRUE)
134 rg_internal_error("Cannot update key last_use!");
135 }
125 136
126 137 if ($must_exit) { if ($must_exit) {
127 138 rg_prof_end("remote.php"); rg_prof_end("remote.php");
 
... ... if (isset($_SERVER['SSH_CONNECTION'])) {
134 145 // we have no client info // we have no client info
135 146 $login_uid = 0; $login_uid = 0;
136 147 $key_id = 0; $key_id = 0;
148 $flags = '';
137 149 $conn_ui = array('uid' => 0, $conn_ui = array('uid' => 0,
138 150 'username' => 'anonymous user', 'username' => 'anonymous user',
139 151 'organization' => 0); 'organization' => 0);
 
... ... if (strcmp($_t[0], "user") == 0) {
191 203
192 204 rg_log("host=[$host] cmd=[$cmd] prefix=[$prefix] user=[$user] repo=[$repo]."); rg_log("host=[$host] cmd=[$cmd] prefix=[$prefix] user=[$user] repo=[$repo].");
193 205
206 if (strstr($flags, 'W')) {
207 // We are a worker, the command may be only for clonning!
208 if (strcmp($cmd, 'git-upload-pack') != 0)
209 fatal('A worker can only clone!');
210 }
211
194 212 // validity/security checks // validity/security checks
195 213 // Load info about the owner // Load info about the owner
196 214 if (rg_user_ok($user) !== TRUE) if (rg_user_ok($user) !== TRUE)
 
... ... putenv("ROCKETGIT_REPO_ID=" . $ri['repo_id']);
277 295 putenv("ROCKETGIT_REPO_PATH=" . $repo_path); putenv("ROCKETGIT_REPO_PATH=" . $repo_path);
278 296 putenv("ROCKETGIT_REPO_NAME=" . $ri['name']); putenv("ROCKETGIT_REPO_NAME=" . $ri['name']);
279 297 putenv("ROCKETGIT_REPO_UID=" . $ri['uid']); putenv("ROCKETGIT_REPO_UID=" . $ri['uid']);
280 putenv("ROCKETGIT_CLONE_URL=" . $ri['clone_url']);
298 putenv("ROCKETGIT_REPO_CLONE_URL=" . $ri['clone_url']);
281 299 putenv("ROCKETGIT_IP=$ip"); putenv("ROCKETGIT_IP=$ip");
282 300 putenv("ROCKETGIT_ITIME=" . microtime(TRUE)); putenv("ROCKETGIT_ITIME=" . microtime(TRUE));
283 301 putenv("ROCKETGIT_HOST=" . $host); putenv("ROCKETGIT_HOST=" . $host);
File scripts/worker.php changed (mode: 100644) (index 16328b0..92b7ab7)
1 1 <?php <?php
2 2 // Client for continuous integration and deployment // Client for continuous integration and deployment
3 // It can run on the same machine as the web server.
3 4 error_reporting(E_ALL); error_reporting(E_ALL);
4 5 ini_set('track_errors', 'On'); ini_set('track_errors', 'On');
5 6 set_time_limit(0); set_time_limit(0);
 
... ... set_time_limit(0);
7 8 define('RG_JOB_INIT', 1); define('RG_JOB_INIT', 1);
8 9 define('RG_JOB_HELPER_STARTED', 2); define('RG_JOB_HELPER_STARTED', 2);
9 10 define('RG_JOB_STARTED', 3); define('RG_JOB_STARTED', 3);
11 define('RG_JOB_ERROR', 4);
10 12 define('RG_JOB_DONE', 10); define('RG_JOB_DONE', 10);
11 13
12 14 $_s = microtime(TRUE); $_s = microtime(TRUE);
 
... ... require_once($INC . "/conn.inc.php");
20 22
21 23 rg_prof_start('MAIN'); rg_prof_start('MAIN');
22 24
25 // TODO: use different files for different workers!
23 26 rg_log_set_file($rg_log_dir . '/worker.log'); rg_log_set_file($rg_log_dir . '/worker.log');
24 27 rg_log_set_sid("000000"); // to spread the logs rg_log_set_sid("000000"); // to spread the logs
25 28
29 if (!isset($_SERVER['argv'][1]))
30 $conf_file = '/etc/rocketgit/worker.conf';
31 else
32 $conf_file = $_SERVER['argv'][1];
33 rg_log('conf_file=' . $conf_file);
26 34
27 35 /* /*
28 36 * Load configuration file * Load configuration file
29 37 */ */
30 38 function reload_config() function reload_config()
31 39 { {
40 global $conf_file;
32 41 global $conf; global $conf;
33 42
34 $_conf = @file('/etc/rocketgit/worker.conf');
43 $_conf = @file($conf_file);
44 if ($_conf === FALSE) {
45 // worker.conf not found
46 exit(0);
47 }
48
35 49 $last_key = FALSE; $last_key = FALSE;
36 if ($_conf !== FALSE) {
37 $conf = array('env' => array());
38 foreach ($_conf as $line) {
39 if (empty(trim($line)))
40 continue;
50 $conf = array('env' => array());
51 foreach ($_conf as $line) {
52 $tline = trim($line);
53 if (empty($tline))
54 continue;
41 55
42 if (strncmp($line, '#', 1) == 0)
56 if (strncmp($tline, '#', 1) == 0)
57 continue;
58
59 $t = explode('=', $line, 2);
60 if (count($t) != 2) {
61 rg_log('Invalid line [' . $line . ']!');
62 continue;
63 }
64
65 $var = trim($t[0]);
66 $value = trim($t[1]);
67
68 if (strcmp($var, 'env') == 0) {
69 $conf['env'][$value] = array('paras' => '');
70 $last_parent = &$conf['env'][$value];
71 } else if ((strncmp($line, " ", 1) == 0)
72 || (strncmp($line, "\t", 1) == 0)) {
73 if ($last_parent === FALSE) {
74 rg_log('Invalid line [' . $line . ']!');
43 75 continue; continue;
76 }
44 77
45 78 $t = explode('=', $line, 2); $t = explode('=', $line, 2);
46 79 if (count($t) != 2) { if (count($t) != 2) {
 
... ... function reload_config()
50 83
51 84 $var = trim($t[0]); $var = trim($t[0]);
52 85 $value = trim($t[1]); $value = trim($t[1]);
86 $last_parent[$var] = $value;
87 } else {
88 $conf[$var] = $value;
89 $last_parent = FALSE;
90 }
91 }
53 92
54 if (strcmp($var, 'env') == 0) {
55 $conf['env'][$value] = array('paras' => '');
56 $last_parent = &$conf['env'][$value];
57 } else if ((strncmp($line, " ", 1) == 0)
58 || (strncmp($line, "\t", 1) == 0)) {
59 if ($last_parent === FALSE) {
60 rg_log('Invalid line [' . $line . ']!');
61 continue;
62 }
63
64 $t = explode('=', $line, 2);
65 if (count($t) != 2) {
66 rg_log('Invalid line [' . $line . ']!');
67 continue;
68 }
69
70 $var = trim($t[0]);
71 $value = trim($t[1]);
72 $last_parent[$var] = $value;
73 } else {
74 $conf[$var] = $value;
75 $last_parent = FALSE;
76 }
93 if (!file_exists($conf['state'] . '/key.pub')) {
94 rg_log('Creating SSH key...');
95 $cmd = 'ssh-keygen -t rsa -b 4096 -N \'\''
96 . ' -C \'Key to connect to builder\''
97 . ' -f ' . escapeshellarg($conf['state'] . '/key');
98 $r = rg_exec($cmd);
99 if ($r['ok'] != 1) {
100 rg_log('Cannot create key: ' . $r['data'] . '!');
101 sleep(60);
102 exit(0);
77 103 } }
78 } else {
79 $conf = array(
80 'workers' => '1',
81 'cost' => 1,
82 'env' => array()
83 );
84 104 } }
105 $conf['ssh_key'] = @file_get_contents($conf['state'] . '/key.pub');
106 if ($conf['ssh_key'] === FALSE) {
107 rg_log('Cannot load key!');
108 sleep(60);
109 exit(0);
110 }
111
85 112 rg_log_ml('conf: ' . print_r($conf, TRUE)); rg_log_ml('conf: ' . print_r($conf, TRUE));
86 113 } }
87 114
 
... ... function start_worker($job)
146 173 break; break;
147 174 } }
148 175
176 // Seems that mkfs is not in PATH when it is runned from cron
177 $path = getenv('PATH');
178 putenv('PATH=' . $path . ':/usr/sbin');
179
149 180 $r = rg_exec('mkfs.ext4 -L RG ' . $img2); $r = rg_exec('mkfs.ext4 -L RG ' . $img2);
150 181 if ($r['ok'] !== 1) { if ($r['ok'] !== 1) {
151 182 $reason = 'cannot create fs: ' . $r['errmsg']; $reason = 'cannot create fs: ' . $r['errmsg'];
 
... ... function start_worker($job)
166 197 $do_umount = TRUE; $do_umount = TRUE;
167 198
168 199 // Clone repo // Clone repo
200 putenv('GIT_SSH_COMMAND=ssh'
201 . ' -o PasswordAuthentication=no'
202 . ' -o IdentityFile='
203 . escapeshellarg($conf['state'] . '/key'));
169 204 $cmd = 'git clone --depth 1' $cmd = 'git clone --depth 1'
170 205 . ' ' . escapeshellarg($job['url']) . ' ' . escapeshellarg($job['url'])
171 206 . ' ' . $emain . '/root/git'; . ' ' . $emain . '/root/git';
 
... ... function start_worker($job)
176 211 } }
177 212
178 213 // Build command list // Build command list
214 // TODO: document how a user can add labels in configure or make
179 215 $s = 'export RG_LABELS=/mnt/status/RG_LABELS' . "\n\n"; $s = 'export RG_LABELS=/mnt/status/RG_LABELS' . "\n\n";
180 216 $s .= 'cd /mnt/git' . "\n\n"; $s .= 'cd /mnt/git' . "\n\n";
181 217 $s .= 'git checkout ' . escapeshellarg($job['head']) . "\n"; $s .= 'git checkout ' . escapeshellarg($job['head']) . "\n";
182 218 foreach ($job['cmds'] as $name => $i) { foreach ($job['cmds'] as $name => $i) {
219 if (empty($i['cmd']))
220 continue;
221
183 222 $prefix = '/mnt/status/' $prefix = '/mnt/status/'
184 223 . escapeshellarg($name); . escapeshellarg($name);
185 224
 
... ... function start_worker($job)
221 260 break; break;
222 261 } }
223 262
263 // Prepare packages - for now, we must list every package
264 // on a single line to avoid not available packages
265 $pkgs = explode(' ', $job['packages']);
266 if (count($pkgs) > 0) {
267 $p_i_cmd = '';
268 $p_i_cmd .= '> /mnt/packages.log' . "\n";
269 foreach ($pkgs as $p) {
270 $p_i_cmd .= $env['pkg_cmd']
271 . ' ' . escapeshellarg($p)
272 . ' >> /mnt/packages.log 2>&1' . "\n";
273 }
274 }
275
224 276 // Store commands // Store commands
225 277 $r = @file_put_contents($job['main'] . '/root/rg.sh', $r = @file_put_contents($job['main'] . '/root/rg.sh',
226 278 'mkdir /mnt/status' . "\n" 'mkdir /mnt/status' . "\n"
227 279 . 'chown -R build:build /mnt/git /mnt/status' . "\n" . 'chown -R build:build /mnt/git /mnt/status' . "\n"
228 280 . 'date +%s > /mnt/T_START' . "\n" . 'date +%s > /mnt/T_START' . "\n"
281 . '# Waiting for net...' . "\n"
282 . 'while [ -z "`ip ro li | grep ^default`" ]; do' . "\n"
283 . ' sleep 1' . "\n"
284 . 'done' . "\n"
285 . 'date +%s > /mnt/T_NET_OK' . "\n\n"
286 . $p_i_cmd
287 . 'date +%s > /mnt/T_PKGS_OK' . "\n\n"
229 288 . 'su - build -c /mnt/build.sh' . "\n" . 'su - build -c /mnt/build.sh' . "\n"
230 . 'date +%s > /mnt/T_DONE' . "\n"
289 . 'date +%s > /mnt/T_DONE' . "\n\n"
231 290 . 'sync' . "\n" . 'sync' . "\n"
232 291 . 'shutdown -h now' . 'shutdown -h now'
233 292 ); );
 
... ... function start_worker($job)
260 319 . ' --memory 256' . ' --memory 256'
261 320 . ' --vcpus 1' . ' --vcpus 1'
262 321 . ' --graphics none' . ' --graphics none'
263 . ' --network none'
322 . ' --network network=default'
264 323 . ' --security type=dynamic' . ' --security type=dynamic'
265 . ' --os-variant fedora22'
324 . ' --os-variant ' . escapeshellarg($env['os-variant'])
266 325 . ' --import' . ' --import'
267 326 . ' --disk path=' . $img . ',discard=unmap' . ' --disk path=' . $img . ',discard=unmap'
268 327 . ' --disk path=' . $img2 . ',discard=unmap' . ' --disk path=' . $img2 . ',discard=unmap'
269 328 . ' --rng /dev/random' . ' --rng /dev/random'
329 . ' --memballoon virtio'
270 330 . ' ' . $env['paras']); . ' ' . $env['paras']);
271 331 if ($r['ok'] !== 1) { if ($r['ok'] !== 1) {
272 332 $reason = 'cannot define and start virtual machine: ' . $r['errmsg']; $reason = 'cannot define and start virtual machine: ' . $r['errmsg'];
 
... ... function start_worker($job)
279 339 if ($do_umount) if ($do_umount)
280 340 rg_exec('umount ' . $emain . '/root'); rg_exec('umount ' . $emain . '/root');
281 341
342 // Seems that any error above must retrigger the build on other worker
282 343 if ($err) if ($err)
283 @file_put_contents($job['main'] . '/error', $reason);
344 @file_put_contents($job['main'] . '/error.log', $reason);
284 345 } }
285 346
286 347 /* /*
287 * Handle commands
348 * Handle received commands
288 349 */ */
289 350 function xhandle($key, $cmd0) function xhandle($key, $cmd0)
290 351 { {
 
... ... function xhandle($key, $cmd0)
304 365 $jid = $job['id']; $jid = $job['id'];
305 366
306 367 if (strcmp($cmd, 'BLD ') == 0) { if (strcmp($cmd, 'BLD ') == 0) {
368 // TODO: should we confirm quickly if the job is accepted,
369 // even if we could not fork?
307 370 if (isset($jobs[$jid])) { if (isset($jobs[$jid])) {
371 // TODO: this should not happen, right?
308 372 rg_log('Job ' . $jid . ' already in queue!'); rg_log('Job ' . $jid . ' already in queue!');
309 373 return; return;
310 374 } }
311 375
312 376 $jobs[$jid] = $job; $jobs[$jid] = $job;
313 $jobs[$jid]['main'] = $conf['state'] . '/j-' . $jid;
377 $jobs[$jid]['main'] = $conf['state'] . '/rocketgit-j-' . $jid;
314 378 $jobs[$jid]['state'] = RG_JOB_INIT; $jobs[$jid]['state'] = RG_JOB_INIT;
315 379
316 380 rg_log_ml('build job: ' . print_r($job, TRUE)); rg_log_ml('build job: ' . print_r($job, TRUE));
 
... ... function xhandle($key, $cmd0)
327 391 exit(0); exit(0);
328 392 } }
329 393
330 rg_log('Started builder with pid ' . $pid);
394 rg_log('Started worker with pid ' . $pid);
331 395 $jobs[$jid]['state'] = RG_JOB_HELPER_STARTED; $jobs[$jid]['state'] = RG_JOB_HELPER_STARTED;
332 396 $pid_to_jid[$pid] = $jid; $pid_to_jid[$pid] = $jid;
333 397 $err = FALSE; $err = FALSE;
 
... ... function xhandle($key, $cmd0)
342 406 return; return;
343 407 } }
344 408 rg_conn_enq('master', 'STA ' . rg_conn_prepare($a) . "\n"); rg_conn_enq('master', 'STA ' . rg_conn_prepare($a) . "\n");
345 } else if (strcmp($cmd, 'DRE ') == 0) {
409 } else if (strcmp($cmd, 'DRE ') == 0) { // DRE = done received
410 // So, we can clean up everything related to this job
411 // TODO: do we clear the state file?
346 412 rg_log('DRE command'); rg_log('DRE command');
347 413 $job = &$jobs[$jid]; $job = &$jobs[$jid];
348 414 unset($pid_to_jid[$job['pid']]); unset($pid_to_jid[$job['pid']]);
 
... ... function xhandle($key, $cmd0)
355 421
356 422 /* /*
357 423 * Extracts info from the virtual disk * Extracts info from the virtual disk
424 * TODO: if something fails, we may keep the file mounted!
358 425 */ */
359 426 function rg_job_extract_info(&$job) function rg_job_extract_info(&$job)
360 427 { {
 
... ... function rg_job_extract_info(&$job)
366 433
367 434 while (1) { while (1) {
368 435 if (!is_dir($job['main'])) { if (!is_dir($job['main'])) {
369 $job['error'] = 'Main dir not presend;'
436 $job['error'] = 'Main dir [' . $job['main']
437 . '] not presend;'
370 438 . ' probably disk space problems'; . ' probably disk space problems';
371 439 break; break;
372 440 } }
373 441
374 $r = @file_get_contents($job['main'] . '/error');
442 $r = @file_get_contents($job['main'] . '/error.log');
375 443 if ($r !== FALSE) { if ($r !== FALSE) {
376 444 $job['error'] = $r; $job['error'] = $r;
377 445 break; break;
 
... ... function rg_job_extract_info(&$job)
384 452 break; break;
385 453 } }
386 454
455 $labels = @file($job['main'] . '/root/status/RG_LABELS');
456 if ($labels === FALSE)
457 $labels = array();
458 foreach ($labels as $index => $l)
459 $labels[$index] = trim($l);
460 // Add worker name as label
461 $labels[] = 'worker/' . $conf['name'] . '/color=fff';
462
387 463 $job['status'] = array( $job['status'] = array(
464 'packages' => @trim(file_get_contents($job['main'] . '/root/packages.log')),
388 465 'start' => @trim(file_get_contents($job['main'] . '/root/T_START')), 'start' => @trim(file_get_contents($job['main'] . '/root/T_START')),
466 'net_ok' => @trim(file_get_contents($job['main'] . '/root/T_NET_OK')),
467 'pkgs_ok' => @trim(file_get_contents($job['main'] . '/root/T_PKGS_OK')),
389 468 'done' => @trim(file_get_contents($job['main'] . '/root/T_DONE')), 'done' => @trim(file_get_contents($job['main'] . '/root/T_DONE')),
390 'labels' => @file($job['main'] . '/root/status/RG_LABELS')
469 'labels' => $labels
391 470 ); );
392 foreach ($job['status']['labels'] as $index => $l)
393 $job['status']['labels'][$index] = trim($l);
394 471
395 472 $job['status']['cmds'] = array(); $job['status']['cmds'] = array();
396 473 foreach ($job['cmds'] as $cmd => $i) { foreach ($job['cmds'] as $cmd => $i) {
 
... ... function rg_job_extract_info(&$job)
402 479 'start' => @trim(file_get_contents($sd . '.start')), 'start' => @trim(file_get_contents($sd . '.start')),
403 480 'done' => @trim(file_get_contents($sd . '.done')), 'done' => @trim(file_get_contents($sd . '.done')),
404 481 'log' => @file_get_contents($sd . '.log', FALSE, 'log' => @file_get_contents($sd . '.log', FALSE,
405 NULL, -1, 2048)
482 NULL, -1, 4 * 4096)
406 483 ); );
407 484 } }
408 485 unset($job['cmds']); unset($job['cmds']);
 
... ... function rg_job_extract_info(&$job)
428 505
429 506 reload_config(); reload_config();
430 507
508
431 509 $socket = @socket_create(AF_INET, SOCK_STREAM, SOL_TCP); $socket = @socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
432 510 if ($socket === FALSE) { if ($socket === FALSE) {
433 511 rg_log('Cannot create socket!'); rg_log('Cannot create socket!');
 
... ... while(1) {
470 548 break; break;
471 549
472 550 $jid = $pid_to_jid[$pid]; $jid = $pid_to_jid[$pid];
473 rg_log('Pid ' . $pid . ' exited (job ' . $jid . ')!');
551 rg_log('Pid ' . $pid . ' exited (job ' . $jid . ')'
552 . ' with status ' . $status . '!');
474 553 unset($pid_to_jid[$pid]); unset($pid_to_jid[$pid]);
475 554 $jobs[$jid]['state'] = RG_JOB_STARTED; $jobs[$jid]['state'] = RG_JOB_STARTED;
476 555 } }
 
... ... while(1) {
492 571
493 572 $name = 'rg-worker-' . $jid; $name = 'rg-worker-' . $jid;
494 573 $k = array_search($name, $vms); $k = array_search($name, $vms);
495 if ($k === FALSE) {
496 rg_log('VM finished');
497 $job['state'] = RG_JOB_DONE;
574 if ($k !== FALSE) {
575 //rg_log('VM in progress');
576 // TODO: if too much time, abort (kill
577 // worker and destroy virtual machine)
578 //TODO: $job['error'] = 'too much time';
579 continue;
580 }
498 581
499 rg_job_extract_info($job);
582 rg_log('VM ' . $jid . ' finished');
500 583
501 // TODO: store in fs to be able to still inform the
502 // master if we are crashing.
584 rg_job_extract_info($job);
585 if (isset($job['error']))
586 $job['state'] = RG_JOB_ERROR;
587 else
503 588 $job['state'] = RG_JOB_DONE; $job['state'] = RG_JOB_DONE;
504 @file_put_contents($job['main'] . '/job.ser',
505 serialize($job));
506 589
507 rg_conn_enq('master', 'DON '
508 . rg_conn_prepare($job) . "\n");
509 } else {
510 //rg_log('VM in progress');
511 // TODO: if too much time, abort
590 // TODO: store in fs to be able to still inform the
591 // master if we are crashing.
592 @file_put_contents($job['main'] . '/job.ser', serialize($job));
593
594 $xjob = $job;
595 unset($xjob['debug']);
596 unset($xjob['packages']);
597 unset($xjob['main']);
598 rg_conn_enq('master', 'DON ' . rg_conn_prepare($xjob) . "\n");
599
600 // TODO: do we destroy the pool in case of crash?
601 $cmd = 'virsh pool-destroy rocketgit-j-' . $jid;
602 $r = rg_exec($cmd);
603 if ($r['ok'] != 1) {
604 $job['error'] = 'Could not destroy pool: ' . $r['data'];
605 rg_log('Error: ' . $job['error']);
606 //break; TODO: do we need to do this?!
607 }
608
609 // TODO: do we clean the pool in case of crash?
610 $cmd = 'virsh pool-undefine rocketgit-j-' . $jid;
611 $r = rg_exec($cmd);
612 if ($r['ok'] != 1) {
613 $job['error'] = 'Could not undefine pool: ' . $r['data'];
614 rg_log('Error: ' . $job['error']);
615 //break; TODO: do we need to do this?!
616 }
617
618 // TODO: do we clean the machine in case of crash?
619 $cmd = 'virsh undefine rg-worker-' . escapeshellarg($jid);
620 $r = rg_exec($cmd);
621 if ($r['ok'] != 1) {
622 $job['error'] = 'Could not undefine machine: ' . $r['data'];
623 rg_log('Error: ' . $job['error']);
624 //break; TODO
512 625 } }
513 626 } }
514 627 } }
File techdocs/slack.txt added (mode: 100644) (index 0000000..7197bf3)
1 == How to do an integration ==
2 - Create channel
3 - Go to channel and click on "+ Add an app or custom integration"
4 - "Build your own"
5 - "Make a custom integration"
6 - "Incoming WebHooks"
7 - "Add Incoming WebHooks integration"
8 - Copy in clipboard the link
9 - "Save settings"
10 - Go to rocketgit website
11 - "Settings" -> "Webhooks" -> "Add" -> "Slack", paste the URL -> "Add"
12 - Done!
File tests/.gitignore changed (mode: 100644) (index 06b1eb8..399dcaf)
... ... git_log1.final
25 25 _pr_anon.git _pr_anon.git
26 26 hook_update_dest.git hook_update_dest.git
27 27 hook_update_src.git hook_update_src.git
28 export.json
File tests/Makefile changed (mode: 100644) (index ea75a33..36aaccf)
1 tests := wh_cloud pr_anon wh_http ssh http_totp totp git_log1.sh \
1 tests := http_forgot \
2 api wh_cloud pr_anon wh_http ssh http_totp totp git_log1.sh \
2 3 http_admin http_bug \ http_admin http_bug \
3 4 http_create_account http_login http_settings http_csrf http_top \ http_create_account http_login http_settings http_csrf http_top \
4 5 token util log state cache prof db event rights keys user repo git \ token util log state cache prof db event rights keys user repo git \
 
... ... all: $(tests)
10 11 @-ls -l err-* @-ls -l err-*
11 12 @echo "Do not forget to check for errors in /var/log/rocketgit!" @echo "Do not forget to check for errors in /var/log/rocketgit!"
12 13
14 http_forgot:
15 php http_forgot.php
16
17 api:
18 ./api.sh
19
13 20 wh_cloud: wh_cloud:
14 21 php wh_cloud.php php wh_cloud.php
15 22
 
... ... clean:
105 112 @rm -rf git_log1 *.log *.strace *.strace.* *.out *.lock err-* *.diff \ @rm -rf git_log1 *.log *.strace *.strace.* *.out *.lock err-* *.diff \
106 113 http.arond *.pub git2key git2 *.in q_merge_requests/mr-* \ http.arond *.pub git2key git2 *.in q_merge_requests/mr-* \
107 114 qstats/* repos/* helper helper.pub keys/* ca *.pid \ qstats/* repos/* helper helper.pub keys/* ca *.pid \
108 _pr_anon.git *.tmp base ubase wh_cloud.git
115 _pr_anon.git *.tmp base ubase wh_cloud.git export.json
File tests/api.sh added (mode: 100755) (index 0000000..9f7b33f)
1 #!/bin/bash
2
3 user="catab"
4 key="925cb5896280c6f132263336a5e90819"
5 curl --header "Authorization: ${user} ${key}" \
6 --include \
7 --data "{\"cmd\": \"user_info\", \"user\": \"${user}\"}" \
8 http://rg:9000/op/api
File tests/email.php changed (mode: 100644) (index baf34aa..a5b64b9)
... ... $rg_scripts = "../";
21 21 $rg_theme = "default"; $rg_theme = "default";
22 22 $rg_event_socket = "/var/lib/rocketgit/sockets/event.sock"; $rg_event_socket = "/var/lib/rocketgit/sockets/event.sock";
23 23
24 rg_log_set_file("email.log");
25
26 24 // This will trigger an e-mail // This will trigger an e-mail
27 25 rg_test_create_user($db, $rg_ui); rg_test_create_user($db, $rg_ui);
28 26
File tests/export.php added (mode: 100644) (index 0000000..c5b707a)
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 . "/export.inc.php");
9 require_once("helpers.inc.php");
10
11 rg_log_set_file("export.log");
12
13 $rg_sql = "host=localhost user=rocketgit dbname=rocketgit connect_timeout=10";
14 $rg_no_db = TRUE;
15 require_once("common.php");
16
17 $_testns = 'export';
18 $rg_cache_enable = TRUE;
19
20 $rg_scripts = "../";
21 $rg_theme = "default";
22 $rg_event_socket = "/var/lib/rocketgit/sockets/event.sock";
23
24 // This will trigger an e-mail
25 rg_test_create_user($db, $rg_ui);
26 rg_test_create_repo($db, $rg_ui, $repo);
27 rg_test_create_rights($db, $rg_ui, $repo, $right_extra);
28 rg_test_create_bug($db, $rg_ui, $repo, $bug_extra);
29 $key_id = rg_test_create_key($db, $rg_ui);
30
31 rg_log('');
32 rg_log('Exporting user info...');
33 $r = rg_export_user($db, $rg_ui['uid'],
34 RG_EXPORT_REPOS | RG_EXPORT_BUGS | RG_EXPORT_KEYS
35 | RG_EXPORT_RIGHTS | RG_EXPORT_PULLS,
36 JSON_PRETTY_PRINT);
37 if ($r === FALSE) {
38 rg_log('Cannot export user info: ' . rg_export_error() . '!');
39 exit(1);
40 }
41 $r = file_put_contents('export.json', $r);
42 if ($r === FALSE) {
43 rg_log('Cannot save json!');
44 exit(1);
45 }
46
47 $cmd = 'cat export.json | json_verify';
48 $a = rg_exec($cmd);
49 if ($a['ok'] !== 1) {
50 rg_log_ml(print_r($a, TRUE));
51 rg_log('Seems the JSON is not valid!');
52 exit(1);
53 }
54
55 rg_log('OK');
56 ?>
File tests/helpers.inc.php changed (mode: 100644) (index 564560b..83c494b)
4 4 /* /*
5 5 * Creating a user * Creating a user
6 6 */ */
7 $_user_id = 1;
7 $_user_id = time();
8 8 $_testns = 'main'; $_testns = 'main';
9 9 function rg_test_create_user($db, &$rg_ui) function rg_test_create_user($db, &$rg_ui)
10 10 { {
11 11 global $_testns; global $_testns;
12 12 global $_user_id; global $_user_id;
13 13
14 if (!isset($_user_id))
15 $_user_id = time();
16
14 17 if (!is_array($rg_ui)) if (!is_array($rg_ui))
15 18 $rg_ui = array(); $rg_ui = array();
16 19
 
... ... function rg_test_create_user($db, &$rg_ui)
30 33 $new['plan_id'] = 0; $new['plan_id'] = 0;
31 34 $new['pass'] = 'pass-' . $_user_id; $new['pass'] = 'pass-' . $_user_id;
32 35 $new['pass2'] = 'pass-' . $_user_id; $new['pass2'] = 'pass-' . $_user_id;
36 $new['disk_used_mb'] = 0;
37 $new['last_ip'] = '?';
33 38 $_user_id++; $_user_id++;
34 39
35 40 // Delete old user // Delete old user
 
... ... function rg_test_create_repo($db, $rg_ui, &$extra)
177 182 return TRUE; return TRUE;
178 183 } }
179 184
185 /*
186 * Creating a ssh key helper
187 */
188 function rg_test_create_key($db, $rg_ui)
189 {
190 rg_log("Creating a key");
191 // spaces are on purpose
192 $skey = 'ssh-rsa AAAAB3Nz aC1yc2EAAAADA QABAAABAQDgy8QSbr13izfGxO0sqOsxu4faw6hF1LLrlcBobT5zzO4wzbokjliRiZ9sfA0zd0WEfdQJ6W01hVNf9QpJlUiGM4OyXBKOc8JLfCyjtcfRcC48hPQ22IY9TtfrxGK38IgwdS7+Ophjs8u0RlqHd8eMtYWcmxlHwdIEb6+IZ6kyA2srmFGN6DQCnOvyYSd+iZ8u4DQBEuWxzsKvrat9gR5H6KNTYisSB9rjLKQd4rFbu6Tl217wJY1LWjH7hlFPxioMCg0Fzv6AkQXWnAr1GrCVgIQDC5dEVUrw2NSVElEC+eaG6OZnkq7CP0B8pSj3BV2TNhSgnQb9Ojo9xNHc2Pwx aaa@aaa.aaa';
193
194 $r = rg_keys_add($db, $rg_ui, $skey);
195 if ($r === FALSE) {
196 rg_log("Cannot add a key (" . rg_keys_error() . ")!");
197 exit(1);
198 }
199
200 return $r;
201 }
202
203 /*
204 * Helper to add some rights
205 */
206 function rg_test_create_rights($db, $rg_ui, $ri, &$extra)
207 {
208 if (!is_array($extra))
209 $extra = array();
210
211 $a = array();
212 $a['right_id'] = 0;
213 $a['who'] = 90;
214 $a['obj_id'] = $ri['repo_id'];
215 $a['uid'] = $rg_ui['uid'];
216 $a['rights'] = "abc";
217 $a['misc'] = "misc1/@USER@/";
218 $a['ip'] = "1.1.1.1 2.2.2.2 10.0.0.0/8";
219 $a['prio'] = 13;
220 $a['description'] = "desc1";
221 $r = rg_rights_set($db, "type1", $a);
222 if ($r !== TRUE) {
223 rg_log("Seems I cannot set rights 1 (" . rg_rights_error() . ")");
224 exit(1);
225 }
226
227 return $r;
228 }
229
230 /*
231 * Helper to add a bug
232 */
233 function rg_test_create_bug($db, $rg_ui, $ri, &$extra)
234 {
235 if (!is_array($extra))
236 $extra = array();
237
238 $a = array();
239 $a['bug_id'] = 0;
240 $a['itime'] = time() - 600;
241 $a['utime'] = time() - 300;
242 $a['uid'] = 30;
243 $a['ip'] = '1.1.1.1 <xss>';
244 $a['title'] = 'a nice title <xss>';
245 $a['body'] = 'a nice body <xss>';
246 $a['assigned_uid'] = 0;
247 $a['deleted'] = 0;
248 $a['deleted_who'] = 0;
249 $a['state'] = 1;
250 $r = rg_bug_edit($db, $rg_ui, $ri, $a);
251 if ($r === FALSE) {
252 rg_log('Seems I cannot add bug: ' . rg_bug_error() . ")");
253 exit(1);
254 }
255
256 return $r;
257 }
258
180 259 /* /*
181 260 * Helper for creating and uploading a ssh key * Helper for creating and uploading a ssh key
182 261 * Returns the key. * Returns the key.
File tests/http_forgot.php added (mode: 100644) (index 0000000..c0779b4)
1 <?php
2 //
3 // Will test the forgot password feature
4 //
5
6 error_reporting(E_ALL | E_STRICT);
7 ini_set("track_errors", "On");
8
9 $INC = dirname(__FILE__) . "/../inc";
10 require_once(dirname(__FILE__) . "/config.php");
11 require_once($INC . "/init.inc.php");
12 require_once($INC . "/util.inc.php");
13 require_once("helpers.inc.php");
14 require_once("http.inc.php");
15
16 rg_log_set_file("http_forgot.log");
17
18 $rg_sql = "host=localhost user=rocketgit dbname=rocketgit connect_timeout=10";
19 $rg_no_db = TRUE;
20 require_once("common.php");
21
22 $_testns = 'http_forgot';
23 $rg_cache_enable = TRUE;
24 $rg_cache_debug = TRUE;
25
26 $rg_user_max_len = 60;
27
28 rg_test_create_user($db, $rg_ui);
29
30
31 rg_log('');
32 rg_log_enter('Loading forgot pass form...');
33 $data = array();
34 $r = do_req($test_url . '/op/forgot_send', $data, $headers);
35 if ($r === FALSE) {
36 rg_log("Cannot load forgot pass page!");
37 exit(1);
38 }
39 rg_log('Posting the forgot pass form...');
40 $data = array(
41 'email' => $rg_ui['email'],
42 'doit' => 1
43 );
44 $r = do_req($test_url . '/op/forgot_send', $data, $headers);
45 if (!strstr($r['body'], 'your inbox and follow the instructions')) {
46 rg_log_ml('r: ' . print_r($r, TRUE));
47 rg_log("Cannot post forgot pass form!");
48 exit(1);
49 }
50 $sql = 'SELECT token FROM forgot_pass WHERE uid = ' . $rg_ui['uid'];
51 $res = rg_sql_query($db, $sql);
52 $rows = rg_sql_num_rows($res);
53 if ($rows > 0)
54 $row = rg_sql_fetch_array($res);
55 rg_sql_free_result($res);
56 if ($rows != 1) {
57 rg_log("Seems the token is not in the database or there are multiple ones!");
58 exit(1);
59 }
60 $db_token = $row['token'];
61 rg_log_exit();
62
63
64 rg_log('');
65 rg_log_enter('Loading token from mail...');
66 $k = 'DEBUG::nouid::mail';
67 $c = rg_cache_get($k);
68 if (($c === FALSE) || !isset($c['body'])) {
69 rg_log_ml(print_r($c, TRUE));
70 rg_log('No c or no body in c var!');
71 exit(1);
72 }
73 $s = strstr($c['body'], '/op/forgot_link/');
74 if ($s === FALSE) {
75 rg_log_ml(print_r($c['body'], TRUE));
76 rg_log('No link in body!');
77 exit(1);
78 }
79
80 $s = substr($s, 16, 20);
81 if (strcmp($db_token, $s) != 0) {
82 rg_log('db token != mail token! [' . $db_token . '] != [' . $s . ']');
83 exit(1);
84 }
85
86 // we add junk because I've seen cases when some junk was appended
87 $s .= 'junk';
88
89 $data = array();
90 $r = do_req($test_url . '/op/forgot_link/' . $s, $data, $headers);
91 if ($r === FALSE) {
92 rg_log("Cannot load forgot_link page!");
93 exit(1);
94 }
95
96 rg_log('Posting the forgot link form...');
97 $pass = rg_id(10);
98 $data = array(
99 'forgot_token' => $s,
100 'pass1' => $pass,
101 'pass2' => $pass,
102 'lock_ip' => 1,
103 'doit' => 1
104 );
105 $r = do_req($test_url . '/op/forgot_link', $data, $headers);
106 if (!strstr($r['body'], 'Home page of user')) {
107 rg_log_ml('r: ' . print_r($r, TRUE));
108 rg_log('Cannot post forgot link form!');
109 exit(1);
110 }
111 $sql = 'SELECT salt, pass FROM users WHERE uid = ' . $rg_ui['uid'];
112 $res = rg_sql_query($db, $sql);
113 $rows = rg_sql_num_rows($res);
114 if ($rows > 0)
115 $row = rg_sql_fetch_array($res);
116 rg_sql_free_result($res);
117 if ($rows != 1) {
118 rg_log('Seems the password was not changed!');
119 exit(1);
120 }
121 $good_pass = rg_user_pass($row['salt'], $pass);
122 if (strcmp($good_pass, $row['pass']) != 0) {
123 rg_log_ml('row: ' . print_r($row, TRUE));
124 rg_log('passwords are not the same pass=[' . $pass . ']!');
125 exit(1);
126 }
127 rg_log_exit();
128
129 // TODO: make sure that the entry from forgot_pass is gone
130
131
132 rg_prof_log();
133 rg_log("OK!");
134 ?>
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