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 0f13d65e13211a91ce077b4a09307e54e9113f38

TOTP fixes: mostly correct error messages
Author: Catalin(ux) M. BOIE
Author date (UTC): 2015-09-08 04:59
Committer name: Catalin(ux) M. BOIE
Committer date (UTC): 2015-09-08 04:59
Parent(s): a34c707720da68378086f73f16dd25c5a1ca8072
Signing key:
Tree: f636a63c2e45202b2d1cf00230cf91f4769b1f53
File Lines added Lines deleted
TODO 20 9
inc/ssh.inc.php 73 71
inc/totp.inc.php 23 6
scripts/remote.php 2 0
tests/http_admin.php 1 1
tests/http_login.php 1 1
File TODO changed (mode: 100644) (index f9df6b6..d75422e)
1 1 == Where I stopped last time == == Where I stopped last time ==
2 [ ] totp: login by token in http_totp.php seems to not work.
3 check server logs.
4 [ ] unit test: do not check for "invalid user ..." - it may change
5 test that we landed on the home page!
6 [ ] totp: should we update at once, and verify that the token is really unused?
7 (do not delay till event processing?)
8 2 [ ] totp: store last ts used, and do not allow reuse. [ ] totp: store last ts used, and do not allow reuse.
9 3 The problem is if both session sends the same token (the attacker and The problem is if both session sends the same token (the attacker and
10 the good user).
11 [ ] totp: update last_use also by ssh!
12 [ ] unit tests fails.
4 the good user). But the attacker can be the first. In this case,
5 the user will be denied access! But, he used the good token also,
6 should I invalidate both sessions and send a recover code by e-mail?
7 What should I do?
13 8 [ ] [ ]
14 9
15 10 == BEFORE NEXT RELEASE == == BEFORE NEXT RELEASE ==
11 [ ] When we copy the tree to prepare the push, copy in a temp folder and do
12 a rename to prevent partial trees? I know I give back an error, but ...
13 [ ] We must clean somehow the namespace dir; think about pushes that fails
14 because of network connections. An idea is to use namespaces with a
15 static format: rg_user_xxx, so we allow to recover from a push request.
16 Is not working for anonymous push. In this case, name it by the sha?
17 Or, server reboots in the middle of the push.
18 [ ] Why first message says that the tag was deleted? Locally?
19 === Testing annotated tag delete without rights (COPYUuMWDS)...
20 Deleted tag 'tag2' (was b7fca5f)
21 remote: ==========
22 remote: RocketGit: refs/tags/tag2
23 remote: RocketGit: No rights to delete an annotated tag.
24 remote: ==========
25 remote: error: hook declined to update refs/tags/tag2
26
16 27 [ ] Extend rg_cache_count for the other rg_cache_* commands. [ ] Extend rg_cache_count for the other rg_cache_* commands.
17 28 [ ] Restart the cache daemon when an upgrade takes place. [ ] Restart the cache daemon when an upgrade takes place.
18 29 Done, test. Done, test.
File inc/ssh.inc.php changed (mode: 100644) (index 5f2797c..bf83dca)
2 2 // //
3 3 // Description: This file deals with commands accepted by ssh // Description: This file deals with commands accepted by ssh
4 4 // //
5 require_once($INC . "/sql.inc.php");
6 require_once($INC . "/state.inc.php");
7 require_once($INC . "/prof.inc.php");
8 require_once($INC . "/repo.inc.php");
9 require_once($INC . "/totp.inc.php");
5 require_once($INC . '/sql.inc.php');
6 require_once($INC . '/state.inc.php');
7 require_once($INC . '/prof.inc.php');
8 require_once($INC . '/repo.inc.php');
9 require_once($INC . '/totp.inc.php');
10 10
11 11 function rg_ssh_status($db, $uid) function rg_ssh_status($db, $uid)
12 12 { {
13 rg_log("ssh_status");
13 rg_log('ssh_status');
14 14
15 echo "Here will be the status.\n";
15 echo 'Here will be the status.' . "\n";
16 16
17 17 // also details about payments: warn if disk space is low etc. // also details about payments: warn if disk space is low etc.
18 18 } }
 
