Fossil SCM
merged in trunk [06e0cb70054d3c3], resolved conflict in login.c.
Commit
81d71d7b9ef90ccbbda360555ce1e17a71b2da7f
Parent
11373d5bb8f40c2…
9 files changed
+2
-3
+2
-3
+1
-1
+1
-1
+1
-1
+1
-1
+46
-2
+46
-2
+18
+2
-3
| --- src/cgi.c | ||
| +++ src/cgi.c | ||
| @@ -1169,18 +1169,17 @@ | ||
| 1169 | 1169 | cgi_setenv("HTTP_HOST", zVal); |
| 1170 | 1170 | }else if( fossil_strcmp(zFieldName,"if-none-match:")==0 ){ |
| 1171 | 1171 | cgi_setenv("HTTP_IF_NONE_MATCH", zVal); |
| 1172 | 1172 | }else if( fossil_strcmp(zFieldName,"if-modified-since:")==0 ){ |
| 1173 | 1173 | cgi_setenv("HTTP_IF_MODIFIED_SINCE", zVal); |
| 1174 | - } | |
| 1175 | 1174 | #if 0 |
| 1176 | - else if( fossil_strcmp(zFieldName,"referer:")==0 ){ | |
| 1175 | + }else if( fossil_strcmp(zFieldName,"referer:")==0 ){ | |
| 1177 | 1176 | cgi_setenv("HTTP_REFERER", zVal); |
| 1177 | +#endif | |
| 1178 | 1178 | }else if( fossil_strcmp(zFieldName,"user-agent:")==0 ){ |
| 1179 | 1179 | cgi_setenv("HTTP_USER_AGENT", zVal); |
| 1180 | 1180 | } |
| 1181 | -#endif | |
| 1182 | 1181 | } |
| 1183 | 1182 | |
| 1184 | 1183 | cgi_init(); |
| 1185 | 1184 | } |
| 1186 | 1185 | |
| 1187 | 1186 |
| --- src/cgi.c | |
| +++ src/cgi.c | |
| @@ -1169,18 +1169,17 @@ | |
| 1169 | cgi_setenv("HTTP_HOST", zVal); |
| 1170 | }else if( fossil_strcmp(zFieldName,"if-none-match:")==0 ){ |
| 1171 | cgi_setenv("HTTP_IF_NONE_MATCH", zVal); |
| 1172 | }else if( fossil_strcmp(zFieldName,"if-modified-since:")==0 ){ |
| 1173 | cgi_setenv("HTTP_IF_MODIFIED_SINCE", zVal); |
| 1174 | } |
| 1175 | #if 0 |
| 1176 | else if( fossil_strcmp(zFieldName,"referer:")==0 ){ |
| 1177 | cgi_setenv("HTTP_REFERER", zVal); |
| 1178 | }else if( fossil_strcmp(zFieldName,"user-agent:")==0 ){ |
| 1179 | cgi_setenv("HTTP_USER_AGENT", zVal); |
| 1180 | } |
| 1181 | #endif |
| 1182 | } |
| 1183 | |
| 1184 | cgi_init(); |
| 1185 | } |
| 1186 | |
| 1187 |
| --- src/cgi.c | |
| +++ src/cgi.c | |
| @@ -1169,18 +1169,17 @@ | |
| 1169 | cgi_setenv("HTTP_HOST", zVal); |
| 1170 | }else if( fossil_strcmp(zFieldName,"if-none-match:")==0 ){ |
| 1171 | cgi_setenv("HTTP_IF_NONE_MATCH", zVal); |
| 1172 | }else if( fossil_strcmp(zFieldName,"if-modified-since:")==0 ){ |
| 1173 | cgi_setenv("HTTP_IF_MODIFIED_SINCE", zVal); |
| 1174 | #if 0 |
| 1175 | }else if( fossil_strcmp(zFieldName,"referer:")==0 ){ |
| 1176 | cgi_setenv("HTTP_REFERER", zVal); |
| 1177 | #endif |
| 1178 | }else if( fossil_strcmp(zFieldName,"user-agent:")==0 ){ |
| 1179 | cgi_setenv("HTTP_USER_AGENT", zVal); |
| 1180 | } |
| 1181 | } |
| 1182 | |
| 1183 | cgi_init(); |
| 1184 | } |
| 1185 | |
| 1186 |
+2
-3
| --- src/cgi.c | ||
| +++ src/cgi.c | ||
| @@ -1169,18 +1169,17 @@ | ||
| 1169 | 1169 | cgi_setenv("HTTP_HOST", zVal); |
| 1170 | 1170 | }else if( fossil_strcmp(zFieldName,"if-none-match:")==0 ){ |
| 1171 | 1171 | cgi_setenv("HTTP_IF_NONE_MATCH", zVal); |
| 1172 | 1172 | }else if( fossil_strcmp(zFieldName,"if-modified-since:")==0 ){ |
| 1173 | 1173 | cgi_setenv("HTTP_IF_MODIFIED_SINCE", zVal); |
| 1174 | - } | |
| 1175 | 1174 | #if 0 |
| 1176 | - else if( fossil_strcmp(zFieldName,"referer:")==0 ){ | |
| 1175 | + }else if( fossil_strcmp(zFieldName,"referer:")==0 ){ | |
| 1177 | 1176 | cgi_setenv("HTTP_REFERER", zVal); |
| 1177 | +#endif | |
| 1178 | 1178 | }else if( fossil_strcmp(zFieldName,"user-agent:")==0 ){ |
| 1179 | 1179 | cgi_setenv("HTTP_USER_AGENT", zVal); |
| 1180 | 1180 | } |
| 1181 | -#endif | |
| 1182 | 1181 | } |
| 1183 | 1182 | |
| 1184 | 1183 | cgi_init(); |
| 1185 | 1184 | } |
| 1186 | 1185 | |
| 1187 | 1186 |
| --- src/cgi.c | |
| +++ src/cgi.c | |
| @@ -1169,18 +1169,17 @@ | |
| 1169 | cgi_setenv("HTTP_HOST", zVal); |
| 1170 | }else if( fossil_strcmp(zFieldName,"if-none-match:")==0 ){ |
| 1171 | cgi_setenv("HTTP_IF_NONE_MATCH", zVal); |
| 1172 | }else if( fossil_strcmp(zFieldName,"if-modified-since:")==0 ){ |
| 1173 | cgi_setenv("HTTP_IF_MODIFIED_SINCE", zVal); |
| 1174 | } |
| 1175 | #if 0 |
| 1176 | else if( fossil_strcmp(zFieldName,"referer:")==0 ){ |
| 1177 | cgi_setenv("HTTP_REFERER", zVal); |
| 1178 | }else if( fossil_strcmp(zFieldName,"user-agent:")==0 ){ |
| 1179 | cgi_setenv("HTTP_USER_AGENT", zVal); |
| 1180 | } |
| 1181 | #endif |
| 1182 | } |
| 1183 | |
| 1184 | cgi_init(); |
| 1185 | } |
| 1186 | |
| 1187 |
| --- src/cgi.c | |
| +++ src/cgi.c | |
| @@ -1169,18 +1169,17 @@ | |
| 1169 | cgi_setenv("HTTP_HOST", zVal); |
| 1170 | }else if( fossil_strcmp(zFieldName,"if-none-match:")==0 ){ |
| 1171 | cgi_setenv("HTTP_IF_NONE_MATCH", zVal); |
| 1172 | }else if( fossil_strcmp(zFieldName,"if-modified-since:")==0 ){ |
| 1173 | cgi_setenv("HTTP_IF_MODIFIED_SINCE", zVal); |
| 1174 | #if 0 |
| 1175 | }else if( fossil_strcmp(zFieldName,"referer:")==0 ){ |
| 1176 | cgi_setenv("HTTP_REFERER", zVal); |
| 1177 | #endif |
| 1178 | }else if( fossil_strcmp(zFieldName,"user-agent:")==0 ){ |
| 1179 | cgi_setenv("HTTP_USER_AGENT", zVal); |
| 1180 | } |
| 1181 | } |
| 1182 | |
| 1183 | cgi_init(); |
| 1184 | } |
| 1185 | |
| 1186 |
+1
-1
| --- src/json_artifact.c | ||
| +++ src/json_artifact.c | ||
| @@ -351,11 +351,11 @@ | ||
| 351 | 351 | }else if(2==rc){ |
| 352 | 352 | g.json.resultCode = FSL_JSON_E_AMBIGUOUS_UUID; |
| 353 | 353 | goto error; |
| 354 | 354 | } |
| 355 | 355 | zUuid = blob_str(&uuid); |
| 356 | - rid = db_int(0, "SELECT rid FROM blob WHERE uuid='%s'", zUuid); | |
| 356 | + rid = db_int(0, "SELECT rid FROM blob WHERE uuid=%Q", zUuid); | |
| 357 | 357 | if(0==rid){ |
| 358 | 358 | g.json.resultCode = FSL_JSON_E_RESOURCE_NOT_FOUND; |
| 359 | 359 | goto error; |
| 360 | 360 | } |
| 361 | 361 | |
| 362 | 362 |
| --- src/json_artifact.c | |
| +++ src/json_artifact.c | |
| @@ -351,11 +351,11 @@ | |
| 351 | }else if(2==rc){ |
| 352 | g.json.resultCode = FSL_JSON_E_AMBIGUOUS_UUID; |
| 353 | goto error; |
| 354 | } |
| 355 | zUuid = blob_str(&uuid); |
| 356 | rid = db_int(0, "SELECT rid FROM blob WHERE uuid='%s'", zUuid); |
| 357 | if(0==rid){ |
| 358 | g.json.resultCode = FSL_JSON_E_RESOURCE_NOT_FOUND; |
| 359 | goto error; |
| 360 | } |
| 361 | |
| 362 |
| --- src/json_artifact.c | |
| +++ src/json_artifact.c | |
| @@ -351,11 +351,11 @@ | |
| 351 | }else if(2==rc){ |
| 352 | g.json.resultCode = FSL_JSON_E_AMBIGUOUS_UUID; |
| 353 | goto error; |
| 354 | } |
| 355 | zUuid = blob_str(&uuid); |
| 356 | rid = db_int(0, "SELECT rid FROM blob WHERE uuid=%Q", zUuid); |
| 357 | if(0==rid){ |
| 358 | g.json.resultCode = FSL_JSON_E_RESOURCE_NOT_FOUND; |
| 359 | goto error; |
| 360 | } |
| 361 | |
| 362 |
+1
-1
| --- src/json_artifact.c | ||
| +++ src/json_artifact.c | ||
| @@ -351,11 +351,11 @@ | ||
| 351 | 351 | }else if(2==rc){ |
| 352 | 352 | g.json.resultCode = FSL_JSON_E_AMBIGUOUS_UUID; |
| 353 | 353 | goto error; |
| 354 | 354 | } |
| 355 | 355 | zUuid = blob_str(&uuid); |
| 356 | - rid = db_int(0, "SELECT rid FROM blob WHERE uuid='%s'", zUuid); | |
| 356 | + rid = db_int(0, "SELECT rid FROM blob WHERE uuid=%Q", zUuid); | |
| 357 | 357 | if(0==rid){ |
| 358 | 358 | g.json.resultCode = FSL_JSON_E_RESOURCE_NOT_FOUND; |
| 359 | 359 | goto error; |
| 360 | 360 | } |
| 361 | 361 | |
| 362 | 362 |
| --- src/json_artifact.c | |
| +++ src/json_artifact.c | |
| @@ -351,11 +351,11 @@ | |
| 351 | }else if(2==rc){ |
| 352 | g.json.resultCode = FSL_JSON_E_AMBIGUOUS_UUID; |
| 353 | goto error; |
| 354 | } |
| 355 | zUuid = blob_str(&uuid); |
| 356 | rid = db_int(0, "SELECT rid FROM blob WHERE uuid='%s'", zUuid); |
| 357 | if(0==rid){ |
| 358 | g.json.resultCode = FSL_JSON_E_RESOURCE_NOT_FOUND; |
| 359 | goto error; |
| 360 | } |
| 361 | |
| 362 |
| --- src/json_artifact.c | |
| +++ src/json_artifact.c | |
| @@ -351,11 +351,11 @@ | |
| 351 | }else if(2==rc){ |
| 352 | g.json.resultCode = FSL_JSON_E_AMBIGUOUS_UUID; |
| 353 | goto error; |
| 354 | } |
| 355 | zUuid = blob_str(&uuid); |
| 356 | rid = db_int(0, "SELECT rid FROM blob WHERE uuid=%Q", zUuid); |
| 357 | if(0==rid){ |
| 358 | g.json.resultCode = FSL_JSON_E_RESOURCE_NOT_FOUND; |
| 359 | goto error; |
| 360 | } |
| 361 | |
| 362 |
+1
-1
| --- src/json_branch.c | ||
| +++ src/json_branch.c | ||
| @@ -204,11 +204,11 @@ | ||
| 204 | 204 | return FSL_JSON_E_INVALID_ARGS; |
| 205 | 205 | } |
| 206 | 206 | if( db_exists( |
| 207 | 207 | "SELECT 1 FROM tagxref" |
| 208 | 208 | " WHERE tagtype>0" |
| 209 | - " AND tagid=(SELECT tagid FROM tag WHERE tagname='sym-%s')", | |
| 209 | + " AND tagid=(SELECT tagid FROM tag WHERE tagname='sym-%q')", | |
| 210 | 210 | zBranch)!=0 ){ |
| 211 | 211 | zOpt->rcErrMsg = "Branch already exists."; |
| 212 | 212 | return FSL_JSON_E_RESOURCE_ALREADY_EXISTS; |
| 213 | 213 | } |
| 214 | 214 | |
| 215 | 215 |
| --- src/json_branch.c | |
| +++ src/json_branch.c | |
| @@ -204,11 +204,11 @@ | |
| 204 | return FSL_JSON_E_INVALID_ARGS; |
| 205 | } |
| 206 | if( db_exists( |
| 207 | "SELECT 1 FROM tagxref" |
| 208 | " WHERE tagtype>0" |
| 209 | " AND tagid=(SELECT tagid FROM tag WHERE tagname='sym-%s')", |
| 210 | zBranch)!=0 ){ |
| 211 | zOpt->rcErrMsg = "Branch already exists."; |
| 212 | return FSL_JSON_E_RESOURCE_ALREADY_EXISTS; |
| 213 | } |
| 214 | |
| 215 |
| --- src/json_branch.c | |
| +++ src/json_branch.c | |
| @@ -204,11 +204,11 @@ | |
| 204 | return FSL_JSON_E_INVALID_ARGS; |
| 205 | } |
| 206 | if( db_exists( |
| 207 | "SELECT 1 FROM tagxref" |
| 208 | " WHERE tagtype>0" |
| 209 | " AND tagid=(SELECT tagid FROM tag WHERE tagname='sym-%q')", |
| 210 | zBranch)!=0 ){ |
| 211 | zOpt->rcErrMsg = "Branch already exists."; |
| 212 | return FSL_JSON_E_RESOURCE_ALREADY_EXISTS; |
| 213 | } |
| 214 | |
| 215 |
+1
-1
| --- src/json_branch.c | ||
| +++ src/json_branch.c | ||
| @@ -204,11 +204,11 @@ | ||
| 204 | 204 | return FSL_JSON_E_INVALID_ARGS; |
| 205 | 205 | } |
| 206 | 206 | if( db_exists( |
| 207 | 207 | "SELECT 1 FROM tagxref" |
| 208 | 208 | " WHERE tagtype>0" |
| 209 | - " AND tagid=(SELECT tagid FROM tag WHERE tagname='sym-%s')", | |
| 209 | + " AND tagid=(SELECT tagid FROM tag WHERE tagname='sym-%q')", | |
| 210 | 210 | zBranch)!=0 ){ |
| 211 | 211 | zOpt->rcErrMsg = "Branch already exists."; |
| 212 | 212 | return FSL_JSON_E_RESOURCE_ALREADY_EXISTS; |
| 213 | 213 | } |
| 214 | 214 | |
| 215 | 215 |
| --- src/json_branch.c | |
| +++ src/json_branch.c | |
| @@ -204,11 +204,11 @@ | |
| 204 | return FSL_JSON_E_INVALID_ARGS; |
| 205 | } |
| 206 | if( db_exists( |
| 207 | "SELECT 1 FROM tagxref" |
| 208 | " WHERE tagtype>0" |
| 209 | " AND tagid=(SELECT tagid FROM tag WHERE tagname='sym-%s')", |
| 210 | zBranch)!=0 ){ |
| 211 | zOpt->rcErrMsg = "Branch already exists."; |
| 212 | return FSL_JSON_E_RESOURCE_ALREADY_EXISTS; |
| 213 | } |
| 214 | |
| 215 |
| --- src/json_branch.c | |
| +++ src/json_branch.c | |
| @@ -204,11 +204,11 @@ | |
| 204 | return FSL_JSON_E_INVALID_ARGS; |
| 205 | } |
| 206 | if( db_exists( |
| 207 | "SELECT 1 FROM tagxref" |
| 208 | " WHERE tagtype>0" |
| 209 | " AND tagid=(SELECT tagid FROM tag WHERE tagname='sym-%q')", |
| 210 | zBranch)!=0 ){ |
| 211 | zOpt->rcErrMsg = "Branch already exists."; |
| 212 | return FSL_JSON_E_RESOURCE_ALREADY_EXISTS; |
| 213 | } |
| 214 | |
| 215 |
+46
-2
| --- src/login.c | ||
| +++ src/login.c | ||
| @@ -117,15 +117,20 @@ | ||
| 117 | 117 | ** But some clients are behind firewalls that shift the IP address |
| 118 | 118 | ** with each HTTP request. To allow such (broken) clients to log in, |
| 119 | 119 | ** extract just a prefix of the IP address. |
| 120 | 120 | */ |
| 121 | 121 | static char *ipPrefix(const char *zIP){ |
| 122 | - int i, j; | |
| 122 | + int i, j; | |
| 123 | + static int ip_prefix_terms = -1; | |
| 124 | + if( ip_prefix_terms<0 ){ | |
| 125 | + ip_prefix_terms = db_get_int("ip-prefix-terms",2); | |
| 126 | + } | |
| 127 | + if( ip_prefix_terms==0 ) return mprintf("0"); | |
| 123 | 128 | for(i=j=0; zIP[i]; i++){ |
| 124 | 129 | if( zIP[i]=='.' ){ |
| 125 | 130 | j++; |
| 126 | - if( j==2 ) break; | |
| 131 | + if( j==ip_prefix_terms ) break; | |
| 127 | 132 | } |
| 128 | 133 | } |
| 129 | 134 | return mprintf("%.*s", i, zIP); |
| 130 | 135 | } |
| 131 | 136 | |
| @@ -347,10 +352,45 @@ | ||
| 347 | 352 | ** downstream problems here. We could alternately use "" here. |
| 348 | 353 | */ |
| 349 | 354 | ; |
| 350 | 355 | } |
| 351 | 356 | } |
| 357 | + | |
| 358 | +/* | |
| 359 | +** Look at the HTTP_USER_AGENT parameter and try to determine if the user agent | |
| 360 | +** is a manually operated browser or a bot. When in doubt, assume a bot. Return | |
| 361 | +** true if we believe the agent is a real person. | |
| 362 | +*/ | |
| 363 | +static int isHuman(const char *zAgent){ | |
| 364 | + int i; | |
| 365 | + if( zAgent==0 ) return 0; | |
| 366 | + for(i=0; zAgent[i]; i++){ | |
| 367 | + if( zAgent[i]=='b' && memcmp(&zAgent[i],"bot",3)==0 ) return 0; | |
| 368 | + if( zAgent[i]=='s' && memcmp(&zAgent[i],"spider",6)==0 ) return 0; | |
| 369 | + } | |
| 370 | + if( memcmp(zAgent, "Mozilla/", 8)==0 ){ | |
| 371 | + return atoi(&zAgent[8])>=4; | |
| 372 | + } | |
| 373 | + if( memcmp(zAgent, "Opera/", 6)==0 ) return 1; | |
| 374 | + if( memcmp(zAgent, "Safari/", 7)==0 ) return 1; | |
| 375 | + if( memcmp(zAgent, "Lynx/", 5)==0 ) return 1; | |
| 376 | + return 0; | |
| 377 | +} | |
| 378 | + | |
| 379 | +/* | |
| 380 | +** COMMAND: test-ishuman | |
| 381 | +** | |
| 382 | +** Read lines of text from standard input. Interpret each line of text | |
| 383 | +** as a User-Agent string from an HTTP header. Label each line as HUMAN | |
| 384 | +** or ROBOT. | |
| 385 | +*/ | |
| 386 | +void test_ishuman(void){ | |
| 387 | + char zLine[3000]; | |
| 388 | + while( fgets(zLine, sizeof(zLine), stdin) ){ | |
| 389 | + fossil_print("%s %s", isHuman(zLine) ? "HUMAN" : "ROBOT", zLine); | |
| 390 | + } | |
| 391 | +} | |
| 352 | 392 | |
| 353 | 393 | /* |
| 354 | 394 | ** SQL function for constant time comparison of two values. |
| 355 | 395 | ** Sets result to 0 if two values are equal. |
| 356 | 396 | */ |
| @@ -831,10 +871,14 @@ | ||
| 831 | 871 | } |
| 832 | 872 | |
| 833 | 873 | /* Set the capabilities */ |
| 834 | 874 | login_replace_capabilities(zCap, 0); |
| 835 | 875 | login_set_anon_nobody_capabilities(); |
| 876 | + if( zCap[0] && !g.perm.History && db_get_boolean("auto-enable-hyperlinks",1) | |
| 877 | + && isHuman(P("HTTP_USER_AGENT")) ){ | |
| 878 | + g.perm.History = 1; | |
| 879 | + } | |
| 836 | 880 | } |
| 837 | 881 | |
| 838 | 882 | /* |
| 839 | 883 | ** Memory of settings |
| 840 | 884 | */ |
| 841 | 885 |
| --- src/login.c | |
| +++ src/login.c | |
| @@ -117,15 +117,20 @@ | |
| 117 | ** But some clients are behind firewalls that shift the IP address |
| 118 | ** with each HTTP request. To allow such (broken) clients to log in, |
| 119 | ** extract just a prefix of the IP address. |
| 120 | */ |
| 121 | static char *ipPrefix(const char *zIP){ |
| 122 | int i, j; |
| 123 | for(i=j=0; zIP[i]; i++){ |
| 124 | if( zIP[i]=='.' ){ |
| 125 | j++; |
| 126 | if( j==2 ) break; |
| 127 | } |
| 128 | } |
| 129 | return mprintf("%.*s", i, zIP); |
| 130 | } |
| 131 | |
| @@ -347,10 +352,45 @@ | |
| 347 | ** downstream problems here. We could alternately use "" here. |
| 348 | */ |
| 349 | ; |
| 350 | } |
| 351 | } |
| 352 | |
| 353 | /* |
| 354 | ** SQL function for constant time comparison of two values. |
| 355 | ** Sets result to 0 if two values are equal. |
| 356 | */ |
| @@ -831,10 +871,14 @@ | |
| 831 | } |
| 832 | |
| 833 | /* Set the capabilities */ |
| 834 | login_replace_capabilities(zCap, 0); |
| 835 | login_set_anon_nobody_capabilities(); |
| 836 | } |
| 837 | |
| 838 | /* |
| 839 | ** Memory of settings |
| 840 | */ |
| 841 |
| --- src/login.c | |
| +++ src/login.c | |
| @@ -117,15 +117,20 @@ | |
| 117 | ** But some clients are behind firewalls that shift the IP address |
| 118 | ** with each HTTP request. To allow such (broken) clients to log in, |
| 119 | ** extract just a prefix of the IP address. |
| 120 | */ |
| 121 | static char *ipPrefix(const char *zIP){ |
| 122 | int i, j; |
| 123 | static int ip_prefix_terms = -1; |
| 124 | if( ip_prefix_terms<0 ){ |
| 125 | ip_prefix_terms = db_get_int("ip-prefix-terms",2); |
| 126 | } |
| 127 | if( ip_prefix_terms==0 ) return mprintf("0"); |
| 128 | for(i=j=0; zIP[i]; i++){ |
| 129 | if( zIP[i]=='.' ){ |
| 130 | j++; |
| 131 | if( j==ip_prefix_terms ) break; |
| 132 | } |
| 133 | } |
| 134 | return mprintf("%.*s", i, zIP); |
| 135 | } |
| 136 | |
| @@ -347,10 +352,45 @@ | |
| 352 | ** downstream problems here. We could alternately use "" here. |
| 353 | */ |
| 354 | ; |
| 355 | } |
| 356 | } |
| 357 | |
| 358 | /* |
| 359 | ** Look at the HTTP_USER_AGENT parameter and try to determine if the user agent |
| 360 | ** is a manually operated browser or a bot. When in doubt, assume a bot. Return |
| 361 | ** true if we believe the agent is a real person. |
| 362 | */ |
| 363 | static int isHuman(const char *zAgent){ |
| 364 | int i; |
| 365 | if( zAgent==0 ) return 0; |
| 366 | for(i=0; zAgent[i]; i++){ |
| 367 | if( zAgent[i]=='b' && memcmp(&zAgent[i],"bot",3)==0 ) return 0; |
| 368 | if( zAgent[i]=='s' && memcmp(&zAgent[i],"spider",6)==0 ) return 0; |
| 369 | } |
| 370 | if( memcmp(zAgent, "Mozilla/", 8)==0 ){ |
| 371 | return atoi(&zAgent[8])>=4; |
| 372 | } |
| 373 | if( memcmp(zAgent, "Opera/", 6)==0 ) return 1; |
| 374 | if( memcmp(zAgent, "Safari/", 7)==0 ) return 1; |
| 375 | if( memcmp(zAgent, "Lynx/", 5)==0 ) return 1; |
| 376 | return 0; |
| 377 | } |
| 378 | |
| 379 | /* |
| 380 | ** COMMAND: test-ishuman |
| 381 | ** |
| 382 | ** Read lines of text from standard input. Interpret each line of text |
| 383 | ** as a User-Agent string from an HTTP header. Label each line as HUMAN |
| 384 | ** or ROBOT. |
| 385 | */ |
| 386 | void test_ishuman(void){ |
| 387 | char zLine[3000]; |
| 388 | while( fgets(zLine, sizeof(zLine), stdin) ){ |
| 389 | fossil_print("%s %s", isHuman(zLine) ? "HUMAN" : "ROBOT", zLine); |
| 390 | } |
| 391 | } |
| 392 | |
| 393 | /* |
| 394 | ** SQL function for constant time comparison of two values. |
| 395 | ** Sets result to 0 if two values are equal. |
| 396 | */ |
| @@ -831,10 +871,14 @@ | |
| 871 | } |
| 872 | |
| 873 | /* Set the capabilities */ |
| 874 | login_replace_capabilities(zCap, 0); |
| 875 | login_set_anon_nobody_capabilities(); |
| 876 | if( zCap[0] && !g.perm.History && db_get_boolean("auto-enable-hyperlinks",1) |
| 877 | && isHuman(P("HTTP_USER_AGENT")) ){ |
| 878 | g.perm.History = 1; |
| 879 | } |
| 880 | } |
| 881 | |
| 882 | /* |
| 883 | ** Memory of settings |
| 884 | */ |
| 885 |
+46
-2
| --- src/login.c | ||
| +++ src/login.c | ||
| @@ -117,15 +117,20 @@ | ||
| 117 | 117 | ** But some clients are behind firewalls that shift the IP address |
| 118 | 118 | ** with each HTTP request. To allow such (broken) clients to log in, |
| 119 | 119 | ** extract just a prefix of the IP address. |
| 120 | 120 | */ |
| 121 | 121 | static char *ipPrefix(const char *zIP){ |
| 122 | - int i, j; | |
| 122 | + int i, j; | |
| 123 | + static int ip_prefix_terms = -1; | |
| 124 | + if( ip_prefix_terms<0 ){ | |
| 125 | + ip_prefix_terms = db_get_int("ip-prefix-terms",2); | |
| 126 | + } | |
| 127 | + if( ip_prefix_terms==0 ) return mprintf("0"); | |
| 123 | 128 | for(i=j=0; zIP[i]; i++){ |
| 124 | 129 | if( zIP[i]=='.' ){ |
| 125 | 130 | j++; |
| 126 | - if( j==2 ) break; | |
| 131 | + if( j==ip_prefix_terms ) break; | |
| 127 | 132 | } |
| 128 | 133 | } |
| 129 | 134 | return mprintf("%.*s", i, zIP); |
| 130 | 135 | } |
| 131 | 136 | |
| @@ -347,10 +352,45 @@ | ||
| 347 | 352 | ** downstream problems here. We could alternately use "" here. |
| 348 | 353 | */ |
| 349 | 354 | ; |
| 350 | 355 | } |
| 351 | 356 | } |
| 357 | + | |
| 358 | +/* | |
| 359 | +** Look at the HTTP_USER_AGENT parameter and try to determine if the user agent | |
| 360 | +** is a manually operated browser or a bot. When in doubt, assume a bot. Return | |
| 361 | +** true if we believe the agent is a real person. | |
| 362 | +*/ | |
| 363 | +static int isHuman(const char *zAgent){ | |
| 364 | + int i; | |
| 365 | + if( zAgent==0 ) return 0; | |
| 366 | + for(i=0; zAgent[i]; i++){ | |
| 367 | + if( zAgent[i]=='b' && memcmp(&zAgent[i],"bot",3)==0 ) return 0; | |
| 368 | + if( zAgent[i]=='s' && memcmp(&zAgent[i],"spider",6)==0 ) return 0; | |
| 369 | + } | |
| 370 | + if( memcmp(zAgent, "Mozilla/", 8)==0 ){ | |
| 371 | + return atoi(&zAgent[8])>=4; | |
| 372 | + } | |
| 373 | + if( memcmp(zAgent, "Opera/", 6)==0 ) return 1; | |
| 374 | + if( memcmp(zAgent, "Safari/", 7)==0 ) return 1; | |
| 375 | + if( memcmp(zAgent, "Lynx/", 5)==0 ) return 1; | |
| 376 | + return 0; | |
| 377 | +} | |
| 378 | + | |
| 379 | +/* | |
| 380 | +** COMMAND: test-ishuman | |
| 381 | +** | |
| 382 | +** Read lines of text from standard input. Interpret each line of text | |
| 383 | +** as a User-Agent string from an HTTP header. Label each line as HUMAN | |
| 384 | +** or ROBOT. | |
| 385 | +*/ | |
| 386 | +void test_ishuman(void){ | |
| 387 | + char zLine[3000]; | |
| 388 | + while( fgets(zLine, sizeof(zLine), stdin) ){ | |
| 389 | + fossil_print("%s %s", isHuman(zLine) ? "HUMAN" : "ROBOT", zLine); | |
| 390 | + } | |
| 391 | +} | |
| 352 | 392 | |
| 353 | 393 | /* |
| 354 | 394 | ** SQL function for constant time comparison of two values. |
| 355 | 395 | ** Sets result to 0 if two values are equal. |
| 356 | 396 | */ |
| @@ -831,10 +871,14 @@ | ||
| 831 | 871 | } |
| 832 | 872 | |
| 833 | 873 | /* Set the capabilities */ |
| 834 | 874 | login_replace_capabilities(zCap, 0); |
| 835 | 875 | login_set_anon_nobody_capabilities(); |
| 876 | + if( zCap[0] && !g.perm.History && db_get_boolean("auto-enable-hyperlinks",1) | |
| 877 | + && isHuman(P("HTTP_USER_AGENT")) ){ | |
| 878 | + g.perm.History = 1; | |
| 879 | + } | |
| 836 | 880 | } |
| 837 | 881 | |
| 838 | 882 | /* |
| 839 | 883 | ** Memory of settings |
| 840 | 884 | */ |
| 841 | 885 |
| --- src/login.c | |
| +++ src/login.c | |
| @@ -117,15 +117,20 @@ | |
| 117 | ** But some clients are behind firewalls that shift the IP address |
| 118 | ** with each HTTP request. To allow such (broken) clients to log in, |
| 119 | ** extract just a prefix of the IP address. |
| 120 | */ |
| 121 | static char *ipPrefix(const char *zIP){ |
| 122 | int i, j; |
| 123 | for(i=j=0; zIP[i]; i++){ |
| 124 | if( zIP[i]=='.' ){ |
| 125 | j++; |
| 126 | if( j==2 ) break; |
| 127 | } |
| 128 | } |
| 129 | return mprintf("%.*s", i, zIP); |
| 130 | } |
| 131 | |
| @@ -347,10 +352,45 @@ | |
| 347 | ** downstream problems here. We could alternately use "" here. |
| 348 | */ |
| 349 | ; |
| 350 | } |
| 351 | } |
| 352 | |
| 353 | /* |
| 354 | ** SQL function for constant time comparison of two values. |
| 355 | ** Sets result to 0 if two values are equal. |
| 356 | */ |
| @@ -831,10 +871,14 @@ | |
| 831 | } |
| 832 | |
| 833 | /* Set the capabilities */ |
| 834 | login_replace_capabilities(zCap, 0); |
| 835 | login_set_anon_nobody_capabilities(); |
| 836 | } |
| 837 | |
| 838 | /* |
| 839 | ** Memory of settings |
| 840 | */ |
| 841 |
| --- src/login.c | |
| +++ src/login.c | |
| @@ -117,15 +117,20 @@ | |
| 117 | ** But some clients are behind firewalls that shift the IP address |
| 118 | ** with each HTTP request. To allow such (broken) clients to log in, |
| 119 | ** extract just a prefix of the IP address. |
| 120 | */ |
| 121 | static char *ipPrefix(const char *zIP){ |
| 122 | int i, j; |
| 123 | static int ip_prefix_terms = -1; |
| 124 | if( ip_prefix_terms<0 ){ |
| 125 | ip_prefix_terms = db_get_int("ip-prefix-terms",2); |
| 126 | } |
| 127 | if( ip_prefix_terms==0 ) return mprintf("0"); |
| 128 | for(i=j=0; zIP[i]; i++){ |
| 129 | if( zIP[i]=='.' ){ |
| 130 | j++; |
| 131 | if( j==ip_prefix_terms ) break; |
| 132 | } |
| 133 | } |
| 134 | return mprintf("%.*s", i, zIP); |
| 135 | } |
| 136 | |
| @@ -347,10 +352,45 @@ | |
| 352 | ** downstream problems here. We could alternately use "" here. |
| 353 | */ |
| 354 | ; |
| 355 | } |
| 356 | } |
| 357 | |
| 358 | /* |
| 359 | ** Look at the HTTP_USER_AGENT parameter and try to determine if the user agent |
| 360 | ** is a manually operated browser or a bot. When in doubt, assume a bot. Return |
| 361 | ** true if we believe the agent is a real person. |
| 362 | */ |
| 363 | static int isHuman(const char *zAgent){ |
| 364 | int i; |
| 365 | if( zAgent==0 ) return 0; |
| 366 | for(i=0; zAgent[i]; i++){ |
| 367 | if( zAgent[i]=='b' && memcmp(&zAgent[i],"bot",3)==0 ) return 0; |
| 368 | if( zAgent[i]=='s' && memcmp(&zAgent[i],"spider",6)==0 ) return 0; |
| 369 | } |
| 370 | if( memcmp(zAgent, "Mozilla/", 8)==0 ){ |
| 371 | return atoi(&zAgent[8])>=4; |
| 372 | } |
| 373 | if( memcmp(zAgent, "Opera/", 6)==0 ) return 1; |
| 374 | if( memcmp(zAgent, "Safari/", 7)==0 ) return 1; |
| 375 | if( memcmp(zAgent, "Lynx/", 5)==0 ) return 1; |
| 376 | return 0; |
| 377 | } |
| 378 | |
| 379 | /* |
| 380 | ** COMMAND: test-ishuman |
| 381 | ** |
| 382 | ** Read lines of text from standard input. Interpret each line of text |
| 383 | ** as a User-Agent string from an HTTP header. Label each line as HUMAN |
| 384 | ** or ROBOT. |
| 385 | */ |
| 386 | void test_ishuman(void){ |
| 387 | char zLine[3000]; |
| 388 | while( fgets(zLine, sizeof(zLine), stdin) ){ |
| 389 | fossil_print("%s %s", isHuman(zLine) ? "HUMAN" : "ROBOT", zLine); |
| 390 | } |
| 391 | } |
| 392 | |
| 393 | /* |
| 394 | ** SQL function for constant time comparison of two values. |
| 395 | ** Sets result to 0 if two values are equal. |
| 396 | */ |
| @@ -831,10 +871,14 @@ | |
| 871 | } |
| 872 | |
| 873 | /* Set the capabilities */ |
| 874 | login_replace_capabilities(zCap, 0); |
| 875 | login_set_anon_nobody_capabilities(); |
| 876 | if( zCap[0] && !g.perm.History && db_get_boolean("auto-enable-hyperlinks",1) |
| 877 | && isHuman(P("HTTP_USER_AGENT")) ){ |
| 878 | g.perm.History = 1; |
| 879 | } |
| 880 | } |
| 881 | |
| 882 | /* |
| 883 | ** Memory of settings |
| 884 | */ |
| 885 |
+18
| --- src/setup.c | ||
| +++ src/setup.c | ||
| @@ -864,10 +864,17 @@ | ||
| 864 | 864 | "remote_user_ok", "remote_user_ok", 0); |
| 865 | 865 | @ <p>When enabled, if the REMOTE_USER environment variable is set to the |
| 866 | 866 | @ login name of a valid user and no other login credentials are available, |
| 867 | 867 | @ then the REMOTE_USER is accepted as an authenticated user. |
| 868 | 868 | @ </p> |
| 869 | + @ | |
| 870 | + @ <hr /> | |
| 871 | + entry_attribute("IP address turns used in login cookie", 3, "ip-prefix-terms", "ipt", | |
| 872 | + "2"); | |
| 873 | + @ <p>The number of octets of of the IP address used in the login cookie. Set to | |
| 874 | + @ zero to omit the IP address from the login cookie. A value of 2 is recommended. | |
| 875 | + @ </p> | |
| 869 | 876 | @ |
| 870 | 877 | @ <hr /> |
| 871 | 878 | entry_attribute("Login expiration time", 6, "cookie-expire", "cex", "8766"); |
| 872 | 879 | @ <p>The number of hours for which a login is valid. This must be a |
| 873 | 880 | @ positive number. The default is 8760 hours which is approximately equal |
| @@ -879,10 +886,21 @@ | ||
| 879 | 886 | @ <p>Fossil tries to limit out-bound sync, clone, and pull packets |
| 880 | 887 | @ to this many bytes, uncompressed. If the client requires more data |
| 881 | 888 | @ than this, then the client will issue multiple HTTP requests. |
| 882 | 889 | @ Values below 1 million are not recommended. 5 million is a |
| 883 | 890 | @ reasonable number.</p> |
| 891 | + | |
| 892 | + @ <hr /> | |
| 893 | + onoff_attribute("Enable hyperlinks for \"nobody\" based on User-Agent", | |
| 894 | + "auto-enable-hyperlinks", "autohyperlink", 1); | |
| 895 | + @ <p>Enable hyperlinks (the equivalent of the "h" permission) for all users | |
| 896 | + @ including user "nobody", as long as the User-Agent string in the HTTP header | |
| 897 | + @ indicates that the request is coming from an actual human being and not a | |
| 898 | + @ a robot or script. Note: Bots can specify whatever User-Agent string they | |
| 899 | + @ that want. So a bot that wants to impersonate a human can easily do so. | |
| 900 | + @ Hence, this technique does not necessarily exclude malicious bots. | |
| 901 | + @ </p> | |
| 884 | 902 | |
| 885 | 903 | @ <hr /> |
| 886 | 904 | onoff_attribute("Allow users to register themselves", |
| 887 | 905 | "self-register", "selfregister", 0); |
| 888 | 906 | @ <p>Allow users to register themselves through the HTTP UI. |
| 889 | 907 |
| --- src/setup.c | |
| +++ src/setup.c | |
| @@ -864,10 +864,17 @@ | |
| 864 | "remote_user_ok", "remote_user_ok", 0); |
| 865 | @ <p>When enabled, if the REMOTE_USER environment variable is set to the |
| 866 | @ login name of a valid user and no other login credentials are available, |
| 867 | @ then the REMOTE_USER is accepted as an authenticated user. |
| 868 | @ </p> |
| 869 | @ |
| 870 | @ <hr /> |
| 871 | entry_attribute("Login expiration time", 6, "cookie-expire", "cex", "8766"); |
| 872 | @ <p>The number of hours for which a login is valid. This must be a |
| 873 | @ positive number. The default is 8760 hours which is approximately equal |
| @@ -879,10 +886,21 @@ | |
| 879 | @ <p>Fossil tries to limit out-bound sync, clone, and pull packets |
| 880 | @ to this many bytes, uncompressed. If the client requires more data |
| 881 | @ than this, then the client will issue multiple HTTP requests. |
| 882 | @ Values below 1 million are not recommended. 5 million is a |
| 883 | @ reasonable number.</p> |
| 884 | |
| 885 | @ <hr /> |
| 886 | onoff_attribute("Allow users to register themselves", |
| 887 | "self-register", "selfregister", 0); |
| 888 | @ <p>Allow users to register themselves through the HTTP UI. |
| 889 |
| --- src/setup.c | |
| +++ src/setup.c | |
| @@ -864,10 +864,17 @@ | |
| 864 | "remote_user_ok", "remote_user_ok", 0); |
| 865 | @ <p>When enabled, if the REMOTE_USER environment variable is set to the |
| 866 | @ login name of a valid user and no other login credentials are available, |
| 867 | @ then the REMOTE_USER is accepted as an authenticated user. |
| 868 | @ </p> |
| 869 | @ |
| 870 | @ <hr /> |
| 871 | entry_attribute("IP address turns used in login cookie", 3, "ip-prefix-terms", "ipt", |
| 872 | "2"); |
| 873 | @ <p>The number of octets of of the IP address used in the login cookie. Set to |
| 874 | @ zero to omit the IP address from the login cookie. A value of 2 is recommended. |
| 875 | @ </p> |
| 876 | @ |
| 877 | @ <hr /> |
| 878 | entry_attribute("Login expiration time", 6, "cookie-expire", "cex", "8766"); |
| 879 | @ <p>The number of hours for which a login is valid. This must be a |
| 880 | @ positive number. The default is 8760 hours which is approximately equal |
| @@ -879,10 +886,21 @@ | |
| 886 | @ <p>Fossil tries to limit out-bound sync, clone, and pull packets |
| 887 | @ to this many bytes, uncompressed. If the client requires more data |
| 888 | @ than this, then the client will issue multiple HTTP requests. |
| 889 | @ Values below 1 million are not recommended. 5 million is a |
| 890 | @ reasonable number.</p> |
| 891 | |
| 892 | @ <hr /> |
| 893 | onoff_attribute("Enable hyperlinks for \"nobody\" based on User-Agent", |
| 894 | "auto-enable-hyperlinks", "autohyperlink", 1); |
| 895 | @ <p>Enable hyperlinks (the equivalent of the "h" permission) for all users |
| 896 | @ including user "nobody", as long as the User-Agent string in the HTTP header |
| 897 | @ indicates that the request is coming from an actual human being and not a |
| 898 | @ a robot or script. Note: Bots can specify whatever User-Agent string they |
| 899 | @ that want. So a bot that wants to impersonate a human can easily do so. |
| 900 | @ Hence, this technique does not necessarily exclude malicious bots. |
| 901 | @ </p> |
| 902 | |
| 903 | @ <hr /> |
| 904 | onoff_attribute("Allow users to register themselves", |
| 905 | "self-register", "selfregister", 0); |
| 906 | @ <p>Allow users to register themselves through the HTTP UI. |
| 907 |