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 c2b73a8e494c4c61ce2d3f0d4101f0836a5a0df6

Added webhooks
Author: Catalin(ux) M. BOIE
Author date (UTC): 2015-10-29 03:55
Committer name: Catalin(ux) M. BOIE
Committer date (UTC): 2015-10-29 03:55
Parent(s): b4e220bf8823cad220183930949e80a6ec7f2fb3
Signing key:
Tree: d9f7ac45488986aec0bbe89361e5e2249ebae0a7
File Lines added Lines deleted
Makefile.in 2 1
TODO 41 17
inc/bug.inc.php 12 0
inc/events.inc.php 23 7
inc/keys.inc.php 16 4
inc/repo.inc.php 40 9
inc/struct.inc.php 23 1
inc/totp.inc.php 16 23
inc/user.inc.php 5 0
inc/user/settings.php 5 0
inc/util.inc.php 34 0
inc/webhooks.inc.php 694 0
rocketgit.spec.in 1 0
root/themes/default/main.css 4 2
root/themes/default/repo/add_edit.html 1 1
root/themes/default/tos.html 10 7
root/themes/default/user/settings/menu.html 1 0
root/themes/default/user/settings/totp/delete_ok.html 1 1
root/themes/default/user/settings/wh/add_edit.html 50 0
root/themes/default/user/settings/wh/delete_ok.html 3 0
root/themes/default/user/settings/wh/edit_ok.html 3 0
root/themes/default/user/settings/wh/hints.html 2 0
root/themes/default/user/settings/wh/list/footer.html 0 0
root/themes/default/user/settings/wh/list/header.html 21 0
root/themes/default/user/settings/wh/list/line.html 12 0
root/themes/default/user/settings/wh/list/nodata.html 1 1
root/themes/default/user/settings/wh/list_err.html 3 0
root/themes/default/user/settings/wh/menu.html 6 0
scripts/cache.php 2 1
tests/.gitignore 2 0
tests/Makefile 5 3
tests/ca.sh 59 0
tests/config.php 1 0
tests/helpers.inc.php 37 1
tests/http.inc.php 2 0
tests/wh-helper.sh 6 0
tests/wh-stunnel.conf 14 0
tests/wh-test.sh 9 0
tests/wh.php 247 0
File Makefile.in changed (mode: 100644) (index 7528f39..00feb72)
... ... install: all
54 54 @mkdir -pv $(I_VAR_LIB)/$(PRJ)/qstats @mkdir -pv $(I_VAR_LIB)/$(PRJ)/qstats
55 55 @mkdir -pv $(I_VAR_LIB)/$(PRJ)/sockets @mkdir -pv $(I_VAR_LIB)/$(PRJ)/sockets
56 56 @echo "Fixing rights..." @echo "Fixing rights..."
57 @-chown -R rocketgit:rocketgit $(I_VAR_LIB)/$(PRJ)
58 57 @-find $(I_VAR_LIB)/$(PRJ) -type d -exec chmod 0755 {} \; @-find $(I_VAR_LIB)/$(PRJ) -type d -exec chmod 0755 {} \;
59 58 @-find $(I_VAR_LIB)/$(PRJ) -type f -exec chmod 0600 {} \; @-find $(I_VAR_LIB)/$(PRJ) -type f -exec chmod 0600 {} \;
59 @mkdir -pv --mode=0700 $(I_VAR_LIB)/$(PRJ)/tmp
60 @-chown -R rocketgit:rocketgit $(I_VAR_LIB)/$(PRJ)
60 61 @ @
61 62 @echo "Installing SELinux stuff..." @echo "Installing SELinux stuff..."
62 63 @mkdir -pv --mode=0755 $(I_USR_SHARE)/selinux/targeted @mkdir -pv --mode=0755 $(I_USR_SHARE)/selinux/targeted
File TODO changed (mode: 100644) (index 279f1f2..931fa4b)
1 1 == Where I stopped last time == == Where I stopped last time ==
2 [ ] Seems that somehow I managed to arrive at
3 'http://r1i:9000/op/repo/create/create'! Not good!
4 I think by creating repositories.
5 [ ] wh test is not working.
6 [ ] rg_debug is sent twice for wh.php unit testing.
2 7 [ ] [ ]
3 8
4 9 == BEFORE NEXT RELEASE == == BEFORE NEXT RELEASE ==
10 [ ] For events, very probably I have to disable the cache.
11 Scenario: adding a webhook1, add a repo1, add a webhook2,
12 add a repo2. webhook2 will not trigger on repo2 creating because
13 only webhook1 is in cache! Very bad!
14 [ ] Add notifications for hook add?
15 [ ] Send an e-mail if webhook fails? Flag when configuring webhook?
16 [ ] unit test: generate a CA, client cert, server cert, and use openssl
17 s_server to test? Or maybe curl in mode server? Or php in listen
18 mode?
19 [ ] Clean 'tmp' folder.
20 [ ] Document webhooks, mostly 'PHP serialize' type. But also other things.
21 [ ] Do not forget that cache.php has its own memory cache!
22 I must not update the database and expect it to see good values.
23 [ ] wh: Add: tag push, issue, merge request
24 [ ] wh: add also XML, JSON
25 [ ] wh: add other conection types: websocket, socket (low priority)
26 [ ] How "Delete selected" button should be aligned?
27 [ ] Use rg_var_a2s for checkboxes.
28 [ ] http://www.w3.org/TR/clipboard-apis/
29 1. maybe support javascript copy API
30 2. The boxes with a border on the left would be nice for hints.
31 [ ] Evaluate https://www.gnu.org/software/repo-criteria.html
32 Also in Compare.txt
5 33 [ ] When I am in "My repositories" and I am doing a search, other users' [ ] When I am in "My repositories" and I am doing a search, other users'
6 34 repositories are shown. repositories are shown.
7 35 [ ] In user/home-page.php, in hints section, add a message when the user is [ ] In user/home-page.php, in hints section, add a message when the user is
8 36 low on scratch codes. Not hint. low on scratch codes. Not hint.
9 [ ] If 'rg_debug'? is defined, do not send mails.
10 37 [ ] test with "short" (0 prepended) codes in unit testing. [ ] test with "short" (0 prepended) codes in unit testing.
11 38 For scs, done, test for devices? This is a little bit harder. For scs, done, test for devices? This is a little bit harder.
12 39 [ ] totp:ssh: do we need a command to remove a set of scratch codes? [ ] totp:ssh: do we need a command to remove a set of scratch codes?
13 40 Something like 'remove-sc [<itime>]'. If <itime> is missing, list the Something like 'remove-sc [<itime>]'. If <itime> is missing, list the
14 41 sets. The IP must be authorized? sets. The IP must be authorized?
15 [ ] http hook: use curl's CURLOPT_SSLCERT to authenticate to the client server.
16 42 [ ] In report, just show the newly added repos, not the totals. Totals in body. [ ] In report, just show the newly added repos, not the totals. Totals in body.
17 43 [ ] Apply to become a member of Software Freedom Conservancy? [ ] Apply to become a member of Software Freedom Conservancy?
18 [ ] Why do we index 'users' by 'username'?! Seems wrong!
44 [ ] Why do we have an index by 'users.username'?! Seems wrong!
19 45 [ ] totp: add sc for ssh! [ ] totp: add sc for ssh!
20 46 Should I validate one after asking the user to store them safe? Should I validate one after asking the user to store them safe?
21 47 Think about power down before scratch codes hit the printer. Think about power down before scratch codes hit the printer.
22 48 [ ] Get rid of {{}} stuff. [ ] Get rid of {{}} stuff.
23 [ ] Some other menus were added, we must load all this pages.
49 [ ] Some other menus were added, we must load all this pages in unit tests.
24 50 At least totp/{list,enroll,sc}. At least totp/{list,enroll,sc}.
25 51 [ ] I inconsistently use /op/repo/create and /user/catab/settings! [ ] I inconsistently use /op/repo/create and /user/catab/settings!
26 52 Why not /user/catab/repo/create? Why not /user/catab/repo/create?
 
63 89 [ ] Report number of lines of code (and how much a project worth) and [ ] Report number of lines of code (and how much a project worth) and
64 90 number of other type of documents. number of other type of documents.
65 91 [ ] Add some flags for users: "Coming from GitHub", to be able to give [ ] Add some flags for users: "Coming from GitHub", to be able to give
66 tailored hints.
92 specific hints.
67 93 [ ] totp: warn user that if a token is not validated for 1 month will be deleted? [ ] totp: warn user that if a token is not validated for 1 month will be deleted?
68 94 [ ] totp: allow prefix for IP addresses. [ ] totp: allow prefix for IP addresses.
69 95 [ ] totp: think about authorizing a push, not the ip (ip may be dynamic). [ ] totp: think about authorizing a push, not the ip (ip may be dynamic).
 
83 109 the browser. the browser.
84 110 [ ] Document how to deny non ascii filenames using repo_path. [ ] Document how to deny non ascii filenames using repo_path.
85 111 [ ] When a right denies access, also output the description of that right. [ ] When a right denies access, also output the description of that right.
112 Maybe add a new box for the text to be shown to the user?
86 113 [ ] Tell clear that rg can be used also for books, articles, documentation etc. [ ] Tell clear that rg can be used also for books, articles, documentation etc.
87 114 [ ] Include uid in namespace path to avoid clashes with other users? [ ] Include uid in namespace path to avoid clashes with other users?
88 115 [ ] ssh: show the fingerprint of the used key? [ ] ssh: show the fingerprint of the used key?
 
103 130 'password/token', right? Also, for https, I cannot provide the token, 'password/token', right? Also, for https, I cannot provide the token,
104 131 only user/pass. Maybe appending token to the pass. only user/pass. Maybe appending token to the pass.
105 132 [ ] Can I remove the redirect after login (that means another request)? [ ] Can I remove the redirect after login (that means another request)?
133 Adding a user is pretty light, we should allow the redirect.
106 134 [ ] In the report, send also stats about the events, especially the failed ones. [ ] In the report, send also stats about the events, especially the failed ones.
107 135 [ ] Document backup procedure. [ ] Document backup procedure.
108 136 [ ] "Forgot password": rate limit it! [ ] "Forgot password": rate limit it!
 