... ... function rg_ssh_status($db, $uid)
22 22 */ */
23 23 function rg_ssh_repos($db, $uid) function rg_ssh_repos($db, $uid)
24 24 { {
25 rg_log("ssh_repos");
26
27 $sql = "SELECT * FROM repos"
28 . " WHERE uid = $uid"
29 . " AND deleted = 0"
30 . " ORDER BY name, itime";
31 $pad = " ";
32 $res = rg_sql_query($db, $sql);
25 rg_log('ssh_repos');
26
27 $params = array('uid' => $uid);
28 $sql = 'SELECT * FROM repos'
29 . ' WHERE uid = @@uid@@'
30 . ' AND deleted = 0'
31 . ' ORDER BY name, itime';
32 $pad = ' ';
33 $res = rg_sql_query_params($db, $sql, $params);
33 34 $rows = rg_sql_num_rows($res); $rows = rg_sql_num_rows($res);
34 35 if ($rows > 0) { if ($rows > 0) {
35 echo "Repositories (name, creation, disk used):\n";
36 echo 'Repositories (name, creation, disk used):' . "\n";
36 37 while (($row = rg_sql_fetch_array($res))) { while (($row = rg_sql_fetch_array($res))) {
37 38 $_name = mb_substr($row['name'], 0, 40, 'UTF-8'); $_name = mb_substr($row['name'], 0, 40, 'UTF-8');
38 39 echo mb_substr($_name . $pad, 0, 32, 'UTF-8') echo mb_substr($_name . $pad, 0, 32, 'UTF-8')
39 . " " . gmdate("Y-m-d", $row['itime'])
40 . " " . rg_1024($row['disk_used_mb'] * 1024 * 1024)
40 . ' ' . gmdate('Y-m-d', $row['itime'])
41 . ' ' . rg_1024($row['disk_used_mb'] * 1024 * 1024)
41 42 . "\n"; . "\n";
42 43 } }
43 44 } else { } else {
44 echo "You have no repository.\n";
45 echo 'You have no repository.' . "\n";
45 46 } }
46 47 rg_sql_free_result($res); rg_sql_free_result($res);
47 48 } }
 
... ... function rg_ssh_repos($db, $uid)
51 52 */ */
52 53 function rg_ssh_repo($db, $uid, $paras) function rg_ssh_repo($db, $uid, $paras)
53 54 { {
54 rg_log("ssh_repo: " . rg_array2string($paras));
55 rg_log('ssh_repo: ' . rg_array2string($paras));
55 56
56 57 if (empty($paras)) { if (empty($paras)) {
57 echo "Please specify repo name.\n";
58 echo 'Please specify the repo name.' . "\n";
58 59 exit(0); exit(0);
59 60 } }
60 61
 
... ... function rg_ssh_repo($db, $uid, $paras)
62 63
63 64 $ri = rg_repo_info($db, 0, $uid, $repo_name); $ri = rg_repo_info($db, 0, $uid, $repo_name);
64 65 if ($ri['exists'] != 1) { if ($ri['exists'] != 1) {
65 echo "Error: unknown repo.\n";
66 echo 'Error: unknown repo.' . "\n";
66 67 exit(0); exit(0);
67 68 } }
68 69
69 echo "Repo: " . $ri['name'] . "\n";
70 echo "Repo type: " . ($ri['public'] == 1 ? "public" : "private") . "\n";
71 echo "Description:\n";
70 echo 'Repo: ' . $ri['name'] . "\n";
71 echo 'Repo type: ' . ($ri['public'] == 1 ? 'public' : 'private') . "\n";
72 echo 'Description:' . "\n";
72 73 $_d = explode("\n", $ri['description']); $_d = explode("\n", $ri['description']);
73 74 if (!empty($_d)) { if (!empty($_d)) {
74 75 foreach ($_d as $_line) foreach ($_d as $_line)
75 echo " " . $_line . "\n";
76 echo ' ' . $_line . "\n";
76 77 } }
77 echo "Creation time: " . gmdate("Y-m-d", $ri['itime']) . " UTC\n";
78 echo "Disk used: " . rg_1024($ri['disk_used_mb'] * 1024 * 1024) . "\n";
78 echo 'Creation time: ' . gmdate('Y-m-d', $ri['itime']) . ' UTC' . "\n";
79 echo 'Disk used: ' . rg_1024($ri['disk_used_mb'] * 1024 * 1024) . "\n";
79 80
80 81 if ($ri['master'] > 0) { if ($ri['master'] > 0) {
81 $mri = rg_repo_info($db, $ri['master'], 0, "");
82 $mri = rg_repo_info($db, $ri['master'], 0, '');
82 83 if ($mri !== FALSE) { if ($mri !== FALSE) {
83 echo "Master: " . $mri['name'] . "\n";
84 echo 'Master: ' . $mri['name'] . "\n";
85 } else {
86 echo 'Master: ' . 'Error getting info' . "\n";
84 87 } }
85 88 } }
86 89 } }
 
