Fossil SCM
Optionally require a CAPTCHA (controlled by Admin/Access) when a user who is not logged in tries to edit wiki, or a ticket, or an attachment.
Commit
82b8587a502f32e9e4a76a3312c55057bcfd1538
Parent
a460326337fc290…
6 files changed
+8
-2
+53
+7
-1
+1
+8
-2
+19
-4
+8
-2
| --- src/attach.c | ||
| +++ src/attach.c | ||
| @@ -236,10 +236,11 @@ | ||
| 236 | 236 | const char *aContent = P("f"); |
| 237 | 237 | const char *zName = PD("f:filename","unknown"); |
| 238 | 238 | const char *zTarget; |
| 239 | 239 | const char *zTargetType; |
| 240 | 240 | int szContent = atoi(PD("f:bytes","0")); |
| 241 | + int goodCaptcha = 1; | |
| 241 | 242 | |
| 242 | 243 | if( P("cancel") ) cgi_redirect(zFrom); |
| 243 | 244 | if( zPage && zTkt ) fossil_redirect_home(); |
| 244 | 245 | if( zPage==0 && zTkt==0 ) fossil_redirect_home(); |
| 245 | 246 | login_check_credentials(); |
| @@ -264,11 +265,11 @@ | ||
| 264 | 265 | } |
| 265 | 266 | if( zFrom==0 ) zFrom = mprintf("%s/home", g.zTop); |
| 266 | 267 | if( P("cancel") ){ |
| 267 | 268 | cgi_redirect(zFrom); |
| 268 | 269 | } |
| 269 | - if( P("ok") && szContent>0 ){ | |
| 270 | + if( P("ok") && szContent>0 && (goodCaptcha = captcha_is_correct()) ){ | |
| 270 | 271 | Blob content; |
| 271 | 272 | Blob manifest; |
| 272 | 273 | Blob cksum; |
| 273 | 274 | char *zUUID; |
| 274 | 275 | const char *zComment; |
| @@ -317,10 +318,13 @@ | ||
| 317 | 318 | assert( blob_is_reset(&manifest) ); |
| 318 | 319 | db_end_transaction(0); |
| 319 | 320 | cgi_redirect(zFrom); |
| 320 | 321 | } |
| 321 | 322 | style_header("Add Attachment"); |
| 323 | + if( !goodCaptcha ){ | |
| 324 | + @ <p class="generalError">Error: Incorrect security code.</p> | |
| 325 | + } | |
| 322 | 326 | @ <h2>Add Attachment To %s(zTargetType)</h2> |
| 323 | 327 | form_begin("enctype='multipart/form-data'", "%R/attachadd"); |
| 324 | 328 | @ <div> |
| 325 | 329 | @ File to Attach: |
| 326 | 330 | @ <input type="file" name="f" size="60" /><br /> |
| @@ -332,11 +336,13 @@ | ||
| 332 | 336 | @ <input type="hidden" name="page" value="%h(zPage)" /> |
| 333 | 337 | } |
| 334 | 338 | @ <input type="hidden" name="from" value="%h(zFrom)" /> |
| 335 | 339 | @ <input type="submit" name="ok" value="Add Attachment" /> |
| 336 | 340 | @ <input type="submit" name="cancel" value="Cancel" /> |
| 337 | - @ </div></form> | |
| 341 | + @ </div> | |
| 342 | + captcha_generate(); | |
| 343 | + @ </form> | |
| 338 | 344 | style_footer(); |
| 339 | 345 | } |
| 340 | 346 | |
| 341 | 347 | /* |
| 342 | 348 | ** WEBPAGE: ainfo |
| 343 | 349 |
| --- src/attach.c | |
| +++ src/attach.c | |
| @@ -236,10 +236,11 @@ | |
| 236 | const char *aContent = P("f"); |
| 237 | const char *zName = PD("f:filename","unknown"); |
| 238 | const char *zTarget; |
| 239 | const char *zTargetType; |
| 240 | int szContent = atoi(PD("f:bytes","0")); |
| 241 | |
| 242 | if( P("cancel") ) cgi_redirect(zFrom); |
| 243 | if( zPage && zTkt ) fossil_redirect_home(); |
| 244 | if( zPage==0 && zTkt==0 ) fossil_redirect_home(); |
| 245 | login_check_credentials(); |
| @@ -264,11 +265,11 @@ | |
| 264 | } |
| 265 | if( zFrom==0 ) zFrom = mprintf("%s/home", g.zTop); |
| 266 | if( P("cancel") ){ |
| 267 | cgi_redirect(zFrom); |
| 268 | } |
| 269 | if( P("ok") && szContent>0 ){ |
| 270 | Blob content; |
| 271 | Blob manifest; |
| 272 | Blob cksum; |
| 273 | char *zUUID; |
| 274 | const char *zComment; |
| @@ -317,10 +318,13 @@ | |
| 317 | assert( blob_is_reset(&manifest) ); |
| 318 | db_end_transaction(0); |
| 319 | cgi_redirect(zFrom); |
| 320 | } |
| 321 | style_header("Add Attachment"); |
| 322 | @ <h2>Add Attachment To %s(zTargetType)</h2> |
| 323 | form_begin("enctype='multipart/form-data'", "%R/attachadd"); |
| 324 | @ <div> |
| 325 | @ File to Attach: |
| 326 | @ <input type="file" name="f" size="60" /><br /> |
| @@ -332,11 +336,13 @@ | |
| 332 | @ <input type="hidden" name="page" value="%h(zPage)" /> |
| 333 | } |
| 334 | @ <input type="hidden" name="from" value="%h(zFrom)" /> |
| 335 | @ <input type="submit" name="ok" value="Add Attachment" /> |
| 336 | @ <input type="submit" name="cancel" value="Cancel" /> |
| 337 | @ </div></form> |
| 338 | style_footer(); |
| 339 | } |
| 340 | |
| 341 | /* |
| 342 | ** WEBPAGE: ainfo |
| 343 |
| --- src/attach.c | |
| +++ src/attach.c | |
| @@ -236,10 +236,11 @@ | |
| 236 | const char *aContent = P("f"); |
| 237 | const char *zName = PD("f:filename","unknown"); |
| 238 | const char *zTarget; |
| 239 | const char *zTargetType; |
| 240 | int szContent = atoi(PD("f:bytes","0")); |
| 241 | int goodCaptcha = 1; |
| 242 | |
| 243 | if( P("cancel") ) cgi_redirect(zFrom); |
| 244 | if( zPage && zTkt ) fossil_redirect_home(); |
| 245 | if( zPage==0 && zTkt==0 ) fossil_redirect_home(); |
| 246 | login_check_credentials(); |
| @@ -264,11 +265,11 @@ | |
| 265 | } |
| 266 | if( zFrom==0 ) zFrom = mprintf("%s/home", g.zTop); |
| 267 | if( P("cancel") ){ |
| 268 | cgi_redirect(zFrom); |
| 269 | } |
| 270 | if( P("ok") && szContent>0 && (goodCaptcha = captcha_is_correct()) ){ |
| 271 | Blob content; |
| 272 | Blob manifest; |
| 273 | Blob cksum; |
| 274 | char *zUUID; |
| 275 | const char *zComment; |
| @@ -317,10 +318,13 @@ | |
| 318 | assert( blob_is_reset(&manifest) ); |
| 319 | db_end_transaction(0); |
| 320 | cgi_redirect(zFrom); |
| 321 | } |
| 322 | style_header("Add Attachment"); |
| 323 | if( !goodCaptcha ){ |
| 324 | @ <p class="generalError">Error: Incorrect security code.</p> |
| 325 | } |
| 326 | @ <h2>Add Attachment To %s(zTargetType)</h2> |
| 327 | form_begin("enctype='multipart/form-data'", "%R/attachadd"); |
| 328 | @ <div> |
| 329 | @ File to Attach: |
| 330 | @ <input type="file" name="f" size="60" /><br /> |
| @@ -332,11 +336,13 @@ | |
| 336 | @ <input type="hidden" name="page" value="%h(zPage)" /> |
| 337 | } |
| 338 | @ <input type="hidden" name="from" value="%h(zFrom)" /> |
| 339 | @ <input type="submit" name="ok" value="Add Attachment" /> |
| 340 | @ <input type="submit" name="cancel" value="Cancel" /> |
| 341 | @ </div> |
| 342 | captcha_generate(); |
| 343 | @ </form> |
| 344 | style_footer(); |
| 345 | } |
| 346 | |
| 347 | /* |
| 348 | ** WEBPAGE: ainfo |
| 349 |
+53
| --- src/captcha.c | ||
| +++ src/captcha.c | ||
| @@ -438,5 +438,58 @@ | ||
| 438 | 438 | z = blob_buffer(&b); |
| 439 | 439 | memcpy(zRes, z, 8); |
| 440 | 440 | zRes[8] = 0; |
| 441 | 441 | return zRes; |
| 442 | 442 | } |
| 443 | + | |
| 444 | +/* | |
| 445 | +** Return true if a CAPTCHA is required. | |
| 446 | +*/ | |
| 447 | +int captcha_needed(void){ | |
| 448 | + if( g.zLogin!=0 ) return 0; | |
| 449 | + return db_get_boolean("require-captcha", 1); | |
| 450 | +} | |
| 451 | + | |
| 452 | +/* | |
| 453 | +** If a captcha is required but the correct captcha code is not supplied | |
| 454 | +** in the query parameters, then return false (0). | |
| 455 | +** | |
| 456 | +** If no captcha is required or if the correct captcha is supplied, return | |
| 457 | +** true (non-zero). | |
| 458 | +*/ | |
| 459 | +int captcha_is_correct(void){ | |
| 460 | + const char *zSeed; | |
| 461 | + const char *zEntered; | |
| 462 | + const char *zDecode; | |
| 463 | + if( !captcha_needed() ){ | |
| 464 | + return 1; /* No captcha needed */ | |
| 465 | + } | |
| 466 | + zSeed = P("captchaseed"); | |
| 467 | + if( zSeed==0 ) return 0; | |
| 468 | + zEntered = P("captcha"); | |
| 469 | + if( zEntered==0 || strlen(zEntered)!=8 ) return 0; | |
| 470 | + zDecode = captcha_decode((unsigned int)atoi(zSeed)); | |
| 471 | + if( strcmp(zDecode,zEntered)!=0 ) return 0; | |
| 472 | + return 1; | |
| 473 | +} | |
| 474 | + | |
| 475 | +/* | |
| 476 | +** Generate a new CAPTCHA seed. Write it as a hidden variable named | |
| 477 | +** "captchaseed". Then return the rendered captcha text. | |
| 478 | +*/ | |
| 479 | +void captcha_generate(void){ | |
| 480 | + unsigned int uSeed; | |
| 481 | + const char *zDecoded; | |
| 482 | + char *zCaptcha; | |
| 483 | + | |
| 484 | + if( !captcha_needed() ) return; | |
| 485 | + uSeed = captcha_seed(); | |
| 486 | + zDecoded = captcha_decode(uSeed); | |
| 487 | + zCaptcha = captcha_render(zDecoded); | |
| 488 | + @ <div class="captcha"><table class="captcha"><tr><td><pre> | |
| 489 | + @ %h(zCaptcha) | |
| 490 | + @ </pre> | |
| 491 | + @ Enter security code shown above: | |
| 492 | + @ <input type="hidden" name="captchaseed" value="%u(uSeed)" /> | |
| 493 | + @ <input type="text" name="captcha" size=8 /> | |
| 494 | + @ </td></tr></table></div> | |
| 495 | +} | |
| 443 | 496 |
| --- src/captcha.c | |
| +++ src/captcha.c | |
| @@ -438,5 +438,58 @@ | |
| 438 | z = blob_buffer(&b); |
| 439 | memcpy(zRes, z, 8); |
| 440 | zRes[8] = 0; |
| 441 | return zRes; |
| 442 | } |
| 443 |
| --- src/captcha.c | |
| +++ src/captcha.c | |
| @@ -438,5 +438,58 @@ | |
| 438 | z = blob_buffer(&b); |
| 439 | memcpy(zRes, z, 8); |
| 440 | zRes[8] = 0; |
| 441 | return zRes; |
| 442 | } |
| 443 | |
| 444 | /* |
| 445 | ** Return true if a CAPTCHA is required. |
| 446 | */ |
| 447 | int captcha_needed(void){ |
| 448 | if( g.zLogin!=0 ) return 0; |
| 449 | return db_get_boolean("require-captcha", 1); |
| 450 | } |
| 451 | |
| 452 | /* |
| 453 | ** If a captcha is required but the correct captcha code is not supplied |
| 454 | ** in the query parameters, then return false (0). |
| 455 | ** |
| 456 | ** If no captcha is required or if the correct captcha is supplied, return |
| 457 | ** true (non-zero). |
| 458 | */ |
| 459 | int captcha_is_correct(void){ |
| 460 | const char *zSeed; |
| 461 | const char *zEntered; |
| 462 | const char *zDecode; |
| 463 | if( !captcha_needed() ){ |
| 464 | return 1; /* No captcha needed */ |
| 465 | } |
| 466 | zSeed = P("captchaseed"); |
| 467 | if( zSeed==0 ) return 0; |
| 468 | zEntered = P("captcha"); |
| 469 | if( zEntered==0 || strlen(zEntered)!=8 ) return 0; |
| 470 | zDecode = captcha_decode((unsigned int)atoi(zSeed)); |
| 471 | if( strcmp(zDecode,zEntered)!=0 ) return 0; |
| 472 | return 1; |
| 473 | } |
| 474 | |
| 475 | /* |
| 476 | ** Generate a new CAPTCHA seed. Write it as a hidden variable named |
| 477 | ** "captchaseed". Then return the rendered captcha text. |
| 478 | */ |
| 479 | void captcha_generate(void){ |
| 480 | unsigned int uSeed; |
| 481 | const char *zDecoded; |
| 482 | char *zCaptcha; |
| 483 | |
| 484 | if( !captcha_needed() ) return; |
| 485 | uSeed = captcha_seed(); |
| 486 | zDecoded = captcha_decode(uSeed); |
| 487 | zCaptcha = captcha_render(zDecoded); |
| 488 | @ <div class="captcha"><table class="captcha"><tr><td><pre> |
| 489 | @ %h(zCaptcha) |
| 490 | @ </pre> |
| 491 | @ Enter security code shown above: |
| 492 | @ <input type="hidden" name="captchaseed" value="%u(uSeed)" /> |
| 493 | @ <input type="text" name="captcha" size=8 /> |
| 494 | @ </td></tr></table></div> |
| 495 | } |
| 496 |
+7
-1
| --- src/setup.c | ||
| +++ src/setup.c | ||
| @@ -934,10 +934,17 @@ | ||
| 934 | 934 | @ if it does, your server will end up computing diffs and annotations for |
| 935 | 935 | @ every historical version of every file and creating ZIPs and tarballs of |
| 936 | 936 | @ every historical check-in, which can use a lot of CPU and bandwidth |
| 937 | 937 | @ even for relatively small projects.</p> |
| 938 | 938 | |
| 939 | + @ <hr /> | |
| 940 | + onoff_attribute("Require a CAPTCHA if not logged in", | |
| 941 | + "require-captcha", "reqcapt", 1); | |
| 942 | + @ <p>Require a CAPTCHA for edit operations (appending, creating, or | |
| 943 | + @ editing wiki or tickets or adding attachments to wiki or tickets) | |
| 944 | + @ for users who are not logged in.</p> | |
| 945 | + | |
| 939 | 946 | @ <hr /> |
| 940 | 947 | entry_attribute("Public pages", 30, "public-pages", |
| 941 | 948 | "pubpage", ""); |
| 942 | 949 | @ <p>A comma-separated list of glob patterns for pages that are accessible |
| 943 | 950 | @ without needing a login and using the privileges given by the |
| @@ -944,11 +951,10 @@ | ||
| 944 | 951 | @ "Default privileges" setting below. Example use case: Set this field |
| 945 | 952 | @ to "/doc/trunk/www/*" to give anonymous users read-only permission to the |
| 946 | 953 | @ latest version of the embedded documentation in the www/ folder without |
| 947 | 954 | @ allowing them to see the rest of the source code. |
| 948 | 955 | @ </p> |
| 949 | - | |
| 950 | 956 | |
| 951 | 957 | @ <hr /> |
| 952 | 958 | onoff_attribute("Allow users to register themselves", |
| 953 | 959 | "self-register", "selfregister", 0); |
| 954 | 960 | @ <p>Allow users to register themselves through the HTTP UI. |
| 955 | 961 |
| --- src/setup.c | |
| +++ src/setup.c | |
| @@ -934,10 +934,17 @@ | |
| 934 | @ if it does, your server will end up computing diffs and annotations for |
| 935 | @ every historical version of every file and creating ZIPs and tarballs of |
| 936 | @ every historical check-in, which can use a lot of CPU and bandwidth |
| 937 | @ even for relatively small projects.</p> |
| 938 | |
| 939 | @ <hr /> |
| 940 | entry_attribute("Public pages", 30, "public-pages", |
| 941 | "pubpage", ""); |
| 942 | @ <p>A comma-separated list of glob patterns for pages that are accessible |
| 943 | @ without needing a login and using the privileges given by the |
| @@ -944,11 +951,10 @@ | |
| 944 | @ "Default privileges" setting below. Example use case: Set this field |
| 945 | @ to "/doc/trunk/www/*" to give anonymous users read-only permission to the |
| 946 | @ latest version of the embedded documentation in the www/ folder without |
| 947 | @ allowing them to see the rest of the source code. |
| 948 | @ </p> |
| 949 | |
| 950 | |
| 951 | @ <hr /> |
| 952 | onoff_attribute("Allow users to register themselves", |
| 953 | "self-register", "selfregister", 0); |
| 954 | @ <p>Allow users to register themselves through the HTTP UI. |
| 955 |
| --- src/setup.c | |
| +++ src/setup.c | |
| @@ -934,10 +934,17 @@ | |
| 934 | @ if it does, your server will end up computing diffs and annotations for |
| 935 | @ every historical version of every file and creating ZIPs and tarballs of |
| 936 | @ every historical check-in, which can use a lot of CPU and bandwidth |
| 937 | @ even for relatively small projects.</p> |
| 938 | |
| 939 | @ <hr /> |
| 940 | onoff_attribute("Require a CAPTCHA if not logged in", |
| 941 | "require-captcha", "reqcapt", 1); |
| 942 | @ <p>Require a CAPTCHA for edit operations (appending, creating, or |
| 943 | @ editing wiki or tickets or adding attachments to wiki or tickets) |
| 944 | @ for users who are not logged in.</p> |
| 945 | |
| 946 | @ <hr /> |
| 947 | entry_attribute("Public pages", 30, "public-pages", |
| 948 | "pubpage", ""); |
| 949 | @ <p>A comma-separated list of glob patterns for pages that are accessible |
| 950 | @ without needing a login and using the privileges given by the |
| @@ -944,11 +951,10 @@ | |
| 951 | @ "Default privileges" setting below. Example use case: Set this field |
| 952 | @ to "/doc/trunk/www/*" to give anonymous users read-only permission to the |
| 953 | @ latest version of the embedded documentation in the www/ folder without |
| 954 | @ allowing them to see the rest of the source code. |
| 955 | @ </p> |
| 956 | |
| 957 | @ <hr /> |
| 958 | onoff_attribute("Allow users to register themselves", |
| 959 | "self-register", "selfregister", 0); |
| 960 | @ <p>Allow users to register themselves through the HTTP UI. |
| 961 |
+1
| --- src/style.c | ||
| +++ src/style.c | ||
| @@ -712,10 +712,11 @@ | ||
| 712 | 712 | @ margin-top: 10px; |
| 713 | 713 | }, |
| 714 | 714 | { "div.captcha", |
| 715 | 715 | "captcha display options", |
| 716 | 716 | @ text-align: center; |
| 717 | + @ padding: 1ex; | |
| 717 | 718 | }, |
| 718 | 719 | { "table.captcha", |
| 719 | 720 | "format for the layout table, used for the captcha display", |
| 720 | 721 | @ margin: auto; |
| 721 | 722 | @ padding: 10px; |
| 722 | 723 |
| --- src/style.c | |
| +++ src/style.c | |
| @@ -712,10 +712,11 @@ | |
| 712 | @ margin-top: 10px; |
| 713 | }, |
| 714 | { "div.captcha", |
| 715 | "captcha display options", |
| 716 | @ text-align: center; |
| 717 | }, |
| 718 | { "table.captcha", |
| 719 | "format for the layout table, used for the captcha display", |
| 720 | @ margin: auto; |
| 721 | @ padding: 10px; |
| 722 |
| --- src/style.c | |
| +++ src/style.c | |
| @@ -712,10 +712,11 @@ | |
| 712 | @ margin-top: 10px; |
| 713 | }, |
| 714 | { "div.captcha", |
| 715 | "captcha display options", |
| 716 | @ text-align: center; |
| 717 | @ padding: 1ex; |
| 718 | }, |
| 719 | { "table.captcha", |
| 720 | "format for the layout table, used for the captcha display", |
| 721 | @ margin: auto; |
| 722 | @ padding: 10px; |
| 723 |
+8
-2
| --- src/tkt.c | ||
| +++ src/tkt.c | ||
| @@ -430,10 +430,14 @@ | ||
| 430 | 430 | int i; |
| 431 | 431 | int nJ = 0; |
| 432 | 432 | Blob tktchng, cksum; |
| 433 | 433 | |
| 434 | 434 | login_verify_csrf_secret(); |
| 435 | + if( !captcha_is_correct() ){ | |
| 436 | + @ <p class="generalError">Error: Incorrect security code.</p> | |
| 437 | + return TH_OK; | |
| 438 | + } | |
| 435 | 439 | zUuid = (const char *)pUuid; |
| 436 | 440 | blob_zero(&tktchng); |
| 437 | 441 | zDate = date_in_standard_format("now"); |
| 438 | 442 | blob_appendf(&tktchng, "D %s\n", zDate); |
| 439 | 443 | free(zDate); |
| @@ -529,19 +533,20 @@ | ||
| 529 | 533 | if( P("date_override") && g.perm.Setup ){ |
| 530 | 534 | @ <input type="hidden" name="date_override" value="%h(P("date_override"))"> |
| 531 | 535 | } |
| 532 | 536 | @ </p> |
| 533 | 537 | zScript = ticket_newpage_code(); |
| 534 | - Th_Store("login", g.zLogin); | |
| 538 | + Th_Store("login", g.zLogin ? g.zLogin : "nobody"); | |
| 535 | 539 | Th_Store("date", db_text(0, "SELECT datetime('now')")); |
| 536 | 540 | Th_CreateCommand(g.interp, "submit_ticket", submitTicketCmd, |
| 537 | 541 | (void*)&zNewUuid, 0); |
| 538 | 542 | if( g.thTrace ) Th_Trace("BEGIN_TKTNEW_SCRIPT<br />\n", -1); |
| 539 | 543 | if( Th_Render(zScript)==TH_RETURN && !g.thTrace && zNewUuid ){ |
| 540 | 544 | cgi_redirect(mprintf("%s/tktview/%s", g.zTop, zNewUuid)); |
| 541 | 545 | return; |
| 542 | 546 | } |
| 547 | + captcha_generate(); | |
| 543 | 548 | @ </form> |
| 544 | 549 | if( g.thTrace ) Th_Trace("END_TKTVIEW<br />\n", -1); |
| 545 | 550 | style_footer(); |
| 546 | 551 | } |
| 547 | 552 | |
| @@ -596,19 +601,20 @@ | ||
| 596 | 601 | form_begin(0, "%R/%s", g.zPath); |
| 597 | 602 | @ <input type="hidden" name="name" value="%s(zName)" /> |
| 598 | 603 | login_insert_csrf_secret(); |
| 599 | 604 | @ </p> |
| 600 | 605 | zScript = ticket_editpage_code(); |
| 601 | - Th_Store("login", g.zLogin); | |
| 606 | + Th_Store("login", g.zLogin ? g.zLogin : "nobody"); | |
| 602 | 607 | Th_Store("date", db_text(0, "SELECT datetime('now')")); |
| 603 | 608 | Th_CreateCommand(g.interp, "append_field", appendRemarkCmd, 0, 0); |
| 604 | 609 | Th_CreateCommand(g.interp, "submit_ticket", submitTicketCmd, (void*)&zName,0); |
| 605 | 610 | if( g.thTrace ) Th_Trace("BEGIN_TKTEDIT_SCRIPT<br />\n", -1); |
| 606 | 611 | if( Th_Render(zScript)==TH_RETURN && !g.thTrace && zName ){ |
| 607 | 612 | cgi_redirect(mprintf("%s/tktview/%s", g.zTop, zName)); |
| 608 | 613 | return; |
| 609 | 614 | } |
| 615 | + captcha_generate(); | |
| 610 | 616 | @ </form> |
| 611 | 617 | if( g.thTrace ) Th_Trace("BEGIN_TKTEDIT<br />\n", -1); |
| 612 | 618 | style_footer(); |
| 613 | 619 | } |
| 614 | 620 | |
| 615 | 621 |
| --- src/tkt.c | |
| +++ src/tkt.c | |
| @@ -430,10 +430,14 @@ | |
| 430 | int i; |
| 431 | int nJ = 0; |
| 432 | Blob tktchng, cksum; |
| 433 | |
| 434 | login_verify_csrf_secret(); |
| 435 | zUuid = (const char *)pUuid; |
| 436 | blob_zero(&tktchng); |
| 437 | zDate = date_in_standard_format("now"); |
| 438 | blob_appendf(&tktchng, "D %s\n", zDate); |
| 439 | free(zDate); |
| @@ -529,19 +533,20 @@ | |
| 529 | if( P("date_override") && g.perm.Setup ){ |
| 530 | @ <input type="hidden" name="date_override" value="%h(P("date_override"))"> |
| 531 | } |
| 532 | @ </p> |
| 533 | zScript = ticket_newpage_code(); |
| 534 | Th_Store("login", g.zLogin); |
| 535 | Th_Store("date", db_text(0, "SELECT datetime('now')")); |
| 536 | Th_CreateCommand(g.interp, "submit_ticket", submitTicketCmd, |
| 537 | (void*)&zNewUuid, 0); |
| 538 | if( g.thTrace ) Th_Trace("BEGIN_TKTNEW_SCRIPT<br />\n", -1); |
| 539 | if( Th_Render(zScript)==TH_RETURN && !g.thTrace && zNewUuid ){ |
| 540 | cgi_redirect(mprintf("%s/tktview/%s", g.zTop, zNewUuid)); |
| 541 | return; |
| 542 | } |
| 543 | @ </form> |
| 544 | if( g.thTrace ) Th_Trace("END_TKTVIEW<br />\n", -1); |
| 545 | style_footer(); |
| 546 | } |
| 547 | |
| @@ -596,19 +601,20 @@ | |
| 596 | form_begin(0, "%R/%s", g.zPath); |
| 597 | @ <input type="hidden" name="name" value="%s(zName)" /> |
| 598 | login_insert_csrf_secret(); |
| 599 | @ </p> |
| 600 | zScript = ticket_editpage_code(); |
| 601 | Th_Store("login", g.zLogin); |
| 602 | Th_Store("date", db_text(0, "SELECT datetime('now')")); |
| 603 | Th_CreateCommand(g.interp, "append_field", appendRemarkCmd, 0, 0); |
| 604 | Th_CreateCommand(g.interp, "submit_ticket", submitTicketCmd, (void*)&zName,0); |
| 605 | if( g.thTrace ) Th_Trace("BEGIN_TKTEDIT_SCRIPT<br />\n", -1); |
| 606 | if( Th_Render(zScript)==TH_RETURN && !g.thTrace && zName ){ |
| 607 | cgi_redirect(mprintf("%s/tktview/%s", g.zTop, zName)); |
| 608 | return; |
| 609 | } |
| 610 | @ </form> |
| 611 | if( g.thTrace ) Th_Trace("BEGIN_TKTEDIT<br />\n", -1); |
| 612 | style_footer(); |
| 613 | } |
| 614 | |
| 615 |
| --- src/tkt.c | |
| +++ src/tkt.c | |
| @@ -430,10 +430,14 @@ | |
| 430 | int i; |
| 431 | int nJ = 0; |
| 432 | Blob tktchng, cksum; |
| 433 | |
| 434 | login_verify_csrf_secret(); |
| 435 | if( !captcha_is_correct() ){ |
| 436 | @ <p class="generalError">Error: Incorrect security code.</p> |
| 437 | return TH_OK; |
| 438 | } |
| 439 | zUuid = (const char *)pUuid; |
| 440 | blob_zero(&tktchng); |
| 441 | zDate = date_in_standard_format("now"); |
| 442 | blob_appendf(&tktchng, "D %s\n", zDate); |
| 443 | free(zDate); |
| @@ -529,19 +533,20 @@ | |
| 533 | if( P("date_override") && g.perm.Setup ){ |
| 534 | @ <input type="hidden" name="date_override" value="%h(P("date_override"))"> |
| 535 | } |
| 536 | @ </p> |
| 537 | zScript = ticket_newpage_code(); |
| 538 | Th_Store("login", g.zLogin ? g.zLogin : "nobody"); |
| 539 | Th_Store("date", db_text(0, "SELECT datetime('now')")); |
| 540 | Th_CreateCommand(g.interp, "submit_ticket", submitTicketCmd, |
| 541 | (void*)&zNewUuid, 0); |
| 542 | if( g.thTrace ) Th_Trace("BEGIN_TKTNEW_SCRIPT<br />\n", -1); |
| 543 | if( Th_Render(zScript)==TH_RETURN && !g.thTrace && zNewUuid ){ |
| 544 | cgi_redirect(mprintf("%s/tktview/%s", g.zTop, zNewUuid)); |
| 545 | return; |
| 546 | } |
| 547 | captcha_generate(); |
| 548 | @ </form> |
| 549 | if( g.thTrace ) Th_Trace("END_TKTVIEW<br />\n", -1); |
| 550 | style_footer(); |
| 551 | } |
| 552 | |
| @@ -596,19 +601,20 @@ | |
| 601 | form_begin(0, "%R/%s", g.zPath); |
| 602 | @ <input type="hidden" name="name" value="%s(zName)" /> |
| 603 | login_insert_csrf_secret(); |
| 604 | @ </p> |
| 605 | zScript = ticket_editpage_code(); |
| 606 | Th_Store("login", g.zLogin ? g.zLogin : "nobody"); |
| 607 | Th_Store("date", db_text(0, "SELECT datetime('now')")); |
| 608 | Th_CreateCommand(g.interp, "append_field", appendRemarkCmd, 0, 0); |
| 609 | Th_CreateCommand(g.interp, "submit_ticket", submitTicketCmd, (void*)&zName,0); |
| 610 | if( g.thTrace ) Th_Trace("BEGIN_TKTEDIT_SCRIPT<br />\n", -1); |
| 611 | if( Th_Render(zScript)==TH_RETURN && !g.thTrace && zName ){ |
| 612 | cgi_redirect(mprintf("%s/tktview/%s", g.zTop, zName)); |
| 613 | return; |
| 614 | } |
| 615 | captcha_generate(); |
| 616 | @ </form> |
| 617 | if( g.thTrace ) Th_Trace("BEGIN_TKTEDIT<br />\n", -1); |
| 618 | style_footer(); |
| 619 | } |
| 620 | |
| 621 |
+19
-4
| --- src/wiki.c | ||
| +++ src/wiki.c | ||
| @@ -263,10 +263,11 @@ | ||
| 263 | 263 | const char *zPageName; |
| 264 | 264 | int n; |
| 265 | 265 | const char *z; |
| 266 | 266 | char *zBody = (char*)P("w"); |
| 267 | 267 | int isWysiwyg = P("wysiwyg")!=0; |
| 268 | + int goodCaptcha = 1; | |
| 268 | 269 | |
| 269 | 270 | if( P("edit-wysiwyg")!=0 ){ isWysiwyg = 1; zBody = 0; } |
| 270 | 271 | if( P("edit-markup")!=0 ){ isWysiwyg = 0; zBody = 0; } |
| 271 | 272 | if( zBody ){ |
| 272 | 273 | if( isWysiwyg ){ |
| @@ -304,11 +305,13 @@ | ||
| 304 | 305 | } |
| 305 | 306 | if( zBody==0 && (pWiki = manifest_get(rid, CFTYPE_WIKI))!=0 ){ |
| 306 | 307 | zBody = pWiki->zWiki; |
| 307 | 308 | } |
| 308 | 309 | } |
| 309 | - if( P("submit")!=0 && zBody!=0 ){ | |
| 310 | + if( P("submit")!=0 && zBody!=0 | |
| 311 | + && (goodCaptcha = captcha_is_correct()) | |
| 312 | + ){ | |
| 310 | 313 | char *zDate; |
| 311 | 314 | Blob cksum; |
| 312 | 315 | blob_zero(&wiki); |
| 313 | 316 | db_begin_transaction(); |
| 314 | 317 | if( isSandbox ){ |
| @@ -343,10 +346,13 @@ | ||
| 343 | 346 | if( zBody==0 ){ |
| 344 | 347 | zBody = mprintf("<i>Empty Page</i>"); |
| 345 | 348 | } |
| 346 | 349 | style_set_current_page("%s?name=%T", g.zPath, zPageName); |
| 347 | 350 | style_header("Edit: %s", zPageName); |
| 351 | + if( !goodCaptcha ){ | |
| 352 | + @ <p class="generalError">Error: Incorrect security code.</p> | |
| 353 | + } | |
| 348 | 354 | blob_zero(&wiki); |
| 349 | 355 | blob_append(&wiki, zBody, -1); |
| 350 | 356 | if( P("preview")!=0 ){ |
| 351 | 357 | @ Preview:<hr /> |
| 352 | 358 | wiki_convert(&wiki, 0, 0); |
| @@ -385,16 +391,18 @@ | ||
| 385 | 391 | blob_reset(&html); |
| 386 | 392 | @ <br /> |
| 387 | 393 | @ <input type="submit" name="edit-markup" value="Markup Editor" |
| 388 | 394 | @ onclick='return confirm("Switching to markup-mode\nwill erase your WYSIWYG\nedits. Continue?")' /> |
| 389 | 395 | } |
| 390 | - @ <input type="submit" name="submit" value="Apply These Changes" /> | |
| 391 | 396 | login_insert_csrf_secret(); |
| 397 | + @ <input type="submit" name="submit" value="Apply These Changes" /> | |
| 392 | 398 | @ <input type="hidden" name="name" value="%h(zPageName)" /> |
| 393 | 399 | @ <input type="submit" name="cancel" value="Cancel" |
| 394 | 400 | @ onclick='confirm("Abandon your changes?")' /> |
| 395 | - @ </div></form> | |
| 401 | + @ </div> | |
| 402 | + captcha_generate(); | |
| 403 | + @ </form> | |
| 396 | 404 | manifest_destroy(pWiki); |
| 397 | 405 | blob_reset(&wiki); |
| 398 | 406 | style_footer(); |
| 399 | 407 | } |
| 400 | 408 | |
| @@ -466,10 +474,11 @@ | ||
| 466 | 474 | char *zTag; |
| 467 | 475 | int rid = 0; |
| 468 | 476 | int isSandbox; |
| 469 | 477 | const char *zPageName; |
| 470 | 478 | const char *zUser; |
| 479 | + int goodCaptcha = 1; | |
| 471 | 480 | |
| 472 | 481 | login_check_credentials(); |
| 473 | 482 | zPageName = PD("name",""); |
| 474 | 483 | if( check_name(zPageName) ) return; |
| 475 | 484 | isSandbox = is_sandbox(zPageName); |
| @@ -488,11 +497,13 @@ | ||
| 488 | 497 | } |
| 489 | 498 | if( !g.perm.ApndWiki ){ |
| 490 | 499 | login_needed(); |
| 491 | 500 | return; |
| 492 | 501 | } |
| 493 | - if( P("submit")!=0 && P("r")!=0 && P("u")!=0 ){ | |
| 502 | + if( P("submit")!=0 && P("r")!=0 && P("u")!=0 | |
| 503 | + && (goodCaptcha = captcha_is_correct()) | |
| 504 | + ){ | |
| 494 | 505 | char *zDate; |
| 495 | 506 | Blob cksum; |
| 496 | 507 | Blob body; |
| 497 | 508 | Blob wiki; |
| 498 | 509 | Manifest *pWiki = 0; |
| @@ -536,10 +547,13 @@ | ||
| 536 | 547 | cgi_redirectf("wiki?name=%T", zPageName); |
| 537 | 548 | return; |
| 538 | 549 | } |
| 539 | 550 | style_set_current_page("%s?name=%T", g.zPath, zPageName); |
| 540 | 551 | style_header("Append Comment To: %s", zPageName); |
| 552 | + if( !goodCaptcha ){ | |
| 553 | + @ <p class="generalError">Error: Incorrect security code.</p> | |
| 554 | + } | |
| 541 | 555 | if( P("preview")!=0 ){ |
| 542 | 556 | Blob preview; |
| 543 | 557 | blob_zero(&preview); |
| 544 | 558 | appendRemark(&preview); |
| 545 | 559 | @ Preview:<hr> |
| @@ -558,10 +572,11 @@ | ||
| 558 | 572 | @ rows="10" wrap="virtual">%h(PD("r",""))</textarea> |
| 559 | 573 | @ <br /> |
| 560 | 574 | @ <input type="submit" name="preview" value="Preview Your Comment" /> |
| 561 | 575 | @ <input type="submit" name="submit" value="Append Your Changes" /> |
| 562 | 576 | @ <input type="submit" name="cancel" value="Cancel" /> |
| 577 | + captcha_generate(); | |
| 563 | 578 | @ </form> |
| 564 | 579 | style_footer(); |
| 565 | 580 | } |
| 566 | 581 | |
| 567 | 582 | /* |
| 568 | 583 |
| --- src/wiki.c | |
| +++ src/wiki.c | |
| @@ -263,10 +263,11 @@ | |
| 263 | const char *zPageName; |
| 264 | int n; |
| 265 | const char *z; |
| 266 | char *zBody = (char*)P("w"); |
| 267 | int isWysiwyg = P("wysiwyg")!=0; |
| 268 | |
| 269 | if( P("edit-wysiwyg")!=0 ){ isWysiwyg = 1; zBody = 0; } |
| 270 | if( P("edit-markup")!=0 ){ isWysiwyg = 0; zBody = 0; } |
| 271 | if( zBody ){ |
| 272 | if( isWysiwyg ){ |
| @@ -304,11 +305,13 @@ | |
| 304 | } |
| 305 | if( zBody==0 && (pWiki = manifest_get(rid, CFTYPE_WIKI))!=0 ){ |
| 306 | zBody = pWiki->zWiki; |
| 307 | } |
| 308 | } |
| 309 | if( P("submit")!=0 && zBody!=0 ){ |
| 310 | char *zDate; |
| 311 | Blob cksum; |
| 312 | blob_zero(&wiki); |
| 313 | db_begin_transaction(); |
| 314 | if( isSandbox ){ |
| @@ -343,10 +346,13 @@ | |
| 343 | if( zBody==0 ){ |
| 344 | zBody = mprintf("<i>Empty Page</i>"); |
| 345 | } |
| 346 | style_set_current_page("%s?name=%T", g.zPath, zPageName); |
| 347 | style_header("Edit: %s", zPageName); |
| 348 | blob_zero(&wiki); |
| 349 | blob_append(&wiki, zBody, -1); |
| 350 | if( P("preview")!=0 ){ |
| 351 | @ Preview:<hr /> |
| 352 | wiki_convert(&wiki, 0, 0); |
| @@ -385,16 +391,18 @@ | |
| 385 | blob_reset(&html); |
| 386 | @ <br /> |
| 387 | @ <input type="submit" name="edit-markup" value="Markup Editor" |
| 388 | @ onclick='return confirm("Switching to markup-mode\nwill erase your WYSIWYG\nedits. Continue?")' /> |
| 389 | } |
| 390 | @ <input type="submit" name="submit" value="Apply These Changes" /> |
| 391 | login_insert_csrf_secret(); |
| 392 | @ <input type="hidden" name="name" value="%h(zPageName)" /> |
| 393 | @ <input type="submit" name="cancel" value="Cancel" |
| 394 | @ onclick='confirm("Abandon your changes?")' /> |
| 395 | @ </div></form> |
| 396 | manifest_destroy(pWiki); |
| 397 | blob_reset(&wiki); |
| 398 | style_footer(); |
| 399 | } |
| 400 | |
| @@ -466,10 +474,11 @@ | |
| 466 | char *zTag; |
| 467 | int rid = 0; |
| 468 | int isSandbox; |
| 469 | const char *zPageName; |
| 470 | const char *zUser; |
| 471 | |
| 472 | login_check_credentials(); |
| 473 | zPageName = PD("name",""); |
| 474 | if( check_name(zPageName) ) return; |
| 475 | isSandbox = is_sandbox(zPageName); |
| @@ -488,11 +497,13 @@ | |
| 488 | } |
| 489 | if( !g.perm.ApndWiki ){ |
| 490 | login_needed(); |
| 491 | return; |
| 492 | } |
| 493 | if( P("submit")!=0 && P("r")!=0 && P("u")!=0 ){ |
| 494 | char *zDate; |
| 495 | Blob cksum; |
| 496 | Blob body; |
| 497 | Blob wiki; |
| 498 | Manifest *pWiki = 0; |
| @@ -536,10 +547,13 @@ | |
| 536 | cgi_redirectf("wiki?name=%T", zPageName); |
| 537 | return; |
| 538 | } |
| 539 | style_set_current_page("%s?name=%T", g.zPath, zPageName); |
| 540 | style_header("Append Comment To: %s", zPageName); |
| 541 | if( P("preview")!=0 ){ |
| 542 | Blob preview; |
| 543 | blob_zero(&preview); |
| 544 | appendRemark(&preview); |
| 545 | @ Preview:<hr> |
| @@ -558,10 +572,11 @@ | |
| 558 | @ rows="10" wrap="virtual">%h(PD("r",""))</textarea> |
| 559 | @ <br /> |
| 560 | @ <input type="submit" name="preview" value="Preview Your Comment" /> |
| 561 | @ <input type="submit" name="submit" value="Append Your Changes" /> |
| 562 | @ <input type="submit" name="cancel" value="Cancel" /> |
| 563 | @ </form> |
| 564 | style_footer(); |
| 565 | } |
| 566 | |
| 567 | /* |
| 568 |
| --- src/wiki.c | |
| +++ src/wiki.c | |
| @@ -263,10 +263,11 @@ | |
| 263 | const char *zPageName; |
| 264 | int n; |
| 265 | const char *z; |
| 266 | char *zBody = (char*)P("w"); |
| 267 | int isWysiwyg = P("wysiwyg")!=0; |
| 268 | int goodCaptcha = 1; |
| 269 | |
| 270 | if( P("edit-wysiwyg")!=0 ){ isWysiwyg = 1; zBody = 0; } |
| 271 | if( P("edit-markup")!=0 ){ isWysiwyg = 0; zBody = 0; } |
| 272 | if( zBody ){ |
| 273 | if( isWysiwyg ){ |
| @@ -304,11 +305,13 @@ | |
| 305 | } |
| 306 | if( zBody==0 && (pWiki = manifest_get(rid, CFTYPE_WIKI))!=0 ){ |
| 307 | zBody = pWiki->zWiki; |
| 308 | } |
| 309 | } |
| 310 | if( P("submit")!=0 && zBody!=0 |
| 311 | && (goodCaptcha = captcha_is_correct()) |
| 312 | ){ |
| 313 | char *zDate; |
| 314 | Blob cksum; |
| 315 | blob_zero(&wiki); |
| 316 | db_begin_transaction(); |
| 317 | if( isSandbox ){ |
| @@ -343,10 +346,13 @@ | |
| 346 | if( zBody==0 ){ |
| 347 | zBody = mprintf("<i>Empty Page</i>"); |
| 348 | } |
| 349 | style_set_current_page("%s?name=%T", g.zPath, zPageName); |
| 350 | style_header("Edit: %s", zPageName); |
| 351 | if( !goodCaptcha ){ |
| 352 | @ <p class="generalError">Error: Incorrect security code.</p> |
| 353 | } |
| 354 | blob_zero(&wiki); |
| 355 | blob_append(&wiki, zBody, -1); |
| 356 | if( P("preview")!=0 ){ |
| 357 | @ Preview:<hr /> |
| 358 | wiki_convert(&wiki, 0, 0); |
| @@ -385,16 +391,18 @@ | |
| 391 | blob_reset(&html); |
| 392 | @ <br /> |
| 393 | @ <input type="submit" name="edit-markup" value="Markup Editor" |
| 394 | @ onclick='return confirm("Switching to markup-mode\nwill erase your WYSIWYG\nedits. Continue?")' /> |
| 395 | } |
| 396 | login_insert_csrf_secret(); |
| 397 | @ <input type="submit" name="submit" value="Apply These Changes" /> |
| 398 | @ <input type="hidden" name="name" value="%h(zPageName)" /> |
| 399 | @ <input type="submit" name="cancel" value="Cancel" |
| 400 | @ onclick='confirm("Abandon your changes?")' /> |
| 401 | @ </div> |
| 402 | captcha_generate(); |
| 403 | @ </form> |
| 404 | manifest_destroy(pWiki); |
| 405 | blob_reset(&wiki); |
| 406 | style_footer(); |
| 407 | } |
| 408 | |
| @@ -466,10 +474,11 @@ | |
| 474 | char *zTag; |
| 475 | int rid = 0; |
| 476 | int isSandbox; |
| 477 | const char *zPageName; |
| 478 | const char *zUser; |
| 479 | int goodCaptcha = 1; |
| 480 | |
| 481 | login_check_credentials(); |
| 482 | zPageName = PD("name",""); |
| 483 | if( check_name(zPageName) ) return; |
| 484 | isSandbox = is_sandbox(zPageName); |
| @@ -488,11 +497,13 @@ | |
| 497 | } |
| 498 | if( !g.perm.ApndWiki ){ |
| 499 | login_needed(); |
| 500 | return; |
| 501 | } |
| 502 | if( P("submit")!=0 && P("r")!=0 && P("u")!=0 |
| 503 | && (goodCaptcha = captcha_is_correct()) |
| 504 | ){ |
| 505 | char *zDate; |
| 506 | Blob cksum; |
| 507 | Blob body; |
| 508 | Blob wiki; |
| 509 | Manifest *pWiki = 0; |
| @@ -536,10 +547,13 @@ | |
| 547 | cgi_redirectf("wiki?name=%T", zPageName); |
| 548 | return; |
| 549 | } |
| 550 | style_set_current_page("%s?name=%T", g.zPath, zPageName); |
| 551 | style_header("Append Comment To: %s", zPageName); |
| 552 | if( !goodCaptcha ){ |
| 553 | @ <p class="generalError">Error: Incorrect security code.</p> |
| 554 | } |
| 555 | if( P("preview")!=0 ){ |
| 556 | Blob preview; |
| 557 | blob_zero(&preview); |
| 558 | appendRemark(&preview); |
| 559 | @ Preview:<hr> |
| @@ -558,10 +572,11 @@ | |
| 572 | @ rows="10" wrap="virtual">%h(PD("r",""))</textarea> |
| 573 | @ <br /> |
| 574 | @ <input type="submit" name="preview" value="Preview Your Comment" /> |
| 575 | @ <input type="submit" name="submit" value="Append Your Changes" /> |
| 576 | @ <input type="submit" name="cancel" value="Cancel" /> |
| 577 | captcha_generate(); |
| 578 | @ </form> |
| 579 | style_footer(); |
| 580 | } |
| 581 | |
| 582 | /* |
| 583 |