Fossil SCM

When rendering the default header via TH1, allow the default Content-Security-Policy content to be overridden via the 'default_csp' variable. Also, add the 'nonce' command to TH1.

mistachkin 2019-02-18 19:09 trunk merge
Commit 8a65cd1831a5c2229aa77bdbd37e0b734d863840f8d3e8626e6d9820ca23d9bc
+14 -5
--- src/style.c
+++ src/style.c
@@ -389,14 +389,11 @@
389389
*/
390390
static char zDfltHeader[] =
391391
@ <html>
392392
@ <head>
393393
@ <base href="$baseurl/$current_page" />
394
-@ <meta http-equiv="Content-Security-Policy" \
395
-@ content="default-src 'self' data: ; \
396
-@ script-src 'self' 'nonce-$<nonce>' ;\
397
-@ style-src 'self' 'unsafe-inline'" />
394
+@ <meta http-equiv="Content-Security-Policy" content="$default_csp" />
398395
@ <meta name="viewport" content="width=device-width, initial-scale=1.0">
399396
@ <title>$<project_name>: $<title></title>
400397
@ <link rel="alternate" type="application/rss+xml" title="RSS Feed" \
401398
@ href="$home/timeline.rss" />
402399
@ <link rel="stylesheet" href="$stylesheet_url" type="text/css" \
@@ -407,11 +404,23 @@
407404
408405
/*
409406
** Initialize all the default TH1 variables
410407
*/
411408
static void style_init_th1_vars(const char *zTitle){
412
- Th_Store("nonce", style_nonce());
409
+ const char *zNonce = style_nonce();
410
+ /*
411
+ ** Do not overwrite the TH1 variable "default_csp" if it exists, as this
412
+ ** allows it to be properly overridden via the TH1 setup script (i.e. it
413
+ ** is evaluated before the header is rendered).
414
+ */
415
+ char *zDfltCsp = sqlite3_mprintf("default-src 'self' data: ; "
416
+ "script-src 'self' 'nonce-%s' ; "
417
+ "style-src 'self' 'unsafe-inline'",
418
+ zNonce);
419
+ Th_MaybeStore("default_csp", zDfltCsp);
420
+ sqlite3_free(zDfltCsp);
421
+ Th_Store("nonce", zNonce);
413422
Th_Store("project_name", db_get("project-name","Unnamed Fossil Project"));
414423
Th_Store("project_description", db_get("project-description",""));
415424
if( zTitle ) Th_Store("title", zTitle);
416425
Th_Store("baseurl", g.zBaseURL);
417426
Th_Store("secureurl", fossil_wants_https(1)? g.zHttpsURL: g.zBaseURL);
418427
--- src/style.c
+++ src/style.c
@@ -389,14 +389,11 @@
389 */
390 static char zDfltHeader[] =
391 @ <html>
392 @ <head>
393 @ <base href="$baseurl/$current_page" />
394 @ <meta http-equiv="Content-Security-Policy" \
395 @ content="default-src 'self' data: ; \
396 @ script-src 'self' 'nonce-$<nonce>' ;\
397 @ style-src 'self' 'unsafe-inline'" />
398 @ <meta name="viewport" content="width=device-width, initial-scale=1.0">
399 @ <title>$<project_name>: $<title></title>
400 @ <link rel="alternate" type="application/rss+xml" title="RSS Feed" \
401 @ href="$home/timeline.rss" />
402 @ <link rel="stylesheet" href="$stylesheet_url" type="text/css" \
@@ -407,11 +404,23 @@
407
408 /*
409 ** Initialize all the default TH1 variables
410 */
411 static void style_init_th1_vars(const char *zTitle){
412 Th_Store("nonce", style_nonce());
 
 
 
 
 
 
 
 
 
 
 
 
413 Th_Store("project_name", db_get("project-name","Unnamed Fossil Project"));
414 Th_Store("project_description", db_get("project-description",""));
415 if( zTitle ) Th_Store("title", zTitle);
416 Th_Store("baseurl", g.zBaseURL);
417 Th_Store("secureurl", fossil_wants_https(1)? g.zHttpsURL: g.zBaseURL);
418
--- src/style.c
+++ src/style.c
@@ -389,14 +389,11 @@
389 */
390 static char zDfltHeader[] =
391 @ <html>
392 @ <head>
393 @ <base href="$baseurl/$current_page" />
394 @ <meta http-equiv="Content-Security-Policy" content="$default_csp" />
 
 
 
395 @ <meta name="viewport" content="width=device-width, initial-scale=1.0">
396 @ <title>$<project_name>: $<title></title>
397 @ <link rel="alternate" type="application/rss+xml" title="RSS Feed" \
398 @ href="$home/timeline.rss" />
399 @ <link rel="stylesheet" href="$stylesheet_url" type="text/css" \
@@ -407,11 +404,23 @@
404
405 /*
406 ** Initialize all the default TH1 variables
407 */
408 static void style_init_th1_vars(const char *zTitle){
409 const char *zNonce = style_nonce();
410 /*
411 ** Do not overwrite the TH1 variable "default_csp" if it exists, as this
412 ** allows it to be properly overridden via the TH1 setup script (i.e. it
413 ** is evaluated before the header is rendered).
414 */
415 char *zDfltCsp = sqlite3_mprintf("default-src 'self' data: ; "
416 "script-src 'self' 'nonce-%s' ; "
417 "style-src 'self' 'unsafe-inline'",
418 zNonce);
419 Th_MaybeStore("default_csp", zDfltCsp);
420 sqlite3_free(zDfltCsp);
421 Th_Store("nonce", zNonce);
422 Th_Store("project_name", db_get("project-name","Unnamed Fossil Project"));
423 Th_Store("project_description", db_get("project-description",""));
424 if( zTitle ) Th_Store("title", zTitle);
425 Th_Store("baseurl", g.zBaseURL);
426 Th_Store("secureurl", fossil_wants_https(1)? g.zHttpsURL: g.zBaseURL);
427
--- src/th_main.c
+++ src/th_main.c
@@ -411,10 +411,30 @@
411411
}
412412
}
413413
Th_SetResult(interp, "file name not found in manifest", -1);
414414
return 0;
415415
}
416
+
417
+/*
418
+** TH1 command: nonce
419
+**
420
+** Returns the value of the cryptographic nonce for the request being
421
+** processed.
422
+*/
423
+static int nonceCmd(
424
+ Th_Interp *interp,
425
+ void *pConvert,
426
+ int argc,
427
+ const char **argv,
428
+ int *argl
429
+){
430
+ if( argc!=1 ){
431
+ return Th_WrongNumArgs(interp, "nonce");
432
+ }
433
+ Th_SetResult(interp, style_nonce(), -1);
434
+ return TH_OK;
435
+}
416436
417437
/*
418438
** TH1 command: puts STRING
419439
** TH1 command: html STRING
420440
**
@@ -2021,10 +2041,11 @@
20212041
{"htmlize", htmlizeCmd, 0},
20222042
{"http", httpCmd, 0},
20232043
{"insertCsrf", insertCsrfCmd, 0},
20242044
{"linecount", linecntCmd, 0},
20252045
{"markdown", markdownCmd, 0},
2046
+ {"nonce", nonceCmd, 0},
20262047
{"puts", putsCmd, (void*)&aFlags[1]},
20272048
{"query", queryCmd, 0},
20282049
{"randhex", randhexCmd, 0},
20292050
{"redirect", redirectCmd, 0},
20302051
{"regexp", regexpCmd, 0},
@@ -2104,10 +2125,24 @@
21042125
}
21052126
}
21062127
g.th1Flags &= ~TH_INIT_MASK;
21072128
g.th1Flags |= (flags & TH_INIT_MASK);
21082129
}
2130
+
2131
+/*
2132
+** Store a string value in a variable in the interpreter if the variable
2133
+** does not already exist.
2134
+*/
2135
+void Th_MaybeStore(const char *zName, const char *zValue){
2136
+ Th_FossilInit(TH_INIT_DEFAULT);
2137
+ if( zValue && !Th_ExistsVar(g.interp, zName, -1) ){
2138
+ if( g.thTrace ){
2139
+ Th_Trace("maybe_set %h {%h}<br />\n", zName, zValue);
2140
+ }
2141
+ Th_SetVar(g.interp, zName, -1, zValue, strlen(zValue));
2142
+ }
2143
+}
21092144
21102145
/*
21112146
** Store a string value in a variable in the interpreter.
21122147
*/
21132148
void Th_Store(const char *zName, const char *zValue){
21142149
--- src/th_main.c
+++ src/th_main.c
@@ -411,10 +411,30 @@
411 }
412 }
413 Th_SetResult(interp, "file name not found in manifest", -1);
414 return 0;
415 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
416
417 /*
418 ** TH1 command: puts STRING
419 ** TH1 command: html STRING
420 **
@@ -2021,10 +2041,11 @@
2021 {"htmlize", htmlizeCmd, 0},
2022 {"http", httpCmd, 0},
2023 {"insertCsrf", insertCsrfCmd, 0},
2024 {"linecount", linecntCmd, 0},
2025 {"markdown", markdownCmd, 0},
 
2026 {"puts", putsCmd, (void*)&aFlags[1]},
2027 {"query", queryCmd, 0},
2028 {"randhex", randhexCmd, 0},
2029 {"redirect", redirectCmd, 0},
2030 {"regexp", regexpCmd, 0},
@@ -2104,10 +2125,24 @@
2104 }
2105 }
2106 g.th1Flags &= ~TH_INIT_MASK;
2107 g.th1Flags |= (flags & TH_INIT_MASK);
2108 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2109
2110 /*
2111 ** Store a string value in a variable in the interpreter.
2112 */
2113 void Th_Store(const char *zName, const char *zValue){
2114
--- src/th_main.c
+++ src/th_main.c
@@ -411,10 +411,30 @@
411 }
412 }
413 Th_SetResult(interp, "file name not found in manifest", -1);
414 return 0;
415 }
416
417 /*
418 ** TH1 command: nonce
419 **
420 ** Returns the value of the cryptographic nonce for the request being
421 ** processed.
422 */
423 static int nonceCmd(
424 Th_Interp *interp,
425 void *pConvert,
426 int argc,
427 const char **argv,
428 int *argl
429 ){
430 if( argc!=1 ){
431 return Th_WrongNumArgs(interp, "nonce");
432 }
433 Th_SetResult(interp, style_nonce(), -1);
434 return TH_OK;
435 }
436
437 /*
438 ** TH1 command: puts STRING
439 ** TH1 command: html STRING
440 **
@@ -2021,10 +2041,11 @@
2041 {"htmlize", htmlizeCmd, 0},
2042 {"http", httpCmd, 0},
2043 {"insertCsrf", insertCsrfCmd, 0},
2044 {"linecount", linecntCmd, 0},
2045 {"markdown", markdownCmd, 0},
2046 {"nonce", nonceCmd, 0},
2047 {"puts", putsCmd, (void*)&aFlags[1]},
2048 {"query", queryCmd, 0},
2049 {"randhex", randhexCmd, 0},
2050 {"redirect", redirectCmd, 0},
2051 {"regexp", regexpCmd, 0},
@@ -2104,10 +2125,24 @@
2125 }
2126 }
2127 g.th1Flags &= ~TH_INIT_MASK;
2128 g.th1Flags |= (flags & TH_INIT_MASK);
2129 }
2130
2131 /*
2132 ** Store a string value in a variable in the interpreter if the variable
2133 ** does not already exist.
2134 */
2135 void Th_MaybeStore(const char *zName, const char *zValue){
2136 Th_FossilInit(TH_INIT_DEFAULT);
2137 if( zValue && !Th_ExistsVar(g.interp, zName, -1) ){
2138 if( g.thTrace ){
2139 Th_Trace("maybe_set %h {%h}<br />\n", zName, zValue);
2140 }
2141 Th_SetVar(g.interp, zName, -1, zValue, strlen(zValue));
2142 }
2143 }
2144
2145 /*
2146 ** Store a string value in a variable in the interpreter.
2147 */
2148 void Th_Store(const char *zName, const char *zValue){
2149
+2 -3
--- test/th1.test
+++ test/th1.test
@@ -1032,21 +1032,20 @@
10321032
protOut "Sorted: $sorted_result"
10331033
set base_commands {anoncap anycap array artifact break breakpoint catch\
10341034
cgiHeaderLine checkout combobox continue date decorate dir enable_output \
10351035
encode64 error expr for getParameter glob_match globalState hascap \
10361036
hasfeature html htmlize http httpize if info insertCsrf lindex linecount \
1037
- list llength lsearch markdown proc puts query randhex redirect regexp\
1038
- reinitialize rename render repository return searchable set\
1037
+ list llength lsearch markdown nonce proc puts query randhex redirect\
1038
+ regexp reinitialize rename render repository return searchable set\
10391039
setParameter setting stime string styleFooter styleHeader styleScript\
10401040
tclReady trace unset unversioned uplevel upvar utime verifyCsrf wiki}
10411041
set tcl_commands {tclEval tclExpr tclInvoke tclIsSafe tclMakeSafe}
10421042
if {$th1Tcl} {
10431043
test th1-info-commands-1 {$sorted_result eq [lsort "$base_commands $tcl_commands"]}
10441044
} else {
10451045
test th1-info-commands-1 {$sorted_result eq [lsort "$base_commands"]}
10461046
}
1047
-
10481047
10491048
###############################################################################
10501049
10511050
fossil test-th-eval "info vars"
10521051
10531052
--- test/th1.test
+++ test/th1.test
@@ -1032,21 +1032,20 @@
1032 protOut "Sorted: $sorted_result"
1033 set base_commands {anoncap anycap array artifact break breakpoint catch\
1034 cgiHeaderLine checkout combobox continue date decorate dir enable_output \
1035 encode64 error expr for getParameter glob_match globalState hascap \
1036 hasfeature html htmlize http httpize if info insertCsrf lindex linecount \
1037 list llength lsearch markdown proc puts query randhex redirect regexp\
1038 reinitialize rename render repository return searchable set\
1039 setParameter setting stime string styleFooter styleHeader styleScript\
1040 tclReady trace unset unversioned uplevel upvar utime verifyCsrf wiki}
1041 set tcl_commands {tclEval tclExpr tclInvoke tclIsSafe tclMakeSafe}
1042 if {$th1Tcl} {
1043 test th1-info-commands-1 {$sorted_result eq [lsort "$base_commands $tcl_commands"]}
1044 } else {
1045 test th1-info-commands-1 {$sorted_result eq [lsort "$base_commands"]}
1046 }
1047
1048
1049 ###############################################################################
1050
1051 fossil test-th-eval "info vars"
1052
1053
--- test/th1.test
+++ test/th1.test
@@ -1032,21 +1032,20 @@
1032 protOut "Sorted: $sorted_result"
1033 set base_commands {anoncap anycap array artifact break breakpoint catch\
1034 cgiHeaderLine checkout combobox continue date decorate dir enable_output \
1035 encode64 error expr for getParameter glob_match globalState hascap \
1036 hasfeature html htmlize http httpize if info insertCsrf lindex linecount \
1037 list llength lsearch markdown nonce proc puts query randhex redirect\
1038 regexp reinitialize rename render repository return searchable set\
1039 setParameter setting stime string styleFooter styleHeader styleScript\
1040 tclReady trace unset unversioned uplevel upvar utime verifyCsrf wiki}
1041 set tcl_commands {tclEval tclExpr tclInvoke tclIsSafe tclMakeSafe}
1042 if {$th1Tcl} {
1043 test th1-info-commands-1 {$sorted_result eq [lsort "$base_commands $tcl_commands"]}
1044 } else {
1045 test th1-info-commands-1 {$sorted_result eq [lsort "$base_commands"]}
1046 }
 
1047
1048 ###############################################################################
1049
1050 fossil test-th-eval "info vars"
1051
1052
--- www/customskin.md
+++ www/customskin.md
@@ -233,10 +233,13 @@
233233
* **current_page** - The name of the page currently being processed,
234234
without the leading "/" and without query parameters.
235235
Examples: "timeline", "doc/trunk/README.txt", "wiki".
236236
237237
* **csrf_token** - A token used to prevent cross-site request forgery.
238
+
239
+ * **default_csp** - The content to be used within the default header
240
+ for the "Content-Security-Policy" meta tag.
238241
239242
* **release_version** - The release version of Fossil. Ex: "1.31"
240243
241244
* **manifest_version** - A prefix on the check-in hash of the
242245
specific version of fossil that is running. Ex: "\[47bb6432a1\]"
243246
--- www/customskin.md
+++ www/customskin.md
@@ -233,10 +233,13 @@
233 * **current_page** - The name of the page currently being processed,
234 without the leading "/" and without query parameters.
235 Examples: "timeline", "doc/trunk/README.txt", "wiki".
236
237 * **csrf_token** - A token used to prevent cross-site request forgery.
 
 
 
238
239 * **release_version** - The release version of Fossil. Ex: "1.31"
240
241 * **manifest_version** - A prefix on the check-in hash of the
242 specific version of fossil that is running. Ex: "\[47bb6432a1\]"
243
--- www/customskin.md
+++ www/customskin.md
@@ -233,10 +233,13 @@
233 * **current_page** - The name of the page currently being processed,
234 without the leading "/" and without query parameters.
235 Examples: "timeline", "doc/trunk/README.txt", "wiki".
236
237 * **csrf_token** - A token used to prevent cross-site request forgery.
238
239 * **default_csp** - The content to be used within the default header
240 for the "Content-Security-Policy" meta tag.
241
242 * **release_version** - The release version of Fossil. Ex: "1.31"
243
244 * **manifest_version** - A prefix on the check-in hash of the
245 specific version of fossil that is running. Ex: "\[47bb6432a1\]"
246
+8
--- www/th1.md
+++ www/th1.md
@@ -187,10 +187,11 @@
187187
* http
188188
* httpize
189189
* insertCsrf
190190
* linecount
191191
* markdown
192
+ * nonce
192193
* puts
193194
* query
194195
* randhex
195196
* redirect
196197
* regexp
@@ -453,10 +454,17 @@
453454
454455
Renders the input string as markdown. The result is a two-element list.
455456
The first element contains the body, rendered as HTML. The second element
456457
is the text-only title string.
457458
459
+<a name="nonce"></a>TH1 nonce Command
460
+-------------------------------------
461
+
462
+ * nonce
463
+
464
+Returns the value of the cryptographic nonce for the request being processed.
465
+
458466
<a name="puts"></a>TH1 puts Command
459467
-----------------------------------
460468
461469
* puts STRING
462470
463471
--- www/th1.md
+++ www/th1.md
@@ -187,10 +187,11 @@
187 * http
188 * httpize
189 * insertCsrf
190 * linecount
191 * markdown
 
192 * puts
193 * query
194 * randhex
195 * redirect
196 * regexp
@@ -453,10 +454,17 @@
453
454 Renders the input string as markdown. The result is a two-element list.
455 The first element contains the body, rendered as HTML. The second element
456 is the text-only title string.
457
 
 
 
 
 
 
 
458 <a name="puts"></a>TH1 puts Command
459 -----------------------------------
460
461 * puts STRING
462
463
--- www/th1.md
+++ www/th1.md
@@ -187,10 +187,11 @@
187 * http
188 * httpize
189 * insertCsrf
190 * linecount
191 * markdown
192 * nonce
193 * puts
194 * query
195 * randhex
196 * redirect
197 * regexp
@@ -453,10 +454,17 @@
454
455 Renders the input string as markdown. The result is a two-element list.
456 The first element contains the body, rendered as HTML. The second element
457 is the text-only title string.
458
459 <a name="nonce"></a>TH1 nonce Command
460 -------------------------------------
461
462 * nonce
463
464 Returns the value of the cryptographic nonce for the request being processed.
465
466 <a name="puts"></a>TH1 puts Command
467 -----------------------------------
468
469 * puts STRING
470
471

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button