... ... function rg_ssh_totp($db, $ip, $uid, $paras)
102 105
103 106 $r = rg_totp_enroll($db, $uid, 'SSH', $secret, $ip, 'f'); $r = rg_totp_enroll($db, $uid, 'SSH', $secret, $ip, 'f');
104 107 if ($r !== TRUE) { if ($r !== TRUE) {
105 echo "An internal error occured; please try again later.\n";
108 echo 'Error: ' . rg_totp_error() . ".\n";
106 109 break; break;
107 110 } }
108 111
109 echo "Scan the following code with the mobile application:\n";
112 echo 'Scan the following code with the mobile application:' . "\n";
110 113 echo rg_totp_text($secret) . "\n"; echo rg_totp_text($secret) . "\n";
111 echo "Or manually enter the following code: " . $secret . "\n";
112 echo "To finish the enrollment you will have to confirm";
113 echo " it by running the following command:";
114 echo " ssh ... enroll <6_digits_code_generated_by_device>\n";
114 echo 'or manually enter the following code: ' . $secret . ".\n";
115 echo 'To finish the enrollment you will have to confirm';
116 echo ' it by running the following command:';
117 echo ' ssh ... totp enroll <6_digits_code_generated_by_device>' . "\n";
115 118 break; break;
116 119 } }
117 120
118 121 $token = array_shift($paras); $token = array_shift($paras);
119 $token = sprintf("%06u", $token);
120 122
121 123 $v = rg_totp_verify_all($db, $uid, $token); $v = rg_totp_verify_all($db, $uid, $token);
122 124 if ($v['ok'] != 1) { if ($v['ok'] != 1) {
123 echo "An internal error occured; please try again later.\n";
125 echo 'Error: ' . rg_totp_error() . ".\n";
124 126 break; break;
125 127 } }
126 128 if ($v['id'] == 0) { if ($v['id'] == 0) {
127 echo "Invalid confirmation token.\n";
129 echo 'Error: ' . rg_totp_error() . ".\n";
128 130 break; break;
129 131 } }
130 echo "Success!\n";
132
133 echo 'Success!' . "\n";
131 134 break; break;
132 135
133 136 case 'val': case 'val':
134 137 $token = array_shift($paras); $token = array_shift($paras);
135 $token = sprintf("%06u", $token);
138
136 139 $days = 0; $days = 0;
137 140 $hours = 0; $hours = 0;
138 141 $minutes = 0; $minutes = 0;
 
