Fossil SCM
Add a CSRF check to /chat-send.
Commit
4caa8cb9ff819f7eee8536f7f4892fca803fdf7072ed25d76a6ac4bd19992b7e
Parent
0c1419a466f2152…
2 files changed
+18
+2
-2
+18
| --- src/chat.c | ||
| +++ src/chat.c | ||
| @@ -389,10 +389,25 @@ | ||
| 389 | 389 | }else{ |
| 390 | 390 | CX("}"); |
| 391 | 391 | } |
| 392 | 392 | fossil_free(zTime); |
| 393 | 393 | } |
| 394 | + | |
| 395 | +/* | |
| 396 | +** Like chat_emit_permissions_error() but emits a single | |
| 397 | +** /chat-message-format JSON object | |
| 398 | +*/ | |
| 399 | +static void chat_emit_csrf_error(void){ | |
| 400 | + char * zTime = cgi_iso8601_datestamp(); | |
| 401 | + cgi_set_content_type("application/json"); | |
| 402 | + CX("{"); | |
| 403 | + CX("\"isError\": true, \"xfrom\": null,"); | |
| 404 | + CX("\"mtime\": %!j, \"lmtime\": %!j,", zTime, zTime); | |
| 405 | + CX("\"xmsg\": \"CSRF validation failure.\""); | |
| 406 | + CX("}"); | |
| 407 | + fossil_free(zTime); | |
| 408 | +} | |
| 394 | 409 | |
| 395 | 410 | /* |
| 396 | 411 | ** WEBPAGE: chat-send hidden loadavg-exempt |
| 397 | 412 | ** |
| 398 | 413 | ** This page receives (via XHR) a new chat-message and/or a new file |
| @@ -421,10 +436,13 @@ | ||
| 421 | 436 | const char *zMsg; |
| 422 | 437 | const char *zUserName; |
| 423 | 438 | login_check_credentials(); |
| 424 | 439 | if( 0==g.perm.Chat ) { |
| 425 | 440 | chat_emit_permissions_error(0); |
| 441 | + return; | |
| 442 | + }else if( 0==cgi_csrf_safe(1) ){ | |
| 443 | + chat_emit_csrf_error(); | |
| 426 | 444 | return; |
| 427 | 445 | } |
| 428 | 446 | zUserName = (g.zLogin && g.zLogin[0]) ? g.zLogin : "nobody"; |
| 429 | 447 | nByte = atoi(PD("file:bytes","0")); |
| 430 | 448 | zMsg = PD("msg",""); |
| 431 | 449 |
| --- src/chat.c | |
| +++ src/chat.c | |
| @@ -389,10 +389,25 @@ | |
| 389 | }else{ |
| 390 | CX("}"); |
| 391 | } |
| 392 | fossil_free(zTime); |
| 393 | } |
| 394 | |
| 395 | /* |
| 396 | ** WEBPAGE: chat-send hidden loadavg-exempt |
| 397 | ** |
| 398 | ** This page receives (via XHR) a new chat-message and/or a new file |
| @@ -421,10 +436,13 @@ | |
| 421 | const char *zMsg; |
| 422 | const char *zUserName; |
| 423 | login_check_credentials(); |
| 424 | if( 0==g.perm.Chat ) { |
| 425 | chat_emit_permissions_error(0); |
| 426 | return; |
| 427 | } |
| 428 | zUserName = (g.zLogin && g.zLogin[0]) ? g.zLogin : "nobody"; |
| 429 | nByte = atoi(PD("file:bytes","0")); |
| 430 | zMsg = PD("msg",""); |
| 431 |
| --- src/chat.c | |
| +++ src/chat.c | |
| @@ -389,10 +389,25 @@ | |
| 389 | }else{ |
| 390 | CX("}"); |
| 391 | } |
| 392 | fossil_free(zTime); |
| 393 | } |
| 394 | |
| 395 | /* |
| 396 | ** Like chat_emit_permissions_error() but emits a single |
| 397 | ** /chat-message-format JSON object |
| 398 | */ |
| 399 | static void chat_emit_csrf_error(void){ |
| 400 | char * zTime = cgi_iso8601_datestamp(); |
| 401 | cgi_set_content_type("application/json"); |
| 402 | CX("{"); |
| 403 | CX("\"isError\": true, \"xfrom\": null,"); |
| 404 | CX("\"mtime\": %!j, \"lmtime\": %!j,", zTime, zTime); |
| 405 | CX("\"xmsg\": \"CSRF validation failure.\""); |
| 406 | CX("}"); |
| 407 | fossil_free(zTime); |
| 408 | } |
| 409 | |
| 410 | /* |
| 411 | ** WEBPAGE: chat-send hidden loadavg-exempt |
| 412 | ** |
| 413 | ** This page receives (via XHR) a new chat-message and/or a new file |
| @@ -421,10 +436,13 @@ | |
| 436 | const char *zMsg; |
| 437 | const char *zUserName; |
| 438 | login_check_credentials(); |
| 439 | if( 0==g.perm.Chat ) { |
| 440 | chat_emit_permissions_error(0); |
| 441 | return; |
| 442 | }else if( 0==cgi_csrf_safe(1) ){ |
| 443 | chat_emit_csrf_error(); |
| 444 | return; |
| 445 | } |
| 446 | zUserName = (g.zLogin && g.zLogin[0]) ? g.zLogin : "nobody"; |
| 447 | nByte = atoi(PD("file:bytes","0")); |
| 448 | zMsg = PD("msg",""); |
| 449 |
+2
-2
| --- src/fossil.dom.js | ||
| +++ src/fossil.dom.js | ||
| @@ -843,12 +843,12 @@ | ||
| 843 | 843 | /** |
| 844 | 844 | Parses a string as HTML. |
| 845 | 845 | |
| 846 | 846 | Usages: |
| 847 | 847 | |
| 848 | - Array (htmlString) | |
| 849 | - DOMElement (DOMElement target, htmlString) | |
| 848 | + Array parseHtml(htmlString) | |
| 849 | + DOMElement parseHtml(DOMElement target, htmlString) | |
| 850 | 850 | |
| 851 | 851 | The first form parses the string as HTML and returns an Array of |
| 852 | 852 | all elements parsed from it. If string is falsy then it returns |
| 853 | 853 | an empty array. |
| 854 | 854 | |
| 855 | 855 |
| --- src/fossil.dom.js | |
| +++ src/fossil.dom.js | |
| @@ -843,12 +843,12 @@ | |
| 843 | /** |
| 844 | Parses a string as HTML. |
| 845 | |
| 846 | Usages: |
| 847 | |
| 848 | Array (htmlString) |
| 849 | DOMElement (DOMElement target, htmlString) |
| 850 | |
| 851 | The first form parses the string as HTML and returns an Array of |
| 852 | all elements parsed from it. If string is falsy then it returns |
| 853 | an empty array. |
| 854 | |
| 855 |
| --- src/fossil.dom.js | |
| +++ src/fossil.dom.js | |
| @@ -843,12 +843,12 @@ | |
| 843 | /** |
| 844 | Parses a string as HTML. |
| 845 | |
| 846 | Usages: |
| 847 | |
| 848 | Array parseHtml(htmlString) |
| 849 | DOMElement parseHtml(DOMElement target, htmlString) |
| 850 | |
| 851 | The first form parses the string as HTML and returns an Array of |
| 852 | all elements parsed from it. If string is falsy then it returns |
| 853 | an empty array. |
| 854 | |
| 855 |