File TODO changed (mode: 100644) (index 0af8ec3..279f1f2) |
2 |
2 |
[ ] |
[ ] |
3 |
3 |
|
|
4 |
4 |
== BEFORE NEXT RELEASE == |
== BEFORE NEXT RELEASE == |
|
5 |
|
[ ] When I am in "My repositories" and I am doing a search, other users' |
|
6 |
|
repositories are shown. |
|
7 |
|
[ ] In user/home-page.php, in hints section, add a message when the user is |
|
8 |
|
low on scratch codes. Not hint. |
|
9 |
|
[ ] If 'rg_debug'? is defined, do not send mails. |
|
10 |
|
[ ] test with "short" (0 prepended) codes in unit testing. |
|
11 |
|
For scs, done, test for devices? This is a little bit harder. |
|
12 |
|
[ ] totp:ssh: do we need a command to remove a set of scratch codes? |
|
13 |
|
Something like 'remove-sc [<itime>]'. If <itime> is missing, list the |
|
14 |
|
sets. The IP must be authorized? |
|
15 |
|
[ ] http hook: use curl's CURLOPT_SSLCERT to authenticate to the client server. |
|
16 |
|
[ ] In report, just show the newly added repos, not the totals. Totals in body. |
|
17 |
|
[ ] Apply to become a member of Software Freedom Conservancy? |
|
18 |
|
[ ] Why do we index 'users' by 'username'?! Seems wrong! |
|
19 |
|
[ ] totp: add sc for ssh! |
|
20 |
|
Should I validate one after asking the user to store them safe? |
|
21 |
|
Think about power down before scratch codes hit the printer. |
|
22 |
|
[ ] Get rid of {{}} stuff. |
|
23 |
|
[ ] Some other menus were added, we must load all this pages. |
|
24 |
|
At least totp/{list,enroll,sc}. |
|
25 |
|
[ ] I inconsistently use /op/repo/create and /user/catab/settings! |
|
26 |
|
Why not /user/catab/repo/create? |
|
27 |
|
[ ] Git stats are done only on master branch. We must done them per branch. |
5 |
28 |
[ ] Test with an empty commit what happens in rg_git_log with patches == TRUE. |
[ ] Test with an empty commit what happens in rg_git_log with patches == TRUE. |
6 |
29 |
Can happen? Maybe for a rename? |
Can happen? Maybe for a rename? |
7 |
30 |
[ ] Add repo stats to ssh repo command. |
[ ] Add repo stats to ssh repo command. |
|
94 |
117 |
Check http://www.postgresql.org/docs/9.4/interactive/sql-grant.html |
Check http://www.postgresql.org/docs/9.4/interactive/sql-grant.html |
95 |
118 |
web user must not be able to create roles/tables/databases/etc. |
web user must not be able to create roles/tables/databases/etc. |
96 |
119 |
Hm. What about the settings?! I must be able to do a select... |
Hm. What about the settings?! I must be able to do a select... |
97 |
|
[ ] totp: warn user if s/he is low on scratch login codes. |
|
98 |
|
[ ] totp:scratch: delete them after use? |
|
99 |
120 |
[ ] totp: Build an Android application which will be able to authenticate also |
[ ] totp: Build an Android application which will be able to authenticate also |
100 |
121 |
the server to the user. |
the server to the user. |
101 |
122 |
[ ] totp: switch to 'password' type for login_token (login page)? |
[ ] totp: switch to 'password' type for login_token (login page)? |
|
173 |
194 |
http://www.valdyas.org/fading/index.cgi/2015/05/29#no-github |
http://www.valdyas.org/fading/index.cgi/2015/05/29#no-github |
174 |
195 |
http://www.adamhyde.net/why-github-is-bad-for-open-source/ |
http://www.adamhyde.net/why-github-is-bad-for-open-source/ |
175 |
196 |
[ ] Add sha1sum of the VM images |
[ ] Add sha1sum of the VM images |
176 |
|
[ ] Show user the entry that must be added for known_hosts |
|
|
197 |
|
[ ] ssh: Show user the entry that must be added for known_hosts |
177 |
198 |
[ ] 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 |
178 |
199 |
[ ] Leave alone the ssh key comment! More exactly, do not convert unk chars. |
[ ] Leave alone the ssh key comment! More exactly, do not convert unk chars. |
179 |
200 |
[ ] Pass only uid to events, we already have it in cache! |
[ ] Pass only uid to events, we already have it in cache! |
|
182 |
203 |
[ ] When we push by ssh, we have the user, so we can give more info about |
[ ] When we push by ssh, we have the user, so we can give more info about |
183 |
204 |
why the push failed. Carefull, not too much info. For example: |
why the push failed. Carefull, not too much info. For example: |
184 |
205 |
"You have no key uploaded, go to ..." |
"You have no key uploaded, go to ..." |
|
206 |
|
No key uploaded is not working. ssh server will ask for pass... |
|
207 |
|
Should we set a special shell and use an empty pass for rocketgit account? |
|
208 |
|
[ ] Should we just set no password somehow for ssh access to be able to signal |
|
209 |
|
the user that has no key uploaded? |
185 |
210 |
[ ] For 'log' and 'tree' we have decorations for links! |
[ ] For 'log' and 'tree' we have decorations for links! |
186 |
211 |
[ ] Sign vm images. |
[ ] Sign vm images. |
187 |
212 |
[ ] In "Tree" section, seems the path is doubled. |
[ ] In "Tree" section, seems the path is doubled. |
|
191 |
216 |
Anyway, we already do double replace for hints) |
Anyway, we already do double replace for hints) |
192 |
217 |
[ ] Saving fields in forms when session exired to be reused next time. |
[ ] Saving fields in forms when session exired to be reused next time. |
193 |
218 |
[ ] Compression off for ssh because objects are already compressed? |
[ ] Compression off for ssh because objects are already compressed? |
194 |
|
[ ] Add a random token in header to prevent watermarking (this is the name?). |
|
|
219 |
|
[ ] Add a random token in HTTP header to prevent watermarking (this is the name?). |
195 |
220 |
[ ] Add "Spread the word!" on website. |
[ ] Add "Spread the word!" on website. |
196 |
221 |
[ ] https://www.kernel.org/pub/software/scm/git/docs/gitworkflows.html |
[ ] https://www.kernel.org/pub/software/scm/git/docs/gitworkflows.html |
197 |
222 |
[ ] git-name-rev is nice. |
[ ] git-name-rev is nice. |
|
205 |
230 |
oriunde - still needed?! |
oriunde - still needed?! |
206 |
231 |
[ ] Backup for rg2! |
[ ] Backup for rg2! |
207 |
232 |
[ ] Add uid to events so we can delete old events for tests or abusing users? |
[ ] Add uid to events so we can delete old events for tests or abusing users? |
208 |
|
[ ] Should we just set no password somehow for ssh access to be able to signal |
|
209 |
|
the user that has no key uploaded? |
|
210 |
233 |
[ ] rocketgit.com: When getting another IP, allow ssh on port 443(https)? |
[ ] rocketgit.com: When getting another IP, allow ssh on port 443(https)? |
211 |
234 |
[ ] Investigate --decorate/--word-diff for git log. |
[ ] Investigate --decorate/--word-diff for git log. |
212 |
235 |
[ ] client_win.html hint is not used. |
[ ] client_win.html hint is not used. |
File inc/ssh.inc.php changed (mode: 100644) (index 59f81dd..25057e5) |
... |
... |
function rg_ssh_repo($db, $uid, $paras) |
88 |
88 |
} |
} |
89 |
89 |
} |
} |
90 |
90 |
|
|
|
91 |
|
/* |
|
92 |
|
* Helper for totp_verify_ip - mostly to not duplicate error messages |
|
93 |
|
*/ |
|
94 |
|
function rg_ssh_totp_verify_ip($db, $uid, $ip) |
|
95 |
|
{ |
|
96 |
|
$ret = FALSE; |
|
97 |
|
while (1) { |
|
98 |
|
$r = rg_totp_verify_ip($db, $uid, $ip); |
|
99 |
|
if (($r['ok'] == 0) || (empty($r['ip_list']))) { |
|
100 |
|
echo 'Error: ' . rg_totp_error() . ".\n"; |
|
101 |
|
break; |
|
102 |
|
} |
|
103 |
|
if ($r['enrolled'] == 0) { |
|
104 |
|
echo 'Info: You are not enrolled.' . "\n"; |
|
105 |
|
break; |
|
106 |
|
} |
|
107 |
|
|
|
108 |
|
$ret = $r['ip_list']; |
|
109 |
|
break; |
|
110 |
|
} |
|
111 |
|
|
|
112 |
|
return $ret; |
|
113 |
|
} |
|
114 |
|
|
91 |
115 |
/* |
/* |
92 |
116 |
* Deal with TOTP stuff |
* Deal with TOTP stuff |
93 |
117 |
*/ |
*/ |
|
... |
... |
function rg_ssh_totp($db, $ip, $uid, $paras) |
99 |
123 |
|
|
100 |
124 |
$cmd = array_shift($paras); |
$cmd = array_shift($paras); |
101 |
125 |
switch ($cmd) { |
switch ($cmd) { |
102 |
|
case 'enroll': |
|
|
126 |
|
case 'enroll': // this has nothing to do with scratch codes |
103 |
127 |
if (empty($paras)) { |
if (empty($paras)) { |
104 |
128 |
$secret = rg_totp_base32_generate(16); |
$secret = rg_totp_base32_generate(16); |
105 |
129 |
|
|
|
... |
... |
function rg_ssh_totp($db, $ip, $uid, $paras) |
120 |
144 |
|
|
121 |
145 |
$token = array_shift($paras); |
$token = array_shift($paras); |
122 |
146 |
|
|
123 |
|
$v = rg_totp_verify_all($db, $uid, $token); |
|
124 |
|
if ($v['ok'] != 1) { |
|
125 |
|
echo 'Error: ' . rg_totp_error() . ".\n"; |
|
126 |
|
break; |
|
127 |
|
} |
|
128 |
|
if ($v['id'] == 0) { |
|
|
147 |
|
$v = rg_totp_device_verify($db, $uid, $token); |
|
148 |
|
if ($v['token_valid'] != 1) { |
129 |
149 |
echo 'Error: ' . rg_totp_error() . ".\n"; |
echo 'Error: ' . rg_totp_error() . ".\n"; |
130 |
150 |
break; |
break; |
131 |
151 |
} |
} |
|
... |
... |
function rg_ssh_totp($db, $ip, $uid, $paras) |
140 |
160 |
$hours = 0; |
$hours = 0; |
141 |
161 |
$minutes = 0; |
$minutes = 0; |
142 |
162 |
if (empty($paras)) { |
if (empty($paras)) { |
143 |
|
$hours = 24; |
|
|
163 |
|
$hours = 1; |
144 |
164 |
} else { |
} else { |
145 |
165 |
$s_expire = array_shift($paras); |
$s_expire = array_shift($paras); |
146 |
166 |
$val = intval($s_expire); |
$val = intval($s_expire); |
|
... |
... |
function rg_ssh_totp($db, $ip, $uid, $paras) |
155 |
175 |
} |
} |
156 |
176 |
//rg_log("token=$token days=$days hours=$hours minutes=$minutes"); |
//rg_log("token=$token days=$days hours=$hours minutes=$minutes"); |
157 |
177 |
|
|
158 |
|
$v = rg_totp_verify_all($db, $uid, $token); |
|
159 |
|
if ($v['ok'] != 1) { |
|
160 |
|
echo 'Error: ' . rg_totp_error() . ".\n"; |
|
161 |
|
break; |
|
162 |
|
} |
|
163 |
|
if ($v['id'] == 0) { |
|
|
178 |
|
$v = rg_totp_verify_any($db, $uid, $token); |
|
179 |
|
if ($v['token_valid'] != 1) { |
164 |
180 |
echo 'Error: ' . rg_totp_error() . ".\n"; |
echo 'Error: ' . rg_totp_error() . ".\n"; |
165 |
181 |
break; |
break; |
166 |
182 |
} |
} |
|
... |
... |
function rg_ssh_totp($db, $ip, $uid, $paras) |
175 |
191 |
} |
} |
176 |
192 |
|
|
177 |
193 |
echo 'Success! IP ' . $ip . ' added and is valid till ' |
echo 'Success! IP ' . $ip . ' added and is valid till ' |
178 |
|
. gmdate('Y-m-d H:i:s', $expire_ts) . ' UTC.' . "\n"; |
|
|
194 |
|
. gmdate('Y-m-d H:i:s', $expire_ts) . ' (UTC).' . "\n"; |
179 |
195 |
break; |
break; |
180 |
196 |
|
|
181 |
197 |
case 'list-val': |
case 'list-val': |
182 |
|
$r = rg_totp_verify_ip($db, $uid, $ip); |
|
183 |
|
if ($r['ok'] != 1) { |
|
184 |
|
echo 'Error: ' . rg_totp_error() . ".\n"; |
|
185 |
|
break; |
|
186 |
|
} |
|
187 |
|
if ($r['enrolled'] == 0) { |
|
188 |
|
echo 'Info: You are not enrolled.' . ".\n"; |
|
|
198 |
|
$r = rg_ssh_totp_verify_ip($db, $uid, $ip); |
|
199 |
|
if ($r === FALSE) |
189 |
200 |
break; |
break; |
190 |
|
} |
|
191 |
201 |
|
|
192 |
202 |
echo 'Insert date (UTC) Expire date (UTC) IP' . "\n"; |
echo 'Insert date (UTC) Expire date (UTC) IP' . "\n"; |
193 |
|
foreach ($r['list'] as $t) { |
|
|
203 |
|
foreach ($r as $t) { |
194 |
204 |
echo gmdate('Y-m-d H:i:s', $t['itime']) |
echo gmdate('Y-m-d H:i:s', $t['itime']) |
195 |
205 |
. ' ' . gmdate('Y-m-d H:i:s', $t['expire']) |
. ' ' . gmdate('Y-m-d H:i:s', $t['expire']) |
196 |
206 |
. ' ' . $t['ip'] |
. ' ' . $t['ip'] |
|
... |
... |
function rg_ssh_totp($db, $ip, $uid, $paras) |
202 |
212 |
case 'unenroll': |
case 'unenroll': |
203 |
213 |
$token = array_shift($paras); |
$token = array_shift($paras); |
204 |
214 |
|
|
205 |
|
$v = rg_totp_verify_all($db, $uid, $token); |
|
206 |
|
if ($v['ok'] != 1) { |
|
|
215 |
|
$v = rg_totp_verify_any($db, $uid, $token); |
|
216 |
|
if ($v['token_valid'] != 1) { |
207 |
217 |
echo 'Error: ' . rg_totp_error() . ".\n"; |
echo 'Error: ' . rg_totp_error() . ".\n"; |
208 |
218 |
break; |
break; |
209 |
219 |
} |
} |
210 |
|
if ($v['id'] == 0) { |
|
|
220 |
|
|
|
221 |
|
$r = rg_totp_unenroll($db, $uid); |
|
222 |
|
if ($r !== TRUE) { |
|
223 |
|
echo'Error: ' . rg_totp_error() . ".\n"; |
|
224 |
|
break; |
|
225 |
|
} |
|
226 |
|
|
|
227 |
|
echo 'You are now unenrolled.' . "\n"; |
|
228 |
|
break; |
|
229 |
|
|
|
230 |
|
case 'remove-device': |
|
231 |
|
$token = array_shift($paras); |
|
232 |
|
|
|
233 |
|
$v = rg_totp_device_verify($db, $uid, $token); |
|
234 |
|
if ($v['token_valid'] != 1) { |
211 |
235 |
echo 'Error: ' . rg_totp_error() . ".\n"; |
echo 'Error: ' . rg_totp_error() . ".\n"; |
212 |
236 |
break; |
break; |
213 |
237 |
} |
} |
|
... |
... |
function rg_ssh_totp($db, $ip, $uid, $paras) |
230 |
254 |
|
|
231 |
255 |
$del_ip = array_shift($paras); |
$del_ip = array_shift($paras); |
232 |
256 |
|
|
233 |
|
$r = rg_totp_verify_ip($db, $uid, $ip); |
|
234 |
|
if ($r['ok'] != 1) { |
|
235 |
|
echo 'Error: ' . rg_totp_error() . ".\n"; |
|
|
257 |
|
if (rg_ssh_totp_verify_ip($db, $uid, $ip) === FALSE) |
236 |
258 |
break; |
break; |
237 |
|
} |
|
238 |
|
if ($r['enrolled'] == 0) { |
|
239 |
|
echo 'Info: You are not enrolled.' . ".\n"; |
|
240 |
|
break; |
|
241 |
|
} |
|
242 |
259 |
|
|
243 |
260 |
$r = rg_totp_del_ip($db, $uid, $del_ip); |
$r = rg_totp_del_ip($db, $uid, $del_ip); |
244 |
|
if ($r !== TRUE) { |
|
|
261 |
|
if ($r['found'] != 1) { |
245 |
262 |
echo 'Error: ' . rg_totp_error() . ".\n"; |
echo 'Error: ' . rg_totp_error() . ".\n"; |
246 |
263 |
break; |
break; |
247 |
264 |
} |
} |
|
... |
... |
function rg_ssh_totp($db, $ip, $uid, $paras) |
252 |
269 |
default: |
default: |
253 |
270 |
echo 'Posible TOTP commands:' . "\n"; |
echo 'Posible TOTP commands:' . "\n"; |
254 |
271 |
echo ' enroll <token> - adds a new device in the system' . "\n"; |
echo ' enroll <token> - adds a new device in the system' . "\n"; |
255 |
|
echo ' val [X(w|d|h|m|s)] - adds your IP to the allow list for X time' . "\n"; |
|
256 |
|
echo ' the default is 24 hours;' . "\n"; |
|
257 |
|
echo ' X: w for weeks, d for days, h for hours, m for minutes, and s for seconds' . "\n"; |
|
|
272 |
|
echo ' val [X(w|d|h|m|s)] <token> - adds your IP to the allow list for X time' . "\n"; |
|
273 |
|
echo ' the default is 1 hour; X is a number; defauls is \'minutes\';' . "\n"; |
|
274 |
|
echo ' w=weeks, d=days, h=hours, m=minutes, and s for seconds' . "\n"; |
258 |
275 |
echo ' list-val - lists the already validated IPs' . "\n"; |
echo ' list-val - lists the already validated IPs' . "\n"; |
259 |
276 |
echo ' inval ip|all - invalidates IP address(es)' . "\n"; |
echo ' inval ip|all - invalidates IP address(es)' . "\n"; |
260 |
|
echo ' unenroll <token> - removes a device from TOTP system' . "\n"; |
|
|
277 |
|
echo ' remove-device <token> - removes a device from TOTP system' . "\n"; |
|
278 |
|
echo ' unenroll <token> - removes all devices and scratch codes from TOTP system' . "\n"; |
|
279 |
|
echo "\n"; |
|
280 |
|
echo 'Notes:' . "\n"; |
|
281 |
|
echo ' - <token> means a code generated by mobile device or a scratch code' . "\n"; |
261 |
282 |
break; |
break; |
262 |
283 |
} |
} |
263 |
284 |
|
|
|
... |
... |
function rg_ssh_dispatch($db, $ip, $uid, $orig_cmd) |
293 |
314 |
case 'totp': break; // totp will verify the ip only for some commands |
case 'totp': break; // totp will verify the ip only for some commands |
294 |
315 |
default: |
default: |
295 |
316 |
$r = rg_totp_verify_ip($db, $uid, $ip); |
$r = rg_totp_verify_ip($db, $uid, $ip); |
296 |
|
if ($r['ok'] != 1) { |
|
|
317 |
|
if (($r['ok'] == 0) |
|
318 |
|
|| (($r['enrolled'] == 1) && (empty($r['ip_list'])))) { |
297 |
319 |
echo 'Error: ' . rg_totp_error() . ".\n"; |
echo 'Error: ' . rg_totp_error() . ".\n"; |
298 |
320 |
exit(0); |
exit(0); |
299 |
321 |
} |
} |
File inc/totp.inc.php changed (mode: 100644) (index 6b55fda..96502f1) |
... |
... |
function rg_totp_verify($key, $ts, $token) |
122 |
122 |
rg_prof_start('totp_verify'); |
rg_prof_start('totp_verify'); |
123 |
123 |
rg_log_enter('totp_verify ts=' . $ts . ', token=' . $token); |
rg_log_enter('totp_verify ts=' . $ts . ', token=' . $token); |
124 |
124 |
|
|
125 |
|
$tc = intval($ts / 30); |
|
126 |
|
$list = array($tc, $tc - 1, $tc - 2, $tc + 1, $tc + 2); |
|
127 |
|
foreach ($list as $tc) { |
|
128 |
|
$ret = rg_totp_verify_tc($key, $tc, $token); |
|
129 |
|
//rg_log('DEBUG: using tc ' . $tc . ', ret=' . $ret); |
|
130 |
|
if ($ret !== FALSE) |
|
|
125 |
|
$ret = FALSE; |
|
126 |
|
while (1) { |
|
127 |
|
if (empty($token)) |
131 |
128 |
break; |
break; |
|
129 |
|
|
|
130 |
|
$token = sprintf("%06u", $token); |
|
131 |
|
$tc = intval($ts / 30); |
|
132 |
|
$list = array($tc, $tc - 1, $tc - 2, $tc + 1, $tc + 2); |
|
133 |
|
foreach ($list as $tc) { |
|
134 |
|
$ret = rg_totp_verify_tc($key, $tc, $token); |
|
135 |
|
//rg_log('DEBUG: using tc ' . $tc . ', ret=' . $ret); |
|
136 |
|
if ($ret !== FALSE) |
|
137 |
|
break; |
|
138 |
|
} |
|
139 |
|
|
|
140 |
|
break; |
132 |
141 |
} |
} |
133 |
142 |
|
|
134 |
143 |
rg_log_exit(); |
rg_log_exit(); |
|
... |
... |
function rg_totp_cosmetic(&$row) |
194 |
203 |
} |
} |
195 |
204 |
} |
} |
196 |
205 |
|
|
|
206 |
|
/* |
|
207 |
|
* Cosmetic fixes for a scratch token row |
|
208 |
|
*/ |
|
209 |
|
function rg_totp_sc_cosmetic(&$row) |
|
210 |
|
{ |
|
211 |
|
if (isset($row['itime'])) |
|
212 |
|
$row['itime_nice'] = gmdate('Y-m-d H:i', $row['itime']); |
|
213 |
|
} |
|
214 |
|
|
|
215 |
|
/* |
|
216 |
|
* Returns if the user is enrolled or not |
|
217 |
|
*/ |
|
218 |
|
function rg_totp_enrolled($db, $uid) |
|
219 |
|
{ |
|
220 |
|
$ret = array(); |
|
221 |
|
$ret['ok'] = 0; |
|
222 |
|
$ret['enrolled'] = 1; |
|
223 |
|
while (1) { |
|
224 |
|
$lt = rg_totp_device_list($db, $uid); |
|
225 |
|
if ($lt['ok'] != 1) |
|
226 |
|
break; |
|
227 |
|
|
|
228 |
|
// We will not consider unconfirmed entries as enrollment |
|
229 |
|
foreach ($lt['list'] as $t) { |
|
230 |
|
if (strcmp($t['conf'], 't') == 0) { |
|
231 |
|
$ret['ok'] = 1; |
|
232 |
|
return $ret; |
|
233 |
|
} |
|
234 |
|
} |
|
235 |
|
|
|
236 |
|
$sc = rg_totp_sc_list($db, $uid); |
|
237 |
|
if ($sc['ok'] != 1) |
|
238 |
|
break; |
|
239 |
|
if (!empty($sc['list'])) { |
|
240 |
|
$ret['ok'] = 1; |
|
241 |
|
return $ret; |
|
242 |
|
} |
|
243 |
|
|
|
244 |
|
$ret['enrolled'] = 0; |
|
245 |
|
$ret['ok'] = 1; |
|
246 |
|
break; |
|
247 |
|
} |
|
248 |
|
return $ret; |
|
249 |
|
} |
|
250 |
|
|
197 |
251 |
/* |
/* |
198 |
252 |
* Sets when a login token was last used |
* Sets when a login token was last used |
199 |
253 |
*/ |
*/ |
|
... |
... |
function rg_totp_set_last_use($db, $uid, $id, $tc, $ts) |
217 |
271 |
. ' AND id = @@id@@'; |
. ' AND id = @@id@@'; |
218 |
272 |
$res = rg_sql_query_params($db, $sql, $params); |
$res = rg_sql_query_params($db, $sql, $params); |
219 |
273 |
if ($res === FALSE) { |
if ($res === FALSE) { |
220 |
|
rg_user_set_error('cannot update last used (' . rg_sql_error()); |
|
|
274 |
|
rg_totp_set_error('cannot update last used (' . rg_sql_error()); |
221 |
275 |
break; |
break; |
222 |
276 |
} |
} |
223 |
277 |
rg_sql_free_result($res); |
rg_sql_free_result($res); |
224 |
278 |
|
|
225 |
279 |
$key = 'user' . '::' . $uid . '::' . 'login_tokens' |
$key = 'user' . '::' . $uid . '::' . 'login_tokens' |
226 |
|
. '::' . 'list' . '::' . $id; |
|
|
280 |
|
. '::' . 'device' . '::' . $id; |
227 |
281 |
$a = array('used' => $ts, 'last_used_tc' => $tc, 'conf' => 't'); |
$a = array('used' => $ts, 'last_used_tc' => $tc, 'conf' => 't'); |
228 |
282 |
rg_totp_cosmetic($a); |
rg_totp_cosmetic($a); |
229 |
283 |
rg_cache_merge($key, $a, RG_SOCKET_NO_WAIT); |
rg_cache_merge($key, $a, RG_SOCKET_NO_WAIT); |
|
... |
... |
function rg_totp_set_last_use($db, $uid, $id, $tc, $ts) |
240 |
294 |
/* |
/* |
241 |
295 |
* Returns a list of login tokens from database |
* Returns a list of login tokens from database |
242 |
296 |
*/ |
*/ |
243 |
|
function rg_totp_list($db, $uid) |
|
|
297 |
|
function rg_totp_device_list($db, $uid) |
244 |
298 |
{ |
{ |
245 |
|
rg_prof_start('totp_list'); |
|
246 |
|
rg_log_enter('totp_list'); |
|
|
299 |
|
rg_prof_start('totp_device_list'); |
|
300 |
|
rg_log_enter('totp_device_list'); |
247 |
301 |
|
|
|
302 |
|
$ret = array(); |
|
303 |
|
$ret['ok'] = 0; |
248 |
304 |
while (1) { |
while (1) { |
249 |
|
$key = 'user' . '::' . $uid . '::' . 'login_tokens'; |
|
250 |
|
$ret = rg_cache_get($key); |
|
251 |
|
if ($ret !== FALSE) { |
|
|
305 |
|
$key = 'user' . '::' . $uid . '::' . 'login_tokens' |
|
306 |
|
. '::' . 'device'; |
|
307 |
|
$r = rg_cache_get($key); |
|
308 |
|
if ($r !== FALSE) { |
|
309 |
|
$ret['list'] = $r; |
252 |
310 |
$ret['ok'] = 1; |
$ret['ok'] = 1; |
253 |
311 |
break; |
break; |
254 |
312 |
} |
} |
|
... |
... |
function rg_totp_list($db, $uid) |
276 |
334 |
} |
} |
277 |
335 |
rg_sql_free_result($res); |
rg_sql_free_result($res); |
278 |
336 |
|
|
279 |
|
unset($ret['ok']); // we do not need it in cache |
|
280 |
|
rg_cache_set($key, $ret, RG_SOCKET_NO_WAIT); |
|
|
337 |
|
rg_cache_set($key, $ret['list'], RG_SOCKET_NO_WAIT); |
281 |
338 |
$ret['ok'] = 1; |
$ret['ok'] = 1; |
282 |
339 |
break; |
break; |
283 |
340 |
} |
} |
284 |
341 |
|
|
285 |
342 |
rg_log_exit(); |
rg_log_exit(); |
286 |
|
rg_prof_end('totp_list'); |
|
|
343 |
|
rg_prof_end('totp_device_list'); |
287 |
344 |
return $ret; |
return $ret; |
288 |
345 |
} |
} |
289 |
346 |
|
|
290 |
347 |
/* |
/* |
291 |
|
* Validates a token |
|
|
348 |
|
* Validates a device token (not a scratch code) |
292 |
349 |
* Also, it marks the tokens as 'confirmed' if needed |
* Also, it marks the tokens as 'confirmed' if needed |
293 |
350 |
*/ |
*/ |
294 |
|
function rg_totp_verify_all($db, $uid, $token) |
|
|
351 |
|
function rg_totp_device_verify($db, $uid, $token) |
295 |
352 |
{ |
{ |
296 |
|
rg_prof_start('totp_verify_all'); |
|
297 |
|
rg_log_enter('totp_verify_all token=' . $token); |
|
|
353 |
|
rg_prof_start('totp_device_verify'); |
|
354 |
|
rg_log_enter('totp_device_verify token=' . $token); |
298 |
355 |
|
|
299 |
356 |
$now = time(); |
$now = time(); |
300 |
357 |
|
|
301 |
358 |
$ret = array(); |
$ret = array(); |
302 |
359 |
$ret['ok'] = 0; |
$ret['ok'] = 0; |
|
360 |
|
$ret['enrolled'] = 0; |
|
361 |
|
$ret['token_valid'] = 0; |
|
362 |
|
$ret['id'] = 0; |
|
363 |
|
$ret['reuse'] = 0; |
303 |
364 |
while (1) { |
while (1) { |
304 |
|
$lt = rg_totp_list($db, $uid); |
|
|
365 |
|
$lt = rg_totp_device_list($db, $uid); |
305 |
366 |
if ($lt['ok'] != 1) |
if ($lt['ok'] != 1) |
306 |
367 |
break; |
break; |
307 |
368 |
|
|
308 |
369 |
$ret['ok'] = 1; |
$ret['ok'] = 1; |
309 |
|
$ret['enrolled'] = 0; |
|
310 |
|
$ret['id'] = 0; |
|
311 |
|
$ret['conf_error'] = 0; |
|
312 |
|
$ret['tc'] = 0; |
|
313 |
|
|
|
314 |
|
if (strlen($token) == 0) { |
|
315 |
|
rg_totp_set_error('token is empty'); |
|
316 |
|
break; |
|
317 |
|
} |
|
318 |
|
$token = sprintf("%06u", $token); |
|
319 |
370 |
|
|
320 |
|
rg_totp_set_error('wrong token; sync the time'); |
|
|
371 |
|
$err_set = FALSE; |
321 |
372 |
foreach ($lt['list'] as $t) { |
foreach ($lt['list'] as $t) { |
322 |
373 |
if (strcmp($t['conf'], 't') == 0) |
if (strcmp($t['conf'], 't') == 0) |
323 |
374 |
if ($ret['enrolled'] == 0) |
if ($ret['enrolled'] == 0) |
|
... |
... |
function rg_totp_verify_all($db, $uid, $token) |
328 |
379 |
continue; |
continue; |
329 |
380 |
|
|
330 |
381 |
if ($tc <= $t['last_used_tc']) { |
if ($tc <= $t['last_used_tc']) { |
331 |
|
rg_totp_set_error('cannot reuse the login token'); |
|
|
382 |
|
$ret['reuse'] = 1; |
332 |
383 |
break; |
break; |
333 |
384 |
} |
} |
334 |
385 |
|
|
|
386 |
|
$ret['token_valid'] = 1; |
335 |
387 |
$ret['id'] = $t['id']; |
$ret['id'] = $t['id']; |
336 |
|
$ret['tc'] = $tc; |
|
337 |
388 |
|
|
338 |
389 |
// Mark it as used and update 'conf' status |
// Mark it as used and update 'conf' status |
339 |
390 |
$r = rg_totp_set_last_use($db, $uid, $t['id'], $tc, $now); |
$r = rg_totp_set_last_use($db, $uid, $t['id'], $tc, $now); |
340 |
391 |
if ($r !== TRUE) { |
if ($r !== TRUE) { |
|
392 |
|
$err_set = TRUE; |
341 |
393 |
$ret['ok'] = 0; |
$ret['ok'] = 0; |
342 |
394 |
break; |
break; |
343 |
395 |
} |
} |
344 |
396 |
|
|
345 |
|
// we just confirmed an unconf entry, so we are enrolled |
|
|
397 |
|
// We just confirmed an unconf entry, so we are enrolled |
346 |
398 |
if ($ret['enrolled'] == 0) |
if ($ret['enrolled'] == 0) |
347 |
399 |
$ret['enrolled'] = 1; |
$ret['enrolled'] = 1; |
348 |
400 |
break; |
break; |
349 |
401 |
} |
} |
350 |
402 |
|
|
|
403 |
|
if ($err_set) { |
|
404 |
|
// Do nothing |
|
405 |
|
} else if ($ret['reuse'] == 1) { |
|
406 |
|
rg_totp_set_error('cannot reuse the login token'); |
|
407 |
|
} else if ($ret['enrolled'] == 0) { |
|
408 |
|
rg_totp_set_error('you are not enrolled'); |
|
409 |
|
} else if ($ret['token_valid'] != 1) { |
|
410 |
|
rg_totp_set_error('invalid token; sync the time'); |
|
411 |
|
} |
|
412 |
|
|
351 |
413 |
break; |
break; |
352 |
414 |
} |
} |
353 |
415 |
|
|
354 |
416 |
rg_log_exit(); |
rg_log_exit(); |
355 |
|
rg_prof_end('totp_verify_all'); |
|
|
417 |
|
rg_prof_end('totp_device_verify'); |
356 |
418 |
return $ret; |
return $ret; |
357 |
419 |
} |
} |
358 |
420 |
|
|
|
... |
... |
function rg_totp_enroll($db, $uid, $name, $secret, $ip, $conf) |
386 |
448 |
$params['id'] = $row['id']; |
$params['id'] = $row['id']; |
387 |
449 |
rg_totp_cosmetic($params); |
rg_totp_cosmetic($params); |
388 |
450 |
$key = 'user' . '::' . $uid . '::' . 'login_tokens' |
$key = 'user' . '::' . $uid . '::' . 'login_tokens' |
389 |
|
. '::' . 'list' . '::' . $params['id']; |
|
|
451 |
|
. '::' . 'device' . '::' . $params['id']; |
390 |
452 |
rg_cache_set($key, $params, RG_SOCKET_NO_WAIT); |
rg_cache_set($key, $params, RG_SOCKET_NO_WAIT); |
391 |
453 |
|
|
392 |
454 |
$ret = TRUE; |
$ret = TRUE; |
|
... |
... |
function rg_totp_add_ip($db, $uid, $token_id, $ip, $expire_ts) |
424 |
486 |
} |
} |
425 |
487 |
rg_sql_free_result($res); |
rg_sql_free_result($res); |
426 |
488 |
|
|
427 |
|
$key = 'user' . '::' . $uid . '::' . 'login_tokens_ip'; |
|
428 |
|
rg_cache_apush($key, $params, RG_SOCKET_NO_WAIT); |
|
|
489 |
|
unset($params['uid']); |
|
490 |
|
$eip = str_replace(':', '_', $ip); |
|
491 |
|
$key = 'user' . '::' . $uid . '::' . 'login_tokens' |
|
492 |
|
. '::' . 'ip' . '::' . $eip; |
|
493 |
|
rg_cache_set($key, $params, RG_SOCKET_NO_WAIT); |
429 |
494 |
|
|
430 |
495 |
$ret = TRUE; |
$ret = TRUE; |
431 |
496 |
break; |
break; |
|
... |
... |
function rg_totp_add_ip($db, $uid, $token_id, $ip, $expire_ts) |
437 |
502 |
} |
} |
438 |
503 |
|
|
439 |
504 |
/* |
/* |
440 |
|
* Del an ip from login_tokens_ip table |
|
|
505 |
|
* Deletes an ip from login_tokens_ip table |
441 |
506 |
*/ |
*/ |
442 |
507 |
function rg_totp_del_ip($db, $uid, $ip) |
function rg_totp_del_ip($db, $uid, $ip) |
443 |
508 |
{ |
{ |
444 |
509 |
rg_prof_start('totp_del_ip'); |
rg_prof_start('totp_del_ip'); |
445 |
510 |
rg_log_enter('totp_del_ip ip=' . $ip); |
rg_log_enter('totp_del_ip ip=' . $ip); |
446 |
511 |
|
|
447 |
|
$ret = FALSE; |
|
|
512 |
|
$ret = array(); |
|
513 |
|
$ret['ok'] = 0; |
|
514 |
|
$ret['found'] = 0; |
448 |
515 |
while (1) { |
while (1) { |
449 |
516 |
$params = array('uid' => $uid, 'ip' => $ip); |
$params = array('uid' => $uid, 'ip' => $ip); |
450 |
517 |
if (strcasecmp($ip, 'all') == 0) { |
if (strcasecmp($ip, 'all') == 0) { |
|
... |
... |
function rg_totp_del_ip($db, $uid, $ip) |
463 |
530 |
$aff = rg_sql_affected_rows($res); |
$aff = rg_sql_affected_rows($res); |
464 |
531 |
rg_sql_free_result($res); |
rg_sql_free_result($res); |
465 |
532 |
|
|
|
533 |
|
$ret['ok'] = 1; |
|
534 |
|
|
466 |
535 |
if ($aff == 0) { |
if ($aff == 0) { |
467 |
536 |
rg_totp_set_error('ip not found'); |
rg_totp_set_error('ip not found'); |
468 |
537 |
break; |
break; |
469 |
538 |
} |
} |
470 |
539 |
|
|
471 |
|
$key = 'user' . '::' . $uid . '::' . 'login_tokens_ip'; |
|
|
540 |
|
$key = 'user' . '::' . $uid . '::' . 'login_tokens' |
|
541 |
|
. '::' . 'ip'; |
|
542 |
|
if (strcasecmp($ip, 'all') != 0) { |
|
543 |
|
$eip = str_replace(':', '_', $ip); |
|
544 |
|
$key .= '::' . $eip; |
|
545 |
|
} |
472 |
546 |
rg_cache_unset($key, RG_SOCKET_NO_WAIT); |
rg_cache_unset($key, RG_SOCKET_NO_WAIT); |
473 |
547 |
|
|
474 |
|
$ret = TRUE; |
|
|
548 |
|
$ret['found'] = 1; |
475 |
549 |
break; |
break; |
476 |
550 |
} |
} |
477 |
551 |
|
|
|
... |
... |
function rg_totp_del_ip($db, $uid, $ip) |
480 |
554 |
return $ret; |
return $ret; |
481 |
555 |
} |
} |
482 |
556 |
|
|
|
557 |
|
/* |
|
558 |
|
* Returns a list of login tokens IPs from database |
|
559 |
|
*/ |
|
560 |
|
function rg_totp_list_ip($db, $uid) |
|
561 |
|
{ |
|
562 |
|
rg_prof_start('totp_list_ip'); |
|
563 |
|
rg_log_enter('totp_list_ip'); |
|
564 |
|
|
|
565 |
|
while (1) { |
|
566 |
|
$key = 'user' . '::' . $uid . '::' . 'login_tokens' |
|
567 |
|
. '::' . 'ip'; |
|
568 |
|
$list = rg_cache_get($key); |
|
569 |
|
if ($list !== FALSE) { |
|
570 |
|
$ret['list'] = $list; |
|
571 |
|
$ret['ok'] = 1; |
|
572 |
|
break; |
|
573 |
|
} |
|
574 |
|
|
|
575 |
|
$ret = array(); |
|
576 |
|
$ret['ok'] = 0; |
|
577 |
|
|
|
578 |
|
$params = array('uid' => $uid, 'now' => time()); |
|
579 |
|
$sql = 'SELECT * FROM login_tokens_ip' |
|
580 |
|
. ' WHERE uid = @@uid@@' |
|
581 |
|
. ' AND expire >= @@now@@' |
|
582 |
|
. ' ORDER BY itime'; |
|
583 |
|
$res = rg_sql_query_params($db, $sql, $params); |
|
584 |
|
if ($res === FALSE) { |
|
585 |
|
rg_totp_set_error('cannot load login tokens ip'); |
|
586 |
|
break; |
|
587 |
|
} |
|
588 |
|
|
|
589 |
|
$ret['list'] = array(); |
|
590 |
|
while (($row = rg_sql_fetch_array($res))) { |
|
591 |
|
unset($row['uid']); |
|
592 |
|
$eip = str_replace(':', '_', $row['ip']); |
|
593 |
|
$ret['list'][$eip] = $row; |
|
594 |
|
} |
|
595 |
|
rg_sql_free_result($res); |
|
596 |
|
|
|
597 |
|
rg_cache_set($key, $ret['list'], RG_SOCKET_NO_WAIT); |
|
598 |
|
$ret['ok'] = 1; |
|
599 |
|
break; |
|
600 |
|
} |
|
601 |
|
|
|
602 |
|
rg_log_exit(); |
|
603 |
|
rg_prof_end('totp_list_ip'); |
|
604 |
|
return $ret; |
|
605 |
|
} |
|
606 |
|
|
|
607 |
|
/* |
|
608 |
|
* Verifies that an IP is in the 'validated' list |
|
609 |
|
* Returns ip_list to be used for an optional dump of the list. |
|
610 |
|
*/ |
|
611 |
|
function rg_totp_verify_ip($db, $uid, $ip) |
|
612 |
|
{ |
|
613 |
|
rg_prof_start('totp_verify_ip'); |
|
614 |
|
rg_log_enter('totp_verify_ip ip=' . $ip); |
|
615 |
|
|
|
616 |
|
$ret = array(); |
|
617 |
|
$ret['ok'] = 0; |
|
618 |
|
$ret['enrolled'] = 1; |
|
619 |
|
$ret['ip_list'] = array(); |
|
620 |
|
while (1) { |
|
621 |
|
$r = rg_totp_enrolled($db, $uid); |
|
622 |
|
if ($r['ok'] != 1) |
|
623 |
|
break; |
|
624 |
|
if ($r['enrolled'] == 0) { |
|
625 |
|
$ret['enrolled'] = 0; |
|
626 |
|
$ret['ok'] = 1; |
|
627 |
|
break; |
|
628 |
|
} |
|
629 |
|
|
|
630 |
|
$r = rg_totp_list_ip($db, $uid); |
|
631 |
|
if ($r['ok'] != 1) |
|
632 |
|
break; |
|
633 |
|
|
|
634 |
|
foreach ($r['list'] as $eip => $t) { |
|
635 |
|
if (strcasecmp($t['ip'], $ip) == 0) { |
|
636 |
|
$ret['ip_list'] = $r['list']; |
|
637 |
|
$ret['ok'] = 1; |
|
638 |
|
break; |
|
639 |
|
} |
|
640 |
|
} |
|
641 |
|
|
|
642 |
|
if (empty($ret['ip_list'])) |
|
643 |
|
rg_totp_set_error('you have no IP validated;' |
|
644 |
|
. ' run \'ssh ... totp\' for help'); |
|
645 |
|
|
|
646 |
|
break; |
|
647 |
|
} |
|
648 |
|
|
|
649 |
|
rg_log_exit(); |
|
650 |
|
rg_prof_end('totp_verify_ip'); |
|
651 |
|
return $ret; |
|
652 |
|
} |
|
653 |
|
|
483 |
654 |
/* |
/* |
484 |
655 |
* Remove a list of login tokens |
* Remove a list of login tokens |
485 |
656 |
*/ |
*/ |
|
... |
... |
function rg_totp_remove($db, $uid, $list) |
525 |
696 |
|
|
526 |
697 |
foreach ($my_list as $junk => $_id) { |
foreach ($my_list as $junk => $_id) { |
527 |
698 |
$key = 'user' . '::' . $uid . '::' . 'login_tokens' |
$key = 'user' . '::' . $uid . '::' . 'login_tokens' |
528 |
|
. '::' . 'list' . $_id; |
|
|
699 |
|
. '::' . 'device' . '::' . $_id; |
529 |
700 |
rg_cache_unset($key, RG_SOCKET_NO_WAIT); |
rg_cache_unset($key, RG_SOCKET_NO_WAIT); |
530 |
701 |
} |
} |
531 |
702 |
|
|
|
... |
... |
function rg_totp_remove($db, $uid, $list) |
539 |
710 |
} |
} |
540 |
711 |
|
|
541 |
712 |
/* |
/* |
542 |
|
* Returns a list of login tokens IPs from database |
|
|
713 |
|
* Validates a scratch code |
|
714 |
|
* TODO: it deletes the used code. |
543 |
715 |
*/ |
*/ |
544 |
|
function rg_totp_list_ip($db, $uid) |
|
|
716 |
|
function rg_totp_sc_verify($db, $uid, $token) |
545 |
717 |
{ |
{ |
546 |
|
rg_prof_start('totp_list_ip'); |
|
547 |
|
rg_log_enter('totp_list_ip'); |
|
|
718 |
|
rg_prof_start('totp_sc_verify'); |
|
719 |
|
rg_log_enter('totp_sc_verify token=' . $token); |
|
720 |
|
|
|
721 |
|
$now = time(); |
|
722 |
|
$token = sprintf("%08u", $token); |
548 |
723 |
|
|
|
724 |
|
$ret = array(); |
|
725 |
|
$ret['ok'] = 0; |
|
726 |
|
$ret['enrolled'] = 0; |
|
727 |
|
$ret['token_valid'] = 0; |
|
728 |
|
$ret['id'] = 0; // we do not have an id for scratch codes; but, we may |
|
729 |
|
// be forced to use one to delete the IPs associated. |
549 |
730 |
while (1) { |
while (1) { |
550 |
|
$key = 'user' . '::' . $uid . '::' . 'login_tokens_ip'; |
|
551 |
|
$list = rg_cache_get($key); |
|
552 |
|
if ($list !== FALSE) { |
|
553 |
|
$ret['list'] = $list; |
|
554 |
|
$ret['ok'] = 1; |
|
|
731 |
|
$sc = rg_totp_sc_list($db, $uid); |
|
732 |
|
if ($sc['ok'] != 1) |
555 |
733 |
break; |
break; |
|
734 |
|
|
|
735 |
|
$ret['ok'] = 1; |
|
736 |
|
|
|
737 |
|
$done = FALSE; |
|
738 |
|
foreach ($sc['list'] as $itime => $per_itime) { |
|
739 |
|
if ($ret['enrolled'] == 0) |
|
740 |
|
$ret['enrolled'] = 1; |
|
741 |
|
|
|
742 |
|
foreach ($per_itime as $sc => $junk) { |
|
743 |
|
rg_log('DEBUG: comparing with ' . $sc); |
|
744 |
|
if (strcmp($sc, $token) == 0) { |
|
745 |
|
$r = rg_totp_sc_remove($db, $uid, |
|
746 |
|
$itime, $token); |
|
747 |
|
if ($r !== TRUE) |
|
748 |
|
$ret['ok'] = 0; |
|
749 |
|
else |
|
750 |
|
$ret['token_valid'] = 1; |
|
751 |
|
$done = TRUE; |
|
752 |
|
break; |
|
753 |
|
} |
|
754 |
|
} |
|
755 |
|
if ($done) |
|
756 |
|
break; |
556 |
757 |
} |
} |
557 |
758 |
|
|
558 |
|
$ret = array(); |
|
559 |
|
$ret['ok'] = 0; |
|
|
759 |
|
if ($ret['enrolled'] == 0) |
|
760 |
|
rg_totp_set_error('you are not enrolled'); |
|
761 |
|
else if ($ret['token_valid'] != 1) |
|
762 |
|
rg_totp_set_error('invalid token'); |
|
763 |
|
break; |
|
764 |
|
} |
560 |
765 |
|
|
561 |
|
$params = array('uid' => $uid, 'now' => time()); |
|
562 |
|
$sql = 'SELECT * FROM login_tokens_ip' |
|
|
766 |
|
rg_log_ml('DEBUG: sc_verify returns: ' . print_r($ret, TRUE)); |
|
767 |
|
|
|
768 |
|
rg_log_exit(); |
|
769 |
|
rg_prof_end('totp_sc_verify'); |
|
770 |
|
return $ret; |
|
771 |
|
} |
|
772 |
|
|
|
773 |
|
/* |
|
774 |
|
* List the scratch codes |
|
775 |
|
*/ |
|
776 |
|
function rg_totp_sc_list($db, $uid) |
|
777 |
|
{ |
|
778 |
|
rg_prof_start('totp_sc_list'); |
|
779 |
|
rg_log_enter('totp_sc_list'); |
|
780 |
|
|
|
781 |
|
$ret = array(); |
|
782 |
|
$ret['ok'] = 0; |
|
783 |
|
while (1) { |
|
784 |
|
$key = 'user' . '::' . $uid . '::' . 'login_tokens' |
|
785 |
|
. '::' . 'sc'; |
|
786 |
|
$r = rg_cache_get($key); |
|
787 |
|
if ($r !== FALSE) { |
|
788 |
|
$ret['list'] = $r; |
|
789 |
|
$ret['ok'] = 1; |
|
790 |
|
break; |
|
791 |
|
} |
|
792 |
|
|
|
793 |
|
$params = array('uid' => $uid); |
|
794 |
|
$sql = 'SELECT * FROM scratch_codes' |
563 |
795 |
. ' WHERE uid = @@uid@@' |
. ' WHERE uid = @@uid@@' |
564 |
|
. ' AND expire >= @@now@@' |
|
565 |
|
. ' ORDER BY itime'; |
|
|
796 |
|
. ' ORDER BY itime DESC'; |
566 |
797 |
$res = rg_sql_query_params($db, $sql, $params); |
$res = rg_sql_query_params($db, $sql, $params); |
567 |
798 |
if ($res === FALSE) { |
if ($res === FALSE) { |
568 |
|
rg_totp_set_error('cannot load login tokens ip'); |
|
|
799 |
|
rg_totp_set_error('cannot load scratch codes'); |
569 |
800 |
break; |
break; |
570 |
801 |
} |
} |
571 |
802 |
|
|
572 |
803 |
$ret['list'] = array(); |
$ret['list'] = array(); |
573 |
804 |
while (($row = rg_sql_fetch_array($res))) { |
while (($row = rg_sql_fetch_array($res))) { |
574 |
|
unset($row['uid']); |
|
575 |
|
$ret['list'][] = $row; |
|
|
805 |
|
$itime = $row['itime']; |
|
806 |
|
$sc = $row['sc']; |
|
807 |
|
|
|
808 |
|
if (!isset($ret['list'][$itime])) |
|
809 |
|
$ret['list'][$itime] = array(); |
|
810 |
|
|
|
811 |
|
$ret['list'][$itime][$sc] = 1; |
576 |
812 |
} |
} |
577 |
813 |
rg_sql_free_result($res); |
rg_sql_free_result($res); |
578 |
814 |
|
|
|
... |
... |
function rg_totp_list_ip($db, $uid) |
581 |
817 |
break; |
break; |
582 |
818 |
} |
} |
583 |
819 |
|
|
|
820 |
|
//rg_log_ml('DEBUG: sc_list ret[list]: ' . print_r($ret['list'], TRUE)); |
|
821 |
|
|
584 |
822 |
rg_log_exit(); |
rg_log_exit(); |
585 |
|
rg_prof_end('totp_list_ip'); |
|
|
823 |
|
rg_prof_end('totp_sc_list'); |
586 |
824 |
return $ret; |
return $ret; |
587 |
825 |
} |
} |
588 |
826 |
|
|
589 |
827 |
/* |
/* |
590 |
|
* Verifies that an IP is in the 'validated' list |
|
591 |
|
* Returns -1 on error, 0 if no IP were present and 1 if all is OK |
|
|
828 |
|
* Generates a list of scratch codes for a user |
592 |
829 |
*/ |
*/ |
593 |
|
function rg_totp_verify_ip($db, $uid, $ip) |
|
|
830 |
|
function rg_totp_sc_generate($db, $uid, $count) |
594 |
831 |
{ |
{ |
595 |
|
rg_prof_start('totp_verify_ip'); |
|
596 |
|
rg_log_enter('totp_verify_ip ip=' . $ip); |
|
|
832 |
|
rg_prof_start('totp_sc_generate'); |
|
833 |
|
rg_log_enter('totp_sc_generate count=' . $count); |
597 |
834 |
|
|
598 |
835 |
$ret = array(); |
$ret = array(); |
599 |
|
$ret['ok'] = -1; |
|
600 |
|
$ret['enrolled'] = 0; |
|
|
836 |
|
$ret['ok'] = 0; |
|
837 |
|
$ret['list'] = array(); |
601 |
838 |
while (1) { |
while (1) { |
602 |
|
// we will return OK if user is not enrolled |
|
603 |
|
$r = rg_totp_list($db, $uid); |
|
604 |
|
if ($r['ok'] != 1) |
|
|
839 |
|
$bin = rg_random_bytes($count * 4); |
|
840 |
|
if ($bin === FALSE) |
605 |
841 |
break; |
break; |
606 |
|
if (empty($r['list'])) { |
|
607 |
|
$ret['ok'] = 1; |
|
|
842 |
|
|
|
843 |
|
for ($i = 0; $i < $count; $i++) { |
|
844 |
|
$t = substr($bin, $i * 4, 4); |
|
845 |
|
$t2 = unpack('L', $t); |
|
846 |
|
$t2 = $t2[1] % 100000000; |
|
847 |
|
$sc = sprintf('%08u', $t2); |
|
848 |
|
$ret['list'][$sc] = 1; |
|
849 |
|
} |
|
850 |
|
|
|
851 |
|
$count -= count($ret['list']); |
|
852 |
|
if ($count != 0) |
|
853 |
|
continue; |
|
854 |
|
|
|
855 |
|
$now = time(); |
|
856 |
|
|
|
857 |
|
$params = array('uid' => $uid, 'itime' => $now); |
|
858 |
|
$sql_add = ''; |
|
859 |
|
$add = ''; |
|
860 |
|
$i = 0; |
|
861 |
|
foreach ($ret['list'] as $sc => $junk) { |
|
862 |
|
$params['token_' . $i] = $sc; |
|
863 |
|
$sql_add .= $add . '(@@uid@@, @@itime@@, @@token_' . $i . '@@)'; |
|
864 |
|
$add = ','; |
|
865 |
|
$i++; |
|
866 |
|
} |
|
867 |
|
|
|
868 |
|
$sql = 'INSERT INTO scratch_codes (uid, itime, sc)' |
|
869 |
|
. ' VALUES ' . $sql_add; |
|
870 |
|
$res = rg_sql_query_params($db, $sql, $params); |
|
871 |
|
if ($res === FALSE) { |
|
872 |
|
rg_totp_set_error('cannot insert scratch codes; try again later'); |
608 |
873 |
break; |
break; |
609 |
874 |
} |
} |
|
875 |
|
rg_sql_free_result($res); |
610 |
876 |
|
|
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 |
|
} |
|
|
877 |
|
rg_totp_cosmetic($params); |
|
878 |
|
$key = 'user' . '::' . $uid . '::' . 'login_tokens' |
|
879 |
|
. '::' . 'sc' . '::' . $now; |
|
880 |
|
rg_cache_set($key, $ret['list'], RG_SOCKET_NO_WAIT); |
|
881 |
|
|
|
882 |
|
$ret['ok'] = 1; |
|
883 |
|
break; |
|
884 |
|
} |
|
885 |
|
|
|
886 |
|
rg_log_exit(); |
|
887 |
|
rg_prof_end('totp_sc_generate'); |
|
888 |
|
return $ret; |
|
889 |
|
} |
|
890 |
|
|
|
891 |
|
/* |
|
892 |
|
* Removes one scratch code |
|
893 |
|
*/ |
|
894 |
|
function rg_totp_sc_remove($db, $uid, $itime, $token) |
|
895 |
|
{ |
|
896 |
|
rg_prof_start('totp_sc_remove'); |
|
897 |
|
rg_log_enter('totp_sc_remove uid=' . $uid |
|
898 |
|
. ' token=' . $token); |
|
899 |
|
|
|
900 |
|
$ret = FALSE; |
|
901 |
|
while (1) { |
|
902 |
|
$params = array('uid' => $uid , |
|
903 |
|
'itime' => $itime, |
|
904 |
|
'token' => $token); |
|
905 |
|
$sql = 'DELETE FROM scratch_codes' |
|
906 |
|
. ' WHERE uid = @@uid@@' |
|
907 |
|
. ' AND itime = @@itime@@' |
|
908 |
|
. ' AND sc = @@token@@'; |
|
909 |
|
$res = rg_sql_query_params($db, $sql, $params); |
|
910 |
|
if ($res === FALSE) { |
|
911 |
|
rg_totp_set_error('cannot remove scratch code'); |
|
912 |
|
break; |
617 |
913 |
} |
} |
|
914 |
|
rg_sql_free_result($res); |
618 |
915 |
|
|
619 |
|
$r = rg_totp_list_ip($db, $uid); |
|
|
916 |
|
$key = 'user' . '::' . $uid . '::' . 'login_tokens' |
|
917 |
|
. '::' . 'sc' . '::' . $itime . '::' . $token; |
|
918 |
|
rg_cache_unset($key, RG_SOCKET_NO_WAIT); |
|
919 |
|
|
|
920 |
|
$ret = TRUE; |
|
921 |
|
break; |
|
922 |
|
} |
|
923 |
|
|
|
924 |
|
rg_log_exit(); |
|
925 |
|
rg_prof_end('totp_sc_remove'); |
|
926 |
|
return $ret; |
|
927 |
|
} |
|
928 |
|
|
|
929 |
|
/* |
|
930 |
|
* Remove a list of scratch codes |
|
931 |
|
*/ |
|
932 |
|
function rg_totp_sc_remove_list($db, $uid, $list) |
|
933 |
|
{ |
|
934 |
|
rg_prof_start('totp_sc_remove_list'); |
|
935 |
|
rg_log_enter('totp_sc_remove_list uid=' . $uid |
|
936 |
|
. ' list=' . rg_array2string($list)); |
|
937 |
|
|
|
938 |
|
$ret = FALSE; |
|
939 |
|
while (1) { |
|
940 |
|
if (empty($list)) { |
|
941 |
|
rg_totp_set_error('you did not select anything'); |
|
942 |
|
break; |
|
943 |
|
} |
|
944 |
|
|
|
945 |
|
$my_list = array(); |
|
946 |
|
foreach ($list as $id => $junk) |
|
947 |
|
$my_list[] = sprintf("%u", $id); |
|
948 |
|
|
|
949 |
|
$params = array('uid' => $uid); |
|
950 |
|
$sql_list = implode(', ', $my_list); |
|
951 |
|
|
|
952 |
|
$sql = 'DELETE FROM scratch_codes' |
|
953 |
|
. ' WHERE uid = @@uid@@' |
|
954 |
|
. ' AND itime IN (' . $sql_list . ')'; |
|
955 |
|
$res = rg_sql_query_params($db, $sql, $params); |
|
956 |
|
if ($res === FALSE) { |
|
957 |
|
rg_totp_set_error('cannot remove scratch codes'); |
|
958 |
|
break; |
|
959 |
|
} |
|
960 |
|
rg_sql_free_result($res); |
|
961 |
|
|
|
962 |
|
foreach ($my_list as $junk => $_itime) { |
|
963 |
|
$key = 'user' . '::' . $uid . '::' . 'login_tokens' |
|
964 |
|
. '::' . 'sc' . '::' . $_itime; |
|
965 |
|
rg_cache_unset($key, RG_SOCKET_NO_WAIT); |
|
966 |
|
} |
|
967 |
|
|
|
968 |
|
$ret = TRUE; |
|
969 |
|
break; |
|
970 |
|
} |
|
971 |
|
|
|
972 |
|
rg_log_exit(); |
|
973 |
|
rg_prof_end('totp_sc_remove_list'); |
|
974 |
|
return $ret; |
|
975 |
|
} |
|
976 |
|
|
|
977 |
|
/* |
|
978 |
|
* Unenroll function - clean everything |
|
979 |
|
*/ |
|
980 |
|
function rg_totp_unenroll($db, $uid) |
|
981 |
|
{ |
|
982 |
|
rg_prof_start('totp_unenroll'); |
|
983 |
|
rg_log_enter('totp_unenroll'); |
|
984 |
|
|
|
985 |
|
$ret = FALSE; |
|
986 |
|
|
|
987 |
|
$rollback = FALSE; |
|
988 |
|
while (1) { |
|
989 |
|
$key = 'user' . '::' . $uid . '::' . 'login_tokens'; |
|
990 |
|
$r = rg_cache_unset($key, 0); |
|
991 |
|
if ($r === FALSE) { |
|
992 |
|
rg_totp_set_error('cannot clear cache'); |
|
993 |
|
break; |
|
994 |
|
} |
|
995 |
|
|
|
996 |
|
$r = rg_sql_begin($db); |
|
997 |
|
if ($r === FALSE) { |
|
998 |
|
rg_totp_set_error('cannot start transaction'); |
|
999 |
|
break; |
|
1000 |
|
} |
|
1001 |
|
$rollback = TRUE; |
|
1002 |
|
|
|
1003 |
|
$r = rg_totp_del_ip($db, $uid, "all"); |
620 |
1004 |
if ($r['ok'] != 1) |
if ($r['ok'] != 1) |
621 |
1005 |
break; |
break; |
622 |
1006 |
|
|
623 |
|
$ret['ok'] = 0; |
|
624 |
|
foreach ($r['list'] as $t) { |
|
625 |
|
if (strcasecmp($t['ip'], $ip) == 0) { |
|
626 |
|
$ret['list'] = $r['list']; |
|
627 |
|
$ret['ok'] = 1; |
|
|
1007 |
|
$ok = TRUE; |
|
1008 |
|
$params = array('uid' => $uid); |
|
1009 |
|
$list = array('login_tokens', 'login_tokens_ip', 'scratch_codes'); |
|
1010 |
|
foreach ($list as $t) { |
|
1011 |
|
$sql = 'DELETE FROM ' . $t |
|
1012 |
|
. ' WHERE uid = @@uid@@'; |
|
1013 |
|
$res = rg_sql_query_params($db, $sql, $params); |
|
1014 |
|
if (!$res) { |
|
1015 |
|
rg_totp_set_error('cannot delete login tokens information'); |
|
1016 |
|
$ok = FALSE; |
628 |
1017 |
break; |
break; |
629 |
1018 |
} |
} |
630 |
1019 |
} |
} |
|
1020 |
|
if (!$ok) |
|
1021 |
|
break; |
631 |
1022 |
|
|
632 |
|
if ($ret['ok'] == 0) |
|
633 |
|
rg_totp_set_error('you have no IP validated;' |
|
634 |
|
. ' run \'ssh ... totp\' for help'); |
|
|
1023 |
|
rg_sql_commit($db); |
|
1024 |
|
$ret = TRUE; |
|
1025 |
|
$rollback = FALSE; |
|
1026 |
|
break; |
|
1027 |
|
} |
|
1028 |
|
|
|
1029 |
|
if ($rollback) |
|
1030 |
|
rg_sql_rollback($db); |
|
1031 |
|
|
|
1032 |
|
rg_log_exit(); |
|
1033 |
|
rg_prof_end('totp_unenroll'); |
|
1034 |
|
return $ret; |
|
1035 |
|
} |
|
1036 |
|
|
|
1037 |
|
/* |
|
1038 |
|
* Verifies either a login token generated by a device or scratch codes |
|
1039 |
|
*/ |
|
1040 |
|
function rg_totp_verify_any($db, $uid, $token) |
|
1041 |
|
{ |
|
1042 |
|
rg_prof_start('totp_verify_any'); |
|
1043 |
|
rg_log_enter('totp_verify_any token=' . $token); |
|
1044 |
|
|
|
1045 |
|
$ret = array(); |
|
1046 |
|
$ret['ok'] = 1; |
|
1047 |
|
$ret['id'] = 0; |
|
1048 |
|
$ret['token_valid'] = 0; |
|
1049 |
|
$ret['enrolled'] = 0; |
|
1050 |
|
while (1) { |
|
1051 |
|
$r = rg_totp_device_verify($db, $uid, $token); |
|
1052 |
|
if ($r['ok'] != 1) { |
|
1053 |
|
$ret['ok'] = 0; |
|
1054 |
|
break; |
|
1055 |
|
} |
|
1056 |
|
|
|
1057 |
|
if ($r['enrolled'] == 1) |
|
1058 |
|
$ret['enrolled'] = 1; |
|
1059 |
|
|
|
1060 |
|
if ($r['reuse'] == 1) |
|
1061 |
|
break; |
|
1062 |
|
|
|
1063 |
|
if ($r['token_valid'] == 1) { |
|
1064 |
|
$ret['token_valid'] = 1; |
|
1065 |
|
$ret['id'] = $r['id']; |
|
1066 |
|
break; |
|
1067 |
|
} |
|
1068 |
|
|
|
1069 |
|
$r = rg_totp_sc_verify($db, $uid, $token); |
|
1070 |
|
if ($r['ok'] != 1) { |
|
1071 |
|
$ret['ok'] = 0; |
|
1072 |
|
break; |
|
1073 |
|
} |
|
1074 |
|
|
|
1075 |
|
if ($r['enrolled'] == 1) |
|
1076 |
|
$ret['enrolled'] = 1; |
|
1077 |
|
|
|
1078 |
|
if ($r['token_valid'] == 1) { |
|
1079 |
|
$ret['token_valid'] = 1; |
|
1080 |
|
break; |
|
1081 |
|
} |
635 |
1082 |
|
|
636 |
1083 |
break; |
break; |
637 |
1084 |
} |
} |
638 |
1085 |
|
|
|
1086 |
|
rg_log_ml("DEBUG: verify_any returns: " . print_r($ret, TRUE)); |
|
1087 |
|
|
639 |
1088 |
rg_log_exit(); |
rg_log_exit(); |
640 |
|
rg_prof_end('totp_verify_ip'); |
|
|
1089 |
|
rg_prof_end('totp_verify_any'); |
|
1090 |
|
return $ret; |
|
1091 |
|
} |
|
1092 |
|
|
|
1093 |
|
/* |
|
1094 |
|
* High-level function for scratch codes |
|
1095 |
|
*/ |
|
1096 |
|
function rg_totp_sc_high_level($db, $rg, $paras) |
|
1097 |
|
{ |
|
1098 |
|
rg_prof_start('totp_sc_high_level'); |
|
1099 |
|
rg_log_enter('totp_sc_high_level'); |
|
1100 |
|
|
|
1101 |
|
$ret = ''; |
|
1102 |
|
|
|
1103 |
|
$rg['HTML:gen_errmsg'] = ''; |
|
1104 |
|
$gen_errmsg = array(); |
|
1105 |
|
$generate = rg_var_uint('generate'); |
|
1106 |
|
while ($generate == 1) { |
|
1107 |
|
if (!rg_valid_referer()) { |
|
1108 |
|
$gen_errmsg[] = 'invalid referer; try again'; |
|
1109 |
|
break; |
|
1110 |
|
} |
|
1111 |
|
|
|
1112 |
|
if (!rg_token_valid($db, $rg, 'sc', FALSE)) { |
|
1113 |
|
$gen_errmsg[] = 'invalid token; try again.'; |
|
1114 |
|
break; |
|
1115 |
|
} |
|
1116 |
|
|
|
1117 |
|
$r = rg_totp_sc_generate($db, $rg['login_ui']['uid'], 20); |
|
1118 |
|
if ($r['ok'] != 1) { |
|
1119 |
|
$gen_errmsg[] = rg_totp_error(); |
|
1120 |
|
break; |
|
1121 |
|
} |
|
1122 |
|
|
|
1123 |
|
$rg['scratch_codes'] = implode(' ', array_keys($r['list'])); |
|
1124 |
|
$ret .= rg_template('user/settings/totp/sc/gen_ok.html', $rg, TRUE /*xss*/); |
|
1125 |
|
break; |
|
1126 |
|
} |
|
1127 |
|
$rg['HTML:gen_errmsg'] = rg_template_errmsg($gen_errmsg); |
|
1128 |
|
|
|
1129 |
|
$rg['HTML:del_errmsg'] = ''; |
|
1130 |
|
$rg['HTML:del_status'] = ''; |
|
1131 |
|
$del_errmsg = array(); |
|
1132 |
|
$delete = rg_var_uint('delete'); |
|
1133 |
|
while ($delete == 1) { |
|
1134 |
|
if (!rg_valid_referer()) { |
|
1135 |
|
$del_errmsg[] = 'invalid referer; try again'; |
|
1136 |
|
break; |
|
1137 |
|
} |
|
1138 |
|
|
|
1139 |
|
if (!rg_token_valid($db, $rg, 'sc', FALSE)) { |
|
1140 |
|
$del_errmsg[] = 'invalid token; try again.'; |
|
1141 |
|
break; |
|
1142 |
|
} |
|
1143 |
|
|
|
1144 |
|
$list = rg_var_str("delete_list"); |
|
1145 |
|
$r = rg_totp_sc_remove_list($db, $rg['login_ui']['uid'], $list); |
|
1146 |
|
if ($r !== TRUE) { |
|
1147 |
|
$del_errmsg[] = 'cannot delete: ' . rg_totp_error(); |
|
1148 |
|
break; |
|
1149 |
|
} |
|
1150 |
|
|
|
1151 |
|
$rg['HTML:del_status'] = rg_template('user/settings/totp/sc/delete_ok.html', |
|
1152 |
|
$rg, TRUE /*xss*/); |
|
1153 |
|
break; |
|
1154 |
|
} |
|
1155 |
|
$rg['HTML:del_errmsg'] = rg_template_errmsg($del_errmsg); |
|
1156 |
|
|
|
1157 |
|
$rg['rg_form_token'] = rg_token_get($db, $rg, 'sc'); |
|
1158 |
|
$ret .= rg_template('user/settings/totp/sc/gen.html', $rg, TRUE /*xss*/); |
|
1159 |
|
|
|
1160 |
|
$r = rg_totp_sc_list($db, $rg['login_ui']['uid']); |
|
1161 |
|
if ($r['ok'] !== 1) { |
|
1162 |
|
$rg['totp_errmsg'] = rg_totp_error(); |
|
1163 |
|
$ret .= rg_template('user/settings/totp/sc/list_err.html', |
|
1164 |
|
$rg, TRUE /*xss*/); |
|
1165 |
|
} else { |
|
1166 |
|
// prepare list |
|
1167 |
|
$_list = array(); |
|
1168 |
|
//rg_log_ml('DEBUG: prepare sc list: ' . print_r($r['list'], TRUE)); |
|
1169 |
|
foreach ($r['list'] as $itime => $per_itime) { |
|
1170 |
|
foreach ($per_itime as $junk => $sc) { |
|
1171 |
|
if (!isset($_list[$itime])) { |
|
1172 |
|
$_list[$itime] = array( |
|
1173 |
|
'itime' => $itime, |
|
1174 |
|
'sc_count' => 1); |
|
1175 |
|
rg_totp_sc_cosmetic($_list[$itime]); |
|
1176 |
|
} else { |
|
1177 |
|
$_list[$itime]['sc_count']++; |
|
1178 |
|
} |
|
1179 |
|
} |
|
1180 |
|
} |
|
1181 |
|
|
|
1182 |
|
$ret .= rg_template_table('user/settings/totp/sc/list', $_list, $rg); |
|
1183 |
|
} |
|
1184 |
|
|
|
1185 |
|
// hints |
|
1186 |
|
$hints = array(); |
|
1187 |
|
$hints[]['HTML:hint'] = rg_template("user/settings/totp/sc/hints.html", $rg, TRUE /*xss*/); |
|
1188 |
|
$ret .= rg_template_table("hints/list", $hints, $rg); |
|
1189 |
|
|
|
1190 |
|
rg_log_exit(); |
|
1191 |
|
rg_prof_end('totp_sc_high_level'); |
641 |
1192 |
return $ret; |
return $ret; |
642 |
1193 |
} |
} |
643 |
1194 |
|
|
644 |
1195 |
/* |
/* |
645 |
1196 |
* High-level function for listing tokens |
* High-level function for listing tokens |
646 |
1197 |
*/ |
*/ |
647 |
|
function rg_totp_list_high_level($db, $rg) |
|
|
1198 |
|
function rg_totp_list_high_level($db, $rg, $paras) |
648 |
1199 |
{ |
{ |
|
1200 |
|
rg_prof_start('totp_list_high_level'); |
|
1201 |
|
rg_log_enter('totp_list_high_level'); |
|
1202 |
|
|
649 |
1203 |
$ret = ''; |
$ret = ''; |
650 |
1204 |
|
|
651 |
1205 |
$del_errmsg = array(); |
$del_errmsg = array(); |
|
... |
... |
function rg_totp_list_high_level($db, $rg) |
676 |
1230 |
break; |
break; |
677 |
1231 |
} |
} |
678 |
1232 |
|
|
679 |
|
$r = rg_totp_list($db, $rg['login_ui']['uid']); |
|
|
1233 |
|
$r = rg_totp_device_list($db, $rg['login_ui']['uid']); |
680 |
1234 |
if ($r['ok'] !== 1) { |
if ($r['ok'] !== 1) { |
681 |
1235 |
$rg['totp_errmsg'] = rg_totp_error(); |
$rg['totp_errmsg'] = rg_totp_error(); |
682 |
1236 |
$ret .= rg_template('user/settings/totp/list_err.html', |
$ret .= rg_template('user/settings/totp/list_err.html', |
|
... |
... |
function rg_totp_list_high_level($db, $rg) |
687 |
1241 |
$ret .= rg_template_table('user/settings/totp/list', $r['list'], $rg); |
$ret .= rg_template_table('user/settings/totp/list', $r['list'], $rg); |
688 |
1242 |
} |
} |
689 |
1243 |
|
|
|
1244 |
|
rg_log_exit(); |
|
1245 |
|
rg_prof_end('totp_list_high_level'); |
690 |
1246 |
return $ret; |
return $ret; |
691 |
1247 |
} |
} |
692 |
1248 |
|
|
693 |
1249 |
/* |
/* |
694 |
|
* Main function for TOTP login token |
|
|
1250 |
|
* Enroll function for TOTP login token |
695 |
1251 |
*/ |
*/ |
696 |
|
function rg_totp_high_level($db, $rg) |
|
|
1252 |
|
function rg_totp_enroll_high_level($db, $rg, $paras) |
697 |
1253 |
{ |
{ |
698 |
|
rg_prof_start('totp_high_level'); |
|
699 |
|
rg_log_enter('totp_high_level'); |
|
|
1254 |
|
rg_prof_start('totp_enroll_high_level'); |
|
1255 |
|
rg_log_enter('totp_enroll_high_level'); |
700 |
1256 |
|
|
701 |
1257 |
$now = time(); |
$now = time(); |
702 |
1258 |
|
|
|
... |
... |
function rg_totp_high_level($db, $rg) |
728 |
1284 |
break; |
break; |
729 |
1285 |
} |
} |
730 |
1286 |
|
|
731 |
|
if (!rg_token_valid($db, $rg, 'user_totp', FALSE)) { |
|
|
1287 |
|
if (!rg_token_valid($db, $rg, 'user_totp_enroll', FALSE)) { |
732 |
1288 |
$errmsg[] = "invalid token; try again"; |
$errmsg[] = "invalid token; try again"; |
733 |
1289 |
break; |
break; |
734 |
1290 |
} |
} |
|
... |
... |
function rg_totp_high_level($db, $rg) |
754 |
1310 |
break; |
break; |
755 |
1311 |
} |
} |
756 |
1312 |
|
|
757 |
|
$ret .= rg_totp_list_high_level($db, $rg); |
|
758 |
|
|
|
759 |
1313 |
// defaults |
// defaults |
760 |
1314 |
if ($enroll == 0) { |
if ($enroll == 0) { |
761 |
1315 |
$name = ''; |
$name = ''; |
|
... |
... |
function rg_totp_high_level($db, $rg) |
777 |
1331 |
|
|
778 |
1332 |
$rg['HTML:errmsg'] = rg_template_errmsg($errmsg); |
$rg['HTML:errmsg'] = rg_template_errmsg($errmsg); |
779 |
1333 |
|
|
780 |
|
$rg['rg_form_token'] = rg_token_get($db, $rg, 'user_totp'); |
|
781 |
|
$ret .= rg_template('user/settings/totp/main.html', $rg, TRUE /*xss*/); |
|
|
1334 |
|
$rg['rg_form_token'] = rg_token_get($db, $rg, 'user_totp_enroll'); |
|
1335 |
|
rg_log_ml('DEBUG rg: ' . print_r($rg, TRUE)); |
|
1336 |
|
$ret .= rg_template('user/settings/totp/enroll.html', $rg, TRUE /*xss*/); |
782 |
1337 |
|
|
783 |
|
// hints |
|
784 |
|
$hints = array(); |
|
785 |
|
$hints[]['HTML:hint'] = rg_template("user/settings/totp/hints.html", $rg, FALSE /*xss*/); |
|
786 |
|
$ret .= rg_template_table("hints/list", $hints, $rg); |
|
|
1338 |
|
rg_log_exit(); |
|
1339 |
|
rg_prof_end('totp_enroll_high_level'); |
|
1340 |
|
return $ret; |
|
1341 |
|
} |
|
1342 |
|
|
|
1343 |
|
/* |
|
1344 |
|
* Main HL function for TOTP login token |
|
1345 |
|
*/ |
|
1346 |
|
function rg_totp_high_level($db, $rg, $paras) |
|
1347 |
|
{ |
|
1348 |
|
rg_prof_start('totp_high_level'); |
|
1349 |
|
rg_log_enter('totp_high_level'); |
|
1350 |
|
|
|
1351 |
|
$now = time(); |
|
1352 |
|
|
|
1353 |
|
$ret = ''; |
|
1354 |
|
|
|
1355 |
|
$op = empty($paras) ? 'info' : array_shift($paras); |
|
1356 |
|
$rg['menu']['totp'][$op] = 1; |
|
1357 |
|
|
|
1358 |
|
$ret .= rg_template('user/settings/totp/menu.html', $rg, TRUE /*xss*/); |
|
1359 |
|
|
|
1360 |
|
switch ($op) { |
|
1361 |
|
case 'info': // we show only the hints |
|
1362 |
|
// hints |
|
1363 |
|
$hints = array(); |
|
1364 |
|
$hints[]['HTML:hint'] = rg_template("user/settings/totp/hints.html", $rg, TRUE /*xss*/); |
|
1365 |
|
$ret .= rg_template_table("hints/list", $hints, $rg); |
|
1366 |
|
break; |
|
1367 |
|
|
|
1368 |
|
case 'enroll': |
|
1369 |
|
$ret .= rg_totp_enroll_high_level($db, $rg, $paras); |
|
1370 |
|
break; |
|
1371 |
|
|
|
1372 |
|
case 'sc': |
|
1373 |
|
$ret .= rg_totp_sc_high_level($db, $rg, $paras); |
|
1374 |
|
break; |
|
1375 |
|
|
|
1376 |
|
default: |
|
1377 |
|
$ret .= rg_totp_list_high_level($db, $rg, $paras); |
|
1378 |
|
break; |
|
1379 |
|
} |
787 |
1380 |
|
|
788 |
1381 |
rg_log_exit(); |
rg_log_exit(); |
789 |
1382 |
rg_prof_end('totp_high_level'); |
rg_prof_end('totp_high_level'); |
File scripts/cache.php changed (mode: 100644) (index 7865345..a07bcab) |
... |
... |
require_once($INC . "/ver.php"); |
31 |
31 |
|
|
32 |
32 |
function rg_destroy($k, &$conn_table) |
function rg_destroy($k, &$conn_table) |
33 |
33 |
{ |
{ |
|
34 |
|
rg_log("Destroying key $k..."); |
34 |
35 |
if (isset($conn_table['r'][$k])) |
if (isset($conn_table['r'][$k])) |
35 |
36 |
unset($conn_table['r'][$k]); |
unset($conn_table['r'][$k]); |
36 |
37 |
if (isset($conn_table['w'][$k])) |
if (isset($conn_table['w'][$k])) |
37 |
38 |
unset($conn_table['w'][$k]); |
unset($conn_table['w'][$k]); |
38 |
39 |
// TODO: seems socket is already closed |
// TODO: seems socket is already closed |
39 |
|
if (is_resource($conn_table['conns'][$k]['socket'])) |
|
40 |
|
socket_close($conn_table['conns'][$k]['socket']); |
|
|
40 |
|
if (isset($conn_table['conns'][$k]['socket'])) |
|
41 |
|
if (is_resource($conn_table['conns'][$k]['socket'])) |
|
42 |
|
socket_close($conn_table['conns'][$k]['socket']); |
41 |
43 |
unset($conn_table['conns'][$k]); |
unset($conn_table['conns'][$k]); |
42 |
44 |
} |
} |
43 |
45 |
|
|
44 |
46 |
function rg_handle_command($k, &$conn_table, $cmd) |
function rg_handle_command($k, &$conn_table, $cmd) |
45 |
47 |
{ |
{ |
46 |
|
rg_log("rg_handle_command: k=$k, cmd=$cmd"); |
|
|
48 |
|
//rg_log("rg_handle_command: k=$k, cmd=$cmd"); |
47 |
49 |
|
|
48 |
50 |
$s = &$conn_table['conns'][$k]; |
$s = &$conn_table['conns'][$k]; |
49 |
51 |
|
|
|
... |
... |
function rg_handle_command($k, &$conn_table, $cmd) |
206 |
208 |
|
|
207 |
209 |
function rg_handle_recv($k, &$conn_table) |
function rg_handle_recv($k, &$conn_table) |
208 |
210 |
{ |
{ |
|
211 |
|
//rg_log("handle_recv on key $k..."); |
209 |
212 |
$s = &$conn_table['conns'][$k]; |
$s = &$conn_table['conns'][$k]; |
210 |
213 |
|
|
211 |
214 |
$ret = @socket_recv($s['socket'], $buf, 32 * 4096, 0); |
$ret = @socket_recv($s['socket'], $buf, 32 * 4096, 0); |
|
... |
... |
function rg_handle_recv($k, &$conn_table) |
215 |
218 |
return; |
return; |
216 |
219 |
} |
} |
217 |
220 |
if ($ret === 0) { |
if ($ret === 0) { |
218 |
|
//rg_log("Remote closed the connection."); |
|
|
221 |
|
rg_log("Remote closed the connection (received 0)."); |
219 |
222 |
rg_destroy($k, $conn_table); |
rg_destroy($k, $conn_table); |
220 |
223 |
return; |
return; |
221 |
224 |
} |
} |
|
... |
... |
function rg_handle_recv($k, &$conn_table) |
223 |
226 |
rg_log("Received data on key $k [$buf]..."); |
rg_log("Received data on key $k [$buf]..."); |
224 |
227 |
|
|
225 |
228 |
$s['recv'] .= $buf; |
$s['recv'] .= $buf; |
226 |
|
$s['close_at'] = time() + 300; |
|
|
229 |
|
$s['close_at'] = time() + 30; |
227 |
230 |
|
|
228 |
231 |
while (1) { |
while (1) { |
229 |
232 |
$pos = strpos($s['recv'], "\n"); |
$pos = strpos($s['recv'], "\n"); |
|
... |
... |
function rg_handle_recv($k, &$conn_table) |
231 |
234 |
return; |
return; |
232 |
235 |
|
|
233 |
236 |
$cmd = substr($s['recv'], 0, $pos); |
$cmd = substr($s['recv'], 0, $pos); |
234 |
|
$s['recv'] = substr($s['recv'], $pos + 1); |
|
235 |
|
|
|
236 |
237 |
rg_handle_command($k, $conn_table, $cmd); |
rg_handle_command($k, $conn_table, $cmd); |
237 |
|
}; |
|
|
238 |
|
|
|
239 |
|
$s['recv'] = substr($s['recv'], $pos + 1); |
|
240 |
|
} |
238 |
241 |
} |
} |
239 |
242 |
|
|
240 |
243 |
function rg_handle_send($k, &$conn_table) |
function rg_handle_send($k, &$conn_table) |
241 |
244 |
{ |
{ |
|
245 |
|
//rg_log("Sending on key $k..."); |
242 |
246 |
$s = &$conn_table['conns'][$k]; |
$s = &$conn_table['conns'][$k]; |
243 |
247 |
|
|
244 |
|
rg_log("Sending on key $k [" . $s['send'] . "]..."); |
|
245 |
248 |
$ret = @socket_send($s['socket'], $s['send'], strlen($s['send']), 0); |
$ret = @socket_send($s['socket'], $s['send'], strlen($s['send']), 0); |
246 |
249 |
if ($ret === FALSE) { |
if ($ret === FALSE) { |
247 |
250 |
rg_log("Cannot send (" . socket_strerror(socket_last_error()) . ")"); |
rg_log("Cannot send (" . socket_strerror(socket_last_error()) . ")"); |
|
... |
... |
function rg_handle_new($client, &$conn_table) |
263 |
266 |
"socket" => $client, |
"socket" => $client, |
264 |
267 |
"recv" => "", |
"recv" => "", |
265 |
268 |
"send" => "", |
"send" => "", |
266 |
|
"close_at" => time() + 300 |
|
|
269 |
|
"close_at" => time() + 30 |
267 |
270 |
); |
); |
268 |
271 |
$conn_table['r'][$key] = $client; |
$conn_table['r'][$key] = $client; |
269 |
|
rg_log("Added client with key $key."); |
|
|
272 |
|
//rg_log("Added client with key $key."); |
|
273 |
|
|
|
274 |
|
/* This way I can enforce the connecting user to be apache/rocketgit |
|
275 |
|
but is seems it does not work correctly in PHP... |
|
276 |
|
$t = socket_get_option($client, SOL_SOCKET, 17 //SO_PEERCRED); |
|
277 |
|
rg_log_ml('PEERCRED: ' . print_r($t, TRUE)); |
|
278 |
|
*/ |
270 |
279 |
} |
} |
271 |
280 |
|
|
272 |
281 |
function rg_handle_idle(&$conn_table) |
function rg_handle_idle(&$conn_table) |
|
... |
... |
function rg_handle_idle(&$conn_table) |
274 |
283 |
$now = time(); |
$now = time(); |
275 |
284 |
|
|
276 |
285 |
foreach ($conn_table['conns'] as $key => $info) { |
foreach ($conn_table['conns'] as $key => $info) { |
277 |
|
if (strcmp($key, "master") == 0) |
|
|
286 |
|
if (!isset($info['close_at'])) { |
|
287 |
|
rg_internal_error('close_at is not set!'); |
278 |
288 |
continue; |
continue; |
279 |
|
|
|
|
289 |
|
} |
280 |
290 |
if ($info['close_at'] < $now) { |
if ($info['close_at'] < $now) { |
281 |
291 |
rg_log("Destroy $key because was too much time idle."); |
rg_log("Destroy $key because was too much time idle."); |
282 |
292 |
rg_destroy($key, $conn_table); |
rg_destroy($key, $conn_table); |
|
... |
... |
$conn_table['r']['master'] = $master; |
329 |
339 |
do { |
do { |
330 |
340 |
rg_log_buffer_clear(); |
rg_log_buffer_clear(); |
331 |
341 |
|
|
|
342 |
|
rg_log_ml("conn_table: " . print_r($conn_table, TRUE)); |
|
343 |
|
|
332 |
344 |
$r2 = $conn_table['r']; $w2 = $conn_table['w']; $ex = array(); |
$r2 = $conn_table['r']; $w2 = $conn_table['w']; $ex = array(); |
333 |
|
$r = socket_select($r2, $w2, $ex, 5); |
|
|
345 |
|
$r = @socket_select($r2, $w2, $ex, 5); |
334 |
346 |
if ($r === FALSE) |
if ($r === FALSE) |
335 |
347 |
rg_fatal("Cannot select (" . socket_strerror(socket_last_error()) . ")!"); |
rg_fatal("Cannot select (" . socket_strerror(socket_last_error()) . ")!"); |
336 |
|
|
|
337 |
|
//rg_log_ml("conn_table: " . print_r($conn_table, TRUE)); |
|
338 |
|
|
|
339 |
|
foreach ($r2 as $key => $socket) { |
|
340 |
|
if (strcmp($key, "master") == 0) { |
|
341 |
|
$client = socket_accept($socket); |
|
342 |
|
if ($client === FALSE) { |
|
343 |
|
rg_log("Connection seems broken!"); |
|
|
348 |
|
if ($r > 0) { |
|
349 |
|
if (!empty($r2)) |
|
350 |
|
rg_log_ml('r2: ' . print_r($r2, TRUE)); |
|
351 |
|
if (!empty($w2)) |
|
352 |
|
rg_log_ml('w2: ' . print_r($w2, TRUE)); |
|
353 |
|
if (!empty($ex)) |
|
354 |
|
rg_log_ml('ex: ' . print_r($ex, TRUE)); |
|
355 |
|
|
|
356 |
|
foreach ($r2 as $key => $socket) { |
|
357 |
|
if (strcmp($key, "master") == 0) { |
|
358 |
|
$client = @socket_accept($socket); |
|
359 |
|
if ($client === FALSE) { |
|
360 |
|
rg_log("Connection seems broken!"); |
|
361 |
|
continue; |
|
362 |
|
} |
|
363 |
|
|
|
364 |
|
rg_handle_new($client, $conn_table); |
344 |
365 |
continue; |
continue; |
345 |
366 |
} |
} |
346 |
367 |
|
|
347 |
|
rg_handle_new($client, $conn_table); |
|
348 |
|
continue; |
|
|
368 |
|
rg_handle_recv($key, $conn_table); |
349 |
369 |
} |
} |
350 |
370 |
|
|
351 |
|
rg_handle_recv($key, $conn_table); |
|
352 |
|
} |
|
|
371 |
|
foreach ($w2 as $key => $sock) { |
|
372 |
|
if (isset($conn_table['conns'][$key])) |
|
373 |
|
rg_handle_send($key, $conn_table); |
|
374 |
|
} |
353 |
375 |
|
|
354 |
|
foreach ($w2 as $key => $sock) |
|
355 |
|
rg_handle_send($key, $conn_table); |
|
|
376 |
|
foreach ($ex as $key => $sock) |
|
377 |
|
rg_destroy($key, $conn_table); |
|
378 |
|
} |
356 |
379 |
|
|
357 |
380 |
rg_handle_idle($conn_table); |
rg_handle_idle($conn_table); |
358 |
381 |
} while (1); |
} while (1); |
File tests/http_totp.php changed (mode: 100644) (index 9ca337f..fca104e) |
... |
... |
require_once("common.php"); |
21 |
21 |
|
|
22 |
22 |
$_testns = 'http_totp'; |
$_testns = 'http_totp'; |
23 |
23 |
$rg_cache_enable = TRUE; |
$rg_cache_enable = TRUE; |
|
24 |
|
$rg_cache_debug = TRUE; |
24 |
25 |
|
|
25 |
26 |
$rg_user_max_len = 60; |
$rg_user_max_len = 60; |
26 |
27 |
|
|
|
... |
... |
rg_test_create_user($db, $rg_ui); |
29 |
30 |
// Add an totp token to this account |
// Add an totp token to this account |
30 |
31 |
$key = 'ACHCBCCVQ7AK4RGM'; |
$key = 'ACHCBCCVQ7AK4RGM'; |
31 |
32 |
|
|
32 |
|
$r = rg_totp_enroll($db, $rg_ui['uid'], 'test', $key, '127.0.0.1', TRUE); |
|
|
33 |
|
$r = rg_totp_enroll($db, $rg_ui['uid'], 'test', $key, '127.0.0.1', 't'); |
33 |
34 |
if ($r !== TRUE) { |
if ($r !== TRUE) { |
34 |
35 |
rg_log('cannot enroll!'); |
rg_log('cannot enroll!'); |
35 |
36 |
exit(1); |
exit(1); |
|
... |
... |
$lt = rg_totp_compute($key, time() / 30, 6); |
40 |
41 |
|
|
41 |
42 |
// First we need to load the form so we can get the token |
// First we need to load the form so we can get the token |
42 |
43 |
// We provide an old cookie to test if we generate a new pre-login one |
// We provide an old cookie to test if we generate a new pre-login one |
|
44 |
|
rg_log(''); |
|
45 |
|
rg_log_enter('Loading login form...'); |
43 |
46 |
$r = do_req($test_url . "/op/login", $data, $headers); |
$r = do_req($test_url . "/op/login", $data, $headers); |
44 |
47 |
if ($r === FALSE) { |
if ($r === FALSE) { |
45 |
48 |
rg_log("Cannot load login form."); |
rg_log("Cannot load login form."); |
|
... |
... |
if ($r === FALSE) { |
47 |
50 |
} |
} |
48 |
51 |
$good_sid = $r['sid']; |
$good_sid = $r['sid']; |
49 |
52 |
$good_token = $r['tokens']['login']; |
$good_token = $r['tokens']['login']; |
|
53 |
|
rg_log_exit(); |
50 |
54 |
|
|
51 |
55 |
|
|
52 |
|
rg_log("Do the login (sid=$good_sid token=$good_token" |
|
|
56 |
|
rg_log(''); |
|
57 |
|
rg_log_enter("Do the login without login token (sid=$good_sid token=$good_token)..."); |
|
58 |
|
$data = array( |
|
59 |
|
"doit" => 1, |
|
60 |
|
"token" => $good_token, |
|
61 |
|
"user" => $rg_ui['username'], |
|
62 |
|
"pass" => $rg_ui['pass'], |
|
63 |
|
"login_token" => '', |
|
64 |
|
"lock_ip" => 0); |
|
65 |
|
$headers = array("Cookie: sid=" . $good_sid); |
|
66 |
|
$r = do_req($test_url . "/op/login", $data, $headers); |
|
67 |
|
if ($r === FALSE) { |
|
68 |
|
rg_log_ml('r=' . print_r($r, TRUE)); |
|
69 |
|
rg_log("Cannot login!"); |
|
70 |
|
exit(1); |
|
71 |
|
} |
|
72 |
|
if (!strstr($r['body'], "invalid user")) { |
|
73 |
|
rg_log_ml('r=' . print_r($r, TRUE)); |
|
74 |
|
rg_log("Seems we can login without token!"); |
|
75 |
|
exit(1); |
|
76 |
|
} |
|
77 |
|
$good_token = $r['tokens']['login']; |
|
78 |
|
rg_log_exit(); |
|
79 |
|
|
|
80 |
|
|
|
81 |
|
rg_log(''); |
|
82 |
|
rg_log_enter("Do the login (sid=$good_sid token=$good_token" |
53 |
83 |
. " login_token=$lt)..."); |
. " login_token=$lt)..."); |
54 |
84 |
$data = array( |
$data = array( |
55 |
85 |
"doit" => 1, |
"doit" => 1, |
|
... |
... |
$data = array( |
61 |
91 |
$headers = array("Cookie: sid=" . $good_sid); |
$headers = array("Cookie: sid=" . $good_sid); |
62 |
92 |
$r = do_req($test_url . "/op/login", $data, $headers); |
$r = do_req($test_url . "/op/login", $data, $headers); |
63 |
93 |
if ($r === FALSE) { |
if ($r === FALSE) { |
64 |
|
rg_log_ml("Cannot login: " . print_r($r, TRUE)); |
|
|
94 |
|
rg_log_ml('r=' . print_r($r, TRUE)); |
|
95 |
|
rg_log("Cannot login!"); |
65 |
96 |
exit(1); |
exit(1); |
66 |
97 |
} |
} |
67 |
98 |
if (strstr($r['body'], "invalid user")) { |
if (strstr($r['body'], "invalid user")) { |
68 |
|
rg_log_ml("Login invalid. r=" . print_r($r, TRUE)); |
|
|
99 |
|
rg_log_ml('r=' . print_r($r, TRUE)); |
|
100 |
|
rg_log("Login invalid!"); |
69 |
101 |
exit(1); |
exit(1); |
70 |
102 |
} |
} |
|
103 |
|
$good_sid = $r['sid']; |
|
104 |
|
rg_log_exit(); |
|
105 |
|
|
|
106 |
|
|
|
107 |
|
rg_log(''); |
|
108 |
|
rg_log_enter('Testing device enrollment...'); |
|
109 |
|
rg_log('Loading enroll form...'); |
|
110 |
|
$data = array(); |
|
111 |
|
$headers = array("Cookie: sid=" . $good_sid); |
|
112 |
|
$r = do_req($test_url . "/op/settings/totp/enroll", $data, $headers); |
|
113 |
|
if ($r === FALSE) { |
|
114 |
|
rg_log("Cannot load enroll page!"); |
|
115 |
|
exit(1); |
|
116 |
|
} |
|
117 |
|
$good_token = $r['tokens']['user_totp_enroll']; |
|
118 |
|
$key = $r['totp_secret']; |
|
119 |
|
if ($key === FALSE) { |
|
120 |
|
rg_log_ml('r: ' . print_r($r, TRUE)); |
|
121 |
|
rg_log("Cannot find totp::secret!"); |
|
122 |
|
exit(1); |
|
123 |
|
} |
|
124 |
|
rg_log('Posting the enroll form...'); |
|
125 |
|
$data = array( |
|
126 |
|
'enroll' => 1, |
|
127 |
|
'token' => $good_token, |
|
128 |
|
'totp::name' => 'test', |
|
129 |
|
'totp::secret' => $key, |
|
130 |
|
'totp::ver' => rg_totp_compute($key, time() / 30, 6) |
|
131 |
|
); |
|
132 |
|
$headers = array("Cookie: sid=" . $good_sid); |
|
133 |
|
$r = do_req($test_url . "/op/settings/totp/enroll", $data, $headers); |
|
134 |
|
if (!strstr($r['body'], 'You enrolled your new device with success')) { |
|
135 |
|
rg_log_ml('r: ' . print_r($r, TRUE)); |
|
136 |
|
rg_log("Cannot enroll!"); |
|
137 |
|
exit(1); |
|
138 |
|
} |
|
139 |
|
$sql = "SELECT 1 FROM login_tokens WHERE secret = '" . $key . "'"; |
|
140 |
|
$res = rg_sql_query($db, $sql); |
|
141 |
|
$rows = rg_sql_num_rows($res); |
|
142 |
|
rg_sql_free_result($res); |
|
143 |
|
if ($rows != 1) { |
|
144 |
|
rg_log("Seems the secret is not in the database!"); |
|
145 |
|
exit(1); |
|
146 |
|
} |
|
147 |
|
rg_log_exit(); |
|
148 |
|
|
|
149 |
|
|
|
150 |
|
rg_log(''); |
|
151 |
|
rg_log_enter('Testing the deletion of scratch codes'); |
|
152 |
|
$sc1 = rg_test_sc_generate($db, $rg_ui, $good_sid); |
|
153 |
|
sleep(1); // to not have the same itime |
|
154 |
|
$sc2 = rg_test_sc_generate($db, $rg_ui, $good_sid); |
|
155 |
|
$sql = "SELECT DISTINCT itime FROM scratch_codes WHERE uid = " . $rg_ui['uid']; |
|
156 |
|
$res = rg_sql_query($db, $sql); |
|
157 |
|
$list = array(); |
|
158 |
|
while (($row = rg_sql_fetch_array($res))) { |
|
159 |
|
$list[] = $row['itime']; |
|
160 |
|
} |
|
161 |
|
rg_sql_free_result($res); |
|
162 |
|
rg_log_ml('list=' . print_r($list, TRUE)); |
|
163 |
|
|
|
164 |
|
$headers = array("Cookie: sid=" . $good_sid); |
|
165 |
|
$r = do_req($test_url . "/op/settings/totp/sc", $data, $headers); |
|
166 |
|
if ($r === FALSE) { |
|
167 |
|
rg_log("Cannot load sc page!"); |
|
168 |
|
exit(1); |
|
169 |
|
} |
|
170 |
|
$good_token = $r['tokens']['sc']; |
|
171 |
|
|
|
172 |
|
$data = array( |
|
173 |
|
'delete' => 1, |
|
174 |
|
'token' => $good_token, |
|
175 |
|
'delete_list[' . $list[0] . ']' => 'on', |
|
176 |
|
'delete_list[' . $list[1] . ']' => 'on' |
|
177 |
|
); |
|
178 |
|
$headers = array("Cookie: sid=" . $good_sid); |
|
179 |
|
$r = do_req($test_url . "/op/settings/totp/sc", $data, $headers); |
|
180 |
|
if (!strstr($r['body'], 'deleted with success')) { |
|
181 |
|
rg_log("Cannot delete scratch codes!"); |
|
182 |
|
exit(1); |
|
183 |
|
} |
|
184 |
|
$sql = "SELECT DISTINCT itime FROM scratch_codes WHERE uid = " . $rg_ui['uid']; |
|
185 |
|
$res = rg_sql_query($db, $sql); |
|
186 |
|
$rows = rg_sql_num_rows($res); |
|
187 |
|
rg_sql_free_result($res); |
|
188 |
|
if ($rows != 0) { |
|
189 |
|
rg_log("Cannot delete scratch codes - sql still returns data!"); |
|
190 |
|
exit(1); |
|
191 |
|
} |
|
192 |
|
$key = 'user::' . $rg_ui['uid'] . '::login_tokens::sc'; |
|
193 |
|
rg_cache_core_unset($key); // else we will get data from local mem! |
|
194 |
|
$r = rg_cache_get($key); |
|
195 |
|
if (count($r) != 0) { |
|
196 |
|
rg_log_ml('cache: ' . print_r($r, TRUE)); |
|
197 |
|
rg_log('Deleted scratch codes are still in cache!'); |
|
198 |
|
exit(1); |
|
199 |
|
} |
|
200 |
|
rg_log_exit(); |
|
201 |
|
|
|
202 |
|
|
|
203 |
|
rg_log(''); |
|
204 |
|
rg_log_enter('Testing the deletion of a device'); |
|
205 |
|
$key = 'ACHCBCCVQ7AK4RGM'; |
|
206 |
|
$r = rg_totp_enroll($db, $rg_ui['uid'], 'test1', $key, 'A', 't'); |
|
207 |
|
if ($r !== TRUE) { |
|
208 |
|
rg_log('cannot enroll!'); |
|
209 |
|
exit(1); |
|
210 |
|
} |
|
211 |
|
$key = 'ACHCBCCVQ7AK4RGX'; |
|
212 |
|
$r = rg_totp_enroll($db, $rg_ui['uid'], 'test2', $key, 'A', 't'); |
|
213 |
|
if ($r !== TRUE) { |
|
214 |
|
rg_log('cannot enroll!'); |
|
215 |
|
exit(1); |
|
216 |
|
} |
|
217 |
|
rg_log('Getting ids from database...'); |
|
218 |
|
$sql = "SELECT id FROM login_tokens WHERE uid = " . $rg_ui['uid']; |
|
219 |
|
$res = rg_sql_query($db, $sql); |
|
220 |
|
$list = array(); |
|
221 |
|
while (($row = rg_sql_fetch_array($res))) { |
|
222 |
|
$list[] = $row['id']; |
|
223 |
|
} |
|
224 |
|
rg_sql_free_result($res); |
|
225 |
|
if (count($list) < 2) { |
|
226 |
|
rg_log_ml('list: ' . print_r($list, TRUE)); |
|
227 |
|
rg_log('I cannot find the enrollments in database!'); |
|
228 |
|
exit(1); |
|
229 |
|
} |
|
230 |
|
rg_log('Loading list devices form...'); |
|
231 |
|
$data = array(); |
|
232 |
|
$r = do_req($test_url . "/op/settings/totp/list", $data, $headers); |
|
233 |
|
if ($r === FALSE) { |
|
234 |
|
rg_log("Cannot load list devices form."); |
|
235 |
|
exit(1); |
|
236 |
|
} |
|
237 |
|
$good_token = $r['tokens']['login_tokens_list']; |
|
238 |
|
$data = array( 'delete' => 1, 'token' => $good_token); |
|
239 |
|
foreach ($list as $id) |
|
240 |
|
$data['delete_list[' . $id . ']'] = 'on'; |
|
241 |
|
$headers = array("Cookie: sid=" . $good_sid); |
|
242 |
|
$r = do_req($test_url . "/op/settings/totp/list", $data, $headers); |
|
243 |
|
if (!strstr($r['body'], 'deleted with success')) { |
|
244 |
|
rg_log("Cannot delete login tokens!"); |
|
245 |
|
exit(1); |
|
246 |
|
} |
|
247 |
|
$sql = "SELECT DISTINCT id FROM login_tokens WHERE uid = " . $rg_ui['uid']; |
|
248 |
|
$res = rg_sql_query($db, $sql); |
|
249 |
|
$rows = rg_sql_num_rows($res); |
|
250 |
|
rg_sql_free_result($res); |
|
251 |
|
if ($rows != 0) { |
|
252 |
|
rg_log("Cannot delete device codes - sql still returns data!"); |
|
253 |
|
exit(1); |
|
254 |
|
} |
|
255 |
|
$key = 'user::' . $rg_ui['uid'] . '::login_tokens::device'; |
|
256 |
|
rg_cache_core_unset($key); // else we will get data from local mem! |
|
257 |
|
$r = rg_cache_get($key); |
|
258 |
|
if (count($r) != 0) { |
|
259 |
|
rg_log_ml($key . ': ' . print_r($r, TRUE)); |
|
260 |
|
rg_log('Deleted device codes are still in cache!'); |
|
261 |
|
exit(1); |
|
262 |
|
} |
|
263 |
|
rg_log_exit(); |
|
264 |
|
|
71 |
265 |
|
|
72 |
266 |
rg_prof_log(); |
rg_prof_log(); |
73 |
267 |
rg_log("OK!"); |
rg_log("OK!"); |
File tests/ssh.php added (mode: 100644) (index 0000000..c3fe87e) |
|
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("ssh.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 |
|
|
|
22 |
|
// This test makes sense only on my devel machine |
|
23 |
|
if (php_uname("n") != "r1.embedromix.ro") { |
|
24 |
|
rg_log("OK!"); |
|
25 |
|
exit(0); |
|
26 |
|
} |
|
27 |
|
|
|
28 |
|
|
|
29 |
|
rg_log("Creating a user..."); |
|
30 |
|
rg_test_create_user($db, $rg_ui); |
|
31 |
|
rg_test_create_repo($db, $rg_ui, $repo); |
|
32 |
|
$r = test_login($test_url, $rg_ui, $good_sid); |
|
33 |
|
if ($r === FALSE) { |
|
34 |
|
rg_log("Cannot login!"); |
|
35 |
|
exit(1); |
|
36 |
|
} |
|
37 |
|
|
|
38 |
|
$cmd = "ssh -i keys/" . $rg_ui['uid'] . " rocketgit@r1i"; |
|
39 |
|
|
|
40 |
|
$key = rg_test_upload_ssh_key($db, $rg_ui, $rg_ui['uid'], $good_sid); |
|
41 |
|
|
|
42 |
|
rg_log(''); |
|
43 |
|
$list = array('', 'status', 'repos', 'repo', 'totp'); |
|
44 |
|
foreach ($list as $s) { |
|
45 |
|
rg_log('Connecting for [' . $s . ']'); |
|
46 |
|
$r = shell_exec($cmd . ' ' . $s . ' 2>&1'); |
|
47 |
|
if (!strstr($r, "Welcome to RocketGit")) { |
|
48 |
|
rg_log('r=' . $r); |
|
49 |
|
rg_log("Trying to get the help detected missing welcome!"); |
|
50 |
|
exit(1); |
|
51 |
|
} |
|
52 |
|
if (strstr($r, 'Error: .')) { |
|
53 |
|
rg_log('r=' . $r); |
|
54 |
|
rg_log('Error is empty for \'' . $s . '\'! Not good!'); |
|
55 |
|
exit(1); |
|
56 |
|
} |
|
57 |
|
} |
|
58 |
|
|
|
59 |
|
$list = array('remove-device', 'unenroll'); |
|
60 |
|
foreach ($list as $s) { |
|
61 |
|
rg_log('Connecting for [totp ' . $s . ']'); |
|
62 |
|
$r = shell_exec($cmd . ' totp ' . $s . ' 2>&1'); |
|
63 |
|
if (strstr($r, 'Error: .')) { |
|
64 |
|
rg_log('r=' . $r); |
|
65 |
|
rg_log('Error is empty for \'' . $s . '\'! Not good!'); |
|
66 |
|
exit(1); |
|
67 |
|
} |
|
68 |
|
} |
|
69 |
|
|
|
70 |
|
|
|
71 |
|
rg_log(''); |
|
72 |
|
rg_log_enter('Testing wrong command'); |
|
73 |
|
$r = shell_exec($cmd . ' wrongcmd ' . ' 2>&1'); |
|
74 |
|
if (!strstr($r, "nknown command")) { |
|
75 |
|
rg_log('r=' . $r); |
|
76 |
|
rg_log("Wrong answer for a wrong command!"); |
|
77 |
|
exit(1); |
|
78 |
|
} |
|
79 |
|
rg_log_exit(); |
|
80 |
|
|
|
81 |
|
|
|
82 |
|
rg_log(''); |
|
83 |
|
rg_log('Testing enroll procedure'); |
|
84 |
|
$r = shell_exec($cmd . ' totp enroll'); |
|
85 |
|
$t = explode('enter the following code: ', $r); |
|
86 |
|
$t = explode('.', $t[1]); |
|
87 |
|
$key = trim($t[0]); |
|
88 |
|
rg_log("key=$key"); |
|
89 |
|
|
|
90 |
|
$tc = intval(time() / 30) - 1; // we try one in the past |
|
91 |
|
$token = rg_totp_compute($key, $tc, 6); |
|
92 |
|
$r = shell_exec($cmd . ' totp enroll ' . $token); |
|
93 |
|
if (!strstr($r, 'Success!')) { |
|
94 |
|
rg_log('r=' . $r); |
|
95 |
|
rg_log('Cannot enroll!'); |
|
96 |
|
exit(1); |
|
97 |
|
} |
|
98 |
|
|
|
99 |
|
|
|
100 |
|
rg_log(''); |
|
101 |
|
rg_log('Testing \'val\' command'); |
|
102 |
|
$tc = intval(time() / 30); |
|
103 |
|
$token = rg_totp_compute($key, $tc, 6); |
|
104 |
|
$r = shell_exec($cmd . ' totp val ' . $token . ' 2m'); |
|
105 |
|
if (!strstr($r, 'Success!')) { |
|
106 |
|
rg_log('r=' . $r); |
|
107 |
|
rg_log('Cannot validate ip!'); |
|
108 |
|
exit(1); |
|
109 |
|
} |
|
110 |
|
$t = explode('valid till ', $r); |
|
111 |
|
$t = explode(' (', $t[1]); |
|
112 |
|
$exp = trim($t[0]); |
|
113 |
|
rg_log('exp=' . $exp); |
|
114 |
|
|
|
115 |
|
rg_log(''); |
|
116 |
|
rg_log('Reuse of the token must be forbidden (device)'); |
|
117 |
|
$r = shell_exec($cmd . ' totp val ' . $token . ' 2m'); |
|
118 |
|
if (!strstr($r, 'cannot reuse')) { |
|
119 |
|
rg_log('r=' . $r); |
|
120 |
|
rg_log('we get no error on token reuse!'); |
|
121 |
|
exit(1); |
|
122 |
|
} |
|
123 |
|
|
|
124 |
|
|
|
125 |
|
rg_log(''); |
|
126 |
|
rg_log('Testing \'list-val\' command'); |
|
127 |
|
$r = shell_exec($cmd . ' totp list-val'); |
|
128 |
|
if (!strstr($r, $exp)) { |
|
129 |
|
rg_log('r=' . $r); |
|
130 |
|
rg_log('Invalid output for list-val!'); |
|
131 |
|
exit(1); |
|
132 |
|
} |
|
133 |
|
|
|
134 |
|
|
|
135 |
|
rg_log(''); |
|
136 |
|
rg_log('Testing \'inval\' command - wrong ip'); |
|
137 |
|
$tc = intval(time() / 30) + 1; // we try one in the future |
|
138 |
|
$token = rg_totp_compute($key, $tc, 6); |
|
139 |
|
$r = shell_exec($cmd . ' totp inval 1.1.1.1'); |
|
140 |
|
if (!strstr($r, 'ip not found')) { |
|
141 |
|
rg_log('r=' . $r); |
|
142 |
|
rg_log('Cannot invalidate ip!'); |
|
143 |
|
exit(1); |
|
144 |
|
} |
|
145 |
|
|
|
146 |
|
|
|
147 |
|
rg_log(''); |
|
148 |
|
rg_log('Testing \'inval\' command - all'); |
|
149 |
|
$tc = intval(time() / 30) + 1; // we try one in the future |
|
150 |
|
$token = rg_totp_compute($key, $tc, 6); |
|
151 |
|
$r = shell_exec($cmd . ' totp inval all'); |
|
152 |
|
if (!strstr($r, 'Success!')) { |
|
153 |
|
rg_log('r=' . $r); |
|
154 |
|
rg_log('Cannot invalidate all!'); |
|
155 |
|
exit(1); |
|
156 |
|
} |
|
157 |
|
|
|
158 |
|
|
|
159 |
|
rg_log(''); |
|
160 |
|
rg_log('Testing \'remove-device\''); |
|
161 |
|
$tc = intval(time() / 30) + 2; |
|
162 |
|
$token = rg_totp_compute($key, $tc, 6); |
|
163 |
|
$_cmd = $cmd . ' totp remove-device ' . $token; |
|
164 |
|
rg_log('Sending cmd ' . $_cmd); |
|
165 |
|
$r = shell_exec($_cmd); |
|
166 |
|
if (!strstr($r, 'Success!')) { |
|
167 |
|
rg_log('r=' . $r); |
|
168 |
|
rg_log('Cannot remove device!'); |
|
169 |
|
exit(1); |
|
170 |
|
} |
|
171 |
|
|
|
172 |
|
|
|
173 |
|
$sc = rg_test_sc_generate($db, $rg_ui, $good_sid); |
|
174 |
|
$sql = "UPDATE scratch_codes SET sc = '0' || substring(sc from 1 for 7)" |
|
175 |
|
. " WHERE uid = " . $rg_ui['uid']; |
|
176 |
|
$res = rg_sql_query($db, $sql); |
|
177 |
|
rg_sql_free_result($res); |
|
178 |
|
// we want to test with a short code, so, insert one and flush cache |
|
179 |
|
$key = 'user::' . $rg_ui['uid'] . '::login_tokens::sc'; |
|
180 |
|
rg_cache_unset($key, 0); |
|
181 |
|
foreach ($sc as &$t) |
|
182 |
|
$t = substr($t, 0, 7); |
|
183 |
|
|
|
184 |
|
|
|
185 |
|
rg_log(''); |
|
186 |
|
rg_log('Testing \'unenroll\''); |
|
187 |
|
$token = array_pop($sc); |
|
188 |
|
$token = ltrim($token, '0'); |
|
189 |
|
$_cmd = $cmd . ' totp unenroll ' . $token; |
|
190 |
|
rg_log('Sending cmd ' . $_cmd); |
|
191 |
|
$r = shell_exec($_cmd); |
|
192 |
|
if (!strstr($r, 'You are now unenrolled')) { |
|
193 |
|
rg_log('r=' . $r); |
|
194 |
|
rg_log('Cannot unenroll!'); |
|
195 |
|
exit(1); |
|
196 |
|
} |
|
197 |
|
|
|
198 |
|
rg_log(''); |
|
199 |
|
rg_log('After enroll we should not be able to use the scratch codes'); |
|
200 |
|
$token = array_pop($sc); |
|
201 |
|
$r = shell_exec($cmd . ' totp val ' . $token . ' 2m'); |
|
202 |
|
if (strstr($r, 'Success!')) { |
|
203 |
|
rg_log('r=' . $r); |
|
204 |
|
rg_log('Seems we are able to use scratch codes after unenroll!'); |
|
205 |
|
exit(1); |
|
206 |
|
} |
|
207 |
|
|
|
208 |
|
|
|
209 |
|
$sc = rg_test_sc_generate($db, $rg_ui, $good_sid); |
|
210 |
|
|
|
211 |
|
|
|
212 |
|
rg_log(''); |
|
213 |
|
rg_log('sc: testing \'val\' cmd...'); |
|
214 |
|
$token = array_pop($sc); |
|
215 |
|
$_cmd = $cmd . ' totp val ' . $token . ' 2m'; |
|
216 |
|
rg_log('Sending cmd ' . $_cmd); |
|
217 |
|
$r = shell_exec($_cmd); |
|
218 |
|
if (!strstr($r, 'Success!')) { |
|
219 |
|
rg_log('r=' . $r); |
|
220 |
|
rg_log('Cannot validate ip!'); |
|
221 |
|
exit(1); |
|
222 |
|
} |
|
223 |
|
|
|
224 |
|
|
|
225 |
|
rg_log(''); |
|
226 |
|
rg_log('Reuse of the scratch code must be forbidden (sc)'); |
|
227 |
|
$_cmd = $cmd . ' totp val ' . $token . ' 2m'; |
|
228 |
|
rg_log('Sending cmd ' . $_cmd); |
|
229 |
|
$r = shell_exec($_cmd); |
|
230 |
|
if (!strstr($r, 'invalid token')) { |
|
231 |
|
rg_log('r=' . $r); |
|
232 |
|
rg_log('we get no error on token reuse!'); |
|
233 |
|
exit(1); |
|
234 |
|
} |
|
235 |
|
|
|
236 |
|
|
|
237 |
|
rg_log("OK!"); |
|
238 |
|
?> |