... ... function rg_ssh_totp($db, $ip, $uid, $paras)
145 148 $days = $val; $days = $val;
146 149 else if (stristr($s_expire, 'h')) else if (stristr($s_expire, 'h'))
147 150 $hours = $val; $hours = $val;
148 else if (stristr($s_expire, 'm'))
151 else
149 152 $minutes = $val; $minutes = $val;
150 153 } }
151 154 //rg_log("token=$token days=$days hours=$hours minutes=$minutes"); //rg_log("token=$token days=$days hours=$hours minutes=$minutes");
152 155
153 156 $v = rg_totp_verify_all($db, $uid, $token); $v = rg_totp_verify_all($db, $uid, $token);
154 157 if ($v['ok'] != 1) { if ($v['ok'] != 1) {
155 echo "An internal error occured; please try again later.\n";
158 echo 'Error: ' . rg_totp_error() . ".\n";
156 159 break; break;
157 160 } }
158 161 if ($v['id'] == 0) { if ($v['id'] == 0) {
159 echo "Invalid token.\n";
162 echo 'Error: ' . rg_totp_error() . ".\n";
160 163 break; break;
161 164 } }
162 165
163 166 $expire_ts = gmmktime(gmdate('H') + $hours, $expire_ts = gmmktime(gmdate('H') + $hours,
164 167 gmdate('i') + $minutes, gmdate('s'), gmdate('m'), gmdate('i') + $minutes, gmdate('s'), gmdate('m'),
165 168 gmdate('d') + $days, gmdate('Y')); gmdate('d') + $days, gmdate('Y'));
166 rg_log("expire_ts=$expire_ts");
167 169 $r = rg_totp_add_ip($db, $uid, $v['id'], $ip, $expire_ts); $r = rg_totp_add_ip($db, $uid, $v['id'], $ip, $expire_ts);
168 170 if ($r === FALSE) { if ($r === FALSE) {
169 echo "An internal error occured; please try again later.\n";
171 echo 'Error: ' . rg_totp_error() . ".\n";
170 172 break; break;
171 173 } }
172 174
173 echo "Success! IP $ip added and is valid till "
174 . gmdate("Y-m-d H:i:s", $expire_ts) . " UTC.\n";
175 echo 'Success! IP ' . $ip . ' added and is valid till '
176 . gmdate('Y-m-d H:i:s', $expire_ts) . ' UTC.' . "\n";
175 177 break; break;
176 178
177 179 case 'list-val': case 'list-val':
178 180 $r = rg_totp_verify_ip($db, $uid, $ip); $r = rg_totp_verify_ip($db, $uid, $ip);
179 181 if ($r['ok'] != 1) { if ($r['ok'] != 1) {
180 echo 'RocketGit: Error: ' . rg_totp_error() . ".\n";
182 echo 'Error: ' . rg_totp_error() . ".\n";
181 183 break; break;
182 184 } }
183 185 if ($r['enrolled'] == 0) { if ($r['enrolled'] == 0) {
184 echo 'RocketGit: Info: You are not enrolled.' . ".\n";
186 echo 'Info: You are not enrolled.' . ".\n";
185 187 break; break;
186 188 } }
187 189
 
... ... function rg_ssh_totp($db, $ip, $uid, $paras)
192 194 . ' ' . $t['ip'] . ' ' . $t['ip']
193 195 . "\n"; . "\n";
194 196 } }
197 echo 'Done!' . "\n";
195 198 break; break;
196 199
197 200 case 'unenroll': case 'unenroll':
198 201 $token = array_shift($paras); $token = array_shift($paras);
199 $token = sprintf("%06u", $token);
200 202
201 203 $v = rg_totp_verify_all($db, $uid, $token); $v = rg_totp_verify_all($db, $uid, $token);
202 204 if ($v['ok'] != 1) { if ($v['ok'] != 1) {
203 echo "An internal error occured; please try again later.\n";
205 echo 'Error: ' . rg_totp_error() . ".\n";
204 206 break; break;
205 207 } }
206 208 if ($v['id'] == 0) { if ($v['id'] == 0) {
207 echo "Invalid token.\n";
209 echo 'Error: ' . rg_totp_error() . ".\n";
208 210 break; break;
209 211 } }
210 212
211 213 $a = array($v['id'] => ''); $a = array($v['id'] => '');
212 214 $r = rg_totp_remove($db, $uid, $a); $r = rg_totp_remove($db, $uid, $a);
213 215 if ($r !== TRUE) { if ($r !== TRUE) {
214 echo "Error: " . rg_totp_error() . ".\n";
216 echo 'Error: ' . rg_totp_error() . ".\n";
215 217 break; break;
216 218 } }
217 219
218 echo "Success!\n";
220 echo 'Success!' . "\n";
219 221 break; break;
220 222
221 223 case 'inval': case 'inval':
222 224 if (empty($paras)) { if (empty($paras)) {
223 echo "Please specify the IP address.\n";
225 echo 'Error: Please specify the IP address or \'all\'.' . "\n";
224 226 break; break;
225 227 } }
226 228
 
