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 85a7d584e031f9b3ce94e2520f998ec6698ca46a

Mostly Amazon CodeDeploy and Lambda, and maked the plugins more generic
Author: Catalin(ux) M. BOIE
Author date (UTC): 2016-01-15 20:14
Committer name: Catalin(ux) M. BOIE
Committer date (UTC): 2016-01-15 20:14
Parent(s): d4d5f86741ca0a3c658879b82ec43877ceb0901b
Signing key:
Tree: 8e62698e5db56fd8bb23f7b5beac8d3f51e372b5
File Lines added Lines deleted
TODO 19 5
docker/Dockerfile 1 0
docker/README 7 0
docker/build.sh 2 2
docker/push.sh 23 0
hooks/update 1 0
inc/admin.inc.php 2 1
inc/bug.inc.php 2 0
inc/fixes.inc.php 130 0
inc/git.inc.php 43 10
inc/repo.inc.php 30 2
inc/struct.inc.php 5 0
inc/util.inc.php 21 3
inc/webhooks.inc.php 50 34
inc/wh/amazon.inc.php 353 0
inc/wh/cloud.inc.php 260 0
inc/wh/core.inc.php 168 23
inc/wh/http.inc.php 44 91
inc/wh/lambda.inc.php 199 0
root/themes/default/user/settings/wh/add_edit.html 7 21
root/themes/default/user/settings/wh/amazon/inv_access_key_id.txt 1 0
root/themes/default/user/settings/wh/amazon/inv_region.txt 1 0
root/themes/default/user/settings/wh/amazon/inv_secret_access_key.txt 1 0
root/themes/default/user/settings/wh/cloud/form.html 51 0
root/themes/default/user/settings/wh/cloud/hints.html 2 0
root/themes/default/user/settings/wh/cloud/inv_app_name.txt 1 0
root/themes/default/user/settings/wh/cloud/inv_bucket.txt 1 0
root/themes/default/user/settings/wh/cloud/inv_group_name.txt 1 0
root/themes/default/user/settings/wh/cloud/show.html 41 0
root/themes/default/user/settings/wh/hints_htype.html 0 9
root/themes/default/user/settings/wh/hints_tags.html 16 0
root/themes/default/user/settings/wh/http/form.html 18 10
root/themes/default/user/settings/wh/http/hints.html 10 0
root/themes/default/user/settings/wh/http/show.html 0 5
root/themes/default/user/settings/wh/inv_events.txt 1 1
root/themes/default/user/settings/wh/inv_flag.txt 0 0
root/themes/default/user/settings/wh/inv_htype.txt 1 1
root/themes/default/user/settings/wh/lambda/form.html 34 0
root/themes/default/user/settings/wh/lambda/hints.html 2 0
root/themes/default/user/settings/wh/lambda/inv_func.txt 1 0
root/themes/default/user/settings/wh/lambda/show.html 26 0
root/themes/default/user/settings/wh/list/header.html 3 4
root/themes/default/user/settings/wh/list/line.html 3 4
root/themes/default/user/settings/wh/plugins_list/line.html 1 1
scripts/remote.php 1 0
techdocs/amazon-CodeDeploy.txt 1 5
tests/.gitignore 1 0
tests/Makefile 5 2
tests/config.php 1 1
tests/git2.php 40 22
tests/helpers.inc.php 2 3
tests/ssh.php 1 1
tests/wh_cloud.git.sh 32 0
tests/wh_cloud.php 198 0
tests/wh_http.php 27 27
File TODO changed (mode: 100644) (index fa9cd0d..ae20e25)
1 1 == Where I stopped last time == == Where I stopped last time ==
2 [ ] wh: where do I specify the repo_id?!
3 [ ] wh: repo/branch/tag regex
4 [ ] wh: Add a regex filter for branches!
5 [ ] wh: unit test: events
6 [ ] wh: id of the hook appears as root-id, but also as root-info-id!
2 7 [ ] [ ]
3 8
4 9 == BEFORE NEXT RELEASE == == BEFORE NEXT RELEASE ==
10 [ ] wh: trigger on assigning a tag? For example, trigger on
11 adding a tag (regex match) to a ref (regex match).
12 I do have two matches here!
13 [ ] wh: what about a user that has access to push in a branch,
14 but is not the owner of a hook. Should I run it?
15 Should I flag a webhook as 'global'?
16 Should I add a field to specify the user or '*'?
17 [ ] wh: we should deploy also if a pull request is accepted.
18 [ ] wh: when editing, some data may be secret...
19 [ ] wh: add a hint about 'opaque'.
20 [ ] docker: add a link to rocketgit.com in description + better description
21 [ ] Add a unit test for repo creation. Didn't have one? Hm.
5 22 [ ] notes: I have a little space below the picture because a <img> inside <a>! [ ] notes: I have a little space below the picture because a <img> inside <a>!
6 23 How to get rid of it? How to get rid of it?
7 24 [ ] When rejecting a push because of rights, show also what rule matched. [ ] When rejecting a push because of rights, show also what rule matched.
8 Maybe why? For example: ip is not in range?
25 Maybe also why? For example: ip is not in range?
9 26 [ ] Discover: I must not say [ ] Discover: I must not say
10 27 "No repositories found. Go to My repositories / Create to add one." "No repositories found. Go to My repositories / Create to add one."
11 28 It is about the others' repos. It is about the others' repos.
 
33 50 [ ] Do we stop event processing when we change the structure? [ ] Do we stop event processing when we change the structure?
34 51 [ ] wh: add 'listen tcp socket', 'connecting tcp/udp socket', 'ssh', 'mail' [ ] wh: add 'listen tcp socket', 'connecting tcp/udp socket', 'ssh', 'mail'
35 52 hooks. hooks.
36 [ ] wh: how to integrate other types of hooks? For example: mail/amazon/etc.
37 Now, I broken it by adding certs to the main wh table, things
38 that do not make sense for other hooks. Are not generic! Bad!
39 Probably I will have to do a 'fix' functin to switch to the new system.
40 53 [ ] git: do not try to show binary files. [ ] git: do not try to show binary files.
41 54 [ ] css: 'source'/'bug_body'/'notes'/'mess' was with display: table [ ] css: 'source'/'bug_body'/'notes'/'mess' was with display: table
42 55 [ ] css: decide aboud island_row if we do not switch to flex [ ] css: decide aboud island_row if we do not switch to flex
 