129 157 Instruct user to remove the token if the phone is lost. But, remind Instruct user to remove the token if the phone is lost. But, remind
130 158 user that the account may not be compromised without pass. user that the account may not be compromised without pass.
131 159 [ ] totp: think about loosing the phone. [ ] totp: think about loosing the phone.
132 [ ] totp: warn about time desync; maybe ask the user to press the 'sync' in
133 the mobile app.
134 160 [ ] totp: what if I encrypt key with the password and decrypt only at login? [ ] totp: what if I encrypt key with the password and decrypt only at login?
135 161 (If somebody steals the database, will not have the keys). (If somebody steals the database, will not have the keys).
136 162 Cannot do. We need it also at push by ssh. Cannot do. We need it also at push by ssh.
137 163 [ ] totp: hints for ssh [ ] totp: hints for ssh
138 164 [ ] totp: Implement 2 factor auth [ ] totp: Implement 2 factor auth
139 (check https://korg.wiki.kernel.org/userdoc/gitolite_2fa)
165 (check https://korg.wiki.kernel.org/userdoc/gitolite_2fa). Done!
140 166 [ ] Use PAM (man pam_start) to be able to use any type of auth, including LDAP. [ ] Use PAM (man pam_start) to be able to use any type of auth, including LDAP.
141 167 [ ] http://www.cybertec.at/shrinking-the-storage-footprint-of-data/ [ ] http://www.cybertec.at/shrinking-the-storage-footprint-of-data/
142 168 [ ] Allow repo admins/owners to delete notes/bugs/etc. [ ] Allow repo admins/owners to delete notes/bugs/etc.
 
152 178 [ ] I should show some plan 'islands' when you create the account [ ] I should show some plan 'islands' when you create the account
153 179 so the user will know the disk space and bandwidth. so the user will know the disk space and bandwidth.
154 180 [ ] In a table, if nothing can be deleted, do not show the delete button. [ ] In a table, if nothing can be deleted, do not show the delete button.
155 [ ] web hooks: start with a http post to a user server.
156 warn the user if is not working?
157 181 [ ] When giving some users rights to your repo, do not spam them with [ ] When giving some users rights to your repo, do not spam them with
158 182 messages. The user must agree to be spammed. Best, no notification messages. The user must agree to be spammed. Best, no notification
159 183 is ever issued. User may go to project to activate them if s/he wants. is ever issued. User may go to project to activate them if s/he wants.
 
196 220 [ ] Add sha1sum of the VM images [ ] Add sha1sum of the VM images
197 221 [ ] ssh: Show user the entry that must be added for known_hosts [ ] ssh: Show user the entry that must be added for known_hosts
198 222 [ ] LDAP: http://mageconfig.blogspot.ro/2014/06/configure-gitgerrit-with-open-ldap-for.html [ ] LDAP: http://mageconfig.blogspot.ro/2014/06/configure-gitgerrit-with-open-ldap-for.html
199 [ ] Leave alone the ssh key comment! More exactly, do not convert unk chars.
200 223 [ ] Pass only uid to events, we already have it in cache! [ ] Pass only uid to events, we already have it in cache!
201 224 [ ] 'confirmed' should be built in the event handlers not in callers. [ ] 'confirmed' should be built in the event handlers not in callers.
202 225 It is already checked in rg_mail_template! It is already checked in rg_mail_template!
 
225 248 [ ] Allow creating tags/branches on web interface. [ ] Allow creating tags/branches on web interface.
226 249 [ ] Use a separate template for main rocketgit.com site. The other users [ ] Use a separate template for main rocketgit.com site. The other users
227 250 should not see the same pages. should not see the same pages.
228 [ ] git-filter-branch is very powerful: offer it to the clients!
251 [ ] git-filter-branch is very powerful: offer it to the users!
229 252 [ ] word-break: break-all; pentru tabelele cu cod. asta permite wrap-ul [ ] word-break: break-all; pentru tabelele cu cod. asta permite wrap-ul
230 253 oriunde - still needed?! oriunde - still needed?!
231 254 [ ] Backup for rg2! [ ] Backup for rg2!
 
300 323 [ ] Before custom hooks, allow enforcing a custom regex for a commit. [ ] Before custom hooks, allow enforcing a custom regex for a commit.
301 324 [ ] rg_repo_delete trebuie sa stearga si rights si bugs si notes si bug files [ ] rg_repo_delete trebuie sa stearga si rights si bugs si notes si bug files
302 325 si watch-uri. si watch-uri.
303 [ ] For unit testing, we need to pass a debug para in http requests and the
304 mails to be saved in a folder, so we can parse them and verify them.
305 326 [ ] Expose "git reflog". [ ] Expose "git reflog".
306 327 [ ] Should I allow state select when adding a bug? Better to consider it open? [ ] Should I allow state select when adding a bug? Better to consider it open?
307 328 [ ] Add regex for label filtering, maybe for other fields? [ ] Add regex for label filtering, maybe for other fields?
308 329 [ ] Add regex for search? [ ] Add regex for search?
309 330 [ ] When showing diff, for the list of files, make links to chunks inside page. [ ] When showing diff, for the list of files, make links to chunks inside page.
331 Already done?
310 332 [ ] php-opcache in docs? [ ] php-opcache in docs?
311 333 [ ] Drop OUTPUT to prevent some attacks? Document in README? [ ] Drop OUTPUT to prevent some attacks? Document in README?
312 334 [ ] Seems I cache not set values: first_install is still "?"! [ ] Seems I cache not set values: first_install is still "?"!
 
... ... mails to be saved in a folder, so we can parse them and verify them.
325 347 [ ] HTTP_X_FORWARDED_FOR variable as this data is effectively user input and [ ] HTTP_X_FORWARDED_FOR variable as this data is effectively user input and
326 348 therefore susceptible to spoofing. therefore susceptible to spoofing.
327 349 [ ] Try to remove non critical queries from main page loading. Just schedule [ ] Try to remove non critical queries from main page loading. Just schedule
328 the operations for later.
350 the operations for later (register_shutdown_function?).
329 351 [ ] We should not delete the tokens. They will be cleaned hourly? [ ] We should not delete the tokens. They will be cleaned hourly?
330 352 [ ] Remove all texts from code and move them to templates. [ ] Remove all texts from code and move them to templates.
331 353 [ ] Storing password in database must apply multiple hashes. Check owasp. [ ] Storing password in database must apply multiple hashes. Check owasp.
 
... ... But, we have a problem with the expiration time!
473 495 [ ] repos.disk_quota_mb must be dropped and do a look-up in plan. [ ] repos.disk_quota_mb must be dropped and do a look-up in plan.
474 496 [ ] Integrate max_public/private_repos into HL. [ ] Integrate max_public/private_repos into HL.
475 497 [ ] Allow specifying base language for a project. [ ] Allow specifying base language for a project.
498 [ ] Add country when creating a user?
476 499 [ ] When changing db structure, invalidate all caches. [ ] When changing db structure, invalidate all caches.
477 500 [ ] When we will switch to C, check UTF-8 validation. [ ] When we will switch to C, check UTF-8 validation.
478 501 [ ] Check http://blog.wikichoon.com/2014/04/github-doesnt-support-pull-request.html [ ] Check http://blog.wikichoon.com/2014/04/github-doesnt-support-pull-request.html
 
... ... But, we have a problem with the expiration time!
528 551 private dir. private dir.
529 552 - "USER" is the user that is logged in. Maybe find a better string - "USER" is the user that is logged in. Maybe find a better string
530 553 because we may have a user "USER". because we may have a user "USER".
531 - Also limit by IP and by time.
554 - Also limit by time.
532 555 - We have a problem: some rights do not map correctly to the plan above. - We have a problem: some rights do not map correctly to the plan above.
533 556 For example, A(admin) etc. Seems we need to have >2 categories. For example, A(admin) etc. Seems we need to have >2 categories.
534 557 - Also, we will have problems classifying a project as public or private. - Also, we will have problems classifying a project as public or private.
 
... ... But, we have a problem with the expiration time!
598 621 [ ] Check http://nvie.com/posts/a-successful-git-branching-model/ [ ] Check http://nvie.com/posts/a-successful-git-branching-model/
599 622 [ ] After resetting password, go to the login form, with user pre-filed so [ ] After resetting password, go to the login form, with user pre-filed so
600 623 the user can cache the password. the user can cache the password.
601 [ ] Add number of bugs multiplied with a value to total disk space.
624 [ ] Add number of bugs multiplied with a factor to total disk space.
625 Same for any row in the database. Should we do it?
602 626 [ ] How should I verify repo rights? [ ] How should I verify repo rights?
603 627 if (admin) if (admin)
604 628 if (owner) if (owner)
File inc/bug.inc.php changed (mode: 100644) (index b050efe..f77b6e2)
... ... function rg_bug_event_add_one($db, $event)
50 50
51 51 $ret = FALSE; $ret = FALSE;
52 52 while (1) { while (1) {
53 if ($event['debug'] == 1) {
54 rg_cache_set('DEBUG::bug_event_add_one', $event, 0);
55 $ret = array();
56 break;
57 }
58
53 59 // lookup user email // lookup user email
54 60 $ui = rg_user_info($db, $event['ui']['uid'], '', ''); $ui = rg_user_info($db, $event['ui']['uid'], '', '');
55 61 if ($ui['exists'] != 1) { if ($ui['exists'] != 1) {
 
... ... function rg_bug_event_note_add_one($db, $event)
127 133
128 134 $ret = FALSE; $ret = FALSE;
129 135 while (1) { while (1) {
136 if ($event['debug'] == 1) {
137 rg_cache_set('DEBUG::bug_event_note_add_one', $event, 0);
138 $ret = array();
139 break;
140 }
141
130 142 // lookup user email // lookup user email
131 143 $ui = rg_user_info($db, $event['ui']['uid'], '', ''); $ui = rg_user_info($db, $event['ui']['uid'], '', '');
132 144 if ($ui['exists'] != 1) { if ($ui['exists'] != 1) {
File inc/events.inc.php changed (mode: 100644) (index 9f67caa..bb4b73f)
... ... function rg_event_signal_daemon($ev_id, $timeout)
52 52 { {
53 53 global $rg_event_socket; global $rg_event_socket;
54 54
55 if (empty($rg_event_socket))
55 if (empty($rg_event_socket)) {
56 rg_log('DEBUG: rg_event_socket is not defined!');
56 57 return TRUE; return TRUE;
58 }
57 59
58 60 if ($timeout === NULL) if ($timeout === NULL)
59 61 $s_timeout = "forever"; $s_timeout = "forever";
 
... ... function rg_event_signal_daemon($ev_id, $timeout)
86 88 */ */
87 89 function rg_event_add($db, $event) function rg_event_add($db, $event)
88 90 { {
91 global $rg_debug;
92
89 93 rg_prof_start("event_add"); rg_prof_start("event_add");
90 94 rg_log_enter("event_add: event=" . rg_array2string($event)); rg_log_enter("event_add: event=" . rg_array2string($event));
91 95
92 96 if (!isset($event['IP'])) if (!isset($event['IP']))
93 97 $event['IP'] = rg_var_str('REMOTE_ADDR'); $event['IP'] = rg_var_str('REMOTE_ADDR');
94 98
99 if (!isset($event['debug']))
100 $event['debug'] = 0;
101 if ($event['debug'] == 0)
102 $event['debug'] = rg_var_uint('rg_debug');
103 if ($rg_debug)
104 $event['debug'] = 1;
105
95 106 $ret = FALSE; $ret = FALSE;
96 107 while (1) { while (1) {
97 108 $now = time(); $now = time();
 
... ... function rg_event_process($db, $event)
146 157 break; break;
147 158 } }
148 159
160 if (!is_array($evs))
161 rg_internal_error("evs is not array!");
162
149 163 if (empty($evs)) { if (empty($evs)) {
150 164 $ret = TRUE; $ret = TRUE;
151 165 break; break;
152 166 } }
153 167
168 // TODO: here we must do a transaction?
169
154 170 $r = TRUE; $r = TRUE;
155 if (!is_array($evs))
156 rg_internal_error("evs is not array!");
157 171 foreach ($evs as $index => $ev) { foreach ($evs as $index => $ev) {
158 172 $r = rg_event_add($db, $ev); $r = rg_event_add($db, $ev);
159 173 if ($r !== TRUE) if ($r !== TRUE)
 
... ... function rg_event_process($db, $event)
162 176 if ($r !== TRUE) if ($r !== TRUE)
163 177 break; break;
164 178
165 rg_event_signal_daemon("", 0);
166
167 179 $ret = TRUE; $ret = TRUE;
168 180 break; break;
169 181 } }
 
... ... function rg_event_process_queue($db, &$notify_list)
238 250
239 251 // We limit to be able to deal with high prio tasks // We limit to be able to deal with high prio tasks
240 252 $sql = "SELECT * FROM events" $sql = "SELECT * FROM events"
241 . " WHERE fail = 0 AND next_try < $now"
253 . " WHERE fail = 0"
254 . " AND next_try < $now"
242 255 . " ORDER BY prio, id" . " ORDER BY prio, id"
243 256 . " FOR UPDATE" . " FOR UPDATE"
244 257 . " LIMIT 100"; . " LIMIT 100";
 
... ... function rg_event_process_queue($db, &$notify_list)
253 266 while (($row = rg_sql_fetch_array($res))) { while (($row = rg_sql_fetch_array($res))) {
254 267 $params = array('id' => $row['id']); $params = array('id' => $row['id']);
255 268
269 $sql = "UPDATE events SET fail = 1 WHERE id = @@id@@";
256 270 while (1) { while (1) {
257 271 $ev = unserialize($row['data']); $ev = unserialize($row['data']);
258 272 if ($ev === FALSE) { if ($ev === FALSE) {
259 273 rg_internal_error("Cannot unserialize data"); rg_internal_error("Cannot unserialize data");
260 $sql = "UPDATE events SET fail = 1 WHERE id = @@id@@";
261 274 break; break;
262 275 } }
263 276
 
... ... function rg_event_process_queue($db, &$notify_list)
266 279
267 280 $r = rg_event_process($db, $ev); $r = rg_event_process($db, $ev);
268 281 if ($r !== TRUE) { if ($r !== TRUE) {
282 if ($ev['debug'] == 1)
283 break;
284
269 285 $sql = "UPDATE events" $sql = "UPDATE events"
270 286 . " SET tries = tries + 1" . " SET tries = tries + 1"
271 287 . ", next_try = $now + tries * 600" . ", next_try = $now + tries * 600"
File inc/keys.inc.php changed (mode: 100644) (index 2999cea..a7a062c)
... ... function rg_keys_event_notify_user($db, $event)
101 101 // TODO: del: Take care: we already deleted the keys. We cannot inspect // TODO: del: Take care: we already deleted the keys. We cannot inspect
102 102 // them anymore! Maybe put info in the event. // them anymore! Maybe put info in the event.
103 103
104 $r = rg_mail_template("mail/user/key/" . $event['op'], $event);
105 if ($r === FALSE)
106 return FALSE;
104 $ret = FALSE;
105 while (1) {
106 if ($event['debug'] == 1) {
107 rg_cache_set('DEBUG::keys_event_notify_user', $event, 0);
108 $ret = array();
109 break;
110 }
111
112 $r = rg_mail_template("mail/user/key/" . $event['op'], $event);
113 if ($r === FALSE)
114 break;
115
116 $ret = array();
117 break;
118 }
107 119
108 120 rg_prof_end("keys_event_notify_user"); rg_prof_end("keys_event_notify_user");
109 return array();
121 return $ret;
110 122 } }
111 123
112 124 /* /*
File inc/repo.inc.php changed (mode: 100644) (index d97d4af..747b083)
... ... require_once($INC . "/git.inc.php");
7 7 require_once($INC . "/rights.inc.php"); require_once($INC . "/rights.inc.php");
8 8 require_once($INC . "/prof.inc.php"); require_once($INC . "/prof.inc.php");
9 9 require_once($INC . "/events.inc.php"); require_once($INC . "/events.inc.php");
10 require_once($INC . "/webhooks.inc.php");
10 11
11 12 $rg_repo_refs_rights = array( $rg_repo_refs_rights = array(
12 13 "F" => "Fetch", "F" => "Fetch",
 
... ... function rg_repo_event_new($db, $event)
274 275 $x['notification'] .= "-notify"; $x['notification'] .= "-notify";
275 276 $ret[] = $x; $ret[] = $x;
276 277
278 // webhook
279 $x = $event;
280 $x['category'] = 10000;
281 $x['prio'] = 50;
282 $x['wh_event'] = 'C'; // see rg_wh_events array
283 $ri = &$event['ri'];
284 $x['wh_data'] = array(
285 'name' => $ri['name'],
286 'public' => $ri['public'],
287 'description' => $ri['description'],
288 'itime' => $ri['itime'],
289 'license' => $ri['license']
290 );
291 $ret[] = $x;
292
277 293 // add a history entry // add a history entry
278 294 $x = $event; $x = $event;
279 295 $x['category'] = 3006; $x['category'] = 3006;
 
... ... function rg_repo_event_notify_user($db, $event)
458 474 { {
459 475 rg_prof_start("repo_event_notify_user"); rg_prof_start("repo_event_notify_user");
460 476
461 $r = rg_mail_template("mail/user/repo/" . $event['op'], $event);
462 if ($r === FALSE)
463 return FALSE;
477 $ret = FALSE;
478 while (1) {
479 if ($event['debug'] == 1) {
480 rg_cache_set('DEBUG::repo_event_notify_user', $event, 0);
481 $ret = array();
482 break;
483 }
484
485 $r = rg_mail_template("mail/user/repo/" . $event['op'], $event);
486 if ($r === FALSE)
487 break;
488
489 $ret = array();
490 break;
491 }
464 492
465 493 rg_prof_end("repo_event_notify_user"); rg_prof_end("repo_event_notify_user");
466 return array();
494 return $ret;
467 495 } }
468 496
469 497 /* /*
 
... ... function rg_repo_edit($db, $login_ui, &$new)
908 936
909 937 if ($new['repo_id'] == 0) { if ($new['repo_id'] == 0) {
910 938 // Check if name is already taken // Check if name is already taken
911 $ri = rg_repo_info($db, 0, $login_ui['uid'], $new['name']);
939 $ri = rg_repo_info($db, 0, $login_ui['uid'],
940 $new['name']);
912 941 if ($ri['ok'] != 1) if ($ri['ok'] != 1)
913 942 break; break;
914 943 if ($ri['exists'] == 1) { if ($ri['exists'] == 1) {
915 rg_repo_set_error("name already taken; choose a different one");
944 rg_repo_set_error('name already taken;'
945 . ' choose a different one');
916 946 break; break;
917 947 } }
918 948 } else { } else {
 
... ... function rg_repo_edit($db, $login_ui, &$new)
922 952 if ($ri['ok'] != 1) if ($ri['ok'] != 1)
923 953 break; break;
924 954 if ($ri['exists'] != 1) { if ($ri['exists'] != 1) {
925 rg_repo_set_error("repo " . $new['repo_id'] . " does not exists.");
955 rg_repo_set_error('repo ' . $new['repo_id']
956 . ' does not exists.');
926 957 break; break;
927 958 } }
928 959 } }
 
... ... function rg_repo_edit($db, $login_ui, &$new)
976 1007 if ($new['repo_id'] == 0) { if ($new['repo_id'] == 0) {
977 1008 $row = rg_sql_fetch_array($res); $row = rg_sql_fetch_array($res);
978 1009 if ($row === FALSE) { if ($row === FALSE) {
979 rg_repo_set_error("cannot fetch row: " . rg_sql_error());
1010 rg_repo_set_error('cannot fetch row');
980 1011 break; break;
981 1012 } }
982 1013 } }
 
... ... function rg_repo_edit($db, $login_ui, &$new)
1025 1056 rg_cache_set("repo_by_name::" . $login_ui['uid'] . "::" rg_cache_set("repo_by_name::" . $login_ui['uid'] . "::"
1026 1057 . $new['name'], $new['repo_id'], RG_SOCKET_NO_WAIT); . $new['name'], $new['repo_id'], RG_SOCKET_NO_WAIT);
1027 1058
1028 rg_event_signal_daemon("", 0);
1059 rg_event_signal_daemon('', 0);
1029 1060
1030 1061 $ret = TRUE; $ret = TRUE;
1031 1062 break; break;
File inc/struct.inc.php changed (mode: 100644) (index b39dbd8..decbaae)
... ... $rg_sql_struct[34]['tables'] = array(
451 451 ); );
452 452 $rg_sql_struct[34]['other'] = array( $rg_sql_struct[34]['other'] = array(
453 453 "scratch_codes_i_uid" => "scratch_codes_i_uid" =>
454 "CREATE INDEX scratch_codes_i_uid ON scratch_codes(uid)",
454 "CREATE INDEX scratch_codes_i_uid ON scratch_codes(uid)"
455 );
456
457 $rg_sql_struct[35] = array();
458 $rg_sql_struct[35]['tables'] = array(
459 "webhooks" =>
460 "CREATE TABLE webhooks (id SERIAL"
461 . ", uid INT NOT NULL DEFAULT 0"
462 . ", repo_id INT NOT NULL DEFAULT 0"
463 . ", itime INT NOT NULL DEFAULT 0"
464 . ", events TEXT NOT NULL DEFAULT ''"
465 . ", url TEXT NOT NULL DEFAULT ''"
466 . ", type SMALLINT NOT NULL DEFAULT 0"
467 . ", client_cert TEXT NOT NULL DEFAULT ''"
468 . ", client_ca_cert TEXT NOT NULL DEFAULT ''"
469 . ", flags TEXT NOT NULL DEFAULT ''"
470 . ", add_ip TEXT NOT NULL DEFAULT ''"
471 . ", description TEXT NOT NULL DEFAULT ''"
472 . ")"
473 );
474 $rg_sql_struct[35]['other'] = array(
475 "webhooks_i_uid" =>
476 "CREATE INDEX webhooks_i_uid ON webhooks(uid)"
455 477 ); );
456 478
457 479 // This must be the last line // This must be the last line
File inc/totp.inc.php changed (mode: 100644) (index 96502f1..2dbebcd)
... ... function rg_totp_set_last_use($db, $uid, $id, $tc, $ts)
269 269 . ', conf = @@conf@@' . ', conf = @@conf@@'
270 270 . ' WHERE uid = @@uid@@' . ' WHERE uid = @@uid@@'
271 271 . ' AND id = @@id@@'; . ' AND id = @@id@@';
272 $res = rg_sql_query_params($db, $sql, $params);
273 if ($res === FALSE) {
274 rg_totp_set_error('cannot update last used (' . rg_sql_error());
272 $res = rg_sql_query_params($db, $sql, $params);
273 if ($res === FALSE) {
274 rg_totp_set_error('cannot update last used (' . rg_sql_error());
275 275 break; break;
276 }
277 rg_sql_free_result($res);
276 }
277 rg_sql_free_result($res);
278 278
279 279 $key = 'user' . '::' . $uid . '::' . 'login_tokens' $key = 'user' . '::' . $uid . '::' . 'login_tokens'
280 280 . '::' . 'device' . '::' . $id; . '::' . 'device' . '::' . $id;
 
... ... function rg_totp_device_list($db, $uid)
311 311 break; break;
312 312 } }
313 313
314 $ret = array();
315 $ret['ok'] = 0;
316
317 314 $params = array('uid' => $uid); $params = array('uid' => $uid);
318 315 $sql = 'SELECT * FROM login_tokens' $sql = 'SELECT * FROM login_tokens'
319 316 . ' WHERE uid = @@uid@@' . ' WHERE uid = @@uid@@'
 
... ... function rg_totp_enroll($db, $uid, $name, $secret, $ip, $conf)
443 440 break; break;
444 441 } }
445 442 $row = rg_sql_fetch_array($res); $row = rg_sql_fetch_array($res);
446 rg_sql_free_result($res);
443 rg_sql_free_result($res);
447 444
448 445 $params['id'] = $row['id']; $params['id'] = $row['id'];
449 446 rg_totp_cosmetic($params); rg_totp_cosmetic($params);
 
... ... function rg_totp_add_ip($db, $uid, $token_id, $ip, $expire_ts)
484 481 rg_totp_set_error('cannot insert login token ip; try again later'); rg_totp_set_error('cannot insert login token ip; try again later');
485 482 break; break;
486 483 } }
487 rg_sql_free_result($res);
484 rg_sql_free_result($res);
488 485
489 486 unset($params['uid']); unset($params['uid']);
490 487 $eip = str_replace(':', '_', $ip); $eip = str_replace(':', '_', $ip);
 
... ... function rg_totp_del_ip($db, $uid, $ip)
528 525 break; break;
529 526 } }
530 527 $aff = rg_sql_affected_rows($res); $aff = rg_sql_affected_rows($res);
531 rg_sql_free_result($res);
528 rg_sql_free_result($res);
532 529
533 530 $ret['ok'] = 1; $ret['ok'] = 1;
534 531
 
... ... function rg_totp_remove($db, $uid, $list)
704 701 break; break;
705 702 } }
706 703
707 rg_log_exit();
704 rg_log_exit();
708 705 rg_prof_end('totp_remove'); rg_prof_end('totp_remove');
709 706 return $ret; return $ret;
710 707 } }
 
... ... function rg_totp_sc_generate($db, $uid, $count)
872 869 rg_totp_set_error('cannot insert scratch codes; try again later'); rg_totp_set_error('cannot insert scratch codes; try again later');
873 870 break; break;
874 871 } }
875 rg_sql_free_result($res);
872 rg_sql_free_result($res);
876 873
877 874 rg_totp_cosmetic($params); rg_totp_cosmetic($params);
878 875 $key = 'user' . '::' . $uid . '::' . 'login_tokens' $key = 'user' . '::' . $uid . '::' . 'login_tokens'
 
... ... function rg_totp_sc_remove($db, $uid, $itime, $token)
921 918 break; break;
922 919 } }
923 920
924 rg_log_exit();
921 rg_log_exit();
925 922 rg_prof_end('totp_sc_remove'); rg_prof_end('totp_sc_remove');
926 923 return $ret; return $ret;
927 924 } }
 
... ... function rg_totp_sc_remove_list($db, $uid, $list)
969 966 break; break;
970 967 } }
971 968
972 rg_log_exit();
969 rg_log_exit();
973 970 rg_prof_end('totp_sc_remove_list'); rg_prof_end('totp_sc_remove_list');
974 971 return $ret; return $ret;
975 972 } }
 
... ... function rg_totp_unenroll($db, $uid)
1008 1005 $params = array('uid' => $uid); $params = array('uid' => $uid);
1009 1006 $list = array('login_tokens', 'login_tokens_ip', 'scratch_codes'); $list = array('login_tokens', 'login_tokens_ip', 'scratch_codes');
1010 1007 foreach ($list as $t) { foreach ($list as $t) {
1011 $sql = 'DELETE FROM ' . $t
1008 $sql = 'DELETE FROM ' . $t
1012 1009 . ' WHERE uid = @@uid@@'; . ' WHERE uid = @@uid@@';
1013 1010 $res = rg_sql_query_params($db, $sql, $params); $res = rg_sql_query_params($db, $sql, $params);
1014 1011 if (!$res) { if (!$res) {
 
... ... function rg_totp_list_high_level($db, $rg, $paras)
1238 1235 } else { } else {
1239 1236 $rg['rg_form_token'] = rg_token_get($db, $rg, 'login_tokens_list'); $rg['rg_form_token'] = rg_token_get($db, $rg, 'login_tokens_list');
1240 1237 $rg['HTML:del_errmsg'] = rg_template_errmsg($del_errmsg); $rg['HTML:del_errmsg'] = rg_template_errmsg($del_errmsg);
1241 $ret .= rg_template_table('user/settings/totp/list', $r['list'], $rg);
1238 $ret .= rg_template_table('user/settings/totp/list',
1239 $r['list'], $rg);
1242 1240 } }
1243 1241
1244 1242 rg_log_exit(); rg_log_exit();
 
... ... function rg_totp_enroll_high_level($db, $rg, $paras)
1256 1254
1257 1255 $now = time(); $now = time();
1258 1256
1259 $rg['totp'] = array();
1260
1261 1257 $ret = ''; $ret = '';
1262 1258 $errmsg = array(); $errmsg = array();
1263 1259
1264 $rg['totp']['name'] = rg_var_str('totp::name');
1265
1266 1260 $enroll = rg_var_uint('enroll'); $enroll = rg_var_uint('enroll');
1267 1261 while ($enroll == 1) { while ($enroll == 1) {
1268 1262 $name = rg_var_str('totp::name'); $name = rg_var_str('totp::name');
 
... ... function rg_totp_enroll_high_level($db, $rg, $paras)
1317 1311 $secret = rg_totp_base32_generate(16); $secret = rg_totp_base32_generate(16);
1318 1312 } }
1319 1313
1314 $rg['totp'] = array();
1320 1315 $rg['totp']['name'] = $name; $rg['totp']['name'] = $name;
1321 1316 $rg['totp']['ver'] = $ver; $rg['totp']['ver'] = $ver;
1322 1317 $rg['totp']['secret'] = $secret; $rg['totp']['secret'] = $secret;
 
... ... function rg_totp_enroll_high_level($db, $rg, $paras)
1330 1325 } }
1331 1326
1332 1327 $rg['HTML:errmsg'] = rg_template_errmsg($errmsg); $rg['HTML:errmsg'] = rg_template_errmsg($errmsg);
1333
1334 1328 $rg['rg_form_token'] = rg_token_get($db, $rg, 'user_totp_enroll'); $rg['rg_form_token'] = rg_token_get($db, $rg, 'user_totp_enroll');
1335 rg_log_ml('DEBUG rg: ' . print_r($rg, TRUE));
1336 1329 $ret .= rg_template('user/settings/totp/enroll.html', $rg, TRUE /*xss*/); $ret .= rg_template('user/settings/totp/enroll.html', $rg, TRUE /*xss*/);
1337 1330
1338 1331 rg_log_exit(); rg_log_exit();
File inc/user.inc.php changed (mode: 100644) (index 1c4bf0d..11fea9c)
... ... function rg_user_event_notify_user($db, $event)
92 92 { {
93 93 rg_log("user_event_notify_user: event=" . rg_array2string($event)); rg_log("user_event_notify_user: event=" . rg_array2string($event));
94 94
95 if ($event['debug'] == 1) {
96 rg_cache_set('DEBUG::user_event_notify_user', $event, 0);
97 return array();
98 }
99
95 100 if (strcmp($event['op'], "rename") == 0) { if (strcmp($event['op'], "rename") == 0) {
96 101 $r = rg_mail_template("mail/user/rename", $event); $r = rg_mail_template("mail/user/rename", $event);
97 102 } else { } else {
File inc/user/settings.php changed (mode: 100644) (index cddd83b..3890c4a)
1 1 <?php <?php
2 2 rg_log("FILE: /inc/user/settings"); rg_log("FILE: /inc/user/settings");
3 require_once($INC . '/webhooks.inc.php');
3 4
4 5 $_settings = ''; $_settings = '';
5 6
 
... ... case 'keys':
37 38 case 'totp': case 'totp':
38 39 $_settings .= rg_totp_high_level($db, $rg, $paras); $_settings .= rg_totp_high_level($db, $rg, $paras);
39 40 break; break;
41
42 case 'wh':
43 $_settings .= rg_wh_high_level($db, $rg, $paras);
44 break;
40 45 } }
41 46
42 47 ?> ?>
File inc/util.inc.php changed (mode: 100644) (index d94706d..6313a70)
... ... function rg_var_cookie_re($name, $re)
357 357 return preg_replace($re, '', $_COOKIE[$name]); return preg_replace($re, '', $_COOKIE[$name]);
358 358 } }
359 359
360 /*
361 * Gets data from request and transforms it into an array
362 * Usefull for checkboxes.
363 * (a2s = array2string)
364 */
365 function rg_var_a2s($var)
366 {
367 $r = rg_var_str($var);
368 if (!is_array($r))
369 return $r;
370
371 $ret = '';
372 foreach ($r as $s => $junk)
373 $ret .= $s;
374
375 return $ret;
376 }
377
360 378 /* /*
361 379 * Enforce chars in a name. It is used for user and repo. * Enforce chars in a name. It is used for user and repo.
362 380 */ */
 
... ... function rg_age($ts)
1595 1613 return $ret; return $ret;
1596 1614 } }
1597 1615
1616 /*
1617 * Creates a temporary file
1618 */
1619 function rg_tmp_file($file, $content)
1620 {
1621 global $rg_state_dir;
1622
1623 $final_name = $rg_state_dir . '/tmp/' . $file;
1624 $r = @file_put_contents($final_name, $content);
1625 if ($r === FALSE)
1626 return FALSE;
1627 // TODO: log error messege?
1628
1629 return $final_name;
1630 }
1631
1598 1632 ?> ?>
File inc/webhooks.inc.php added (mode: 100644) (index 0000000..5da2344)
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
7 $rg_wh_error = "";
8
9 function rg_wh_set_error($str)
10 {
11 global $rg_wh_error;
12
13 $rg_wh_error = $str;
14 rg_log($str);
15 }
16
17 function rg_wh_error()
18 {
19 global $rg_wh_error;
20 return $rg_wh_error;
21 }
22
23 $rg_wh_functions = array(
24 10000 => 'rg_wh_send',
25 10001 => 'rg_wh_send_one'
26 );
27 rg_event_register_functions($rg_wh_functions);
28
29 /*
30 * Helper for rg_wh_send
31 */
32 function rg_wh_send_one($db, $event)
33 {
34 rg_prof_start('wh_send_helper');
35
36 $wh = &$event['wh'];
37 $info = &$wh['info'];
38
39 rg_log('flags=' . $info['flags']);
40
41 $headers = array();
42
43 $c = curl_init($info['url']);
44 curl_setopt($c, CURLOPT_POST, 1);
45 curl_setopt($c, CURLOPT_POSTFIELDS, $wh['data']);
46 curl_setopt($c, CURLOPT_RETURNTRANSFER, TRUE);
47 curl_setopt($c, CURLOPT_FOLLOWLOCATION, 0);
48 curl_setopt($c, CURLOPT_HEADER, 1);
49 curl_setopt($c, CURLOPT_HTTPHEADER, $headers);
50 curl_setopt($c, CURLOPT_USERAGENT, 'RocketGit WebHook');
51 curl_setopt($c, CURLOPT_CONNECTTIMEOUT, 30);
52 curl_setopt($c, CURLOPT_ENCODING, ''); // => use all methods
53 curl_setopt($c, CURLOPT_VERBOSE, TRUE);
54 curl_setopt($c, CURLOPT_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS);
55 $err = @fopen('php://temp', 'w');
56 if ($err !== FALSE)
57 curl_setopt($c, CURLOPT_STDERR, $err);
58
59 if (strchr($info['flags'], 'I'))
60 curl_setopt($c, CURLOPT_SSL_VERIFYPEER, FALSE);
61
62 if (strchr($info['flags'], 'H'))
63 curl_setopt($c, CURLOPT_SSL_VERIFYHOST, FALSE);
64
65 $ret = FALSE;
66 $cert_file = FALSE;
67 $ca_file = FALSE;
68 while (1) {
69 if (!empty($info['client_cert'])) {
70 $f = 'wh-' . $event['ui']['uid'] . '-' . $wh['id'] . '-client';
71 $cert_file = rg_tmp_file($f, $info['client_cert']);
72 if ($cert_file === FALSE)
73 break;
74
75 curl_setopt($c, CURLOPT_SSLCERT, $cert_file);
76 }
77
78 if (!empty($info['client_ca_cert'])) {
79 $f = 'wh-' . $event['ui']['uid'] . '-' . $wh['id'] . '-ca';
80 $ca_file = rg_tmp_file($f, $info['client_ca_cert']);
81 if ($ca_file === FALSE)
82 break;
83
84 curl_setopt($c, CURLOPT_CAINFO, $ca_file);
85 }
86
87 $r = curl_exec($c);
88 if ($r === FALSE) {
89 rg_log('Cannot execute curl: ' . curl_error($c));
90 $info = curl_getinfo($c);
91 rg_log_ml('Debug: ' . print_r($info, TRUE));
92
93 if ($event['debug'] == 1)
94 rg_cache_set('DEBUG::webhooks::' . $event['ui']['uid']
95 . '::' . $wh['id'],
96 'BAD', RG_SOCKET_NO_WAIT);
97 break;
98 }
99
100 rg_log_ml('Answer: ' . print_r($r, TRUE));
101
102 if ($err !== FALSE) {
103 rewind($err);
104 $xerr = @fread($err, 4 * 4096);
105 fclose($err);
106 rg_log_ml('xerr = ' . $xerr);
107 }
108
109 if ($event['debug'] == 1)
110 rg_cache_set('DEBUG::webhooks::' . $event['ui']['uid']
111 . '::' . $wh['id'],
112 'OK', RG_SOCKET_NO_WAIT);
113
114 $ret = array();
115 break;
116 }
117 curl_close($c);
118
119 if ($cert_file !== FALSE)
120 @unlink($cert_file);
121
122 if ($ca_file !== FALSE)
123 @unlink($ca_file);
124
125 rg_prof_end('wh_send_helper');
126 return $ret;
127 }
128
129 /*
130 * Generic function which will be called when a webhook must be posted
131 */
132 function rg_wh_send($db, $event)
133 {
134 rg_prof_start('wh_send');
135
136 rg_log_ml('event: ' . print_r($event, TRUE));
137
138 // First, get the list of hooks
139 $r = rg_wh_list($db, $event['ui']['uid']);
140 if ($r['ok'] != 1)
141 return FALSE;
142
143 // Filter them by repo_id
144 $real_list = array();
145 foreach ($r['list'] as $id => $info) {
146 if (($info['repo_id'] != 0)
147 && ($event['ri']['repo_id'] != $info['repo_id'])) {
148 rg_log('hook is not for this repo');
149 continue;
150 }
151
152 // If the web hook does not contain our type, skip it
153 if (!strchr($info['events'], $event['wh_event'])) {
154 rg_log($event['wh_event'] . ' is not present in ' . $info['events']);
155 continue;
156 }
157
158 $real_list[] = $id;
159 }
160
161 // Something to do?
162 if (empty($real_list))
163 return array();
164
165 $cache = array();
166 $wh = array();
167 $ret = array();
168 foreach ($real_list as $id) {
169 $wh['info'] = $r['list'][$id];
170 $wh['id'] = $id;
171
172 $type = $wh['info']['type'];
173 if (!isset($cache[$type])) {
174 switch ($type) {
175 case 0: // http post
176 $cache[$type] = &$event['wh_data'];
177 break;
178
179 case 1: // php serialize
180 $cache[$type] = array(
181 'data' => serialize($event['wh_data']));
182 break;
183
184 default:
185 rg_log('Unknown type ' . $type . '!');
186 $cache[$type] = '';
187 break;
188 }
189 }
190 $wh['data'] = $cache[$type];
191
192 $x = $event;
193 $x['category'] = 10001;
194 $x['wh'] = $wh;
195 $ret[] = $x;
196 }
197
198 rg_prof_end('wh_send');
199 return $ret;
200 }
201
202 $rg_wh_types = array(
203 0 => 'HTTP (application/x-www-form-urlencoded)',
204 1 => 'PHP serialize'
205 );
206 /*
207 * Transforms a type into HTML select
208 */
209 function rg_wh_select_type($type)
210 {
211 global $rg_wh_types;
212
213 $ret = '<select name="wh::type" id="type">';
214 foreach ($rg_wh_types as $_type => $name) {
215 $add = '';
216 if ($_type == $type)
217 $add = ' selected';
218
219 $ret .= '<option value="' . $_type . '"' . $add . '>'
220 . $name
221 . '</option>' . "\n";
222 }
223 $ret .= '</select>' . "\n";
224
225 return $ret;
226 }
227
228 /*
229 * Returns type text based on id
230 */
231 function rg_wh_type($type)
232 {
233 global $rg_wh_types;
234
235 foreach ($rg_wh_types as $_type => $name)
236 if ($_type == $type)
237 return $name;
238 }
239
240 $rg_wh_events = array(
241 'C' => 'Create repository',
242 'P' => 'Push',
243 'B' => 'Create branch'
244 );
245 /*
246 * Generates event list as html
247 */
248 function rg_wh_check_events($events)
249 {
250 global $rg_wh_events;
251
252 $ret = '<fieldset>';
253 $ret .= '<legend>Select trigger events</legend>';
254 $br = '';
255 foreach ($rg_wh_events as $id => $name) {
256 $add = '';
257 if (strchr($events, $id))
258 $add = ' checked="checked"';
259
260 $ret .= $br
261 . '<input type="checkbox" name="wh::events[' . $id . ']"'
262 . ' id="events-' . $id . '"'
263 . $add . ' />'
264 . "\n"
265 . '<label for="events-' . $id . '">' . $name . '</label>';
266 $br = '<br />' . "\n";
267 }
268 $ret .= '</fieldset>' . "\n";
269
270 return $ret;
271 }
272
273 /*
274 * Generates an events list as text
275 */
276 function rg_wh_events($events)
277 {
278 global $rg_wh_events;
279
280 $a = array();
281 foreach ($rg_wh_events as $id => $name) {
282 if (strchr($events, $id))
283 $a[] = $name;
284 }
285
286 return implode(', ', $a);
287 }
288
289 $rg_wh_flags = array(
290 'I' => 'Do not verify the certificate',
291 'H' => 'Do not verify the hostname'
292 );
293 /*
294 * Generates flags list
295 */
296 function rg_wh_check_flags($flags)
297 {
298 global $rg_wh_flags;
299
300 $ret = '<fieldset>';
301 $ret .= '<legend>Flags</legend>';
302 $br = '';
303 foreach ($rg_wh_flags as $id => $name) {
304 $add = '';
305 if (strchr($flags, $id))
306 $add = ' checked="checked"';
307
308 $ret .= $br
309 . '<input type="checkbox" name="wh::flags[' . $id . ']"'
310 . ' id="flags-' . $id . '"'
311 . $add . ' />'
312 . "\n"
313 . '<label for="flags-' . $id . '">' . $name . '</label>';
314 $br = '<br />' . "\n";
315 }
316 $ret .= '</fieldset>' . "\n";
317
318 return $ret;
319 }
320
321 /*
322 * Generates a flags list as text
323 */
324 function rg_wh_flags($flags)
325 {
326 global $rg_wh_flags;
327
328 $a = array();
329 foreach ($rg_wh_flags as $id => $name) {
330 if (strchr($flags, $id))
331 $a[] = $name;
332 }
333
334 return implode(', ', $a);
335 }
336
337 /*
338 * Some cosmetics applied to a webhook
339 */
340 function rg_wh_cosmetic(&$list)
341 {
342 foreach ($list as $id => &$row) {
343 if (isset($row['itime']))
344 $row['itime_nice'] = gmdate('Y-m-d H:i', $row['itime']);
345
346 if (isset($row['description']))
347 $row['HTML:description_nice'] =
348 nl2br(rg_xss_safe($row['description']));
349
350 if (isset($row['type']))
351 $row['type_text'] = rg_wh_type($row['type']);
352
353 if (isset($row['events']))
354 $row['events_text'] = rg_wh_events($row['events']);
355
356 if (isset($row['flags']))
357 $row['flags_text'] = rg_wh_flags($row['flags']);
358
359 if (isset($row['client_cert']))
360 $row['HTML:client_cert_short'] =
361 empty($row['client_cert']) ?
362 '' : nl2br(rg_xss_safe(substr($row['client_cert'], 0, 32))) . '...';
363
364 if (isset($row['client_ca_cert']))
365 $row['HTML:client_ca_cert_short'] =
366 empty($row['client_ca_cert']) ?
367 '' : nl2br(rg_xss_safe(substr($row['client_ca_cert'], 0, 32))) . '...';
368 }
369 }
370
371 /*
372 * Returns a list of webhooks associated with a user
373 * @repo_id may be 0 => hooks installed on user account
374 */
375 function rg_wh_list($db, $uid)
376 {
377 rg_prof_start('wh_list');
378 rg_log_enter('wh_list');
379
380 $ret = array('ok' => 0, 'list' => array());
381 while (1) {
382 $key = 'user' . '::' . $uid . '::' . 'wh';
383 $r = rg_cache_get($key);
384 if ($r !== FALSE) {
385 $ret['list'] = $r;
386 $ret['ok'] = 1;
387 break;
388 }
389
390 $params = array('uid' => $uid);
391 $sql = 'SELECT * FROM webhooks'
392 . ' WHERE uid = @@uid@@';
393 $res = rg_sql_query_params($db, $sql, $params);
394 if ($res === FALSE) {
395 rg_wh_set_error('cannot load data');
396 break;
397 }
398
399 while (($row = rg_sql_fetch_array($res))) {
400 $id = $row['id'];
401
402 $ret['list'][$id] = $row;
403 }
404 rg_sql_free_result($res);
405
406 rg_cache_set($key, $ret['list'], RG_SOCKET_NO_WAIT);
407 $ret['ok'] = 1;
408 break;
409 }
410
411 rg_log_exit();
412 rg_prof_end('wh_list');
413 return $ret;
414 }
415
416 /*
417 * Adds/edits a webhook
418 */
419 function rg_wh_add($db, $uid, $data)
420 {
421 rg_prof_start('wh_add');
422 rg_log_enter('wh_add');
423
424 $ret = array('ok' => 0);
425 while (1) {
426 $params = $data;
427 $params['uid'] = $uid;
428 $params['itime'] = time();
429
430 if ($data['id'] == 0)
431 $sql = 'INSERT INTO webhooks (uid, repo_id, itime, events'
432 . ', url, client_cert, client_ca_cert, flags'
433 . ', add_ip, description)'
434 . ' VALUES (@@uid@@, @@repo_id@@, @@itime@@'
435 . ', @@events@@, @@url@@, @@client_cert@@'
436 . ', @@client_ca_cert@@, @@flags@@, @@add_ip@@'
437 . ', @@description@@)'
438 . ' RETURNING id';
439 else
440 $sql = 'UPDATE webhooks'
441 . ' SET events = @@events@@'
442 . ', url = @@url@@'
443 . ', client_cert = @@client_cert@@'
444 . ', client_ca_cert = @@client_ca_cert@@'
445 . ', flags = @@flags@@'
446 . ', type = @@type@@'
447 . ', description = @@description@@'
448 . ' WHERE uid = @@uid@@'
449 . ' AND id = @@id@@';
450
451 $res = rg_sql_query_params($db, $sql, $params);
452 if ($res === FALSE) {
453 rg_wh_set_error('cannot insert/update data');
454 break;
455 }
456 if ($data['id'] == 0)
457 $row = rg_sql_fetch_array($res);
458 rg_sql_free_result($res);
459
460 if ($data['id'] == 0)
461 $params['id'] = $row['id'];
462 $key = 'user' . '::' . $uid . '::' . 'wh'
463 . '::' . $params['id'];
464 rg_cache_set($key, $params, RG_SOCKET_NO_WAIT);
465
466 $ret['ok'] = 1;
467 break;
468 }
469
470 rg_log_exit();
471 rg_prof_end('wh_add');
472 return $ret;
473 }
474
475 /*
476 * Removes a list of webhooks
477 */
478 function rg_wh_remove($db, $uid, $list)
479 {
480 rg_prof_start('wh_remove');
481 rg_log_enter('wh_remove');
482
483 $ret = array('ok' => 0);
484 while (1) {
485 if (empty($list)) {
486 rg_wh_set_error('you did not select anything');
487 break;
488 }
489
490 $my_list = array();
491 foreach ($list as $id => $junk)
492 $my_list[] = sprintf("%u", $id);
493
494 $params = array('uid' => $uid);
495 $sql_list = implode(', ', $my_list);
496
497 $sql = 'DELETE FROM webhooks'
498 . ' WHERE uid = @@uid@@'
499 . ' AND id IN (' . $sql_list . ')';
500 $res = rg_sql_query_params($db, $sql, $params);
501 if ($res === FALSE) {
502 rg_wh_set_error('cannot remove webhooks');
503 break;
504 }
505 rg_sql_free_result($res);
506
507 foreach ($my_list as $junk => $id) {
508 $key = 'user' . '::' . $uid . '::' . 'wh' . '::' . $id;
509 rg_cache_unset($key, RG_SOCKET_NO_WAIT);
510 }
511
512 $ret['ok'] = 1;
513 break;
514 }
515
516 rg_log_exit();
517 rg_prof_end('wh_remove');
518 return $ret;
519 }
520
521 /*
522 * High level function to list the webhooks
523 */
524 function rg_wh_list_high_level($db, $rg, $paras)
525 {
526 rg_prof_start('wh_list_high_level');
527 rg_log_enter('wh_list_high_level');
528
529 $ret = '';
530
531 $errmsg = array();
532
533 $delete = rg_var_uint('delete');
534 while ($delete == 1) {
535 if (!rg_valid_referer()) {
536 $errmsg[] = 'invalid referer; try again';
537 break;
538 }
539
540 if (!rg_token_valid($db, $rg, 'wh_list', FALSE)) {
541 $errmsg[] = 'invalid token; try again.';
542 break;
543 }
544
545 $list = rg_var_str("delete_list");
546 $r = rg_wh_remove($db, $rg['login_ui']['uid'], $list);
547 if ($r['ok'] !== 1) {
548 $errmsg[] = 'cannot delete: ' . rg_wh_error();
549 break;
550 }
551
552 $ret .= rg_template('user/settings/wh/delete_ok.html',
553 $rg, TRUE /*xss*/);
554 break;
555 }
556
557 $r = rg_wh_list($db, $rg['login_ui']['uid']);
558 if ($r['ok'] !== 1) {
559 $rg['errmsg'] = rg_wh_error();
560 $ret .= rg_template('user/settings/wh/list_err.html',
561 $rg, TRUE /*xss*/);
562 } else {
563 rg_wh_cosmetic($r['list']);
564 //rg_log_ml("DEBUG: r[list]: " . print_r($r['list'], TRUE));
565 $rg['rg_form_token'] = rg_token_get($db, $rg, 'wh_list');
566 $rg['HTML:errmsg'] = rg_template_errmsg($errmsg);
567 $ret .= rg_template_table('user/settings/wh/list',
568 $r['list'], $rg);
569 }
570
571 rg_log_exit();
572 rg_prof_end('wh_list_high_level');
573 return $ret;
574 }
575
576 /*
577 * High level function to add/edit a web hook
578 */
579 function rg_wh_add_high_level($db, $rg, $paras)
580 {
581 rg_prof_start('wh_add_high_level');
582 rg_log_enter('wh_add_high_level');
583
584 $ret = '';
585 $errmsg = array();
586 $show_form = TRUE;
587
588 $rg['wh'] = array();
589 // We need the id in any case
590 $rg['wh']['id'] = rg_var_str('wh::id');
591
592 $add = rg_var_uint('add');
593 while ($add == 1) {
594 $rg['wh']['repo_id'] = rg_var_uint('wh::repo_id');
595 $rg['wh']['itime'] = time();
596 $rg['wh']['events'] = rg_var_a2s('wh::events'); // TODO
597 $rg['wh']['url'] = rg_var_str('wh::url');
598 $rg['wh']['type'] = rg_var_uint('wh::type');
599 $rg['wh']['client_cert'] = trim(rg_var_str('wh::client_cert'));
600 $rg['wh']['client_ca_cert'] = trim(rg_var_str('wh::client_ca_cert'));
601 $rg['wh']['flags'] = rg_var_a2s('wh::flags');
602 $rg['wh']['add_ip'] = isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : '';
603 $rg['wh']['description'] = rg_var_str('wh::description');
604
605 // TODO: validate here the paras
606 if ((strncasecmp($rg['wh']['url'], "http", 4) != 0)
607 || (strncasecmp($rg['wh']['url'], "https", 5) != 0)) {
608 $errmsg[] = 'invalid protocol; only http and https supported now';
609 break;
610 }
611
612 if (!rg_valid_referer()) {
613 $errmsg[] = 'invalid referer; try again';
614 break;
615 }
616
617 if (!rg_token_valid($db, $rg, 'wh_add', FALSE)) {
618 $errmsg[] = 'invalid token; try again.';
619 break;
620 }
621
622 $r = rg_wh_add($db, $rg['login_ui']['uid'], $rg['wh']);
623 if ($r['ok'] !== 1) {
624 $errmsg[] = rg_wh_error();
625 break;
626 }
627
628 $ret .= rg_template('user/settings/wh/edit_ok.html',
629 $rg, TRUE /*xss*/);
630
631 $show_form = FALSE;
632 break;
633 }
634
635 if ($show_form) {
636 // defaults
637 if ($add == 0) {
638 // TODO: if edit, load data based on id
639 if ($rg['wh']['id'] > 0) {
640 rg_log('TODO: edit is not yet implemented');
641 } else {
642 // here is clear an add
643 $rg['wh']['id'] = 0;
644 $rg['wh']['events'] = '';
645 $rg['wh']['url'] = '';
646 $rg['wh']['type'] = 0;
647 $rg['wh']['client_cert'] = '';
648 $rg['wh']['client_ca_cert'] = '';
649 $rg['wh']['flags'] = '';
650 $rg['wh']['description'] = '';
651 }
652 }
653
654 $rg['HTML:errmsg'] = rg_template_errmsg($errmsg);
655 $rg['HTML:check_flags'] = rg_wh_check_flags($rg['wh']['flags']);
656 $rg['HTML:check_events'] = rg_wh_check_events($rg['wh']['events']);
657 $rg['HTML:select_type'] = rg_wh_select_type($rg['wh']['type']);
658 $rg['rg_form_token'] = rg_token_get($db, $rg, 'wh_add');
659 $ret .= rg_template('user/settings/wh/add_edit.html',
660 $rg, TRUE /*xss*/);
661 }
662
663 rg_log_exit();
664 rg_prof_end('wh_add_high_level');
665 return $ret;
666 }
667
668 /*
669 * Main HL function for webhooks
670 */
671 function rg_wh_high_level($db, $rg, $paras)
672 {
673 rg_prof_start('wh_high_level');
674 rg_log_enter('wh_high_level');
675
676 $ret = '';
677
678 $op = empty($paras) ? 'list' : array_shift($paras);
679 $rg['menu']['wh'][$op] = 1;
680
681 rg_log("DEBUG: op=$op");
682 $ret .= rg_template('user/settings/wh/menu.html', $rg, TRUE /*xss*/);
683
684 switch ($op) {
685 case 'add': $ret .= rg_wh_add_high_level($db, $rg, $paras); break;
686 default: $ret .= rg_wh_list_high_level($db, $rg, $paras); break;
687 }
688
689 rg_log_exit();
690 rg_prof_end('wh_high_level');
691 return $ret;
692 }
693
694 ?>
File rocketgit.spec.in changed (mode: 100644) (index 4cf6dc8..51a49f9)
... ... rm -rf ${RPM_BUILD_ROOT}
95 95 %attr(0755,rocketgit,rocketgit) %dir @VAR_LIB@/@PRJ@/repos %attr(0755,rocketgit,rocketgit) %dir @VAR_LIB@/@PRJ@/repos
96 96 %attr(0755,rocketgit,rocketgit) %dir @VAR_LIB@/@PRJ@/q_merge_requests %attr(0755,rocketgit,rocketgit) %dir @VAR_LIB@/@PRJ@/q_merge_requests
97 97 %attr(0755,rocketgit,rocketgit) %dir @VAR_LIB@/@PRJ@/sockets %attr(0755,rocketgit,rocketgit) %dir @VAR_LIB@/@PRJ@/sockets
98 %attr(0700,rocketgit,rocketgit) %dir @VAR_LIB@/@PRJ@/tmp
98 99 @USR_SHARE@/@PRJ@/* @USR_SHARE@/@PRJ@/*
99 100 @USR_SHARE@/selinux/*/@PRJ@.pp @USR_SHARE@/selinux/*/@PRJ@.pp
100 101
File root/themes/default/main.css changed (mode: 100644) (index 672c0b9..945fcc5)
... ... form textarea, form select {
54 54 margin: 2px 0px; margin: 2px 0px;
55 55 } }
56 56 form input[type="checkbox"] { form input[type="checkbox"] {
57 margin-right: 4pt;
57 margin-right: 2pt;
58 58 } }
59 59 form input[type="radio"] { form input[type="radio"] {
60 margin-right: 4pt;
60 margin-right: 2pt;
61 61 } }
62 62 form select option { padding: 1px 4px 1px 4px; } form select option { padding: 1px 4px 1px 4px; }
63 63 form input[type="submit"] { form input[type="submit"] {
 
... ... legend { padding: 0px 2pt; }
281 281 margin-top: 20px; margin-top: 20px;
282 282 } }
283 283
284 .rg_wh_list {}
285
284 286 .blob_title { .blob_title {
285 287 font-size: 11pt; font-size: 11pt;
286 288 color: #F00; color: #F00;
File root/themes/default/repo/add_edit.html changed (mode: 100644) (index fcdca7d..2564a21)
18 18 </p> </p>
19 19
20 20 <p> <p>
21 <label for="license">License(s)</label><br />
21 <label for="license">License(s) (recommended: GPLv3)</label><br />
22 22 <input type="text" name="license" id="license" value="@@ri::license@@" /> <input type="text" name="license" id="license" value="@@ri::license@@" />
23 23 </p> </p>
24 24
File root/themes/default/tos.html changed (mode: 100644) (index 34f31b4..0f87fcc)
5 5 <div class="island_cell"> <div class="island_cell">
6 6 <div class="island"> <div class="island">
7 7
8 The RocketGit code is copyright (c) 2015 by Catalin BOIE and is
9 covered by <a href="https://gnu.org/licenses/agpl.html">Affero GPLv3</a>
8 The RocketGit code is copyright (c) 2015 Catalin BOIE and it is
9 covered by the
10 <a href="https://gnu.org/licenses/agpl.html">Affero GPLv3</a>
10 11 license.<br /> license.<br />
11 12 <br /> <br />
12 13
13 The service offered by rocketgit.com site is covered by the
14 following terms:<br />
15
16 - If you do not agree the terms, you cannot use our services
17 and will result in account termination.<br />
14 The services offered by the rocketgit.com site are covered by the
15 terms below. If you do not agree with these terms, please do not use
16 this site or any of the services provided by it. By continuing to
17 use them, you agree to be bound by this terms.<br />
18 <br >
18 19
19 20 - You must understand that we cannot review all content hosted here, - You must understand that we cannot review all content hosted here,
20 21 therefore you agree to be exposed to any type of content. therefore you agree to be exposed to any type of content.
 
72 73 - We may modify this document at any time. You are responsible to - We may modify this document at any time. You are responsible to
73 74 check this document from time to time for changes.<br /> check this document from time to time for changes.<br />
74 75
76 - Disrespecting the terms above will result in account termination.<br />
77
75 78 - You must enjoy your stay here.<br /> - You must enjoy your stay here.<br />
76 79 </div> </div>
77 80 </div> </div>
File root/themes/default/user/settings/menu.html changed (mode: 100644) (index ca19265..bcb50e1)
6 6 <li@@if(@@set_menu::change_pass@@ == 1){{ class="selected"}}{{}}><a href="/op/settings/change_pass">Change password</a></li> <li@@if(@@set_menu::change_pass@@ == 1){{ class="selected"}}{{}}><a href="/op/settings/change_pass">Change password</a></li>
7 7 <li@@if(@@set_menu::keys@@ == 1){{ class="selected"}}{{}}><a href="/op/settings/keys">SSH keys</a></li> <li@@if(@@set_menu::keys@@ == 1){{ class="selected"}}{{}}><a href="/op/settings/keys">SSH keys</a></li>
8 8 <li@@if(@@set_menu::totp@@ == 1){{ class="selected"}}{{}}><a href="/op/settings/totp">Login tokens</a></li> <li@@if(@@set_menu::totp@@ == 1){{ class="selected"}}{{}}><a href="/op/settings/totp">Login tokens</a></li>
9 <li@@if(@@set_menu::wh@@ == 1){{ class="selected"}}{{}}><a href="/op/settings/wh">Webhooks</a></li>
9 10 </ul> </ul>
10 11 </div> </div>
File root/themes/default/user/settings/totp/delete_ok.html changed (mode: 100644) (index 03b636e..bb40ba1)
1 1 <div class="mess ok"> <div class="mess ok">
2 Login token deleted with success.
2 Login token(s) deleted with success.
3 3 </div> </div>
File root/themes/default/user/settings/wh/add_edit.html added (mode: 100644) (index 0000000..14233f0)
1 <div class="formarea">
2
3 <div class="formarea_title">@@if(@@wh::id@@ == 0){{Add}}{{Edit}} a webhook</div>
4
5 @@errmsg@@
6
7 <form method="post" action="/op/settings/wh/add">
8 <input type="hidden" name="add" value="1" />
9 <input type="hidden" name="token" value="@@rg_form_token@@" />
10
11 <p>
12 <label for="url">URL (example: https://my_server_dot_com/hook.cgi; only http/https are supported)</label><br />
13 <input type="text" name="wh::url" id="url" value="@@wh::url@@" />
14 </p>
15
16 <p>
17 <label for="type">Type</label><br />
18 @@select_type@@
19 </p>
20
21 @@check_events@@
22
23 @@check_flags@@
24
25 <p>
26 <label for="description">Description</label><br />
27 <textarea name="wh::description" id="description" rows="3" cols="80">
28 @@wh::description@@
29 </textarea>
30 </p>
31
32 <p>
33 <label for="client_cert">Optional concatenated certificate and key used to
34 authenticate us to the server (PEM format, no password)</label><br />
35 <textarea name="wh::client_cert" id="client_cert" rows="3" cols="80">
36 @@wh::client_cert@@
37 </textarea>
38 </p>
39
40 <p>
41 <label for="client_ca_cert">Optional certificate(s) used to authenticate your server (PEM format, no password)</label><br />
42 <textarea name="wh::client_ca_cert" id="client_ca_cert" rows="3" cols="80">
43 @@wh::client_ca_cert@@
44 </textarea>
45 </p>
46
47 <input type="submit" name="button" value="@@if(@@wh::id@@ == 0){{Add}}{{Edit}}" />
48
49 </form>
50 </div>
File root/themes/default/user/settings/wh/delete_ok.html added (mode: 100644) (index 0000000..f001c96)
1 <div class="mess ok">
2 Webhook(s) deleted with success.
3 </div>
File root/themes/default/user/settings/wh/edit_ok.html added (mode: 100644) (index 0000000..0b7043a)
1 <div class="mess ok">
2 Webhook added/edited with success.
3 </div>
File root/themes/default/user/settings/wh/hints.html added (mode: 100644) (index 0000000..22bb562)
1 Webhooks helps you to trigger some actions on your server when an event
2 happens with you repositories.
File root/themes/default/user/settings/wh/list/footer.html copied from file root/themes/default/user/settings/totp/list/footer.html (similarity 100%)
File root/themes/default/user/settings/wh/list/header.html added (mode: 100644) (index 0000000..1a91665)
1 <div class="rg_wh_list">
2
3 @@errmsg@@
4
5 <form method="post" action="/op/settings/wh/list">
6 <input type="hidden" name="delete" value="1" />
7 <input type="hidden" name="token" value="@@rg_form_token@@" />
8
9 <table summary="webhooks">
10 <tr>
11 <th>Select</th>
12 <th>Date (UTC)</th>
13 <th>Events</th>
14 <th>URL</th>
15 <th>Description</th>
16 <th>Client cert</th>
17 <th>CA cert</th>
18 <th>Type</th>
19 <th>Flags</th>
20 <th>Add IP</th>
21 </tr>
File root/themes/default/user/settings/wh/list/line.html added (mode: 100644) (index 0000000..36181e6)
1 <tr>
2 <td><input type="checkbox" name="delete_list[@@id@@]" /></td>
3 <td>@@itime_nice@@</td>
4 <td>@@events_text@@</td>
5 <td>@@url@@</td>
6 <td>@@description@@</td>
7 <td>@@client_cert_short@@</td>
8 <td>@@client_ca_cert_short@@</td>
9 <td>@@type_text@@</td>
10 <td>@@flags_text@@</td>
11 <td>@@add_ip@@</td>
12 </tr>
File root/themes/default/user/settings/wh/list/nodata.html copied from file root/themes/default/user/settings/totp/list/nodata.html (similarity 66%) (mode: 100644) (index 5c1aea8..8408cd3)
1 1 @@del_status@@ @@del_status@@
2 2
3 3 <div class="mess ok"> <div class="mess ok">
4 No login tokens found.
4 No webhooks present.
5 5 </div> </div>
File root/themes/default/user/settings/wh/list_err.html added (mode: 100644) (index 0000000..b3c9532)
1 <div class="mess error">
2 Could not load webhooks (@@errmsg@@). Please try again later.
3 </div>
File root/themes/default/user/settings/wh/menu.html added (mode: 100644) (index 0000000..2d75c30)
1 <div class="menu menu3">
2 <ul>
3 <li@@if(@@menu::wh::list@@ == 1){{ class="selected"}}><a href="/op/settings/wh/list">List</a></li>
4 <li@@if(@@menu::wh::add@@ == 1){{ class="selected"}}><a href="/op/settings/wh/add">Add</a></li>
5 </ul>
6 </div>
File scripts/cache.php changed (mode: 100644) (index a07bcab..21ba6b5)
... ... do {
377 377 rg_destroy($key, $conn_table); rg_destroy($key, $conn_table);
378 378 } }
379 379
380 rg_handle_idle($conn_table);
380 // TODO: if we activate this, we broke the connection with events.php
381 //rg_handle_idle($conn_table);
381 382 } while (1); } while (1);
382 383
383 384 socket_close($master); socket_close($master);
File tests/.gitignore changed (mode: 100644) (index 8151b7c..a329ce5)
... ... q_merge_requests
17 17 qstats qstats
18 18 git_bin git_bin
19 19 keys/* keys/*
20 *.pid
21 ca
File tests/Makefile changed (mode: 100644) (index 0c7b822..6fb4e7c)
1 tests := ssh http_totp totp git_log1.sh \
1 tests := wh 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:
14 php wh.php
15
13 16 ssh: ssh:
14 17 php ssh.php php ssh.php
15 18
 
... ... git2:
95 98 clean: clean:
96 99 @rm -rf git_log1 *.log *.strace *.strace.* *.out *.lock err-* *.diff \ @rm -rf git_log1 *.log *.strace *.strace.* *.out *.lock err-* *.diff \
97 100 http.arond *.pub git2key git2 *.in q_merge_requests/mr-* \ http.arond *.pub git2key git2 *.in q_merge_requests/mr-* \
98 qstats/* repos/* helper helper.pub keys/*
99
101 qstats/* repos/* helper helper.pub keys/* ca *.pid
File tests/ca.sh added (mode: 100755) (index 0000000..64ccaed)
1 #!/bin/bash
2
3 set -e
4
5 # Generates a CA
6
7 if [ -z "${1}" ]; then
8 echo "Usage: ca.sh name_of_the_ca"
9 exit 1
10 fi
11
12 ca_conf=${PWD}/ca.conf
13
14 mkdir -p "ca/${1}"
15 cd "ca/${1}"
16
17 mkdir -p certs private csr
18
19 if [ ! -r private/cakey.pem ]; then
20 echo "Creating CA key..."
21 openssl genrsa -out private/cakey.pem 2048
22 fi
23
24 if [ ! -r certs/cacert.pem ]; then
25 echo "Generating cert..."
26 openssl req -new -x509 \
27 -days 3650 \
28 -extensions v3_ca \
29 -key private/cakey.pem \
30 -out certs/cacert.pem \
31 -subj "/C=XX/ST=XXX/L=XXX/O=XXX/CN=ca.example.com"
32 fi
33
34 for i in localhost client; do
35 if [ ! -r private/${i}.key ]; then
36 echo "Generating ${i} key..."
37 openssl genrsa -out private/${i}.key 2048
38 fi
39
40 if [ ! -r csr/${i}.csr ]; then
41 echo "Generating ${i} csr..."
42 openssl req -new -key private/${i}.key -out csr/${i}.csr \
43 -subj "/C=XX/ST=XXX/L=XXX/O=XXX/CN=${i}"
44 fi
45
46 if [ ! -r certs/${i}.pem ]; then
47 echo "Generating ${i} cert..."
48 openssl x509 -req -in csr/${i}.csr \
49 -CA certs/cacert.pem \
50 -CAkey private/cakey.pem \
51 -CAcreateserial \
52 -days 500 \
53 -out certs/${i}.pem
54 fi
55 done
56
57 chmod -R 0600 private
58
59 echo "CA_SH_OK"
File tests/config.php changed (mode: 100644) (index 6b47d20..1890788)
... ... $rg_git_port = 9418;
36 36
37 37 // For http testing // For http testing
38 38 $test_url = "http://r1i:9000"; $test_url = "http://r1i:9000";
39 $rg_debug = 1;
39 40
40 41 ?> ?>
File tests/helpers.inc.php changed (mode: 100644) (index e17349f..6b03636)
... ... function rg_test_create_repo($db, $rg_ui, &$extra)
123 123 $new['license'] = 'GPL <xss>'; $new['license'] = 'GPL <xss>';
124 124 $_repo_id++; $_repo_id++;
125 125
126 rg_log("Deleting repo " . $repo_id);
126 rg_log("Deleting repo " . $repo_id . "/" . $new['name']);
127 127 $sql = 'DELETE FROM repos WHERE repo_id = ' . $repo_id $sql = 'DELETE FROM repos WHERE repo_id = ' . $repo_id
128 128 . ' OR name = \'' . $new['name'] . '\''; . ' OR name = \'' . $new['name'] . '\'';
129 129 $res = rg_sql_query($db, $sql); $res = rg_sql_query($db, $sql);
 
... ... function rg_test_sc_generate($db, $rg_ui, $good_sid)
252 252 return $sc; return $sc;
253 253 } }
254 254
255 /*
256 * Helper for adding a webhook
257 */
258 function rg_test_wh_add_edit($db, $rg_ui, $good_sid, $extra)
259 {
260 global $test_url;
261
262 rg_log("Loading webhook add form...");
263 $data = array();
264 $headers = array("Cookie: sid=" . $good_sid);
265 $r = do_req($test_url . "/op/settings/wh/add", $data, $headers);
266 if ($r === FALSE) {
267 rg_log("Cannot load form!");
268 exit(1);
269 }
270 if (empty($r['tokens']['wh_add'])) {
271 rg_log_ml("token not found! r:" . print_r($r, TRUE));
272 exit(1);
273 }
274
275 rg_log("Adding webhook...");
276 $data = array('add' => 1, 'token' => $r['tokens']['wh_add']);
277 $data = array_merge($data, $extra);
278 $headers = array('Cookie: sid=' . $good_sid);
279 $r = do_req($test_url . '/op/settings/wh/add', $data, $headers);
280 if ($r === FALSE) {
281 rg_log_ml("Cannot add webhook: " . print_r($r, TRUE));
282 exit(1);
283 }
284
285 if (!strstr($r['body'], 'with success')) {
286 rg_log_ml("Cannot add webhook (no success message): " . print_r($r, TRUE));
287 exit(1);
288 }
289 }
290
255 291 ?> ?>
File tests/http.inc.php changed (mode: 100644) (index e6c9857..94ba37a)
... ... function do_req($url, &$data, &$headers)
13 13 if (!is_array($data)) if (!is_array($data))
14 14 $data = array(); $data = array();
15 15
16 $data['rg_rebug'] = 1;
17
16 18 if (!is_array($headers)) { if (!is_array($headers)) {
17 19 rg_log("Headers is not an array, reset it."); rg_log("Headers is not an array, reset it.");
18 20 $headers = array(); $headers = array();
File tests/wh-helper.sh added (mode: 100755) (index 0000000..9bfb8e9)
1 #!/bin/bash
2
3 echo "HTTP/1.1 200 OK"
4 echo "Content-Length: 3"
5 echo ""
6 echo -n "OK!"
File tests/wh-stunnel.conf added (mode: 100644) (index 0000000..5555be0)
1 debug = 5
2 log = overwrite
3 CAfile = ca/wh/certs/cacert.pem
4 cert = ca/wh/certs/localhost.pem
5 key = ca/wh/private/localhost.key
6 output = wh-stunnel.log
7 foreground = yes
8 exec = ./wh-helper.sh
9 syslog = no
10 socket = a:SO_REUSEADDR=yes
11
12 [me]
13 accept = 127.0.0.1:64000
14 verify = 2
File tests/wh-test.sh added (mode: 100755) (index 0000000..dd7636a)
1 #!/bin/bash
2
3 curl \
4 --verbose \
5 --cacert ca/wh/certs/cacert.pem \
6 --cert ca/wh/certs/client.pem \
7 --key ca/wh/private/client.key \
8 https://localhost:64000 \
9 -d a=1
File tests/wh.php added (mode: 100644) (index 0000000..cab3d90)
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.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 = 'ssh';
19 $rg_cache_enable = TRUE;
20 $rg_cache_debug = TRUE;
21 $rg_event_socket = "/var/lib/rocketgit/sockets/event.sock";
22 $port = 64000;
23
24
25 function clean($pid)
26 {
27 rg_log("Killing pid $pid...");
28 $r = posix_kill($pid, SIGQUIT);
29 if ($r === FALSE)
30 rg_log('Fail to kill!');
31
32 system('fuser -k wh-stunnel.log');
33 }
34
35
36 rg_log('');
37 rg_log('Generating certificates...');
38 $r = shell_exec('./ca.sh wh');
39 if (!strstr($r, 'CA_SH_OK')) {
40 rg_log_ml('r: ' . print_r($r, TRUE));
41 rg_log('Cannot generate certificates!');
42 exit(1);
43 }
44
45
46 rg_log('');
47 rg_log('Starting stunnel1...');
48 $pid = pcntl_fork();
49 if ($pid == -1) {
50 rg_log('Cannot fork1');
51 exit(1);
52 }
53 if ($pid == 0) { //child
54 $r = exec('stunnel wh-stunnel.conf 2>/dev/null');
55 exit(0);
56 }
57 register_shutdown_function('clean', $pid);
58
59
60 rg_log('');
61 rg_log("Creating a user...");
62 rg_test_create_user($db, $rg_ui);
63 $key = 'DEBUG::webhooks::' . $rg_ui['uid'];
64
65
66 rg_log('');
67 rg_log('Login...');
68 $r = test_login($test_url, $rg_ui, $good_sid);
69 if ($r === FALSE) {
70 rg_log("Cannot login!");
71 exit(1);
72 }
73
74
75 rg_log('');
76 rg_log('Registering webhook1...');
77 $extra = array('wh::url' => 'https://localhost:' . $port . '/wh.html',
78 'wh::type' => 0,
79 'wh::events[C]' => 'on',
80 'wh::events[P]' => 'on',
81 'wh::events[B]' => 'on',
82 'wh::description' => 'description1 <xss>',
83 'wh::client_cert' => '',
84 'wh::client_ca_cert' => file_get_contents('ca/wh/certs/cacert.pem')
85 );
86 rg_test_wh_add_edit($db, $rg_ui, $good_sid, $extra);
87
88
89 rg_log('');
90 rg_log('Registering webhook2...');
91 $extra = array('wh::url' => 'https://localhost:' . $port . '/wh.html',
92 'wh::type' => 0,
93 'wh::events[C]' => 'on',
94 'wh::events[P]' => 'on',
95 'wh::events[B]' => 'on',
96 'wh::description' => 'description <xss>',
97 'wh::client_cert' => file_get_contents('ca/wh/certs/client.pem')
98 . file_get_contents('ca/wh/private/client.key'),
99 'wh::client_ca_cert' => file_get_contents('ca/wh/certs/cacert.pem')
100 );
101 rg_test_wh_add_edit($db, $rg_ui, $good_sid, $extra);
102
103
104 rg_log('Finding out the ids...');
105 for ($i = 0; $i < 10; $i++) {
106 $r = rg_cache_get('user::' . $rg_ui['uid'] . '::wh');
107 if ($r !== FALSE)
108 break;
109 sleep(1);
110 }
111 if ($r === FALSE) {
112 rg_log('Cannot get id from cache');
113 exit(1);
114 }
115 rg_log_ml('r=' . print_r($r, TRUE));
116 $t = array_keys($r);
117 $wh_id1 = $t[0];
118 $wh_id2 = $t[1];
119 rg_log('wh_id1=' . $wh_id1);
120 rg_log('wh_id2=' . $wh_id2);
121
122
123 rg_log('');
124 rg_log('Creating a repo and waiting for trigger');
125 rg_log("rg_debug=$rg_debug.");
126 $repo = array();
127 rg_test_create_repo($db, $rg_ui, $repo);
128
129
130 rg_log('');
131 rg_log('Testing if the curl posted with success');
132 for ($i = 0; $i < 10; $i++) {
133 $r = rg_cache_get($key. '::' . $wh_id1);
134 rg_log_ml('cache: ' . $r);
135 if ($r !== FALSE)
136 break;
137 sleep(1);
138 }
139 if ($r === FALSE) {
140 rg_log('Seems the event does not set the cache!');
141 exit(1);
142 }
143 if (strcmp($r, "BAD") != 0) {
144 rg_log('Seems the webhook executed correctly without client cert!');
145 exit(1);
146 }
147
148
149 rg_log('');
150 rg_log('Testing if the curl posted with success');
151 for ($i = 0; $i < 10; $i++) {
152 $r = rg_cache_get($key. '::' . $wh_id2);
153 if ($r !== FALSE)
154 break;
155 rg_log_ml('cache: ' . print_r($r, TRUE));
156 sleep(1);
157 }
158 if (strcmp($r, "OK") != 0) {
159 rg_log('Seems the webhook did not returned success!');
160 exit(1);
161 }
162
163
164 rg_log('');
165 rg_log('Testing the edit of webhook1...');
166 $extra = array('wh::url' => 'https://localhost:' . $port . '/wh.html',
167 'wh::id' => $wh_id1,
168 'wh::type' => 1,
169 'wh::flags[I]' => 'on',
170 'wh::events[C]' => 'on',
171 'wh::events[B]' => 'on',
172 'wh::description' => 'desc2',
173 'wh::client_cert' => 'abc',
174 'wh::client_ca_cert' => 'zzz'
175 );
176 rg_test_wh_add_edit($db, $rg_ui, $good_sid, $extra);
177 $sql = "SELECT * FROM webhooks WHERE uid = " . $rg_ui['uid']
178 . " AND id = " . $wh_id1;
179 $res = rg_sql_query($db, $sql);
180 $row = rg_sql_fetch_array($res);
181 rg_sql_free_result($res);
182 $key1 = 'user' . '::' . $rg_ui['uid'] . '::' . 'wh' . '::' . $wh_id1;
183 rg_cache_core_unset($key1); // else we will get previous copy!
184 $c = rg_cache_get($key1);
185 $list = array('flags' => 'I', 'events' => 'CB', 'type' => '1',
186 'description' => 'desc2', 'client_cert' => 'abc',
187 'client_ca_cert' => 'zzz');
188 foreach ($list as $k => $v) {
189 if (strcmp($row[$k], $v) != 0) {
190 rg_log_ml('row: ' . print_r($row, TRUE));
191 rg_log("db: Seems that $k was not updated [" . $row[$k] . "] != " . $v);
192 exit(1);
193 }
194
195 if (strcmp($c[$k], $v) != 0) {
196 rg_log_ml('c: ' . print_r($c, TRUE));
197 rg_log("cache: Seems that $k was not updated [" . $c[$k] . "] != " . $v);
198 exit(1);
199 }
200 }
201
202
203 rg_log('');
204 rg_log_enter('Testing the delete - loading form...');
205 $data = array();
206 $headers = array("Cookie: sid=" . $good_sid);
207 $r = do_req($test_url . "/op/settings/wh/list", $data, $headers);
208 if ($r === FALSE) {
209 rg_log("Cannot load list form.");
210 exit(1);
211 }
212 if (!isset($r['tokens']['wh_list'])) {
213 rg_log_ml('tokens: ' . print_r($r['tokens'], TRUE));
214 rg_log('Cannot find wh_list token!');
215 exit(1);
216 }
217 $good_token = $r['tokens']['wh_list'];
218 $data = array( 'delete' => 1,
219 'token' => $good_token,
220 'delete_list[' . $wh_id1 . ']' => 'on');
221 $r = do_req($test_url . "/op/settings/wh/list", $data, $headers);
222 if (!strstr($r['body'], 'deleted with success')) {
223 rg_log_ml('r: ' . print_r($r, TRUE));
224 rg_log("Cannot delete webhook!");
225 exit(1);
226 }
227 $sql = "SELECT id FROM webhooks WHERE id = " . $wh_id1;
228 $res = rg_sql_query($db, $sql);
229 $rows = rg_sql_num_rows($res);
230 rg_sql_free_result($res);
231 if ($rows != 0) {
232 rg_log("Cannot delete webhook - sql still returns data!");
233 exit(1);
234 }
235 $key = 'user::' . $rg_ui['uid'] . '::wh::' . $wh_id1;
236 rg_cache_core_unset($key); // else we will get data from local mem!
237 $r = rg_cache_get($key);
238 if (strcmp($r, '') != 0) {
239 rg_log_ml($key . ': ' . print_r($r, TRUE));
240 rg_log('Deleted webhooks are still in cache!');
241 exit(1);
242 }
243 rg_log_exit();
244
245
246 rg_log("OK!");
247 ?>
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