... ... function rg_ssh_totp($db, $ip, $uid, $paras)
228 230
229 231 $r = rg_totp_verify_ip($db, $uid, $ip); $r = rg_totp_verify_ip($db, $uid, $ip);
230 232 if ($r['ok'] != 1) { if ($r['ok'] != 1) {
231 echo 'RocketGit: Error: ' . rg_totp_error() . ".\n";
233 echo 'Error: ' . rg_totp_error() . ".\n";
232 234 break; break;
233 235 } }
234 236 if ($r['enrolled'] == 0) { if ($r['enrolled'] == 0) {
235 echo 'RocketGit: Info: You are not enrolled.' . ".\n";
237 echo 'Info: You are not enrolled.' . ".\n";
236 238 break; break;
237 239 } }
238 240
239 241 $r = rg_totp_del_ip($db, $uid, $del_ip); $r = rg_totp_del_ip($db, $uid, $del_ip);
240 242 if ($r !== TRUE) { if ($r !== TRUE) {
241 echo "Error: " . rg_totp_error() . ".\n";
243 echo 'Error: ' . rg_totp_error() . ".\n";
242 244 break; break;
243 245 } }
244 246
245 echo "Success!\n";
247 echo 'Success!' . "\n";
246 248 break; break;
247 249
248 250 default: default:
249 echo "Posible TOTP commands:\n";
250 echo " enroll <token> - adds a new device in the system\n";
251 echo " val [X(m|h|d)] - adds your IP to the allow list for X time\n";
252 echo " default is 24 hours;\n";
253 echo " you can specify m for minutes, h for hours and d for days\n";
254 echo " list-val - list the already validated IPs\n";
255 echo " inval ip|all - Invalidate IP address(es)\n";
256 echo " unenroll <token> - remove a device from TOTP system\n";
251 echo 'Posible TOTP commands:' . "\n";
252 echo ' enroll <token> - adds a new device in the system' . "\n";
253 echo ' val [X(m|h|d)] - adds your IP to the allow list for X time' . "\n";
254 echo ' the default is 24 hours;' . "\n";
255 echo ' you can specify m for minutes, h for hours and d for days' . "\n";
256 echo ' list-val - list the already validated IPs' . "\n";
257 echo ' inval ip|all - Invalidate IP address(es)' . "\n";
258 echo ' unenroll <token> - remove a device from TOTP system' . "\n";
257 259 break; break;
258 260 } }
259 261
 
