Fossil SCM
Allow login using either the username or the first email address found in the USER.INFO column. Note that it might be useful to create an index on user(find_emailaddr(info)) to make this efficient in the case where there are many rows in the user table.
Commit
8c91be8bf085e85f7755d3029ef03c8053d24239b86aac772c64ceccbb57c8f5
Parent
8a20d41fce12bec…
1 file changed
+29
-11
+29
-11
| --- src/login.c | ||
| +++ src/login.c | ||
| @@ -211,21 +211,39 @@ | ||
| 211 | 211 | ** zPassword may be either the plain-text form or the encrypted |
| 212 | 212 | ** form of the user's password. |
| 213 | 213 | */ |
| 214 | 214 | int login_search_uid(const char *zUsername, const char *zPasswd){ |
| 215 | 215 | char *zSha1Pw = sha1_shared_secret(zPasswd, zUsername, 0); |
| 216 | - int const uid = | |
| 217 | - db_int(0, | |
| 218 | - "SELECT uid FROM user" | |
| 219 | - " WHERE login=%Q" | |
| 220 | - " AND length(cap)>0 AND length(pw)>0" | |
| 221 | - " AND login NOT IN ('anonymous','nobody','developer','reader')" | |
| 222 | - " AND (pw=%Q OR (length(pw)<>40 AND pw=%Q))" | |
| 223 | - " AND (info NOT LIKE '%%expires 20%%'" | |
| 224 | - " OR substr(info,instr(lower(info),'expires')+8,10)>datetime('now'))", | |
| 225 | - zUsername, zSha1Pw, zPasswd | |
| 226 | - ); | |
| 216 | + int uid = db_int(0, | |
| 217 | + "SELECT uid FROM user" | |
| 218 | + " WHERE login=%Q" | |
| 219 | + " AND length(cap)>0 AND length(pw)>0" | |
| 220 | + " AND login NOT IN ('anonymous','nobody','developer','reader')" | |
| 221 | + " AND (pw=%Q OR (length(pw)<>40 AND pw=%Q))" | |
| 222 | + " AND (info NOT LIKE '%%expires 20%%'" | |
| 223 | + " OR substr(info,instr(lower(info),'expires')+8,10)>datetime('now'))", | |
| 224 | + zUsername, zSha1Pw, zPasswd | |
| 225 | + ); | |
| 226 | + | |
| 227 | + /* If we did not find a login on the first attempt, and the username | |
| 228 | + ** looks like an email address, the perhaps the user entired their | |
| 229 | + ** email address instead of their login. Try again to match the user | |
| 230 | + ** against email addresses contained in the "info" field. | |
| 231 | + */ | |
| 232 | + if( uid==0 && strchr(zUsername,'@')!=0 ){ | |
| 233 | + Stmt q; | |
| 234 | + db_prepare(&q, | |
| 235 | + "SELECT login FROM user" | |
| 236 | + " WHERE find_emailaddr(info)=%Q" | |
| 237 | + " AND instr(login,'@')==0", | |
| 238 | + zUsername | |
| 239 | + ); | |
| 240 | + while( uid==0 && db_step(&q)==SQLITE_ROW ){ | |
| 241 | + uid = login_search_uid(db_column_text(&q,0),zPasswd); | |
| 242 | + } | |
| 243 | + db_finalize(&q); | |
| 244 | + } | |
| 227 | 245 | free(zSha1Pw); |
| 228 | 246 | return uid; |
| 229 | 247 | } |
| 230 | 248 | |
| 231 | 249 | /* |
| 232 | 250 |
| --- src/login.c | |
| +++ src/login.c | |
| @@ -211,21 +211,39 @@ | |
| 211 | ** zPassword may be either the plain-text form or the encrypted |
| 212 | ** form of the user's password. |
| 213 | */ |
| 214 | int login_search_uid(const char *zUsername, const char *zPasswd){ |
| 215 | char *zSha1Pw = sha1_shared_secret(zPasswd, zUsername, 0); |
| 216 | int const uid = |
| 217 | db_int(0, |
| 218 | "SELECT uid FROM user" |
| 219 | " WHERE login=%Q" |
| 220 | " AND length(cap)>0 AND length(pw)>0" |
| 221 | " AND login NOT IN ('anonymous','nobody','developer','reader')" |
| 222 | " AND (pw=%Q OR (length(pw)<>40 AND pw=%Q))" |
| 223 | " AND (info NOT LIKE '%%expires 20%%'" |
| 224 | " OR substr(info,instr(lower(info),'expires')+8,10)>datetime('now'))", |
| 225 | zUsername, zSha1Pw, zPasswd |
| 226 | ); |
| 227 | free(zSha1Pw); |
| 228 | return uid; |
| 229 | } |
| 230 | |
| 231 | /* |
| 232 |
| --- src/login.c | |
| +++ src/login.c | |
| @@ -211,21 +211,39 @@ | |
| 211 | ** zPassword may be either the plain-text form or the encrypted |
| 212 | ** form of the user's password. |
| 213 | */ |
| 214 | int login_search_uid(const char *zUsername, const char *zPasswd){ |
| 215 | char *zSha1Pw = sha1_shared_secret(zPasswd, zUsername, 0); |
| 216 | int uid = db_int(0, |
| 217 | "SELECT uid FROM user" |
| 218 | " WHERE login=%Q" |
| 219 | " AND length(cap)>0 AND length(pw)>0" |
| 220 | " AND login NOT IN ('anonymous','nobody','developer','reader')" |
| 221 | " AND (pw=%Q OR (length(pw)<>40 AND pw=%Q))" |
| 222 | " AND (info NOT LIKE '%%expires 20%%'" |
| 223 | " OR substr(info,instr(lower(info),'expires')+8,10)>datetime('now'))", |
| 224 | zUsername, zSha1Pw, zPasswd |
| 225 | ); |
| 226 | |
| 227 | /* If we did not find a login on the first attempt, and the username |
| 228 | ** looks like an email address, the perhaps the user entired their |
| 229 | ** email address instead of their login. Try again to match the user |
| 230 | ** against email addresses contained in the "info" field. |
| 231 | */ |
| 232 | if( uid==0 && strchr(zUsername,'@')!=0 ){ |
| 233 | Stmt q; |
| 234 | db_prepare(&q, |
| 235 | "SELECT login FROM user" |
| 236 | " WHERE find_emailaddr(info)=%Q" |
| 237 | " AND instr(login,'@')==0", |
| 238 | zUsername |
| 239 | ); |
| 240 | while( uid==0 && db_step(&q)==SQLITE_ROW ){ |
| 241 | uid = login_search_uid(db_column_text(&q,0),zPasswd); |
| 242 | } |
| 243 | db_finalize(&q); |
| 244 | } |
| 245 | free(zSha1Pw); |
| 246 | return uid; |
| 247 | } |
| 248 | |
| 249 | /* |
| 250 |