68 81 [ ] rights: if a user has 'admin/give_rights' rights, allow push? [ ] rights: if a user has 'admin/give_rights' rights, allow push?
69 82 [ ] wh: add prios - we may want to have a hook for storing in s3 and a hook for [ ] wh: add prios - we may want to have a hook for storing in s3 and a hook for
70 83 deployment. Hm. deployment. Hm.
84 [ ] wh: tweets for pushes?
71 85 [ ] amazon: CodeDeploy a very nice presentation: [ ] amazon: CodeDeploy a very nice presentation:
72 86 https://confluence.atlassian.com/bamboo/using-the-aws-codedeploy-task-750396059.html https://confluence.atlassian.com/bamboo/using-the-aws-codedeploy-task-750396059.html
73 87 [ ] amazon: allow deploy to multiple regions [ ] amazon: allow deploy to multiple regions
File docker/Dockerfile changed (mode: 100644) (index 598c2dd..eb9637f)
... ... MAINTAINER Catalin(ux) M. BOIE <catab-docker@embedromix.ro>
4 4 RUN dnf -y upgrade --best --allowerasing RUN dnf -y upgrade --best --allowerasing
5 5 RUN dnf -y install http://kernel.embedromix.ro/dinorepo-0.0.10-1.noarch.rpm RUN dnf -y install http://kernel.embedromix.ro/dinorepo-0.0.10-1.noarch.rpm
6 6 RUN dnf -y install psmisc procps-ng sendmail php-opcache qrencode RUN dnf -y install psmisc procps-ng sendmail php-opcache qrencode
7 RUN dnf -y --disablerepo=* --enablerepo dinorepo clean all; echo no_cache_1
7 8 RUN dnf -y install rocketgit-0.46 RUN dnf -y install rocketgit-0.46
8 9
9 10 COPY rg.sh / COPY rg.sh /
File docker/README changed (mode: 100644) (index 488fa98..5567ffe)
1 == TODO add to download page? ==
2 docker pull rocketgit/rocketgit-postgresql
3 docker run -d -P --name rp rocketgit/rocketgit-postgresql
4 docker pull rocketgit/rocketgit
5 docker run -d -P --name rg --link rp rocketgit/rocketgit
6
7
1 8 == me == == me ==
2 9 docker run -d -P --name rp rocketgit-postgresql docker run -d -P --name rp rocketgit-postgresql
3 10 docker logs rp docker logs rp
File docker/build.sh changed (mode: 100755) (index 41b6aa9..6f15072)
3 3 set -e set -e
4 4
5 5 echo "Building rocketgit-postgresql..." echo "Building rocketgit-postgresql..."
6 docker build --tag="rocketgit-postgresql" -f Dockerfile-postgresql .
6 docker build --tag="rocketgit/rocketgit-postgresql" -f Dockerfile-postgresql .
7 7
8 8 echo "Building rocketgit..." echo "Building rocketgit..."
9 docker build --tag="rocketgit" .
9 docker build --tag="rocketgit/rocketgit" .
File docker/push.sh added (mode: 100755) (index 0000000..86c474a)
1 #!/bin/bash
2
3 set -u
4 set -e
5
6 . ../duilder.conf
7
8 echo "VER=${VER}"
9
10 echo "Is it ok (y/n)?"
11 read answer
12
13 if [ "${answer}" != "y" ]; then
14 exit 1
15 fi
16
17 docker tag rocketgit-postgresql rocketgit/rocketgit-postgresql:latest
18 docker tag rocketgit-postgresql rocketgit/rocketgit-postgresql:${VER}
19 docker push rocketgit/rocketgit-postgresql
20
21 docker tag rocketgit rocketgit/rocketgit:latest
22 docker tag rocketgit rocketgit/rocketgit:${VER}
23 docker push rocketgit/rocketgit
File hooks/update changed (mode: 100755) (index 8377624..d9a3412)
... ... $a['repo_id'] = sprintf("%u", getenv("ROCKETGIT_REPO_ID"));
42 42 $a['ip'] = getenv("ROCKETGIT_IP"); $a['ip'] = getenv("ROCKETGIT_IP");
43 43 $a['namespace'] = getenv("GIT_NAMESPACE"); $a['namespace'] = getenv("GIT_NAMESPACE");
44 44 $a['repo_path'] = getenv("ROCKETGIT_REPO_PATH"); $a['repo_path'] = getenv("ROCKETGIT_REPO_PATH");
45 $a['repo_name'] = getenv("ROCKETGIT_REPO_NAME");
45 46 $a['repo_uid'] = sprintf("%u", getenv("ROCKETGIT_REPO_UID")); $a['repo_uid'] = sprintf("%u", getenv("ROCKETGIT_REPO_UID"));
46 47
47 48 rg_log("Start a=" . rg_array2string($a)); rg_log("Start a=" . rg_array2string($a));
File inc/admin.inc.php changed (mode: 100644) (index 18fd2d9..b67aba9)
... ... function rg_admin_invites_high_level($db, $rg)
159 159
160 160 $event = array( $event = array(
161 161 'category' => 6000, 'category' => 6000,
162 'prio' => 50);
162 'prio' => 50,
163 'ui' => array('uid' => $rg['login_ui']['uid']));
163 164 $event = array_merge($event, $inv); $event = array_merge($event, $inv);
164 165 $event['list'] = $list; $event['list'] = $list;
165 166 $r = rg_event_add($db, $event); $r = rg_event_add($db, $event);
File inc/bug.inc.php changed (mode: 100644) (index 9ae0346..7ae7f92)
... ... function rg_bug_edit($db, $login_ui, $ri, $data)
505 505
506 506 // TODO: seems I do not distinguish between 'add' and 'edit' // TODO: seems I do not distinguish between 'add' and 'edit'
507 507 $event = array("category" => 4100, "prio" => 200, $event = array("category" => 4100, "prio" => 200,
508 'ui' => array('uid' => $login_ui['uid']),
508 509 'ri' => array( 'ri' => array(
509 510 'repo_id' => $ri['repo_id'], 'repo_id' => $ri['repo_id'],
510 511 'name' => $ri['name']), 'name' => $ri['name']),
 
... ... function rg_bug_note_add($db, $repo_id, $bug_id, $login_uid, $data)
1020 1021 $who_added_text = $_ui['username']; $who_added_text = $_ui['username'];
1021 1022
1022 1023 $event = array("category" => 4000, "prio" => 200, $event = array("category" => 4000, "prio" => 200,
1024 'ui' => array('uid' => $login_uid),
1023 1025 'bug' => array( 'bug' => array(
1024 1026 'bug_id' => $bug_id, 'bug_id' => $bug_id,
1025 1027 'title' => $_bi['title'], 'title' => $_bi['title'],
File inc/fixes.inc.php changed (mode: 100644) (index 4dc8d88..1823204)
... ... $rg_fixes[2] = array("rg_fixes_repo_index_by_id");
17 17 $rg_fixes[3] = array("rg_fixes_keys_regen"); $rg_fixes[3] = array("rg_fixes_keys_regen");
18 18 $rg_fixes[4] = array("rg_fixes_repos_last_bug_id"); $rg_fixes[4] = array("rg_fixes_repos_last_bug_id");
19 19 $rg_fixes[5] = array("rg_fixes_wh_ver2"); $rg_fixes[5] = array("rg_fixes_wh_ver2");
20 $rg_fixes[6] = array("rg_fixes_wh_ver3");
21 $rg_fixes[7] = array("rg_fixes_wh_ver4");
20 22
21 23 // This must be the last line // This must be the last line
22 24 $rg_fixes_ver = count($rg_fixes); $rg_fixes_ver = count($rg_fixes);
 
... ... function rg_fixes_wh_ver2($db)
369 371 return $ret; return $ret;
370 372 } }
371 373
374 /*
375 * Move to the more generic webhooks structure
376 */
377 function rg_fixes_wh_ver3($db)
378 {
379 global $rg_repos;
380
381 rg_prof_start("fixes_wh_ver3");
382 rg_log_enter("fixes_wh_ver3");
383
384 $ret = FALSE;
385 while (1) {
386 $sql = "SELECT * FROM webhooks";
387 $res = rg_sql_query($db, $sql);
388 if ($res === FALSE)
389 break;
390
391 $all_fixed = TRUE;
392 while (($row = rg_sql_fetch_array($res))) {
393 if (empty($row['idata']))
394 $idata = array();
395 else
396 $idata = unserialize($row['idata']);
397 $idata['url'] = $row['url'];
398 $idata['key'] = $row['key'];
399 $idata['opaque'] = $row['opaque'];
400 $idata['events'] = $row['events'];
401
402 $params = array(
403 'id' => $row['id'],
404 'idata' => serialize($idata)
405 );
406 $sql = 'UPDATE webhooks SET idata = @@idata@@'
407 . ' WHERE id = @@id@@';
408 $res2 = rg_sql_query_params($db, $sql, $params);
409 rg_sql_free_result($res2);
410 if ($res2 === FALSE) {
411 $all_fixed = FALSE;
412 break;
413 }
414 }
415 rg_sql_free_result($res);
416 if ($all_fixed !== TRUE)
417 break;
418
419 // Remove old fileds
420 $all_good = TRUE;
421 $a = array('url', 'key', 'opaque', 'events');
422 foreach ($a as $t) {
423 $sql = 'ALTER TABLE webhooks DROP ' . $t;
424 $res = rg_sql_query($db, $sql);
425 if ($res === FALSE) {
426 rg_log('Could not drop ' . $t . '!');
427 $all_good = FALSE;
428 break;
429 }
430 rg_sql_free_result($res);
431 }
432 if (!$all_good)
433 break;
434
435 $ret = TRUE;
436 break;
437 }
438
439 rg_log_exit();
440 rg_prof_end("fixes_wh_ver3");
441 return $ret;
442 }
443
444 /*
445 * Move to the more generic webhooks structure
446 */
447 function rg_fixes_wh_ver4($db)
448 {
449 global $rg_repos;
450
451 rg_prof_start("fixes_wh_ver4");
452 rg_log_enter("fixes_wh_ver4");
453
454 $ret = FALSE;
455 while (1) {
456 $sql = "SELECT * FROM webhooks";
457 $res = rg_sql_query($db, $sql);
458 if ($res === FALSE)
459 break;
460
461 $all_fixed = TRUE;
462 while (($row = rg_sql_fetch_array($res))) {
463 if (empty($row['idata']))
464 $idata = array();
465 else
466 $idata = unserialize($row['idata']);
467 if (isset($idata['flags'])) {
468 $flags = $idata['flags'];
469 unset($idata['flags']);
470 } else {
471 $flags = '';
472 }
473
474 $params = array(
475 'id' => $row['id'],
476 'flags' => $flags,
477 'idata' => serialize($idata)
478 );
479 $sql = 'UPDATE webhooks SET flags = @@flags@@'
480 . ', idata = @@idata@@'
481 . ' WHERE id = @@id@@';
482 $res2 = rg_sql_query_params($db, $sql, $params);
483 rg_sql_free_result($res2);
484 if ($res2 === FALSE) {
485 $all_fixed = FALSE;
486 break;
487 }
488 }
489 rg_sql_free_result($res);
490 if ($all_fixed !== TRUE)
491 break;
492
493 $ret = TRUE;
494 break;
495 }
496
497 rg_log_exit();
498 rg_prof_end("fixes_wh_ver4");
499 return $ret;
500 }
501
372 502
373 503 /* /*
374 504 * Apply fixes * Apply fixes
File inc/git.inc.php changed (mode: 100644) (index 015e059..66ff96f)
... ... function rg_git_ls_tree($repo_path, $tree, $path)
455 455 break; break;
456 456 } }
457 457
458 if (empty($a['data'])) {
459 rg_git_set_error("error on ls-tree: empty answer");
460 break;
461 }
462
463 458 $output = explode("\n", trim($a['data'])); $output = explode("\n", trim($a['data']));
464 459 $ret = array(); $ret = array();
465 460 foreach ($output as $line) { foreach ($output as $line) {
 
... ... function rg_git_files($old, $new)
930 925 break; break;
931 926 } }
932 927
933 if (empty($a['data'])) {
934 rg_git_set_error("error on ls-tree: empty answer");
935 break;
936 }
937
938 928 $ret = explode("\n", trim($a['data'])); $ret = explode("\n", trim($a['data']));
939 929 break; break;
940 930 } }
 
... ... function rg_git_update_branch($db, $a)
1339 1329 $ev = $a; $ev = $a;
1340 1330 $ev['category'] = 7000; $ev['category'] = 7000;
1341 1331 $ev['prio'] = 100; $ev['prio'] = 100;
1332 $ev['ui'] = array('uid' => $a['login_uid']);
1342 1333 $r = rg_event_add($db, $ev); $r = rg_event_add($db, $ev);
1343 1334 if ($r !== TRUE) if ($r !== TRUE)
1344 1335 rg_git_fatal($a['refname'] . ": " . rg_event_error()); rg_git_fatal($a['refname'] . ": " . rg_event_error());
 
... ... function rg_git_update_branch($db, $a)
1368 1359 . rg_git_error() . ")"); . rg_git_error() . ")");
1369 1360 } }
1370 1361
1362 $ev = $a;
1363 $ev['category'] = 3007;
1364 $ev['prio'] = 50;
1365 $ev['ui'] = array('uid' => $a['login_uid']);
1366 $r = rg_event_add($db, $ev);
1367 if ($r !== TRUE)
1368 rg_git_fatal($a['refname'] . ": " . rg_event_error());
1369 rg_event_signal_daemon('', 0);
1370
1371 1371 // Here, the namespace ref is not yet updated // Here, the namespace ref is not yet updated
1372 1372 } }
1373 1373
 
... ... function rg_git_log2listing($log, $rg, $commit_table)
1626 1626 return $ret; return $ret;
1627 1627 } }
1628 1628
1629 /*
1630 * Creates an archive from a git repo
1631 */
1632 function rg_git_archive($repo_path, $treeish, $archive_name, $format)
1633 {
1634 rg_prof_start('git_archive');
1635 rg_log_enter('git_archives repo_path=' . $repo_path
1636 . ' treeish=' . $treeish
1637 . ' archive_name=' . $archive_name
1638 . ' format=' . $format);
1639
1640 $ret = FALSE;
1641 while (1) {
1642 $cmd = 'git --git-dir=' . escapeshellarg($repo_path)
1643 . ' archive --format=' . escapeshellarg($format)
1644 . ' --output=' . escapeshellarg($archive_name)
1645 . ' ' . escapeshellarg($treeish);
1646 $a = rg_exec($cmd);
1647 if ($a['ok'] != 1) {
1648 rg_git_set_error('error on git archive'
1649 . ' (' . $a['errmsg'] . ')');
1650 break;
1651 }
1652
1653 $ret = TRUE;
1654 break;
1655 }
1656
1657 rg_log_exit();
1658 rg_prof_end("git_archive");
1659 return $ret;
1660 }
1661
1629 1662 ?> ?>
File inc/repo.inc.php changed (mode: 100644) (index 35f844a..8197ddf)
... ... $rg_repo_functions = array(
358 358 3003 => "rg_repo_event_notify_user", 3003 => "rg_repo_event_notify_user",
359 359 3004 => "rg_repo_event_symlink_by_name", 3004 => "rg_repo_event_symlink_by_name",
360 360 3005 => "rg_repo_event_storage_create", 3005 => "rg_repo_event_storage_create",
361 3006 => "rg_repo_history_insert"
361 3006 => "rg_repo_history_insert",
362 3007 => 'rg_repo_event_push'
362 363 ); );
363 364 rg_event_register_functions($rg_repo_functions); rg_event_register_functions($rg_repo_functions);
364 365
 
... ... function rg_repo_event_new($db, $event)
394 395
395 396 // webhook // webhook
396 397 $x = $event; $x = $event;
397 $x['category'] = 10000;
398 $x['category'] = 30000;
398 399 $x['prio'] = 50; $x['prio'] = 50;
399 400 $x['wh_event'] = 'C'; // see rg_wh_events array $x['wh_event'] = 'C'; // see rg_wh_events array
400 401 $ri = &$event['ri']; $ri = &$event['ri'];
 
... ... function rg_repo_history_insert($db, $event)
641 642 return $ret; return $ret;
642 643 } }
643 644
645 /*
646 * Event for pushing into a repo
647 */
648 function rg_repo_event_push($db, $event)
649 {
650 $ret = array();
651
652 // notify user
653 if (0) { // TODO
654 $x = $event;
655 $x['category'] = 3003;
656 $x['prio'] = 100;
657 $x['notification'] .= "-notify";
658 $ret[] = $x;
659 }
660
661 // webhook
662 $x = $event;
663 $x['category'] = 30000;
664 $x['wh_event'] = 'P'; // push
665 $ret[] = $x;
666
667 // TODO: notify watchers of the user
668
669 return $ret;
670 }
671
644 672 /* /*
645 673 * Returns last events from repo_history * Returns last events from repo_history
646 674 * @category: 0 for any * @category: 0 for any
File inc/struct.inc.php changed (mode: 100644) (index 09c3ed3..ffe5018)
... ... $rg_sql_struct[36]['other'] = array(
506 506 'watch_user_i_uid' => "CREATE INDEX watch_user_i_uid on watch_repo(uid)" 'watch_user_i_uid' => "CREATE INDEX watch_user_i_uid on watch_repo(uid)"
507 507 ); );
508 508
509 $rg_sql_struct[37]['other'] = array(
510 'webhooks - flags is back' =>
511 "ALTER TABLE webhooks ADD flags TEXT NOT NULL DEFAULT ''"
512 );
513
509 514 // This must be the last line // This must be the last line
510 515 $rg_sql_schema_ver = count($rg_sql_struct); $rg_sql_schema_ver = count($rg_sql_struct);
511 516
File inc/util.inc.php changed (mode: 100644) (index 683a12e..c5ac91d)
... ... function rg_re_repo_git($organization, $user, $repo)
272 272
273 273 function rg_var_get($name) function rg_var_get($name)
274 274 { {
275 $ret = FALSE;
276
277 275 if (isset($_SERVER[$name])) if (isset($_SERVER[$name]))
278 276 $ret = $_SERVER[$name]; $ret = $_SERVER[$name];
279 277 else if (isset($_POST[$name])) else if (isset($_POST[$name]))
280 278 $ret = $_POST[$name]; $ret = $_POST[$name];
281 279 else if (isset($_GET[$name])) else if (isset($_GET[$name]))
282 280 $ret = $_GET[$name]; $ret = $_GET[$name];
281 else
282 return FALSE;
283 283
284 return $ret;
284 return str_replace("\r", "", $ret);
285 285 } }
286 286
287 287 function rg_var_is_set($name) function rg_var_is_set($name)
 
... ... function rg_age($ts)
1568 1568 return $ret; return $ret;
1569 1569 } }
1570 1570
1571 /*
1572 * Creates a temporary file name and returns it
1573 */
1574 function rg_tmp_file_name($file)
1575 {
1576 global $rg_state_dir;
1577
1578 return $rg_state_dir . '/tmp/' . $file;
1579 }
1580
1571 1581 /* /*
1572 1582 * Creates a temporary file * Creates a temporary file
1573 1583 */ */
 
... ... function rg_fix_ip($ip)
1613 1623 return $ip; return $ip;
1614 1624 } }
1615 1625
1626 /*
1627 * Escape json fields - TODO - for now do nothing
1628 */
1629 function rg_json_escape($s)
1630 {
1631 return $s;
1632 }
1633
1616 1634 ?> ?>
File inc/webhooks.inc.php changed (mode: 100644) (index 37920bd..3f2155c)
... ... require_once($INC . "/log.inc.php");
4 4 require_once($INC . "/sql.inc.php"); require_once($INC . "/sql.inc.php");
5 5 require_once($INC . "/prof.inc.php"); require_once($INC . "/prof.inc.php");
6 6 require_once($INC . "/wh/http.inc.php"); require_once($INC . "/wh/http.inc.php");
7 require_once($INC . "/wh/cloud.inc.php");
8 require_once($INC . "/wh/lambda.inc.php");
9
10 $rg_wh_functions = array(
11 30000 => 'rg_wh_send',
12 );
13 rg_event_register_functions($rg_wh_functions);
14
15 function rg_wh_send($db, $ev)
16 {
17 rg_log_ml('wh_send: ev: ' . print_r($ev, TRUE));
18
19 $ret = array();
20
21 $x = $ev;
22 $x['category'] = 10000;
23 $ret[] = $x;
24
25 // we add a cloud event, only for pushes
26 if (strcmp($ev['wh_event'], "P") == 0) {
27 $x = $ev;
28 $x['category'] = 20000;
29 $ret[] = $x;
30 }
31
32 return $ret;
33 }
7 34
8 35 /* /*
9 36 * High level function to list the webhooks * High level function to list the webhooks
 
... ... function rg_wh_list_high_level($db, $rg, $paras)
68 95 /* /*
69 96 * High level function to add/edit a web hook * High level function to add/edit a web hook
70 97 */ */
71 function rg_wh_add_high_level($db, $rg, $paras)
98 function rg_wh_add_high_level($db, $rg, $op, $paras)
72 99 { {
73 100 rg_prof_start('wh_add_high_level'); rg_prof_start('wh_add_high_level');
74 rg_log_enter('wh_add_high_level');
101 rg_log_enter('wh_add_high_level op=' . $op);
75 102
76 103 rg_log('DEBUG: paras:' . rg_array2string($paras)); rg_log('DEBUG: paras:' . rg_array2string($paras));
77 104
 
... ... function rg_wh_add_high_level($db, $rg, $paras)
80 107 $show_form = TRUE; $show_form = TRUE;
81 108
82 109 $rg['wh'] = array(); $rg['wh'] = array();
83 $rg['wh']['htype'] = rg_var_str('wh::htype');
84 // We need the id in any case
85 if (isset($paras[0])) {
86 $rg['wh']['id'] = intval($paras[0]);
87 } else {
88 $rg['wh']['id'] = rg_var_uint('wh::id');
110
111 if (strcmp($op, 'add') == 0) {
112 $rg['wh']['htype'] = array_shift($paras);
113 $rg['wh']['id'] = 0;
114
115 if (!rg_wh_valid($rg['wh']['htype']))
116 $rg['wh']['htype'] = '';
89 117
90 118 if (empty($rg['wh']['htype'])) { if (empty($rg['wh']['htype'])) {
91 119 $ret .= rg_wh_htypes($rg); $ret .= rg_wh_htypes($rg);
92 120 $show_form = FALSE; $show_form = FALSE;
93 121 } }
94
122 } else { // edit
123 $rg['wh']['htype'] = rg_var_str('wh::htype');
124 if (isset($paras[0]))
125 $rg['wh']['id'] = intval($paras[0]);
126 else
127 $rg['wh']['id'] = 0;
95 128 } }
96 129 rg_log('DEBUG: wh::id=' . $rg['wh']['id']); rg_log('DEBUG: wh::id=' . $rg['wh']['id']);
130 rg_log('DEBUG: wh::htype=' . $rg['wh']['htype']);
97 131
98 $add = rg_var_uint('add');
99 while ($add == 1) {
100 $rg['wh']['repo_id'] = rg_var_uint('wh::repo_id');
101 $rg['wh']['itime'] = time();
102 $rg['wh']['events'] = rg_var_a2s('wh::events'); // TODO
103 $rg['wh']['url'] = rg_var_str('wh::url');
104 $rg['wh']['add_ip'] = isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : '';
105 $rg['wh']['description'] = trim(rg_var_str('wh::description'));
106 $rg['wh']['opaque'] = rg_var_str('wh::opaque');
107 $rg['wh']['key'] = rg_var_str('wh::key');
132 $doit = rg_var_uint('doit');
133 while ($doit == 1) {
108 134 rg_wh_fill_vars($rg); rg_wh_fill_vars($rg);
109 135
110 136 $r = rg_wh_validate_vars($rg, $errmsg); $r = rg_wh_validate_vars($rg, $errmsg);
 
... ... function rg_wh_add_high_level($db, $rg, $paras)
136 162
137 163 $hints = array(); $hints = array();
138 164 if ($show_form) { if ($show_form) {
139 // defaults
140 if ($add == 0) {
141 // TODO: if edit, load data based on id
142 if ($rg['wh']['id'] > 0) {
165 if ($doit == 0) {
166 if (strcmp($op, 'add') == 0) {
167 rg_wh_default_paras($rg);
168 } else { // edit
143 169 $r = rg_wh_list($db, $rg['login_ui']['uid']); $r = rg_wh_list($db, $rg['login_ui']['uid']);
144 170 if ($r['ok'] != 1) { if ($r['ok'] != 1) {
145 171 $errmsg[] = 'cannot load webhook info; try again later'; $errmsg[] = 'cannot load webhook info; try again later';
 
... ... function rg_wh_add_high_level($db, $rg, $paras)
148 174 } else { } else {
149 175 $rg['wh'] = $r['list'][$rg['wh']['id']]; $rg['wh'] = $r['list'][$rg['wh']['id']];
150 176 } }
151 } else {
152 // here is clear an add
153 $rg['wh']['id'] = 0;
154 $rg['wh']['events'] = '';
155 $rg['wh']['url'] = '';
156 $rg['wh']['description'] = '';
157 $rg['wh']['opaque'] = '';
158 $rg['wh']['key'] = '';
159 rg_wh_default_paras($rg);
160 177 } }
161 178 } }
162 179
 
... ... function rg_wh_add_high_level($db, $rg, $paras)
167 184 rg_wh_fill_hints($rg, $hints); rg_wh_fill_hints($rg, $hints);
168 185
169 186 $rg['HTML:errmsg'] = rg_template_errmsg($errmsg); $rg['HTML:errmsg'] = rg_template_errmsg($errmsg);
170 $rg['HTML:check_events'] = rg_wh_check_events($rg['wh']['events']);
171 187 $rg['rg_form_token'] = rg_token_get($db, $rg, 'wh_add'); $rg['rg_form_token'] = rg_token_get($db, $rg, 'wh_add');
172 188 $ret .= rg_template('user/settings/wh/add_edit.html', $ret .= rg_template('user/settings/wh/add_edit.html',
173 189 $rg, TRUE /*xss*/); $rg, TRUE /*xss*/);
 
... ... function rg_wh_high_level($db, $rg, $paras)
202 218 switch ($op) { switch ($op) {
203 219 case 'add': case 'add':
204 220 case 'edit': case 'edit':
205 $ret .= rg_wh_add_high_level($db, $rg, $paras);
221 $ret .= rg_wh_add_high_level($db, $rg, $op, $paras);
206 222 break; break;
207 223
208 224 default: default:
File inc/wh/amazon.inc.php added (mode: 100644) (index 0000000..c8f3c4d)
1 <?php
2
3 /*
4 * Builds the signature for a request
5 */
6 function rg_amazon_auth($a)
7 {
8 rg_prof_start('amazon_auth');
9 rg_log_enter('amazon_auth');
10 rg_log_ml('a: ' . print_r($a, TRUE));
11
12 $ret = array('ok' => 0);
13 while (1) {
14 $iheaders_final = array();
15 $iheaders_list = array();
16 foreach ($a['iheaders'] as $head => $val) {
17 $iheaders_final[] = strtolower($head)
18 . ':' . trim($val);
19 $iheaders_list[] = strtolower($head);
20 }
21 asort($iheaders_list);
22 asort($iheaders_final);
23 $iheaders_list = implode(';', $iheaders_list);
24 $iheaders_final = implode("\n", $iheaders_final) . "\n\n";
25
26 $canonical_request = $a['method'] . "\n"
27 . '/' . urlencode($a['file']) . "\n"
28 . "\n"
29 . $iheaders_final
30 . $iheaders_list . "\n"
31 . bin2hex($a['x-amz-content-sha256']);
32 rg_log_ml('canonical_request:' . "\n" . $canonical_request
33 . "\n" . '===');
34
35 $string_to_sign = 'AWS4-HMAC-SHA256' . "\n"
36 . $a['x-amz-date'] . "\n"
37 . gmdate('Ymd', $a['ts'])
38 . '/' . $a['region']
39 . '/' . $a['service']
40 . '/' . 'aws4_request'
41 . "\n"
42 . hash('sha256', $canonical_request);
43 rg_log_ml('string_to_sign:' . "\n" . $string_to_sign
44 . "\n" . '===');
45
46 $date_key = hash_hmac('sha256', gmdate('Ymd', $a['ts']),
47 'AWS4' . $a['secret_access_key'], TRUE);
48 $date_region_key = hash_hmac('sha256', $a['region'],
49 $date_key, TRUE);
50 $date_region_service_key = hash_hmac('sha256',
51 $a['service'], $date_region_key, TRUE);
52 $signing_key = hash_hmac('sha256', 'aws4_request',
53 $date_region_service_key, TRUE);
54 $signature = hash_hmac('sha256', $string_to_sign, $signing_key);
55 rg_log('DEBUG: signature=' . $signature);
56
57 $cred = $a['access_key_id']
58 . '/' . gmdate('Ymd')
59 . '/' . $a['region']
60 . '/' . $a['service']
61 . '/aws4_request';
62
63 $ret['data'] = 'AWS4-HMAC-SHA256'
64 . ' Credential=' . $cred
65 . ', SignedHeaders=' . $iheaders_list
66 . ', Signature=' . $signature;
67 $ret['ok'] = 1;
68 break;
69 }
70
71 rg_log_exit();
72 rg_prof_end('amazon_auth');
73 return $ret;
74 }
75
76 /*
77 * Make a generic request to the amazon
78 */
79 function rg_amazon_req($a)
80 {
81 rg_prof_start('amazon_req');
82 rg_log_enter('amazon_req');
83 rg_log_ml('DEBUG: a:' . print_r($a, TRUE));
84
85 $ret = array('ok' => 0);
86 while (1) {
87 $url = 'https://' . $a['host'] . '/' . urlencode($a['file']);
88 $c = curl_init($url);
89 if ($c === FALSE) {
90 $ret['error'] = 'cannot init curl';
91 break;
92 }
93
94 $a['region'] = trim(strtolower($a['region']));
95
96 $a['ts'] = time();
97 $a['x-amz-date'] = gmdate('Ymd', $a['ts'])
98 . 'T' . gmdate('His', $a['ts']) . 'Z';
99 $a['x-amz-content-sha256'] = hash('sha256', $a['content'], TRUE);
100 $a['host'] = trim(strtolower($a['host']));
101 $a['service'] = trim(strtolower($a['service']));
102
103 if (!isset($a['iheaders']))
104 $a['iheaders'] = array();
105 $a['iheaders']['Host'] = $a['host'];
106 $a['iheaders']['x-amz-date'] = $a['x-amz-date'];
107 $a['iheaders']['x-amz-content-sha256'] = bin2hex($a['x-amz-content-sha256']);
108
109 $auth = rg_amazon_auth($a);
110 if ($auth['ok'] != 1) {
111 $ret['error'] = $auth['error'];
112 break;
113 }
114
115 $headers = array();
116 if (isset($a['content_type']))
117 $headers[] = 'Content-Type: ' . $a['content_type'];
118 $headers[] = 'Authorization: ' . $auth['data'];
119 foreach ($a['iheaders'] as $head => $val)
120 $headers[] = $head . ': ' . $val;
121 //rg_log_ml('HEADERS:' . print_r($headers, TRUE));
122
123 curl_setopt($c, CURLOPT_CUSTOMREQUEST, $a['method']);
124 //curl_setopt($c, CURLOPT_POST, 1);
125 curl_setopt($c, CURLOPT_POSTFIELDS, $a['content']);
126 curl_setopt($c, CURLOPT_RETURNTRANSFER, TRUE);
127 curl_setopt($c, CURLOPT_FOLLOWLOCATION, 1);
128 //curl_setopt($c, CURLOPT_HEADER, 1);
129 curl_setopt($c, CURLOPT_HTTPHEADER, $headers);
130 curl_setopt($c, CURLOPT_USERAGENT, 'RocketGit Cloud client');
131 curl_setopt($c, CURLOPT_CONNECTTIMEOUT, 30);
132 curl_setopt($c, CURLOPT_ENCODING, ''); // => use all methods
133 curl_setopt($c, CURLOPT_VERBOSE, TRUE);
134 curl_setopt($c, CURLOPT_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS);
135 //curl_setopt($c, CURLOPT_CERTINFO, TRUE);
136
137 $err = @fopen('php://temp', 'w');
138 if ($err !== FALSE)
139 curl_setopt($c, CURLOPT_STDERR, $err);
140
141 $r = curl_exec($c);
142 rg_log_ml('DEBUG: curl_exec returned: ' . $r);
143
144 if ($err !== FALSE) {
145 rewind($err);
146 $xerr = @fread($err, 16 * 4096);
147 fclose($err);
148 $ret['debug'] = $xerr;
149 rg_log_ml('xerr=' . $xerr);
150 }
151
152 if ($r === FALSE) {
153 $ret['error'] = curl_error($c);
154
155 $_info = curl_getinfo($c);
156 rg_log_ml('Debug: ' . print_r($_info, TRUE));
157 break;
158 }
159
160 $_info = curl_getinfo($c);
161 rg_log_ml('Debug: ' . print_r($_info, TRUE));
162
163 if ($_info['http_code'] != 200) {
164 $ret['error'] = $r;
165 break;
166 }
167
168 $ret['ok'] = 1;
169 $ret['answer'] = $r;
170 break;
171 }
172 curl_close($c);
173
174 rg_log_exit();
175 rg_prof_end('amazon_req');
176 return $ret;
177 }
178
179 /*
180 *
181 * @bucket contains the domain part (s3.amazonaws.com for example)
182 */
183 function rg_amazon_s3_put_object($a, $content)
184 {
185 rg_prof_start('amazon_s3_put_object');
186 rg_log_enter('amazon_s3_put_object');
187 rg_log_ml('a: ' . print_r($a, TRUE));
188
189 $ret = array('ok' => 0);
190 while (1) {
191 $a['service'] = 's3';
192 $a['method'] = 'PUT';
193 $a['host'] = $a['bucket'] . '.' . $a['service'] . '.'
194 . $a['region'] . '.amazonaws.com';
195 $a['content'] = $content;
196
197 $ret = rg_amazon_req($a);
198 break;
199 }
200
201 rg_log_exit();
202 rg_prof_end('amazon_s3_put_object');
203 return $ret;
204 }
205
206 /*
207 * Create a code deploy
208 * http://docs.aws.amazon.com/codedeploy/latest/APIReference/API_CreateDeployment.html
209 */
210 function rg_amazon_codedeploy_create($a)
211 {
212 rg_prof_start('amazon_codedeploy_create');
213 rg_log_ml_enter('amazon_codedeploy_create');
214
215 if (empty($a['deployment_config_name']))
216 $a['deployment_config_name'] = 'CodeDeployDefault.OneAtATime';
217
218 // do the codedeploy - we may want to add "version" to "s3Location"
219 $json = '{'
220 . '"applicationName": "' . rg_json_escape($a['application_name']) . '"'
221 . ', "deploymentGroupName": "' . rg_json_escape($a['deployment_group_name']) . '"'
222 . ', "description": "test description"'
223 . ', "deploymentConfigName": "' . rg_json_escape($a['deployment_config_name']) . '"'
224 . ', "ignoreApplicationStopFailures": ' . (strchr($a['flags'], 'I') ? 'true' : 'false')
225 . ', "revision": {'
226 . '"revisionType": "S3"'
227 . ', "s3Location": {'
228 . '"bundleType": "zip"'
229 . ', "bucket": "' . rg_json_escape($a['bucket']) . '"'
230 . ', "key": "' . rg_json_escape($a['file']) . '"'
231 . '}'
232 . '}'
233 . '}';
234
235 $ret = array('ok' => 0);
236 while (1) {
237 $a['service'] = 'codedeploy';
238 $a['method'] = 'POST';
239 $a['file'] = '';
240 $a['host'] = $a['service'] . '.' . $a['region'] . '.amazonaws.com';
241 $a['iheaders'] = array('x-amz-target' => 'CodeDeploy_20141006.CreateDeployment');
242 $a['content'] = $json;
243 $a['content_type'] = 'application/x-amz-json-1.1';
244
245 $ret = rg_amazon_req($a);
246 break;
247 }
248
249 rg_log_exit();
250 rg_prof_end('amazon_codedeploy_create');
251 return $ret;
252 }
253
254 /*
255 * Calls an Amazon Lambda function
256 * http://docs.aws.amazon.com/lambda/latest/dg/API_Invoke.html
257 */
258 function rg_amazon_lambda_invoke($a)
259 {
260 rg_prof_start('amazon_lambda_invoke');
261 rg_log_ml_enter('amazon_lambda_invoke');
262
263 if (!isset($a['invocation_type']))
264 $a['invocation_type'] = 'RequestResponse';
265
266 $ret = array('ok' => 0);
267 while (1) {
268 $a['service'] = 'lambda';
269 $a['method'] = 'POST';
270 $a['file'] = '2015-03-31/functions/' . $a['function']
271 . '/invocations';
272 $a['host'] = $a['service'] . '.' . $a['region'] . '.amazonaws.com';
273 $a['iheaders'] = array(
274 'x-Amz-Client-Context' => '',
275 'x-Amz-Invocation-Type' => $a['invocation_type'],
276 'x-Amz-Log-Type' => 'Tail');
277
278 $ret = rg_amazon_req($a);
279 break;
280 }
281
282 rg_log_exit();
283 rg_prof_end('amazon_lambda_invoke');
284 return $ret;
285 }
286
287 /*
288 * Generic cosmetic for Amazon
289 */
290 function rg_wh_amazon_cosmetic(&$row)
291 {
292 $a = $row['idata']['access_key_id'];
293 $row['idata']['HTML:access_key_id_secure'] =
294 rg_xss_safe(substr($a, 0, 1) . '...' . substr($a, -1, 1));
295
296 $a = $row['idata']['secret_access_key'];
297 $row['idata']['HTML:secret_access_key_secure'] =
298 rg_xss_safe(substr($a, 0, 1) . '...' . substr($a, -1, 1));
299 }
300
301 /*
302 * Generic fill_vars for Amazon
303 */
304 function rg_wh_amazon_fill_vars(&$a)
305 {
306 $a['access_key_id'] = trim(rg_var_str('wh::idata::access_key_id'));
307 $a['secret_access_key'] = trim(rg_var_str('wh::idata::secret_access_key'));
308 $a['region'] = trim(rg_var_str('wh::idata::region'));
309 }
310
311 /*
312 * Generic validation for Amazon
313 */
314 function rg_wh_amazon_validate_vars($a, &$errmsg)
315 {
316 $ret = FALSE;
317 while (1) {
318 if (empty($a['access_key_id'])) {
319 $errmsg[] = rg_template('user/settings/wh/amazon/inv_access_key_id.txt',
320 $rg, TRUE /*xss*/);
321 break;
322 }
323
324 if (empty($a['secret_access_key'])) {
325 $errmsg[] = rg_template('user/settings/wh/amazon/inv_secret_access_key.txt',
326 $rg, TRUE /*xss*/);
327 break;
328 }
329
330 if (empty($a['region'])) {
331 $errmsg[] = rg_template('user/settings/wh/amazon/inv_region.txt',
332 $rg, TRUE /*xss*/);
333 break;
334 }
335
336 $ret = TRUE;
337 break;
338 }
339
340 return $ret;
341 }
342
343 /*
344 * Generic default_paras for Amazon
345 */
346 function rg_wh_amazon_default_paras(&$a)
347 {
348 $a['region'] = '';
349 $a['access_key_id'] = '';
350 $a['secret_access_key'] = '';
351 }
352
353 ?>
File inc/wh/cloud.inc.php added (mode: 100644) (index 0000000..5c43e4b)
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 . "/prof.inc.php");
6 require_once($INC . "/events.inc.php");
7 require_once($INC . "/wh/core.inc.php");
8 require_once($INC . "/wh/amazon.inc.php");
9
10 $rg_wh_cloud_functions = array(
11 20000 => 'rg_wh_cloud_send',
12 20001 => 'rg_wh_cloud_send_one'
13 );
14 rg_event_register_functions($rg_wh_cloud_functions);
15
16
17 /*
18 * Helper for rg_wh_cloud_send
19 */
20 function rg_wh_cloud_send_one($db, $event)
21 {
22 rg_prof_start('wh_cloud_send_one');
23 rg_log_ml('wh_cloud_send_one: event: ' . print_r($event, TRUE));
24
25 $ret = FALSE;
26
27 $wh = &$event['wh'];
28 $info = &$wh['info'];
29
30 $xid = rg_id(8);
31 $f = 'wh-' . $event['ui']['uid'] . '-' . $wh['id'] . '-' . $xid . '.zip';
32 $path = rg_tmp_file_name($f);
33
34 $last_output = '';
35 while (1) {
36 // TODO: cache the output?
37 // generate archive (TODO: specify branch)
38 // TODO: the id of the commit should be passed to the hook, else another
39 // push will "destroy" the reference.
40 $r = rg_git_archive($event['repo_path'], $event['new_rev'],
41 $path, 'zip');
42 if ($r === FALSE) {
43 $last_output .= rg_git_error();
44 break;
45 }
46
47 // replace ##tags##
48 rg_wh_replace_tags($event);
49
50 // store to s3
51 $info['idata']['content_type'] = 'application/zip';
52 // we need to copy 'flags' because we pass idata
53 $info['idata']['flags'] = $info['flags'];
54 $c = @file_get_contents($path);
55 if ($c === FALSE) {
56 $last_output .= 'missing archive; very strange!';
57 break;
58 }
59 $r = rg_amazon_s3_put_object($info['idata'], $c);
60 if ($r['ok'] != 1) {
61 $last_output .= $r['error'];
62 break;
63 }
64 $last_output .= 'S3: ' . $r['answer'];
65
66 // c = skip the CodeDeploy step
67 if (!strchr($info['flags'], 'c')) {
68 // Do the code deploy
69 $r = rg_amazon_codedeploy_create($info['idata']);
70 if ($r['ok'] != 1) {
71 $last_output .= $r['error'];
72 break;
73 }
74
75 $last_output .= "\n" . 'CodeDeploy: ' . $r['answer'];
76 }
77
78 $ret = array();
79 break;
80 }
81 @unlink($path);
82
83 rg_wh_set_last_output($db, $event['ui']['uid'], $wh['id'],
84 substr($last_output, 0, 4096));
85
86 if ($info['idata']['debug'] == 1)
87 rg_cache_set('DEBUG::' . $event['ui']['uid']
88 . '::webhooks::' . $wh['id'], $last_output,
89 RG_SOCKET_NO_WAIT);
90
91 rg_prof_end('wh_cloud_send_one');
92 return $ret;
93 }
94
95 /*
96 * Generic function which will be called when a webhook must be posted
97 */
98 function rg_wh_cloud_send($db, $event)
99 {
100 rg_prof_start('wh_cloud_send');
101 rg_log_ml('wh_cloud_send: event: ' . print_r($event, TRUE));
102
103 $ret = array();
104
105 // First, get the list of hooks
106 $r = rg_wh_list($db, $event['ui']['uid']);
107 if ($r['ok'] != 1)
108 return FALSE;
109
110 // Filter them by repo_id
111 foreach ($r['list'] as $id => $info) {
112 if (($info['repo_id'] > 0)
113 && ($event['repo_id'] != $info['repo_id'])) {
114 rg_log('hook is not for this repo');
115 continue;
116 }
117
118 if (strcmp($info['htype'], 'cloud') != 0)
119 continue;
120
121 // Diabled?
122 if (strchr($info['flags'], 'D'))
123 continue;
124
125 $wh = array();
126 $wh['id'] = $id;
127 $wh['info'] = $info;
128
129 $x = $event;
130 $x['category'] = 20001;
131 $x['wh'] = $wh;
132 $ret[] = $x;
133 }
134
135 rg_prof_end('wh_cloud_send');
136 return $ret;
137 }
138
139 /*
140 * Some cosmetics applied to a webhook
141 */
142 function rg_wh_cloud_cosmetic(&$row)
143 {
144 rg_wh_amazon_cosmetic($row);
145
146 $row['idata']['HTML:private'] = rg_template(
147 'user/settings/wh/cloud/show.html', $row['idata'], TRUE /*xss*/);
148 }
149
150 /*
151 * Fill private data based on parameters passed
152 */
153 function rg_wh_cloud_fill_vars(&$rg)
154 {
155 $a = &$rg['wh']['idata'];
156 rg_wh_amazon_fill_vars($a);
157 $a['application_name'] = trim(rg_var_str('wh::idata::application_name'));
158 $a['deployment_group_name'] = trim(rg_var_str('wh::idata::deployment_group_name'));
159 $a['deployment_config_name'] = trim(rg_var_str('wh::idata::deployment_config_name'));
160 $a['bucket'] = trim(rg_var_str('wh::idata::bucket'));
161 $a['file'] = trim(rg_var_str('wh::idata::file'));
162 }
163
164 /*
165 * Validate parameters passed
166 */
167 function rg_wh_cloud_validate_vars($rg, &$errmsg)
168 {
169 global $rg_wh_cloud_itypes;
170
171 $a = $rg['wh'];
172
173 $ret = FALSE;
174 while (1) {
175 if (!rg_wh_amazon_validate_vars($a['idata'], $errmsg))
176 break;
177
178 if (empty($a['idata']['bucket'])) {
179 $errmsg[] = rg_template('user/settings/wh/cloud/inv_bucket.txt',
180 $rg, TRUE /*xss*/);
181 break;
182 }
183
184 // c = skip the CodeDeploy step
185 if (strchr($a['flags'], 'c')) {
186 $ret = TRUE;
187 break;
188 }
189
190 if (empty($a['idata']['application_name'])) {
191 $errmsg[] = rg_template('user/settings/wh/cloud/inv_app_name.txt',
192 $rg, TRUE /*xss*/);
193 break;
194 }
195
196 if (empty($a['idata']['deployment_group_name'])) {
197 $errmsg[] = rg_template('user/settings/wh/cloud/inv_group_name.txt',
198 $rg, TRUE /*xss*/);
199 break;
200 }
201
202 $ret = TRUE;
203 break;
204 }
205
206 return $ret;
207 }
208
209 /*
210 * Transfers to $rg the custom parameters - used when showing the form
211 */
212 function rg_wh_cloud_add_form(&$rg)
213 {
214 $rg['HTML:custom_form'] = rg_template('user/settings/wh/cloud/form.html',
215 $rg, TRUE /*xss*/);
216 }
217
218 /*
219 * Add custom hints
220 */
221 function rg_wh_cloud_fill_hints($rg, &$hints)
222 {
223 $hints[]['HTML:hint'] = rg_template('user/settings/wh/cloud/hints.html',
224 $rg, TRUE /*xss*/);
225 }
226
227 /*
228 * Loads default paras for a form
229 */
230 function rg_wh_cloud_default_paras(&$rg)
231 {
232 $a = &$rg['wh']['idata'];
233 rg_wh_amazon_default_paras($a);
234 $a['application_name'] = '';
235 $a['deployment_group_name'] = '';
236 $a['deployment_config_name'] = '';
237 $a['bucket'] = '';
238 $a['file'] = '';
239 }
240
241
242
243 $rg_wh_plugins['cloud'] = array(
244 'htype' => 'cloud',
245 'description' => 'Store into Amazon S3 and (optionally) do a CodeDeploy',
246 'cosmetic' => 'rg_wh_cloud_cosmetic',
247 'html_form' => 'rg_wh_cloud_form',
248 'fill_vars' => 'rg_wh_cloud_fill_vars',
249 'validate_vars' => 'rg_wh_cloud_validate_vars',
250 'add_form' => 'rg_wh_cloud_add_form',
251 'default_paras' => 'rg_wh_cloud_default_paras',
252 'fill_hints' => 'rg_wh_cloud_fill_hints',
253 'have_events' => FALSE,
254 'flags' => array(
255 'I' => 'Ignore application stop failures',
256 'c' => 'Skip the CodeDeploy step'
257 )
258 );
259
260 ?>
File inc/wh/core.inc.php changed (mode: 100644) (index b687018..1b6ec6b)
... ... function rg_wh_error()
23 23 // Here plugins will store the functions // Here plugins will store the functions
24 24 $rg_wh_plugins = array(); $rg_wh_plugins = array();
25 25
26 $rg_wh_flags = array(
27 'D' => 'Hook disabled'
28 );
29
26 30 $rg_wh_events = array( $rg_wh_events = array(
27 31 'C' => 'Create repository', 'C' => 'Create repository',
28 32 'P' => 'Push', 'P' => 'Push',
29 33 'B' => 'Create branch' 'B' => 'Create branch'
30 34 ); );
35
31 36 /* /*
32 37 * Generates event list as html * Generates event list as html
33 38 */ */
 
... ... function rg_wh_check_events($events)
35 40 { {
36 41 global $rg_wh_events; global $rg_wh_events;
37 42
43 if (empty($rg_wh_events))
44 return '';
45
38 46 $ret = '<fieldset>'; $ret = '<fieldset>';
39 47 $ret .= '<legend>Select trigger events</legend>'; $ret .= '<legend>Select trigger events</legend>';
40 48 $br = ''; $br = '';
 
... ... function rg_wh_check_events($events)
44 52 $add = ' checked="checked"'; $add = ' checked="checked"';
45 53
46 54 $ret .= $br $ret .= $br
47 . '<input type="checkbox" name="wh::events[' . $id . ']"'
55 . '<input type="checkbox" name="wh::idata::events[' . $id . ']"'
48 56 . ' id="events-' . $id . '"' . ' id="events-' . $id . '"'
49 57 . $add . ' />' . $add . ' />'
50 58 . "\n" . "\n"
 
... ... function rg_wh_events($events)
72 80 return implode(', ', $a); return implode(', ', $a);
73 81 } }
74 82
83 /*
84 * Generates flags list
85 */
86 function rg_wh_check_flags($all_flags, $flags)
87 {
88 global $rg_wh_flags;
89
90 $ret = '';
91 $br = '';
92 $list = array_merge($rg_wh_flags, $all_flags);
93 foreach ($list as $id => $name) {
94 $add = '';
95 if (strchr($flags, $id))
96 $add = ' checked="checked"';
97
98 $ret .= $br
99 . '<input type="checkbox" name="wh::flags[' . $id . ']"'
100 . ' id="flags-' . $id . '"'
101 . $add . ' />'
102 . "\n"
103 . '<label for="flags-' . $id . '">' . $name . '</label>';
104 $br = '<br />' . "\n";
105 }
106
107 return $ret;
108 }
109
110 /*
111 * Generates a flags list as text
112 */
113 function rg_wh_flags($all_flags, $flags)
114 {
115 global $rg_wh_flags;
116
117 $a = array();
118 $list = array_merge($rg_wh_flags, $all_flags);
119 foreach ($list as $id => $name) {
120 if (strchr($flags, $id))
121 $a[] = $name;
122 }
123
124 return implode(', ', $a);
125 }
126
75 127 /* /*
76 128 * Some cosmetics applied to a webhook * Some cosmetics applied to a webhook
77 129 */ */
 
... ... function rg_wh_cosmetic(&$list)
80 132 global $rg_wh_plugins; global $rg_wh_plugins;
81 133
82 134 foreach ($list as $id => &$row) { foreach ($list as $id => &$row) {
135 $t = $row['htype'];
136
83 137 if (isset($row['itime'])) if (isset($row['itime']))
84 138 $row['itime_nice'] = gmdate('Y-m-d H:i', $row['itime']); $row['itime_nice'] = gmdate('Y-m-d H:i', $row['itime']);
85 139
140 $row['HTML:flags_text'] =
141 rg_wh_flags($rg_wh_plugins[$t]['flags'],
142 $row['flags']);
143
86 144 if (isset($row['description'])) { if (isset($row['description'])) {
87 145 if (empty($row['description'])) if (empty($row['description']))
88 146 $row['HTML:description_nice'] = 'n/a'; $row['HTML:description_nice'] = 'n/a';
 
... ... function rg_wh_cosmetic(&$list)
91 149 nl2br(rg_xss_safe($row['description'])); nl2br(rg_xss_safe($row['description']));
92 150 } }
93 151
94 if (isset($row['events']))
95 $row['events_text'] = rg_wh_events($row['events']);
96
97 152 if (isset($row['last_output'])) { if (isset($row['last_output'])) {
98 153 if (empty($row['last_output'])) if (empty($row['last_output']))
99 154 $row['HTML:last_output_nice'] = 'n/a'; $row['HTML:last_output_nice'] = 'n/a';
 
... ... function rg_wh_cosmetic(&$list)
102 157 nl2br(rg_xss_safe($row['last_output'])); nl2br(rg_xss_safe($row['last_output']));
103 158 } }
104 159
105 $t = $row['htype'];
160 if ($rg_wh_plugins[$t]['have_events'] == 1) {
161 if (isset($row['idata']['events']))
162 $row['idata']['events_text'] =
163 rg_wh_events($row['idata']['events']);
164 }
165
106 166 if (isset($rg_wh_plugins[$t]['cosmetic'])) if (isset($rg_wh_plugins[$t]['cosmetic']))
107 167 $rg_wh_plugins[$t]['cosmetic']($row); $rg_wh_plugins[$t]['cosmetic']($row);
108 168 } }
 
... ... function rg_wh_cosmetic(&$list)
114 174 function rg_wh_set_last_output($db, $uid, $id, $output) function rg_wh_set_last_output($db, $uid, $id, $output)
115 175 { {
116 176 rg_prof_start('wh_set_last_output'); rg_prof_start('wh_set_last_output');
117 rg_log_enter('wh_set_last_output id=$id');
177 rg_log_enter('wh_set_last_output id=' . $id);
118 178
119 179 $ret = FALSE; $ret = FALSE;
120 180 while (1) { while (1) {
 
... ... function rg_wh_add($db, $uid, $data)
233 293 if ($data['id'] == 0) { if ($data['id'] == 0) {
234 294 $data['last_output'] = ''; $data['last_output'] = '';
235 295 $sql = 'INSERT INTO webhooks (uid, repo_id, itime' $sql = 'INSERT INTO webhooks (uid, repo_id, itime'
236 . ', htype, events, url'
237 . ', add_ip, description, key, opaque, idata)'
296 . ', htype, flags'
297 . ', add_ip, description, idata)'
238 298 . ' VALUES (@@uid@@, @@repo_id@@, @@itime@@' . ' VALUES (@@uid@@, @@repo_id@@, @@itime@@'
239 . ', @@htype@@, @@events@@, @@url@@'
240 . ', @@add_ip@@'
241 . ', @@description@@, @@key@@, @@opaque@@'
242 . ', @@idata@@)'
299 . ', @@htype@@, @@flags@@, @@add_ip@@'
300 . ', @@description@@, @@idata@@)'
243 301 . ' RETURNING id'; . ' RETURNING id';
244 302 } else { } else {
245 303 $sql = 'UPDATE webhooks' $sql = 'UPDATE webhooks'
246 . ' SET events = @@events@@'
247 . ', url = @@url@@'
248 . ', description = @@description@@'
249 . ', key = @@key@@'
250 . ', opaque = @@opaque@@'
304 . ' SET description = @@description@@'
305 . ', flags = @@flags@@'
251 306 . ', idata = @@idata@@' . ', idata = @@idata@@'
252 307 . ' WHERE uid = @@uid@@' . ' WHERE uid = @@uid@@'
253 308 . ' AND id = @@id@@'; . ' AND id = @@id@@';
 
... ... function rg_wh_fill_vars(&$rg)
335 390 while (1) { while (1) {
336 391 $t = $rg['wh']['htype']; $t = $rg['wh']['htype'];
337 392
393 $rg['wh']['flags'] = rg_var_a2s('wh::flags');
394 $rg['wh']['repo_id'] = rg_var_uint('wh::repo_id');
395 $rg['wh']['itime'] = time();
396 $rg['wh']['add_ip'] = isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : '';
397 $rg['wh']['description'] = trim(rg_var_str('wh::description'));
398
399 $rg['wh']['idata'] = array();
400 $rg['wh']['idata']['debug'] = $rg['debug'];
401 $rg['wh']['idata']['events'] = rg_var_a2s('wh::idata::events'); // TODO
402
338 403 if (!isset($rg_wh_plugins[$t])) { if (!isset($rg_wh_plugins[$t])) {
339 404 $errmsg[] = rg_template('user/settings/wh/invalid_htype', $errmsg[] = rg_template('user/settings/wh/invalid_htype',
340 405 $rg, TRUE /*xss*/); $rg, TRUE /*xss*/);
 
... ... function rg_wh_fill_vars(&$rg)
358 423 */ */
359 424 function rg_wh_validate_vars($rg, &$errmsg) function rg_wh_validate_vars($rg, &$errmsg)
360 425 { {
426 global $rg_wh_flags;
361 427 global $rg_wh_plugins; global $rg_wh_plugins;
362 428
363 429 $ret = FALSE; $ret = FALSE;
364 430 while (1) { while (1) {
365 if (empty($rg['wh']['events'])) {
366 $errmsg[] = rg_template('user/settings/wh/inv_events.txt',
367 $rg, TRUE /*xss*/);
368 break;
369 }
370
371 431 $t = $rg['wh']['htype']; $t = $rg['wh']['htype'];
372 432
373 433 if (!isset($rg_wh_plugins[$t])) { if (!isset($rg_wh_plugins[$t])) {
 
... ... function rg_wh_validate_vars($rg, &$errmsg)
376 436 break; break;
377 437 } }
378 438
439 $all_ok = TRUE;
440 $list = array_merge($rg_wh_flags, $rg_wh_plugins[$t]['flags']);
441 $len = strlen($rg['wh']['flags']);
442 for ($i = 0; $i < $len; $i++) {
443 $f = $rg['wh']['flags'][$i];
444 if (!isset($list[$f])) {
445 $all_ok = FALSE;
446 $errmsg[] = rg_template('user/settings/wh/inv_flag.txt',
447 $rg, TRUE /*xss*/);
448 break;
449 }
450 }
451 if (!$all_ok)
452 break;
453
454 // Some hooks do not need events, for example CodeDeploy
455 if ($rg_wh_plugins[$t]['have_events'] == 1) {
456 if (empty($rg['wh']['idata']['events'])) {
457 $errmsg[] = rg_template('user/settings/wh/inv_events.txt',
458 $rg, TRUE /*xss*/);
459 break;
460 }
461 }
462
379 463 if (isset($rg_wh_plugins[$t]['validate_vars'])) { if (isset($rg_wh_plugins[$t]['validate_vars'])) {
380 464 $r = $rg_wh_plugins[$t]['validate_vars']($rg, $errmsg); $r = $rg_wh_plugins[$t]['validate_vars']($rg, $errmsg);
381 465 if ($r !== TRUE) if ($r !== TRUE)
 
... ... function rg_wh_add_form(&$rg)
402 486 if (!isset($rg_wh_plugins[$t])) if (!isset($rg_wh_plugins[$t]))
403 487 break; break;
404 488
489 $rg['HTML:check_flags'] =
490 rg_wh_check_flags($rg_wh_plugins[$t]['flags'],
491 $rg['wh']['flags']);
492
493 if ($rg_wh_plugins[$t]['have_events'] == 1)
494 $rg['HTML:check_events'] =
495 rg_wh_check_events($rg['wh']['idata']['events']);
496
405 497 if (isset($rg_wh_plugins[$t]['add_form'])) { if (isset($rg_wh_plugins[$t]['add_form'])) {
406 498 $rg_wh_plugins[$t]['add_form']($rg); $rg_wh_plugins[$t]['add_form']($rg);
407 499 break; break;
 
... ... function rg_wh_default_paras(&$rg)
421 513 while (1) { while (1) {
422 514 $t = $rg['wh']['htype']; $t = $rg['wh']['htype'];
423 515
516 $rg['wh']['id'] = 0;
517 $rg['wh']['description'] = '';
518 $rg['wh']['flags'] = '';
519
520 $rg['wh']['idata'] = array();
521 $rg['wh']['idata']['events'] = '';
522
424 523 if (!isset($rg_wh_plugins[$t])) if (!isset($rg_wh_plugins[$t]))
425 524 break; break;
426 525
 
... ... function rg_wh_fill_hints(&$rg, &$hints)
443 542 while (1) { while (1) {
444 543 $t = $rg['wh']['htype']; $t = $rg['wh']['htype'];
445 544
545 $hints[]['HTML:hint'] =
546 rg_template('user/settings/wh/hints_tags.html',
547 $rg, TRUE /*xss*/);
548
446 549 if (!isset($rg_wh_plugins[$t])) if (!isset($rg_wh_plugins[$t]))
447 550 break; break;
448 551
 
... ... function rg_wh_htypes($rg)
462 565 { {
463 566 global $rg_wh_plugins; global $rg_wh_plugins;
464 567
568 asort($rg_wh_plugins);
569
465 570 return rg_template_table('user/settings/wh/plugins_list', return rg_template_table('user/settings/wh/plugins_list',
466 571 $rg_wh_plugins, $rg); $rg_wh_plugins, $rg);
467 572 } }
468 573
574 /*
575 * Returns TRUE if htype is valid
576 */
577 function rg_wh_valid($htype)
578 {
579 global $rg_wh_plugins;
580
581 return isset($rg_wh_plugins[$htype]);
582 }
583
584 /*
585 * Function used to replace ##tag##
586 */
587 function rg_wh_replace_tags(&$ev)
588 {
589 rg_log_ml('wh_replace_tags: ev=' . print_r($ev, TRUE));
590
591 $wh = &$ev['wh'];
592 $info = &$wh['info'];
593 $idata = &$info['idata'];
594
595 $branch = rg_repo_ref_nice($ev['refname']);
596
597 $keys = array('##branch##', '##repo##', '##who##',
598 '##hook_id##', '##commit##',
599 '##date##', '##time##',
600 '##ip##', '##timestamp##');
601
602 $values = array($branch, $ev['repo_name'], $ev['login_username'],
603 $info['id'], $ev['new_rev'],
604 gmdate('Y-m-d', $ev['itime']),
605 gmdate('H:i:s', $ev['itime']),
606 $ev['ip'], $ev['itime']);
607
608 foreach ($idata as $var => &$value)
609 $value = str_replace($keys, $values, $value);
610
611 rg_log_ml('after: ' . print_r($idata, TRUE));
612 }
613
469 614 ?> ?>
File inc/wh/http.inc.php changed (mode: 100644) (index c142d9c..77eebea)
... ... require_once($INC . "/util.inc.php");
3 3 require_once($INC . "/log.inc.php"); require_once($INC . "/log.inc.php");
4 4 require_once($INC . "/sql.inc.php"); require_once($INC . "/sql.inc.php");
5 5 require_once($INC . "/prof.inc.php"); require_once($INC . "/prof.inc.php");
6 require_once($INC . "/events.inc.php");
6 7 require_once($INC . "/wh/core.inc.php"); require_once($INC . "/wh/core.inc.php");
7 8
8 9 $rg_wh_http_functions = array( $rg_wh_http_functions = array(
 
... ... $rg_wh_http_functions = array(
12 13 rg_event_register_functions($rg_wh_http_functions); rg_event_register_functions($rg_wh_http_functions);
13 14
14 15 /* /*
15 * Helper for rg_wh_send
16 * Helper for rg_wh_http_send
16 17 */ */
17 18 function rg_wh_http_send_one($db, $event) function rg_wh_http_send_one($db, $event)
18 19 { {
 
... ... function rg_wh_http_send_one($db, $event)
21 22 $wh = &$event['wh']; $wh = &$event['wh'];
22 23 $info = &$wh['info']; $info = &$wh['info'];
23 24
24 rg_log_ml('wh_send_one: event: ' . print_r($event, TRUE));
25 if ($event['debug'] == 1)
25 rg_log_ml('wh_http_send_one: event: ' . print_r($event, TRUE));
26 if ($info['idata']['debug'] == 1)
26 27 rg_log_ml('XXX DEBUG: wh[data]=' . print_r($wh['data'], TRUE)); rg_log_ml('XXX DEBUG: wh[data]=' . print_r($wh['data'], TRUE));
27 28
28 29 $headers = array(); $headers = array();
29 30
30 while (!empty($info['key'])) {
31 while (!empty($info['idata']['key'])) {
31 32 if ($info['idata']['itype'] == 0) if ($info['idata']['itype'] == 0)
32 33 break; break;
33 34
34 35 $headers[] = 'X-RocketGit-Signature: ' $headers[] = 'X-RocketGit-Signature: '
35 . hash_hmac('sha512', $wh['data'], $info['key']);
36 . hash_hmac('sha512', $wh['data'], $info['idata']['key']);
36 37 break; break;
37 38 } }
38 39
39 $c = curl_init($info['url']);
40 $c = curl_init($info['idata']['url']);
40 41 curl_setopt($c, CURLOPT_POST, 1); curl_setopt($c, CURLOPT_POST, 1);
41 42 curl_setopt($c, CURLOPT_POSTFIELDS, $wh['data']); curl_setopt($c, CURLOPT_POSTFIELDS, $wh['data']);
42 43 curl_setopt($c, CURLOPT_RETURNTRANSFER, TRUE); curl_setopt($c, CURLOPT_RETURNTRANSFER, TRUE);
 
... ... function rg_wh_http_send_one($db, $event)
56 57 if ($err !== FALSE) if ($err !== FALSE)
57 58 curl_setopt($c, CURLOPT_STDERR, $err); curl_setopt($c, CURLOPT_STDERR, $err);
58 59
59 if (strchr($info['idata']['flags'], 'I'))
60 if (strchr($info['flags'], 'I'))
60 61 curl_setopt($c, CURLOPT_SSL_VERIFYPEER, FALSE); curl_setopt($c, CURLOPT_SSL_VERIFYPEER, FALSE);
61 62
62 if (strchr($info['idata']['flags'], 'H'))
63 if (strchr($info['flags'], 'H'))
63 64 curl_setopt($c, CURLOPT_SSL_VERIFYHOST, 0); // TODO verify 0 is a good value (default 2) curl_setopt($c, CURLOPT_SSL_VERIFYHOST, 0); // TODO verify 0 is a good value (default 2)
64 65
65 66 $ret = FALSE; $ret = FALSE;
 
... ... function rg_wh_http_send_one($db, $event)
68 69 while (1) { while (1) {
69 70 $xid = rg_id(8); $xid = rg_id(8);
70 71
72 // replace ##tags##
73 rg_wh_replace_tags($event);
74
71 75 if (!empty($info['idata']['client_cert'])) { if (!empty($info['idata']['client_cert'])) {
72 76 rg_log('DEBUG: will provide client cert...'); rg_log('DEBUG: will provide client cert...');
73 77 $f = 'wh-' . $event['ui']['uid'] . '-' . $wh['id'] . '-client-' . $xid; $f = 'wh-' . $event['ui']['uid'] . '-' . $wh['id'] . '-client-' . $xid;
 
... ... function rg_wh_http_send_one($db, $event)
107 111 $_info = curl_getinfo($c); $_info = curl_getinfo($c);
108 112 rg_log_ml('Debug: ' . print_r($_info, TRUE)); rg_log_ml('Debug: ' . print_r($_info, TRUE));
109 113
110 if ($event['debug'] == 1)
114 if ($info['idata']['debug'] == 1)
111 115 rg_cache_set('DEBUG::' . $event['ui']['uid'] rg_cache_set('DEBUG::' . $event['ui']['uid']
112 . '::webhooks::' . $info['opaque']
116 . '::webhooks::' . $info['idata']['opaque']
113 117 . '::' . $wh['id'], . '::' . $wh['id'],
114 118 'BAD', RG_SOCKET_NO_WAIT); 'BAD', RG_SOCKET_NO_WAIT);
115 119 break; break;
 
... ... function rg_wh_http_send_one($db, $event)
117 121
118 122 $xerr = &$r; $xerr = &$r;
119 123 rg_log_ml('Answer: ' . print_r($r, TRUE)); rg_log_ml('Answer: ' . print_r($r, TRUE));
124 $xerr .= $r;
120 125
121 if ($event['debug'] == 1)
126 if ($info['idata']['debug'] == 1)
122 127 rg_cache_set('DEBUG::' . $event['ui']['uid'] rg_cache_set('DEBUG::' . $event['ui']['uid']
123 . '::webhooks::' . $info['opaque']
128 . '::webhooks::' . $info['idata']['opaque']
124 129 . '::' . $wh['id'], . '::' . $wh['id'],
125 130 'OK', RG_SOCKET_NO_WAIT); 'OK', RG_SOCKET_NO_WAIT);
126 131
 
... ... function rg_wh_http_send_one($db, $event)
143 148 } }
144 149
145 150 /* /*
146 * Generic function which will be called when a webhook must be posted
151 * Generic function which will be called when a webhook must be run
147 152 */ */
148 153 function rg_wh_http_send($db, $event) function rg_wh_http_send($db, $event)
149 154 { {
 
... ... function rg_wh_http_send($db, $event)
165 170 continue; continue;
166 171 } }
167 172
173 if (strcmp($info['htype'], 'http') != 0)
174 continue;
175
176 // Diabled?
177 if (strchr($info['flags'], 'D'))
178 continue;
179
168 180 // If the web hook does not contain our type, skip it // If the web hook does not contain our type, skip it
169 if (!strchr($info['events'], $event['wh_event'])) {
170 rg_log($event['wh_event'] . ' is not present in ' . $info['events']);
181 if (!strchr($info['idata']['events'], $event['wh_event'])) {
182 rg_log($event['wh_event'] . ' is not present in '
183 . $info['idata']['events']);
171 184 continue; continue;
172 185 } }
173 186
 
... ... function rg_wh_http_itype($itype)
256 269 return $name; return $name;
257 270 } }
258 271
259 $rg_wh_http_flags = array(
260 'I' => 'Do not verify the server certificate',
261 'H' => 'Do not verify the server hostname'
262 );
263 /*
264 * Generates flags list
265 */
266 function rg_wh_http_check_flags($flags)
267 {
268 global $rg_wh_http_flags;
269
270 $ret = '';
271 $br = '';
272 foreach ($rg_wh_http_flags as $id => $name) {
273 $add = '';
274 if (strchr($flags, $id))
275 $add = ' checked="checked"';
276
277 $ret .= $br
278 . '<input type="checkbox" name="wh::idata::flags[' . $id . ']"'
279 . ' id="flags-' . $id . '"'
280 . $add . ' />'
281 . "\n"
282 . '<label for="flags-' . $id . '">' . $name . '</label>';
283 $br = '<br />' . "\n";
284 }
285
286 return $ret;
287 }
288
289 /*
290 * Generates a flags list as text
291 */
292 function rg_wh_http_flags($flags)
293 {
294 global $rg_wh_http_flags;
295
296 $a = array();
297 foreach ($rg_wh_http_flags as $id => $name) {
298 if (strchr($flags, $id))
299 $a[] = $name;
300 }
301
302 return implode(', ', $a);
303 }
304
305 272 /* /*
306 273 * Some cosmetics applied to a webhook * Some cosmetics applied to a webhook
307 274 */ */
 
... ... function rg_wh_http_cosmetic(&$row)
313 280
314 281 $row['idata']['itype_text'] = rg_wh_http_itype($row['idata']['itype']); $row['idata']['itype_text'] = rg_wh_http_itype($row['idata']['itype']);
315 282
316 $row['idata']['flags_text'] = rg_wh_http_flags($row['idata']['flags']);
317
318 283 $row['idata']['HTML:client_cert_short'] = $row['idata']['HTML:client_cert_short'] =
319 284 rg_xss_safe(rg_cert_short($row['idata']['client_cert'])); rg_xss_safe(rg_cert_short($row['idata']['client_cert']));
320 285
 
... ... function rg_wh_http_cosmetic(&$row)
330 295 */ */
331 296 function rg_wh_http_fill_vars(&$rg) function rg_wh_http_fill_vars(&$rg)
332 297 { {
333 $a = array();
298 $a = &$rg['wh']['idata'];
299 $a['url'] = rg_var_str('wh::idata::url');
334 300 $a['itype'] = rg_var_uint('wh::idata::itype'); $a['itype'] = rg_var_uint('wh::idata::itype');
335 301 $a['client_cert'] = trim(rg_var_str('wh::idata::client_cert')); $a['client_cert'] = trim(rg_var_str('wh::idata::client_cert'));
336 302 $a['client_ca_cert'] = trim(rg_var_str('wh::idata::client_ca_cert')); $a['client_ca_cert'] = trim(rg_var_str('wh::idata::client_ca_cert'));
337 $a['flags'] = rg_var_a2s('wh::idata::flags');
338 $rg['wh']['idata'] = $a;
303 $a['opaque'] = rg_var_str('wh::idata::opaque');
304 $a['key'] = rg_var_str('wh::idata::key');
339 305 } }
340 306
341 307 /* /*
 
... ... function rg_wh_http_fill_vars(&$rg)
344 310 function rg_wh_http_validate_vars($rg, &$errmsg) function rg_wh_http_validate_vars($rg, &$errmsg)
345 311 { {
346 312 global $rg_wh_http_itypes; global $rg_wh_http_itypes;
347 global $rg_wh_http_flags;
348 313
349 314 $a = $rg['wh']; $a = $rg['wh'];
350 315
351 316 $ret = FALSE; $ret = FALSE;
352 317 while (1) { while (1) {
353 if ((strncasecmp($a['url'], 'http', 4) != 0)
354 && (strncasecmp($a['url'], 'https', 5) != 0)) {
318 if ((strncasecmp($a['idata']['url'], 'http', 4) != 0)
319 && (strncasecmp($a['idata']['url'], 'https', 5) != 0)) {
355 320 $errmsg[] = rg_template('user/settings/wh/http/inv_proto.txt', $errmsg[] = rg_template('user/settings/wh/http/inv_proto.txt',
356 321 $rg, TRUE /*xss*/); $rg, TRUE /*xss*/);
357 322 break; break;
 
... ... function rg_wh_http_validate_vars($rg, &$errmsg)
363 328 break; break;
364 329 } }
365 330
366 $all_ok = TRUE;
367 $len = strlen($a['idata']['flags']);
368 for ($i = 0; $i < $len; $i++) {
369 $f = $a['idata']['flags'][$i];
370 if (!isset($rg_wh_http_flags[$f])) {
371 $all_ok = FALSE;
372 $errmsg[] = rg_template('user/settings/wh/http/inv_flag.txt',
373 $rg, TRUE /*xss*/);
374 break;
375 }
376 }
377 if (!$all_ok)
378 break;
379
380 331 $ret = TRUE; $ret = TRUE;
381 332 break; break;
382 333 } }
 
... ... function rg_wh_http_validate_vars($rg, &$errmsg)
389 340 */ */
390 341 function rg_wh_http_add_form(&$rg) function rg_wh_http_add_form(&$rg)
391 342 { {
392 // TODO DEBUG remove this
393 if (!isset($rg['wh']['idata']['itype']))
394 $rg['wh']['idata']['itype'] = 0;
395 343 $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']);
396 $rg['HTML:check_flags'] = rg_wh_http_check_flags($rg['wh']['idata']['flags']);
397 344
398 345 $rg['HTML:custom_form'] = rg_template('user/settings/wh/http/form.html', $rg['HTML:custom_form'] = rg_template('user/settings/wh/http/form.html',
399 346 $rg, TRUE /*xss*/); $rg, TRUE /*xss*/);
 
... ... function rg_wh_http_fill_hints($rg, &$hints)
413 360 */ */
414 361 function rg_wh_http_default_paras(&$rg) function rg_wh_http_default_paras(&$rg)
415 362 { {
416 $a = array();
363 $a = &$rg['wh']['idata'];
364 $a['url'] = '';
417 365 $a['itype'] = 0; $a['itype'] = 0;
418 $a['flags'] = '';
419 366 $a['client_cert'] = ''; $a['client_cert'] = '';
420 367 $a['client_ca_cert'] = ''; $a['client_ca_cert'] = '';
421 $rg['wh']['idata'] = $a;
368 $a['opaque'] = '';
369 $a['key'] = '';
422 370 } }
423 371
424 372
 
... ... $rg_wh_plugins['http'] = array(
432 380 'validate_vars' => 'rg_wh_http_validate_vars', 'validate_vars' => 'rg_wh_http_validate_vars',
433 381 'add_form' => 'rg_wh_http_add_form', 'add_form' => 'rg_wh_http_add_form',
434 382 'default_paras' => 'rg_wh_http_default_paras', 'default_paras' => 'rg_wh_http_default_paras',
435 'fill_hints' => 'rg_wh_http_fill_hints'
383 'fill_hints' => 'rg_wh_http_fill_hints',
384 'have_events' => TRUE,
385 'flags' => array(
386 'I' => 'Do not verify the server certificate',
387 'H' => 'Do not verify the server hostname'
388 )
436 389 ); );
437 390
438 391 ?> ?>
File inc/wh/lambda.inc.php added (mode: 100644) (index 0000000..93fcabf)
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 . "/prof.inc.php");
6 require_once($INC . "/events.inc.php");
7 require_once($INC . "/wh/core.inc.php");
8 require_once($INC . "/wh/amazon.inc.php");
9
10 $rg_wh_lambda_functions = array(
11 30000 => 'rg_wh_lambda_send',
12 30001 => 'rg_wh_lambda_send_one'
13 );
14 rg_event_register_functions($rg_wh_lambda_functions);
15
16
17 /*
18 * Helper for rg_wh_lambda_send
19 */
20 function rg_wh_lambda_send_one($db, $event)
21 {
22 rg_prof_start('wh_lambda_send_one');
23 rg_log_ml('wh_lambda_send_one: event: ' . print_r($event, TRUE));
24
25 $ret = FALSE;
26
27 $wh = &$event['wh'];
28 $info = &$wh['info'];
29
30 $last_output = '';
31 while (1) {
32 // replace ##tags##
33 rg_wh_replace_tags($event);
34
35 // we need to copy 'flags' because we pass idata
36 $info['idata']['flags'] = $info['flags'];
37
38 // Call the function
39 $r = rg_amazon_lambda_invoke($info['idata']);
40 if ($r['ok'] != 1) {
41 $last_output .= $r['error'];
42 break;
43 }
44
45 $ret = array();
46 $last_output .= $r['answer'];
47 break;
48 }
49
50 rg_wh_set_last_output($db, $event['ui']['uid'], $wh['id'],
51 substr($last_output, 0, 4096));
52
53 rg_prof_end('wh_lambda_send_one');
54 return $ret;
55 }
56
57 /*
58 * Generic function which will be called when a webhook must be posted
59 */
60 function rg_wh_lambda_send($db, $event)
61 {
62 rg_prof_start('wh_lambda_send');
63 rg_log_ml('wh_lambda_send: event: ' . print_r($event, TRUE));
64
65 $ret = array();
66
67 // First, get the list of hooks
68 $r = rg_wh_list($db, $event['ui']['uid']);
69 if ($r['ok'] != 1)
70 return FALSE;
71
72 // Filter them by repo_id
73 foreach ($r['list'] as $id => $info) {
74 if (($info['repo_id'] > 0)
75 && ($event['repo_id'] != $info['repo_id'])) {
76 rg_log('hook is not for this repo');
77 continue;
78 }
79
80 if (strcmp($info['htype'], 'lambda') != 0)
81 continue;
82
83 // Diabled?
84 if (strchr($info['flags'], 'D'))
85 continue;
86
87 $wh = array();
88 $wh['id'] = $id;
89 $wh['info'] = $info;
90
91 $x = $event;
92 $x['category'] = 30001;
93 $x['wh'] = $wh;
94 $ret[] = $x;
95 }
96
97 rg_prof_end('wh_lambda_send');
98 return $ret;
99 }
100
101 /*
102 * Some cosmetics applied to a webhook
103 */
104 function rg_wh_lambda_cosmetic(&$row)
105 {
106 rg_wh_amazon_cosmetic($row);
107
108 $row['idata']['HTML:payload_nice'] = nl2br(rg_xss_safe($row['idata']['payload']));
109
110 $row['idata']['HTML:private'] = rg_template(
111 'user/settings/wh/lambda/show.html', $row['idata'], TRUE /*xss*/);
112 }
113
114 /*
115 * Fill private data based on parameters passed
116 */
117 function rg_wh_lambda_fill_vars(&$rg)
118 {
119 $a = &$rg['wh']['idata'];
120 rg_wh_amazon_fill_vars($a);
121 $a['function'] = trim(rg_var_str('wh::idata::function'));
122 $a['payload'] = trim(rg_var_str('wh::idata::payload'));
123 }
124
125 /*
126 * Validate parameters passed
127 */
128 function rg_wh_lambda_validate_vars($rg, &$errmsg)
129 {
130 global $rg_wh_lambda_itypes;
131
132 $a = $rg['wh'];
133
134 $ret = FALSE;
135 while (1) {
136 if (!rg_wh_amazon_validate_vars($a['idata'], $errmsg))
137 break;
138
139 if (empty($a['idata']['function'])) {
140 $errmsg[] = rg_template('user/settings/wh/lambda/inv_func.txt',
141 $rg, TRUE /*xss*/);
142 break;
143 }
144
145 $ret = TRUE;
146 break;
147 }
148
149 return $ret;
150 }
151
152 /*
153 * Transfers to $rg the custom parameters - used when showing the form
154 */
155 function rg_wh_lambda_add_form(&$rg)
156 {
157 $rg['HTML:custom_form'] = rg_template('user/settings/wh/lambda/form.html',
158 $rg, TRUE /*xss*/);
159 }
160
161 /*
162 * Add custom hints
163 */
164 function rg_wh_lambda_fill_hints($rg, &$hints)
165 {
166 $hints[]['HTML:hint'] = rg_template('user/settings/wh/amazon/hints.html',
167 $rg, TRUE /*xss*/);
168 $hints[]['HTML:hint'] = rg_template('user/settings/wh/hints_tags.html',
169 $rg, TRUE /*xss*/);
170 }
171
172 /*
173 * Loads default paras for a form
174 */
175 function rg_wh_lambda_default_paras(&$rg)
176 {
177 $a = &$rg['wh']['idata'];
178 rg_wh_amazon_default_paras($a);
179 $a['function'] = '';
180 $a['payload'] = '';
181 }
182
183
184
185 $rg_wh_plugins['lambda'] = array(
186 'htype' => 'lambda',
187 'description' => 'Call an Amazon Lambda function',
188 'cosmetic' => 'rg_wh_lambda_cosmetic',
189 'html_form' => 'rg_wh_lambda_form',
190 'fill_vars' => 'rg_wh_lambda_fill_vars',
191 'validate_vars' => 'rg_wh_lambda_validate_vars',
192 'add_form' => 'rg_wh_lambda_add_form',
193 'default_paras' => 'rg_wh_lambda_default_paras',
194 'fill_hints' => 'rg_wh_lambda_fill_hints',
195 'have_events' => TRUE,
196 'flags' => array()
197 );
198
199 ?>
File root/themes/default/user/settings/wh/add_edit.html changed (mode: 100644) (index 5529dfa..65f1a96)
4 4
5 5 @@errmsg@@ @@errmsg@@
6 6
7 <form method="post" action="/op/settings/wh/@@if(@@wh::id@@ == 0){{add}}{{edit/@@wh::id@@}}">
8 <input type="hidden" name="add" value="1" />
7 <form method="post" action="/op/settings/wh/@@if(@@wh::id@@ == 0){{add/@@wh::htype@@}}{{edit/@@wh::id@@}}">
8 <input type="hidden" name="doit" value="1" />
9 9 <input type="hidden" name="wh::htype" value="@@wh::htype@@" /> <input type="hidden" name="wh::htype" value="@@wh::htype@@" />
10 10 <input type="hidden" name="token" value="@@rg_form_token@@" /> <input type="hidden" name="token" value="@@rg_form_token@@" />
11 11
12 <p>
13 <label for="url">URL (example: https://my_server_dot_tld/hook.cgi)</label><br />
14 <input type="text" name="wh::url" id="url" value="@@wh::url@@" size="80" />
15 </p>
16
17 @@check_events@@
12 <fieldset>
13 <legend>Flags</legend>
14 @@check_flags@@
15 </fieldset>
18 16
19 17 <p> <p>
20 18 <label for="description">Description</label><br /> <label for="description">Description</label><br />
21 <textarea name="wh::description" id="description" rows="3" cols="80">
22 @@wh::description@@
23 </textarea>
24 </p>
25
26 <p>
27 <label for="key">HMAC SHA512 key (optional, see hints)</label><br />
28 <input type="text" name="wh::key" id="key" value="@@wh::key@@" size="80" />
29 </p>
30
31 <p>
32 <label for="opaque">Opaque string (optional, will be sent in the request)</label><br />
33 <input type="text" name="wh::opaque" id="opaque" value="@@wh::opaque@@" size="80" />
19 <textarea name="wh::description" id="description" rows="3" cols="80">@@wh::description@@</textarea>
34 20 </p> </p>
35 21
36 22 @@custom_form@@ @@custom_form@@
File root/themes/default/user/settings/wh/amazon/inv_access_key_id.txt added (mode: 100644) (index 0000000..03cc6b7)
1 invalid access key id
File root/themes/default/user/settings/wh/amazon/inv_region.txt added (mode: 100644) (index 0000000..920aa56)
1 invalid region
File root/themes/default/user/settings/wh/amazon/inv_secret_access_key.txt added (mode: 100644) (index 0000000..997044f)
1 invalid secret access key
File root/themes/default/user/settings/wh/cloud/form.html added (mode: 100644) (index 0000000..b9b517d)
1 <fieldset>
2 <legend>Amazon</legend>
3
4 <p>
5 <label for="access_key_id">Access key id</label><br />
6 <input type="text" name="wh::idata::access_key_id" id="access_key_id" size="80" value="@@wh::idata::access_key_id@@" />
7 </p>
8
9 <p>
10 <label for="secret_access_key">Secret access key</label><br />
11 <input type="text" name="wh::idata::secret_access_key" id="secret_access_key" size="80" value="@@wh::idata::secret_access_key@@" />
12 </p>
13
14 <p>
15 <label for="region">Region (example: eu-central-1)</label><br />
16 <input type="text" name="wh::idata::region" id="region" size="80" value="@@wh::idata::region@@" />
17 </p>
18 </fieldset>
19
20 <fieldset>
21 <legend>S3</legend>
22
23 <p>
24 <label for="bucket">Bucket</label><br />
25 <input type="text" name="wh::idata::bucket" id="bucket" size="80" value="@@wh::idata::bucket@@" />
26 </p>
27
28 <p>
29 <label for="file">File name</label><br />
30 <input type="text" name="wh::idata::file" id="file" size="80" value="@@wh::idata::file@@" />
31 </p>
32 </fieldset>
33
34 <fieldset>
35 <legend>CodeDeploy (optional)</legend>
36
37 <p>
38 <label for="application_name">Application name</label><br />
39 <input type="text" name="wh::idata::application_name" id="application_name" size="80" value="@@wh::idata::application_name@@" />
40 </p>
41
42 <p>
43 <label for="deployment_group_name">Deployment group name</label><br />
44 <input type="text" name="wh::idata::deployment_group_name" id="deployment_group_name" size="80" value="@@wh::idata::deployment_group_name@@" />
45 </p>
46
47 <p>
48 <label for="deployment_config_name">Deployment config name</label><br />
49 <input type="text" name="wh::idata::deployment_config_name" id="deployment_config_name" size="80" value="@@wh::idata::deployment_config_name@@" />
50 </p>
51 </fieldset>
File root/themes/default/user/settings/wh/cloud/hints.html added (mode: 100644) (index 0000000..943c52d)
1 <br />
2 Use a cloud user with only CodeDeploy rights.<br />
File root/themes/default/user/settings/wh/cloud/inv_app_name.txt added (mode: 100644) (index 0000000..5eb9548)
1 invalid application name
File root/themes/default/user/settings/wh/cloud/inv_bucket.txt added (mode: 100644) (index 0000000..939dc84)
1 invalid bucket
File root/themes/default/user/settings/wh/cloud/inv_group_name.txt added (mode: 100644) (index 0000000..d01d4ac)
1 invalid deployment group name
File root/themes/default/user/settings/wh/cloud/show.html added (mode: 100644) (index 0000000..1627140)
1 <table summary="plugin internal info">
2 <tr>
3 <td>Access key ID</td>
4 <td>@@access_key_id_secure@@</td>
5 </tr>
6
7 <tr>
8 <td>Secret access key</td>
9 <td>@@secret_access_key_secure@@</td>
10 </tr>
11
12 <tr>
13 <td>Region</td>
14 <td>@@region@@</td>
15 </tr>
16
17 <tr>
18 <td>Bucket</td>
19 <td>@@bucket@@</td>
20 </tr>
21
22 <tr>
23 <td>File name</td>
24 <td>@@file@@</td>
25 </tr>
26
27 <tr>
28 <td>Application name</td>
29 <td>@@application_name@@</td>
30 </tr>
31
32 <tr>
33 <td>Deployment group name</td>
34 <td>@@deployment_group_name@@</td>
35 </tr>
36
37 <tr>
38 <td>Deployment config name</td>
39 <td>@@deployment_config_name@@</td>
40 </tr>
41 </table>
File root/themes/default/user/settings/wh/hints_htype.html changed (mode: 100644) (index 1896446..e69de29)
1 <br />
2 HMAC SHA512 key: it is a string that will be used to sign the payload;
3 this way you can be sure that the server knows the secret and you can go on to
4 process the request. You can use any character you want: letters, digits and
5 any symbol.<br />
6 The server will create a HMAC over the payload using SHA512 and will add
7 a HTTP header: <i>X-RocketGit-Signature: &lt;signature&gt;</i>. It is
8 recommended to verify it before parsing the body, for security reasons.
9 It is not generated for <i>application/x-www-form-urlencoded</i> encoding.<br />
File root/themes/default/user/settings/wh/hints_tags.html added (mode: 100644) (index 0000000..2e82d17)
1 <br />
2 Most of the fields allow you to specify a special tag (##tag##) which will
3 be replaced at hook execution. It is a feature that allows you to minimize
4 the number of hooks you must maintain.<br />
5 The complete list of tags:
6 <ul>
7 <li>##branch## - the branch name just created or pushed to</li>
8 <li>##repo## - the repository name</li>
9 <li>##who## - the user who triggered the hook</li>
10 <li>##hook_id## - the id of the hook</li>
11 <li>##commit## - the git's SHA-1 commit id</li>
12 <li>##date## - the UTC date (example: 2016-01-15)</li>
13 <li>##time## - the UTC time (example: 00:36:23)</li>
14 <li>##timestamp## - the UNIX epoch (example: 1452810114)</li>
15 <li>##ip## - the IP address from where the push took place</li>
16 </ul>
File root/themes/default/user/settings/wh/http/form.html changed (mode: 100644) (index 8020fb4..f46dfe8)
1 @@check_events@@
2
3 <p>
4 <label for="url">URL (example: https://my_server_dot_tld/hook.cgi)</label><br />
5 <input type="text" name="wh::idata::url" id="url" value="@@wh::idata::url@@" size="80" />
6 </p>
7
1 8 <p> <p>
2 9 <label for="itype">Data encoding</label><br /> <label for="itype">Data encoding</label><br />
3 10 @@select_itype@@ @@select_itype@@
4 11 </p> </p>
5 12
6 <fieldset>
7 <legend>Flags</legend>
8 @@check_flags@@
9 </fieldset>
13 <p>
14 <label for="key">HMAC SHA512 key (optional, see hints)</label><br />
15 <input type="text" name="wh::idata::key" id="key" value="@@wh::idata::key@@" size="80" />
16 </p>
17
18 <p>
19 <label for="opaque">Opaque string (optional, will be sent in the request)</label><br />
20 <input type="text" name="wh::idata::opaque" id="opaque" value="@@wh::idata::opaque@@" size="80" />
21 </p>
10 22
11 23 <p> <p>
12 24 <label for="client_cert">Optional concatenated certificate and key used to <label for="client_cert">Optional concatenated certificate and key used to
13 25 authenticate us to the server (PEM format, no password)</label><br /> authenticate us to the server (PEM format, no password)</label><br />
14 <textarea name="wh::idata::client_cert" id="client_cert" rows="3" cols="80">
15 @@wh::idata::client_cert@@
16 </textarea>
26 <textarea name="wh::idata::client_cert" id="client_cert" rows="3" cols="80">@@wh::idata::client_cert@@</textarea>
17 27 </p> </p>
18 28
19 29 <p> <p>
 
... ... authenticate us to the server (PEM format, no password)</label><br />
21 31 Optional CA certificate(s) used to authenticate your server Optional CA certificate(s) used to authenticate your server
22 32 (PEM format) (PEM format)
23 33 </label><br /> </label><br />
24 <textarea name="wh::idata::client_ca_cert" id="client_ca_cert" rows="3" cols="80">
25 @@wh::idata::client_ca_cert@@
26 </textarea>
34 <textarea name="wh::idata::client_ca_cert" id="client_ca_cert" rows="3" cols="80">@@wh::idata::client_ca_cert@@</textarea>
27 35 </p> </p>
28 36
File root/themes/default/user/settings/wh/http/hints.html changed (mode: 100644) (index acd67c8..a4e5f6f)
... ... Optional CA certificates(s): if you have a self-signed CA, you may want to
3 3 add the CA certificate here, to be able to verify that the server we are add the CA certificate here, to be able to verify that the server we are
4 4 connecting to is the real one. If you add it and a man-in-the-middle attack connecting to is the real one. If you add it and a man-in-the-middle attack
5 5 takes place, the link will not be made.<br /> takes place, the link will not be made.<br />
6
7 <br />
8 HMAC SHA512 key: it is a string that will be used to sign the payload;
9 this way you can be sure that the server knows the secret and you can go on to
10 process the request. You can use any character you want: letters, digits and
11 any symbol.<br />
12 The server will create a HMAC over the payload using SHA512 and will add
13 a HTTP header: <i>X-RocketGit-Signature: &lt;signature&gt;</i>. It is
14 recommended to verify it before parsing the body, for security reasons.
15 It is not generated for <i>application/x-www-form-urlencoded</i> encoding.<br />
File root/themes/default/user/settings/wh/http/show.html changed (mode: 100644) (index 4a8e317..0f5ec1d)
4 4 <td>@@itype_text@@</td> <td>@@itype_text@@</td>
5 5 </tr> </tr>
6 6
7 <tr>
8 <td>Flags</td>
9 <td>@@flags_text@@</td>
10 </tr>
11
12 7 <tr> <tr>
13 8 <td>Client cert</td> <td>Client cert</td>
14 9 <td>@@client_cert_short@@</td> <td>@@client_cert_short@@</td>
File root/themes/default/user/settings/wh/inv_events.txt changed (mode: 100644) (index 5675d45..df9debe)
1 No events selected.
1 no events selected
File root/themes/default/user/settings/wh/inv_flag.txt renamed from root/themes/default/user/settings/wh/http/inv_flag.txt (similarity 100%)
File root/themes/default/user/settings/wh/inv_htype.txt changed (mode: 100644) (index bce4e38..3ccc511)
1 Invalid plugin type.
1 invalid plugin type
File root/themes/default/user/settings/wh/lambda/form.html added (mode: 100644) (index 0000000..2bee253)
1 @@check_events@@
2
3 <fieldset>
4 <legend>Amazon</legend>
5
6 <p>
7 <label for="access_key_id">Access key id</label><br />
8 <input type="text" name="wh::idata::access_key_id" id="access_key_id" size="80" value="@@wh::idata::access_key_id@@" />
9 </p>
10
11 <p>
12 <label for="secret_access_key">Secret access key</label><br />
13 <input type="text" name="wh::idata::secret_access_key" id="secret_access_key" size="80" value="@@wh::idata::secret_access_key@@" />
14 </p>
15
16 <p>
17 <label for="region">Region (example: eu-central-1)</label><br />
18 <input type="text" name="wh::idata::region" id="region" size="80" value="@@wh::idata::region@@" />
19 </p>
20 </fieldset>
21
22 <fieldset>
23 <legend>Lambda function</legend>
24
25 <p>
26 <label for="function">Function name</label><br />
27 <input type="text" name="wh::idata::function" id="function" size="80" value="@@wh::idata::function@@" />
28 </p>
29
30 <p>
31 <label for="payload">JSON payload</label><br />
32 <textarea name="wh::idata::payload" id="payload" rows="5" cols="80">@@wh::idata::payload@@</textarea>
33 </p>
34 </fieldset>
File root/themes/default/user/settings/wh/lambda/hints.html added (mode: 100644) (index 0000000..5a55ff3)
1 <br />
2 Use a user with only LambdaInvoke rights.<br />
File root/themes/default/user/settings/wh/lambda/inv_func.txt added (mode: 100644) (index 0000000..dab687b)
1 invalid function
File root/themes/default/user/settings/wh/lambda/show.html added (mode: 100644) (index 0000000..18eec1e)
1 <table summary="plugin internal info">
2 <tr>
3 <td>Access key ID</td>
4 <td>@@access_key_id_secure@@</td>
5 </tr>
6
7 <tr>
8 <td>Secret access key</td>
9 <td>@@secret_access_key_secure@@</td>
10 </tr>
11
12 <tr>
13 <td>Region</td>
14 <td>@@region@@</td>
15 </tr>
16
17 <tr>
18 <td>Function name</td>
19 <td>@@function@@</td>
20 </tr>
21
22 <tr>
23 <td>JSON</td>
24 <td>@@payload_nice@@</td>
25 </tr>
26 </table>
File root/themes/default/user/settings/wh/list/header.html changed (mode: 100644) (index 91e537e..94ca0ee)
8 8 <tr> <tr>
9 9 <th>ID</th> <th>ID</th>
10 10 <th>Select</th> <th>Select</th>
11 <th>Type</th>
11 12 <th>Edit</th> <th>Edit</th>
12 <th>Date (UTC)</th>
13 <th>Events</th>
14 <th>URL</th>
13 <th>Date (UTC) / Add IP</th>
15 14 <th>Description</th> <th>Description</th>
16 <th>Add IP</th>
15 <th>Flags</th>
17 16 <th>Private info</th> <th>Private info</th>
18 17 <th>Last output</th> <th>Last output</th>
19 18 </tr> </tr>
File root/themes/default/user/settings/wh/list/line.html changed (mode: 100644) (index 5fb4284..4bcfe10)
1 1 <tr> <tr>
2 2 <td>@@id@@</td> <td>@@id@@</td>
3 3 <td><input type="checkbox" name="delete_list[@@id@@]" /></td> <td><input type="checkbox" name="delete_list[@@id@@]" /></td>
4 <td>@@htype@@</td>
4 5 <td><a href="/op/settings/wh/edit/@@id@@">Edit</a></td> <td><a href="/op/settings/wh/edit/@@id@@">Edit</a></td>
5 <td>@@itime_nice@@</td>
6 <td>@@events_text@@</td>
7 <td>@@url@@</td>
6 <td>@@itime_nice@@<br />@@add_ip@@</td>
8 7 <td class="small">@@description_nice@@</td> <td class="small">@@description_nice@@</td>
9 <td>@@add_ip@@</td>
8 <td>@@flags_text@@</td>
10 9 <td>@@idata::private@@</td> <td>@@idata::private@@</td>
11 10 <td class="small">@@last_output_nice@@</td> <td class="small">@@last_output_nice@@</td>
12 11 </tr> </tr>
File root/themes/default/user/settings/wh/plugins_list/line.html changed (mode: 100644) (index ff6ebda..09ac4ab)
1 1 <tr> <tr>
2 2 <td>@@htype@@</td> <td>@@htype@@</td>
3 3 <td>@@description@@</td> <td>@@description@@</td>
4 <td><a href="/op/settings/wh/add?wh::htype=@@htype@@">Add</a></td>
4 <td><a href="/op/settings/wh/add/@@htype@@">Add</a></td>
5 5 </tr> </tr>
File scripts/remote.php changed (mode: 100644) (index 6003ee9..e1cda18)
... ... putenv("ROCKETGIT_LOGIN_USERNAME=" . $conn_ui['username']);
262 262 putenv("ROCKETGIT_KEY_ID=" . $key_id); putenv("ROCKETGIT_KEY_ID=" . $key_id);
263 263 putenv("ROCKETGIT_REPO_ID=" . $ri['repo_id']); putenv("ROCKETGIT_REPO_ID=" . $ri['repo_id']);
264 264 putenv("ROCKETGIT_REPO_PATH=" . $repo_path); putenv("ROCKETGIT_REPO_PATH=" . $repo_path);
265 putenv("ROCKETGIT_REPO_NAME=" . $ri['name']);
265 266 putenv("ROCKETGIT_REPO_UID=" . $ri['uid']); putenv("ROCKETGIT_REPO_UID=" . $ri['uid']);
266 267 putenv("ROCKETGIT_IP=$ip"); putenv("ROCKETGIT_IP=$ip");
267 268 putenv("ROCKETGIT_ITIME=" . microtime(TRUE)); putenv("ROCKETGIT_ITIME=" . microtime(TRUE));
File techdocs/amazon-CodeDeploy.txt changed (mode: 100644) (index 22ed62a..719b6de)
... ... This documents the interactions between Amazon CodeDeploy and RocketGit.
2 2
3 3 The plan is to create a new deployment for every push/merge. The plan is to create a new deployment for every push/merge.
4 4 TODO: not clear how should I add this hook TODO: not clear how should I add this hook
5 Maybe existing ones are HTTP/HTTPS hooks. Amazon will be another type.
6 But, because we do not use JavaScript, adding 'Setup phase'
7 parameters must be done on a second page? Or, have a link
8 to multiple types, to have a custom form. How should I build this list
9 and the forms to enter data? Plugins?
10 5 TODO: filter by branch. TODO: filter by branch.
11 6
12 7 User requirements: User requirements:
 
... ... Documentation:
37 32 http://docs.aws.amazon.com/cli/latest/reference/deploy/push.html http://docs.aws.amazon.com/cli/latest/reference/deploy/push.html
38 33 http://docs.aws.amazon.com/cli/latest/reference/deploy/create-deployment.html http://docs.aws.amazon.com/cli/latest/reference/deploy/create-deployment.html
39 34
35 == euca2ools ==
File tests/.gitignore changed (mode: 100644) (index 1e238b1..2a1ed93)
... ... keys/*
21 21 ca ca
22 22 pr_anon.git pr_anon.git
23 23 *.tmp *.tmp
24 wh_cloud.git
File tests/Makefile changed (mode: 100644) (index 7a20f07..a23a63f)
1 tests := pr_anon wh_http ssh http_totp totp git_log1.sh \
1 tests := wh_cloud pr_anon wh_http ssh http_totp totp git_log1.sh \
2 2 http_admin http_bug \ http_admin http_bug \
3 3 http_create_account http_login http_settings http_csrf http_top \ http_create_account http_login http_settings http_csrf http_top \
4 4 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 10 @-ls -l err-* @-ls -l err-*
11 11 @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 12
13 wh_cloud:
14 php wh_cloud.php
15
13 16 pr_anon: pr_anon:
14 17 php pr_anon.php php pr_anon.php
15 18
 
... ... clean:
102 105 @rm -rf git_log1 *.log *.strace *.strace.* *.out *.lock err-* *.diff \ @rm -rf git_log1 *.log *.strace *.strace.* *.out *.lock err-* *.diff \
103 106 http.arond *.pub git2key git2 *.in q_merge_requests/mr-* \ http.arond *.pub git2key git2 *.in q_merge_requests/mr-* \
104 107 qstats/* repos/* helper helper.pub keys/* ca *.pid pr_anon.git \ qstats/* repos/* helper helper.pub keys/* ca *.pid pr_anon.git \
105 *.tmp base ubase
108 *.tmp base ubase wh_cloud.git
File tests/config.php changed (mode: 100644) (index 2375f69..a202ae1)
... ... $rg_theme = "util";
29 29 $rg_lang = "en"; $rg_lang = "en";
30 30 $rg_cache_enable = FALSE; $rg_cache_enable = FALSE;
31 31 $rg_event_socket = ""; $rg_event_socket = "";
32 $rg_ssh_host = 'localhost';
32 $rg_ssh_host = 'r1i';
33 33 $rg_ssh_port = 2222; $rg_ssh_port = 2222;
34 34 $rg_git_host = 'localhost'; $rg_git_host = 'localhost';
35 35 $rg_git_port = 9418; $rg_git_port = 9418;
File tests/git2.php changed (mode: 100644) (index 7b55f2e..eee1b63)
... ... require_once("common.php");
18 18 $_testns = 'git2'; $_testns = 'git2';
19 19 $rg_cache_enable = TRUE; $rg_cache_enable = TRUE;
20 20
21 system("./git2.sh &>git2.log");
21 system("./git2.sh &>git2.sh.log");
22 $_err = file_get_contents('git2.sh.log');
23 @unlink('git2.log');
22 24 if (!file_exists("git2/.git/refs/heads/group1/branch1")) { if (!file_exists("git2/.git/refs/heads/group1/branch1")) {
23 rg_log("Something wrong generating the git2 tree: "
24 . file_get_contents("git2.log"));
25 rg_log("Something wrong generating the git2 tree: " . $_err);
25 26 exit(1); exit(1);
26 27 } }
27 28
 
... ... if (strcmp($refs['branch'][0], "group1/branch1") != 0) {
40 41 exit(1); exit(1);
41 42 } }
42 43
43 // This test makes sense only on my devel machine
44 if (php_uname("n") != "r1.embedromix.ro") {
45 rg_log("OK!");
46 exit(0);
47 }
48
49 44
50 rg_log("Creating a user...");
51 45 rg_test_create_user($db, $rg_ui); rg_test_create_user($db, $rg_ui);
46 rg_log('Created user ' . $rg_ui['uid']);
52 47 rg_test_create_repo($db, $rg_ui, $repo); rg_test_create_repo($db, $rg_ui, $repo);
48 rg_log('Created repo ' . $repo['repo_id']);
53 49 $r = test_login($test_url, $rg_ui, $good_sid); $r = test_login($test_url, $rg_ui, $good_sid);
54 50 if ($r === FALSE) { if ($r === FALSE) {
55 51 rg_log("Cannot login!"); rg_log("Cannot login!");
56 52 exit(1); exit(1);
57 53 } }
58 54
59 $key = rg_test_upload_ssh_key($db, $rg_ui, "git2", $good_sid);
60 55
61 $remote = 'ssh://rocketgit@rgtest/user/' . escapeshellarg($rg_ui['username'])
56 rg_log('');
57 rg_log_enter('Uploading a key...');
58 rg_test_upload_ssh_key($db, $rg_ui, "git2", $good_sid);
59 rg_log_exit();
60
61
62 rg_log('');
63 rg_log_enter('Trying to push master...');
64 $remote = 'ssh://rocketgit@' . $rg_ssh_host . ':' .$rg_ssh_port
65 . '/user/' . escapeshellarg($rg_ui['username'])
62 66 . '/' . escapeshellarg($repo['name']); . '/' . escapeshellarg($repo['name']);
63 system("cd git2; git remote add origin $remote");
64 exec("cd git2; git push origin master", $out, $err);
65 if ($err != 0) {
66 rg_log_ml('out: ' . print_r($out, TRUE));
67 $r = rg_exec("cd git2 && git remote add origin $remote"
68 . " && export GIT_SSH_COMMAND=\"ssh -v -o IdentityFile=../keys/git2\""
69 . " && git push origin master");
70 if ($r['ok'] != 1) {
71 rg_log_ml('out: ' . $r['errmsg']);
67 72 rg_log("Seems I cannot push master! err=$err"); rg_log("Seems I cannot push master! err=$err");
68 73 exit(1); exit(1);
69 74 } }
70 exec("cd git2; git push --tags origin", $out, $err);
71 if ($err != 0) {
72 rg_log_ml('out: ' . print_r($out, TRUE));
73 rg_log("Seems I cannot push tags! err=$err");
75 rg_log_exit();
76
77
78 rg_log('');
79 rg_log_enter('Trying to push tags...');
80 $r = rg_exec("cd git2"
81 . " && export GIT_SSH_COMMAND=\"ssh -v -o IdentityFile=../keys/git2\""
82 . " && git push --tags origin");
83 if ($r['ok'] != 1) {
84 rg_log_ml('error: ' . $r['errmsg']);
85 rg_log("Seems I cannot push tags!");
74 86 exit(1); exit(1);
75 87 } }
88 rg_log_exit();
76 89
77 90
78 91 $commit = trim(file_get_contents('git2/.git/refs/heads/master')); $commit = trim(file_get_contents('git2/.git/refs/heads/master'));
79 92 rg_log("Load master from .git: $commit"); rg_log("Load master from .git: $commit");
80 93
81 rg_log("Checking on web that everything is OK...");
94 rg_log('');
95 rg_log_enter('Checking on web that everything is OK...');
82 96 $data = array(); $data = array();
83 97 $headers = array("Cookie: sid=" . $good_sid); $headers = array("Cookie: sid=" . $good_sid);
84 98 $r = do_req($test_url . '/user/' . rawurlencode($rg_ui['username']) $r = do_req($test_url . '/user/' . rawurlencode($rg_ui['username'])
 
... ... if ($r === FALSE) {
88 102 rg_log("Cannot load master commit!"); rg_log("Cannot load master commit!");
89 103 exit(1); exit(1);
90 104 } }
105 rg_log_exit();
106
91 107
92 rg_log("Checking on web that tag is OK...");
108 rg_log('');
109 rg_log_enter('Checking on web that tag is OK...');
93 110 $data = array(); $data = array();
94 111 $headers = array("Cookie: sid=" . $good_sid); $headers = array("Cookie: sid=" . $good_sid);
95 112 $r = do_req($test_url . '/user/' . rawurlencode($rg_ui['username']) $r = do_req($test_url . '/user/' . rawurlencode($rg_ui['username'])
 
... ... if (strstr($r['body'], 'a signature') === FALSE) {
99 116 rg_log_ml("Cannot see the tag: " . print_r($r, TRUE)); rg_log_ml("Cannot see the tag: " . print_r($r, TRUE));
100 117 exit(1); exit(1);
101 118 } }
119 rg_log_exit();
102 120
103 121
104 122 rg_log("OK!"); rg_log("OK!");
File tests/helpers.inc.php changed (mode: 100644) (index d57e7d5..01aaf99)
... ... function rg_test_wh_add_edit($db, $rg_ui, $good_sid, $htype, $extra)
285 285 global $test_url; global $test_url;
286 286
287 287 rg_log("Loading webhook add form..."); rg_log("Loading webhook add form...");
288 $data = array('wh::htype' => $htype);
289 288 $headers = array("Cookie: sid=" . $good_sid); $headers = array("Cookie: sid=" . $good_sid);
290 289
291 290 if (!isset($extra['wh::id'])) if (!isset($extra['wh::id']))
292 291 $extra['wh::id'] = 0; $extra['wh::id'] = 0;
293 292
294 293 if ($extra['wh::id'] == 0) if ($extra['wh::id'] == 0)
295 $url = 'add';
294 $url = 'add/' . $htype;
296 295 else else
297 296 $url = 'edit/' . $extra['wh::id']; $url = 'edit/' . $extra['wh::id'];
298 297 $r = do_req($test_url . "/op/settings/wh/" . $url, $data, $headers); $r = do_req($test_url . "/op/settings/wh/" . $url, $data, $headers);
 
... ... function rg_test_wh_add_edit($db, $rg_ui, $good_sid, $htype, $extra)
307 306 } }
308 307
309 308 rg_log("Adding webhook..."); rg_log("Adding webhook...");
310 $data = array('add' => 1, 'token' => $r['tokens']['wh_add']);
309 $data = array('doit' => 1, 'token' => $r['tokens']['wh_add']);
311 310 $data = array_merge($data, $extra); $data = array_merge($data, $extra);
312 311 $headers = array('Cookie: sid=' . $good_sid); $headers = array('Cookie: sid=' . $good_sid);
313 312 $r = do_req($test_url . '/op/settings/wh/' . $url, $data, $headers); $r = do_req($test_url . '/op/settings/wh/' . $url, $data, $headers);
File tests/ssh.php changed (mode: 100644) (index 20cf572..5753a7e)
... ... if ($r === FALSE) {
38 38
39 39 $cmd = "ssh -i keys/" . $rg_ui['uid'] . " rocketgit@r1i"; $cmd = "ssh -i keys/" . $rg_ui['uid'] . " rocketgit@r1i";
40 40
41 $key = rg_test_upload_ssh_key($db, $rg_ui, $rg_ui['uid'], $good_sid);
41 rg_test_upload_ssh_key($db, $rg_ui, $rg_ui['uid'], $good_sid);
42 42
43 43 rg_log(''); rg_log('');
44 44 $list = array('', 'status', 'repos', 'repo', 'totp'); $list = array('', 'status', 'repos', 'repo', 'totp');
File tests/wh_cloud.git.sh added (mode: 100755) (index 0000000..517f779)
1 #!/bin/bash
2
3 set -e
4 set -u
5
6 rm -rf wh_cloud.git
7 git clone "${1}" wh_cloud.git
8 cd wh_cloud.git
9 cat >appspec.yml <<EOF
10 version: 0.0
11 os: linux
12 files:
13 - source: /index.html
14 destination: /var/www/html/
15 hooks:
16 BeforeInstall:
17 - location: scripts/install_dependencies
18 timeout: 3
19 runas: root
20 - location: scripts/start_server
21 timeout: 3
22 runas: root
23 ApplicationStop:
24 - location: scripts/stop_server
25 timeout: 3
26 runas: root
27 EOF
28 git add appspec.yml
29 git commit -a -m "a commit"
30
31 export GIT_SSH_COMMAND="ssh -o IdentityFile=../keys/wg_cloud"
32 git push origin master
File tests/wh_cloud.php added (mode: 100644) (index 0000000..90a5cdf)
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 . "/user.inc.php");
9 require_once("helpers.inc.php");
10 require_once("http.inc.php");
11
12 rg_log_set_file("wh_cloud.log");
13
14 $rg_sql = "host=localhost user=rocketgit dbname=rocketgit connect_timeout=10";
15 $rg_no_db = TRUE;
16 require_once("common.php");
17
18 $_testns = 'wh_cloud';
19 $rg_cache_enable = TRUE;
20 $rg_cache_debug = TRUE;
21 $rg_event_socket = "/var/lib/rocketgit/sockets/event.sock";
22
23 $home = getenv('HOME');
24 if (!file_exists($home . '/.aws/conf.php')) {
25 rg_log('no ~/.aws.conf.php file!');
26 exit(0);
27 }
28
29 // this will load $a array
30 include($home . '/.aws/conf.php');
31
32
33 rg_log('');
34 rg_log("Creating a user...");
35 rg_test_create_user($db, $rg_ui);
36
37
38 rg_log('');
39 rg_log_enter('Login...');
40 $r = test_login($test_url, $rg_ui, $good_sid);
41 if ($r === FALSE) {
42 rg_log("Cannot login!");
43 exit(1);
44 }
45 rg_log_exit();
46
47
48 rg_log('');
49 rg_log_enter('Registering webhook1...');
50 $extra = array(
51 'wh::htype' => 'cloud',
52 'wh::description' => 'description1 <xss>',
53 'wh::idata::access_key_id' => $a['access_key_id'],
54 'wh::idata::secret_access_key' => $a['secret_access_key'],
55 'wh::idata::region' => 'eu-central-1',
56 'wh::idata::application_name' => 'DemoApplication-##repo##',
57 'wh::idata::deployment_group_name' => 'DemoFleet-##repo##-##branch##',
58 'wh::idata::deployment_config_name' => '',
59 'wh::idata::bucket' => 'test-deploy-500-##repo##-##branch##',
60 'wh::idata::file' =>
61 '##repo##-##branch##-##who##-##hook_id##'
62 . '-##commit##-##date##-##time##-##ip##-##timestamp##.zip',
63 );
64 rg_test_wh_add_edit($db, $rg_ui, $good_sid, 'cloud', $extra);
65 rg_log_exit();
66
67
68 rg_log('');
69 rg_log_enter('Finding out the hook id...');
70 for ($i = 0; $i < 10; $i++) {
71 $r = rg_cache_get('wh' . '::' . $rg_ui['uid']);
72 if ($r !== FALSE)
73 break;
74 sleep(1);
75 }
76 if ($r === FALSE) {
77 rg_log('Cannot get id from cache');
78 exit(1);
79 }
80 rg_log_ml('r=' . print_r($r, TRUE));
81 $t = array_keys($r['list']);
82 if (count($t) != 1) {
83 rg_log('We do not have 1 id!');
84 exit(1);
85 }
86 $wh_id = $t[0];
87 rg_log('wh_id=' . $wh_id);
88 rg_log_exit();
89
90
91 rg_log('');
92 rg_log_enter('Creating and upload a ssh key...');
93 rg_test_upload_ssh_key($db, $rg_ui, "wg_cloud", $good_sid);
94 rg_log_exit();
95
96
97 rg_log('');
98 rg_log_enter('Creating a repo and pushing it');
99 $repo = array('name' => 'wh-cloud');
100 rg_test_create_repo($db, $rg_ui, $repo);
101 $repo_url = 'ssh://rocketgit@' . $rg_ssh_host . ':' . $rg_ssh_port
102 . '/user/' . $rg_ui['username'] . '/' . $repo['name'];
103 rg_log('repo_url=' . escapeshellarg($repo_url));
104 $r = rg_exec('./wh_cloud.git.sh ' . escapeshellarg($repo_url));
105 if ($r['ok'] != 1) {
106 rg_log('Could not create local git repo: ' . $r['errmsg'] . '!');
107 exit(1);
108 }
109 rg_log_exit();
110
111
112 rg_log('');
113 rg_log_enter('Testing if hook executed with success');
114 for ($i = 0; $i < 10; $i++) {
115 $key = 'DEBUG::' . $rg_ui['uid'] . '::webhooks::' . $wh_id;
116 $r = rg_cache_get($key);
117 rg_log_ml('cache: ' . $r);
118 if ($r !== FALSE)
119 break;
120 sleep(1);
121 }
122 if ($r === FALSE) {
123 rg_log('Seems the event did not set the cache!');
124 exit(1);
125 }
126 if (!strstr($r, '"deploymentId":"d-') && !strstr($r, 'is already deploying')) {
127 rg_log_ml('r: ' . print_r($r, TRUE));
128 rg_log('Seems hook did not executed correctly!');
129 exit(1);
130 }
131 rg_log_exit();
132
133
134 rg_log('');
135 rg_log_enter('Testing the edit of webhook...');
136 $extra = array(
137 'wh::id' => $wh_id,
138 'wh::htype' => 'cloud',
139 'wh::description' => 'desc2 <xss>',
140 'wh::flags' => 'D',
141 'wh::idata::access_key_id' => 'aaa',
142 'wh::idata::secret_access_key' => 'bbb',
143 'wh::idata::region' => 'ccc',
144 'wh::idata::application_name' => 'xxx',
145 'wh::idata::deployment_group_name' => 'yyy',
146 'wh::idata::deployment_config_name' => 'zzz',
147 'wh::idata::bucket' => 'buck',
148 'wh::idata::file' => 'rrr',
149 );
150 rg_test_wh_add_edit($db, $rg_ui, $good_sid, 'cloud', $extra);
151 $sql = "SELECT * FROM webhooks WHERE uid = " . $rg_ui['uid']
152 . " AND id = " . $wh_id;
153 $res = rg_sql_query($db, $sql);
154 $row = rg_sql_fetch_array($res);
155 rg_sql_free_result($res);
156 $row['idata'] = unserialize($row['idata']);
157 $key = 'wh' . '::' . $rg_ui['uid'] . '::' . 'list' . '::' . $wh_id;
158 rg_cache_core_unset($key); // else we will get previous copy!
159 $c = rg_cache_get($key);
160 $list = array('htype' => 'cloud',
161 'description' => 'desc2 <xss>', 'flags' => 'D',
162 'access_key_id' => 'aaa',
163 'secret_access_key' => 'bbb', 'region' => 'ccc',
164 'application_name' => 'xxx', 'deployment_group_name' => 'yyy',
165 'deployment_config_name' => 'zzz', 'bucket' => 'buck',
166 'file' => 'rrr');
167 foreach ($list as $k => $v) {
168 if (isset($row[$k]))
169 $a = $row[$k];
170 else if (isset($row['idata'][$k]))
171 $a = $row['idata'][$k];
172 else {
173 rg_log('Key [' . $k . '] not found! Bad!');
174 exit(1);
175 }
176 if (strcmp($a, $v) != 0) {
177 rg_log_ml('row: ' . print_r($row, TRUE));
178 rg_log("db: Seems that [$k] has not been updated"
179 . " [" . $a . "] != " . $v);
180 exit(1);
181 }
182
183 if (isset($c[$k]))
184 $a = $c[$k];
185 else
186 $a = $c['idata'][$k];
187 if (strcmp($a, $v) != 0) {
188 rg_log_ml('c: ' . print_r($c, TRUE));
189 rg_log("cache: Seems that [$k] has not been updated"
190 . " [" . $a . "] != " . $v);
191 exit(1);
192 }
193 }
194 rg_log_exit();
195
196
197 rg_log("OK!");
198 ?>
File tests/wh_http.php changed (mode: 100644) (index 76214d5..e301f49)
... ... rg_log('');
135 135 rg_log('Registering webhook1...'); rg_log('Registering webhook1...');
136 136 $extra = array( $extra = array(
137 137 'wh::htype' => 'http', 'wh::htype' => 'http',
138 'wh::url' => 'https://localhost:' . $port1 . '/wh.html',
139 'wh::events[C]' => 'on',
140 'wh::events[P]' => 'on',
141 'wh::events[B]' => 'on',
142 138 'wh::description' => 'description1 <xss>', 'wh::description' => 'description1 <xss>',
143 'wh::key' => 'key1 <xss>',
144 'wh::opaque' => $port1,
145 'wh::client_cert' => '',
139 'wh::idata::url' => 'https://localhost:' . $port1 . '/wh.html',
140 'wh::idata::events[C]' => 'on',
141 'wh::idata::events[P]' => 'on',
142 'wh::idata::events[B]' => 'on',
143 'wh::idata::key' => 'key1 <xss>',
144 'wh::idata::opaque' => $port1,
145 'wh::idata::client_cert' => '',
146 146 'wh::idata::itype' => 0, 'wh::idata::itype' => 0,
147 147 'wh::idata::client_ca_cert' => file_get_contents('ca/wh/certs/cacert.pem') 'wh::idata::client_ca_cert' => file_get_contents('ca/wh/certs/cacert.pem')
148 148 ); );
 
... ... rg_log('');
153 153 rg_log('Registering webhook2...'); rg_log('Registering webhook2...');
154 154 $extra = array( $extra = array(
155 155 'wh::htype' => 'http', 'wh::htype' => 'http',
156 'wh::url' => 'https://localhost:' . $port2 . '/wh.html',
157 'wh::events[C]' => 'on',
158 'wh::events[P]' => 'on',
159 'wh::events[B]' => 'on',
160 156 'wh::description' => 'description1 <xss>', 'wh::description' => 'description1 <xss>',
161 'wh::key' => 'key2 <xss>',
162 'wh::opaque' => $port2,
157 'wh::idata::url' => 'https://localhost:' . $port2 . '/wh.html',
158 'wh::idata::events[C]' => 'on',
159 'wh::idata::events[P]' => 'on',
160 'wh::idata::events[B]' => 'on',
161 'wh::idata::key' => 'key2 <xss>',
162 'wh::idata::opaque' => $port2,
163 163 'wh::idata::itype' => 1, 'wh::idata::itype' => 1,
164 164 'wh::idata::client_cert' => file_get_contents('ca/wh/certs/client.pem') 'wh::idata::client_cert' => file_get_contents('ca/wh/certs/client.pem')
165 165 . file_get_contents('ca/wh/private/client.key'), . file_get_contents('ca/wh/private/client.key'),
 
... ... rg_log('');
172 172 rg_log('Registering webhook3...'); rg_log('Registering webhook3...');
173 173 $extra = array( $extra = array(
174 174 'wh::htype' => 'http', 'wh::htype' => 'http',
175 'wh::url' => 'https://localhost:' . $port3 . '/wh.html',
176 'wh::events[C]' => 'on',
177 'wh::events[P]' => 'on',
178 'wh::events[B]' => 'on',
179 175 'wh::description' => 'description1 <xss>', 'wh::description' => 'description1 <xss>',
180 'wh::key' => 'key2 <xss>',
181 'wh::opaque' => $port3,
176 'wh::idata::url' => 'https://localhost:' . $port3 . '/wh.html',
177 'wh::idata::events[C]' => 'on',
178 'wh::idata::events[P]' => 'on',
179 'wh::idata::events[B]' => 'on',
180 'wh::idata::key' => 'key2 <xss>',
181 'wh::idata::opaque' => $port3,
182 182 'wh::idata::itype' => 1, 'wh::idata::itype' => 1,
183 183 'wh::idata::client_cert' => '', 'wh::idata::client_cert' => '',
184 184 'wh::idata::client_ca_cert' => file_get_contents('ca/wh/certs/cacert.pem') 'wh::idata::client_ca_cert' => file_get_contents('ca/wh/certs/cacert.pem')
 
... ... if (strcmp($r, "OK") != 0) {
272 272 rg_log(''); rg_log('');
273 273 rg_log('Testing the edit of webhook1...'); rg_log('Testing the edit of webhook1...');
274 274 $extra = array( $extra = array(
275 'wh::htype' => 'http',
276 'wh::url' => 'https://localhost:' . $port1 . '/wh.html',
277 275 'wh::id' => $wh_id1, 'wh::id' => $wh_id1,
278 'wh::events[C]' => 'on',
279 'wh::events[B]' => 'on',
276 'wh::htype' => 'http',
280 277 'wh::description' => 'desc2 <xss>', 'wh::description' => 'desc2 <xss>',
281 'wh::key' => 'another key <xss>',
282 'wh::opaque' => 'xxx',
278 'wh::flags[D]' => 'on',
279 'wh::idata::url' => 'https://localhost:' . $port1 . '/wh.html',
280 'wh::idata::events[C]' => 'on',
281 'wh::idata::events[B]' => 'on',
282 'wh::idata::key' => 'another key <xss>',
283 'wh::idata::opaque' => 'xxx',
283 284 'wh::idata::itype' => 1, 'wh::idata::itype' => 1,
284 'wh::idata::flags[I]' => 'on',
285 285 'wh::idata::client_cert' => 'abc <xss>', 'wh::idata::client_cert' => 'abc <xss>',
286 286 'wh::idata::client_ca_cert' => 'zzz <xss>' 'wh::idata::client_ca_cert' => 'zzz <xss>'
287 287 ); );
 
... ... rg_cache_core_unset($key); // else we will get previous copy!
297 297 $c = rg_cache_get($key); $c = rg_cache_get($key);
298 298 $list = array('htype' => 'http', 'events' => 'CB', $list = array('htype' => 'http', 'events' => 'CB',
299 299 'description' => 'desc2 <xss>', 'key' => 'another key <xss>', 'description' => 'desc2 <xss>', 'key' => 'another key <xss>',
300 'opaque' => 'xxx', 'itype' => '1', 'flags' => 'I',
300 'opaque' => 'xxx', 'itype' => '1', 'flags' => 'D',
301 301 'client_cert' => 'abc <xss>', 'client_ca_cert' => 'zzz <xss>'); 'client_cert' => 'abc <xss>', 'client_ca_cert' => 'zzz <xss>');
302 302 foreach ($list as $k => $v) { foreach ($list as $k => $v) {
303 303 if (isset($row[$k])) if (isset($row[$k]))
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