... ... function rg_ssh_dispatch($db, $ip, $uid, $orig_cmd)
278 280
279 281 $ui = rg_user_info($db, $uid, '', ''); $ui = rg_user_info($db, $uid, '', '');
280 282 if ($ui['exists'] == 1) if ($ui['exists'] == 1)
281 echo 'RocketGit: You are connecting as user'
283 echo 'You are connecting as user'
282 284 . ' \'' . $ui['username'] . '\'.' . "\n"; . ' \'' . $ui['username'] . '\'.' . "\n";
283 285
284 echo 'RocketGit: You are connecting from IP ' . $ip . ".\n";
286 echo 'You are connecting from IP ' . $ip . ".\n";
285 287
286 288 // First, test if the IP is validated // First, test if the IP is validated
287 289 switch ($cmd) { switch ($cmd) {
 
... ... function rg_ssh_dispatch($db, $ip, $uid, $orig_cmd)
290 292 default: default:
291 293 $r = rg_totp_verify_ip($db, $uid, $ip); $r = rg_totp_verify_ip($db, $uid, $ip);
292 294 if ($r['ok'] != 1) { if ($r['ok'] != 1) {
293 echo 'RocketGit: Error: ' . rg_totp_error() . ".\n";
295 echo 'Error: ' . rg_totp_error() . ".\n";
294 296 exit(0); exit(0);
295 297 } }
296 298 break; break;
File inc/totp.inc.php changed (mode: 100644) (index 57048d2..6b55fda)
... ... function rg_totp_verify_all($db, $uid, $token)
306 306 break; break;
307 307
308 308 $ret['ok'] = 1; $ret['ok'] = 1;
309 $ret['enrolled'] = empty($lt['list']) ? 0 : 1;
309 $ret['enrolled'] = 0;
310 310 $ret['id'] = 0; $ret['id'] = 0;
311 311 $ret['conf_error'] = 0; $ret['conf_error'] = 0;
312 312 $ret['tc'] = 0; $ret['tc'] = 0;
313 313
314 if (strlen($token) < 6)
314 if (strlen($token) == 0) {
315 rg_totp_set_error('token is empty');
315 316 break; break;
317 }
318 $token = sprintf("%06u", $token);
319
320 rg_totp_set_error('wrong token; sync the time');
321 foreach ($lt['list'] as $t) {
322 if (strcmp($t['conf'], 't') == 0)
323 if ($ret['enrolled'] == 0)
324 $ret['enrolled'] = 1;
316 325
317 foreach ($lt['list'] as $_id => $t) {
318 326 $tc = rg_totp_verify($t['secret'], $now, $token); $tc = rg_totp_verify($t['secret'], $now, $token);
319 327 if ($tc === FALSE) if ($tc === FALSE)
320 328 continue; continue;
 
... ... function rg_totp_verify_all($db, $uid, $token)
328 336 $ret['tc'] = $tc; $ret['tc'] = $tc;
329 337
330 338 // Mark it as used and update 'conf' status // Mark it as used and update 'conf' status
331 // TODO: Should we give error if we cannot update it?
332 339 $r = rg_totp_set_last_use($db, $uid, $t['id'], $tc, $now); $r = rg_totp_set_last_use($db, $uid, $t['id'], $tc, $now);
333 340 if ($r !== TRUE) { if ($r !== TRUE) {
334 341 $ret['ok'] = 0; $ret['ok'] = 0;
335 342 break; break;
336 343 } }
337 344
345 // we just confirmed an unconf entry, so we are enrolled
346 if ($ret['enrolled'] == 0)
347 $ret['enrolled'] = 1;
338 348 break; break;
339 349 } }
340 350
 
... ... function rg_totp_verify_ip($db, $uid, $ip)
587 597
588 598 $ret = array(); $ret = array();
589 599 $ret['ok'] = -1; $ret['ok'] = -1;
590 $ret['enrolled'] = 1;
600 $ret['enrolled'] = 0;
591 601 while (1) { while (1) {
592 602 // we will return OK if user is not enrolled // we will return OK if user is not enrolled
593 603 $r = rg_totp_list($db, $uid); $r = rg_totp_list($db, $uid);
 
... ... function rg_totp_verify_ip($db, $uid, $ip)
595 605 break; break;
596 606 if (empty($r['list'])) { if (empty($r['list'])) {
597 607 $ret['ok'] = 1; $ret['ok'] = 1;
598 $ret['enrolled'] = 0;
599 608 break; break;
600 609 } }
601 610
611 // let's see if we enrolled
612 foreach ($r['list'] as $t) {
613 if (strcmp($t['conf'], 't') == 0) {
614 $ret['enrolled'] = 1;
615 break;
616 }
617 }
618
602 619 $r = rg_totp_list_ip($db, $uid); $r = rg_totp_list_ip($db, $uid);
603 620 if ($r['ok'] != 1) if ($r['ok'] != 1)
604 621 break; break;
File scripts/remote.php changed (mode: 100644) (index 75d88ff..7861c8c)
... ... if ($login_uid > 0) {
179 179 info('you are connecting as anonymous.'); info('you are connecting as anonymous.');
180 180 } }
181 181
182 info('you are connecting from IP ' . $ip);
183
182 184 // Loading info about the repository // Loading info about the repository
183 185 if (rg_repo_ok($repo) !== TRUE) if (rg_repo_ok($repo) !== TRUE)
184 186 fatal("Repo is invalid (" . rg_repo_error() . ")"); fatal("Repo is invalid (" . rg_repo_error() . ")");
File tests/http_admin.php changed (mode: 100644) (index 789ce9a..080c7d5)
... ... if ($r === FALSE) {
47 47 rg_log_ml("Cannot login: " . print_r($r, TRUE)); rg_log_ml("Cannot login: " . print_r($r, TRUE));
48 48 exit(1); exit(1);
49 49 } }
50 if (strstr($r['body'], "invalid user or pass")) {
50 if (strstr($r['body'], "invalid user")) {
51 51 rg_log_ml("Login invalid. r=" . print_r($r, TRUE)); rg_log_ml("Login invalid. r=" . print_r($r, TRUE));
52 52 exit(1); exit(1);
53 53 } }
File tests/http_login.php changed (mode: 100644) (index 1d55066..2d74e60)
... ... if ($r === FALSE) {
88 88 rg_log_ml("Cannot login: " . print_r($r, TRUE)); rg_log_ml("Cannot login: " . print_r($r, TRUE));
89 89 exit(1); exit(1);
90 90 } }
91 if (strstr($r['body'], "invalid user or pass")) {
91 if (strstr($r['body'], "invalid user")) {
92 92 rg_log_ml(print_r($r, TRUE)); rg_log_ml(print_r($r, TRUE));
93 93 rg_log("Login invalid. Check above!"); rg_log("Login invalid. Check above!");
94 94 exit(1); exit(1);
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