Fossil SCM
Merge in trunk latest developments.
Commit
08291fec9f6f215bee8acbbbf5a7c8e4b5ee49a98ed493dcb0809ceb49a76f8b
Parent
70d091eaccf98c7…
17 files changed
+1
-1
+1
+21
-7
+2
-2
+1
-1
+2
-2
+11
+5
-1
+53
+1
+24
-19
+151
-69
+36
-31
+35
-21
+63
-68
+121
-35
+13
-10
~
skins/default/header.txt
~
src/checkin.c
~
src/db.c
~
src/doc.c
~
src/fshell.c
~
src/login.c
~
src/main.c
~
src/markdown_html.c
~
src/util.c
~
src/wiki.c
~
src/wikiformat.c
~
www/defcsp.md
~
www/server/any/althttpd.md
~
www/server/any/scgi.md
~
www/server/debian/nginx.md
~
www/server/index.html
~
www/server/whyuseaserver.wiki
+1
-1
| --- skins/default/header.txt | ||
| +++ skins/default/header.txt | ||
| @@ -17,11 +17,11 @@ | ||
| 17 | 17 | html "<a href='$home$url' class='active $cls'>$name</a>\n" |
| 18 | 18 | } else { |
| 19 | 19 | html "<a href='$home$url' class='$cls'>$name</a>\n" |
| 20 | 20 | } |
| 21 | 21 | } |
| 22 | -html "<a id='hbbtn' href='#'>☰</a>" | |
| 22 | +html "<a id='hbbtn' href='/sitemap'>☰</a>" | |
| 23 | 23 | menulink $index_page Home {} |
| 24 | 24 | if {[anycap jor]} { |
| 25 | 25 | menulink /timeline Timeline {} |
| 26 | 26 | } |
| 27 | 27 | if {[hascap oh]} { |
| 28 | 28 |
| --- skins/default/header.txt | |
| +++ skins/default/header.txt | |
| @@ -17,11 +17,11 @@ | |
| 17 | html "<a href='$home$url' class='active $cls'>$name</a>\n" |
| 18 | } else { |
| 19 | html "<a href='$home$url' class='$cls'>$name</a>\n" |
| 20 | } |
| 21 | } |
| 22 | html "<a id='hbbtn' href='#'>☰</a>" |
| 23 | menulink $index_page Home {} |
| 24 | if {[anycap jor]} { |
| 25 | menulink /timeline Timeline {} |
| 26 | } |
| 27 | if {[hascap oh]} { |
| 28 |
| --- skins/default/header.txt | |
| +++ skins/default/header.txt | |
| @@ -17,11 +17,11 @@ | |
| 17 | html "<a href='$home$url' class='active $cls'>$name</a>\n" |
| 18 | } else { |
| 19 | html "<a href='$home$url' class='$cls'>$name</a>\n" |
| 20 | } |
| 21 | } |
| 22 | html "<a id='hbbtn' href='/sitemap'>☰</a>" |
| 23 | menulink $index_page Home {} |
| 24 | if {[anycap jor]} { |
| 25 | menulink /timeline Timeline {} |
| 26 | } |
| 27 | if {[hascap oh]} { |
| 28 |
+1
| --- src/checkin.c | ||
| +++ src/checkin.c | ||
| @@ -1939,10 +1939,11 @@ | ||
| 1939 | 1939 | /* |
| 1940 | 1940 | ** COMMAND: ci* |
| 1941 | 1941 | ** COMMAND: commit |
| 1942 | 1942 | ** |
| 1943 | 1943 | ** Usage: %fossil commit ?OPTIONS? ?FILE...? |
| 1944 | +** or: %fossil ci ?OPTIONS? ?FILE...? | |
| 1944 | 1945 | ** |
| 1945 | 1946 | ** Create a new version containing all of the changes in the current |
| 1946 | 1947 | ** checkout. You will be prompted to enter a check-in comment unless |
| 1947 | 1948 | ** the comment has been specified on the command-line using "-m" or a |
| 1948 | 1949 | ** file containing the comment using -M. The editor defined in the |
| 1949 | 1950 |
| --- src/checkin.c | |
| +++ src/checkin.c | |
| @@ -1939,10 +1939,11 @@ | |
| 1939 | /* |
| 1940 | ** COMMAND: ci* |
| 1941 | ** COMMAND: commit |
| 1942 | ** |
| 1943 | ** Usage: %fossil commit ?OPTIONS? ?FILE...? |
| 1944 | ** |
| 1945 | ** Create a new version containing all of the changes in the current |
| 1946 | ** checkout. You will be prompted to enter a check-in comment unless |
| 1947 | ** the comment has been specified on the command-line using "-m" or a |
| 1948 | ** file containing the comment using -M. The editor defined in the |
| 1949 |
| --- src/checkin.c | |
| +++ src/checkin.c | |
| @@ -1939,10 +1939,11 @@ | |
| 1939 | /* |
| 1940 | ** COMMAND: ci* |
| 1941 | ** COMMAND: commit |
| 1942 | ** |
| 1943 | ** Usage: %fossil commit ?OPTIONS? ?FILE...? |
| 1944 | ** or: %fossil ci ?OPTIONS? ?FILE...? |
| 1945 | ** |
| 1946 | ** Create a new version containing all of the changes in the current |
| 1947 | ** checkout. You will be prompted to enter a check-in comment unless |
| 1948 | ** the comment has been specified on the command-line using "-m" or a |
| 1949 | ** file containing the comment using -M. The editor defined in the |
| 1950 |
M
src/db.c
+21
-7
| --- src/db.c | ||
| +++ src/db.c | ||
| @@ -117,10 +117,11 @@ | ||
| 117 | 117 | /* |
| 118 | 118 | ** Arrange for the given file to be deleted on a failure. |
| 119 | 119 | */ |
| 120 | 120 | void db_delete_on_failure(const char *zFilename){ |
| 121 | 121 | assert( db.nDeleteOnFail<count(db.azDeleteOnFail) ); |
| 122 | + if( zFilename==0 ) return; | |
| 122 | 123 | db.azDeleteOnFail[db.nDeleteOnFail++] = fossil_strdup(zFilename); |
| 123 | 124 | } |
| 124 | 125 | |
| 125 | 126 | /* |
| 126 | 127 | ** Return the transaction nesting depth. 0 means we are currently |
| @@ -799,10 +800,13 @@ | ||
| 799 | 800 | } |
| 800 | 801 | |
| 801 | 802 | /* |
| 802 | 803 | ** Initialize a new database file with the given schema. If anything |
| 803 | 804 | ** goes wrong, call db_err() to exit. |
| 805 | +** | |
| 806 | +** If zFilename is NULL, then create an empty repository in an in-memory | |
| 807 | +** database. | |
| 804 | 808 | */ |
| 805 | 809 | void db_init_database( |
| 806 | 810 | const char *zFileName, /* Name of database file to create */ |
| 807 | 811 | const char *zSchema, /* First part of schema */ |
| 808 | 812 | ... /* Additional SQL to run. Terminate with NULL. */ |
| @@ -810,11 +814,11 @@ | ||
| 810 | 814 | sqlite3 *db; |
| 811 | 815 | int rc; |
| 812 | 816 | const char *zSql; |
| 813 | 817 | va_list ap; |
| 814 | 818 | |
| 815 | - db = db_open(zFileName); | |
| 819 | + db = db_open(zFileName ? zFileName : ":memory:"); | |
| 816 | 820 | sqlite3_exec(db, "BEGIN EXCLUSIVE", 0, 0, 0); |
| 817 | 821 | rc = sqlite3_exec(db, zSchema, 0, 0, 0); |
| 818 | 822 | if( rc!=SQLITE_OK ){ |
| 819 | 823 | db_err("%s", sqlite3_errmsg(db)); |
| 820 | 824 | } |
| @@ -825,11 +829,15 @@ | ||
| 825 | 829 | db_err("%s", sqlite3_errmsg(db)); |
| 826 | 830 | } |
| 827 | 831 | } |
| 828 | 832 | va_end(ap); |
| 829 | 833 | sqlite3_exec(db, "COMMIT", 0, 0, 0); |
| 830 | - sqlite3_close(db); | |
| 834 | + if( zFileName || g.db!=0 ){ | |
| 835 | + sqlite3_close(db); | |
| 836 | + }else{ | |
| 837 | + g.db = db; | |
| 838 | + } | |
| 831 | 839 | } |
| 832 | 840 | |
| 833 | 841 | /* |
| 834 | 842 | ** Function to return the number of seconds since 1970. This is |
| 835 | 843 | ** the same as strftime('%s','now') but is more compact. |
| @@ -1768,12 +1776,13 @@ | ||
| 1768 | 1776 | |
| 1769 | 1777 | /* |
| 1770 | 1778 | ** Flags for the db_find_and_open_repository() function. |
| 1771 | 1779 | */ |
| 1772 | 1780 | #if INTERFACE |
| 1773 | -#define OPEN_OK_NOT_FOUND 0x001 /* Do not error out if not found */ | |
| 1774 | -#define OPEN_ANY_SCHEMA 0x002 /* Do not error if schema is wrong */ | |
| 1781 | +#define OPEN_OK_NOT_FOUND 0x001 /* Do not error out if not found */ | |
| 1782 | +#define OPEN_ANY_SCHEMA 0x002 /* Do not error if schema is wrong */ | |
| 1783 | +#define OPEN_SUBSTITUTE 0x004 /* Fake in-memory repo if not found */ | |
| 1775 | 1784 | #endif |
| 1776 | 1785 | |
| 1777 | 1786 | /* |
| 1778 | 1787 | ** Try to find the repository and open it. Use the -R or --repository |
| 1779 | 1788 | ** option to locate the repository. If no such option is available, then |
| @@ -1802,11 +1811,16 @@ | ||
| 1802 | 1811 | if( g.repositoryOpen ){ |
| 1803 | 1812 | if( (bFlags & OPEN_ANY_SCHEMA)==0 ) db_verify_schema(); |
| 1804 | 1813 | return; |
| 1805 | 1814 | } |
| 1806 | 1815 | rep_not_found: |
| 1807 | - if( (bFlags & OPEN_OK_NOT_FOUND)==0 ){ | |
| 1816 | + if( bFlags & OPEN_OK_NOT_FOUND ){ | |
| 1817 | + /* No errors if the database is not found */ | |
| 1818 | + if( bFlags & OPEN_SUBSTITUTE ){ | |
| 1819 | + db_create_repository(0); | |
| 1820 | + } | |
| 1821 | + }else{ | |
| 1808 | 1822 | #ifdef FOSSIL_ENABLE_JSON |
| 1809 | 1823 | g.json.resultCode = FSL_JSON_E_DB_NOT_FOUND; |
| 1810 | 1824 | #endif |
| 1811 | 1825 | if( nArgUsed==0 ){ |
| 1812 | 1826 | fossil_fatal("use --repository or -R to specify the repository database"); |
| @@ -2032,12 +2046,12 @@ | ||
| 2032 | 2046 | } |
| 2033 | 2047 | db_multi_exec( |
| 2034 | 2048 | "INSERT OR IGNORE INTO user(login, info) VALUES(%Q,'')", zUser |
| 2035 | 2049 | ); |
| 2036 | 2050 | db_multi_exec( |
| 2037 | - "UPDATE user SET cap='s', pw=lower(hex(randomblob(3)))" | |
| 2038 | - " WHERE login=%Q", zUser | |
| 2051 | + "UPDATE user SET cap='s', pw=%Q" | |
| 2052 | + " WHERE login=%Q", fossil_random_password(10), zUser | |
| 2039 | 2053 | ); |
| 2040 | 2054 | if( !setupUserOnly ){ |
| 2041 | 2055 | db_multi_exec( |
| 2042 | 2056 | "INSERT OR IGNORE INTO user(login,pw,cap,info)" |
| 2043 | 2057 | " VALUES('anonymous',hex(randomblob(8)),'hmnc','Anon');" |
| 2044 | 2058 |
| --- src/db.c | |
| +++ src/db.c | |
| @@ -117,10 +117,11 @@ | |
| 117 | /* |
| 118 | ** Arrange for the given file to be deleted on a failure. |
| 119 | */ |
| 120 | void db_delete_on_failure(const char *zFilename){ |
| 121 | assert( db.nDeleteOnFail<count(db.azDeleteOnFail) ); |
| 122 | db.azDeleteOnFail[db.nDeleteOnFail++] = fossil_strdup(zFilename); |
| 123 | } |
| 124 | |
| 125 | /* |
| 126 | ** Return the transaction nesting depth. 0 means we are currently |
| @@ -799,10 +800,13 @@ | |
| 799 | } |
| 800 | |
| 801 | /* |
| 802 | ** Initialize a new database file with the given schema. If anything |
| 803 | ** goes wrong, call db_err() to exit. |
| 804 | */ |
| 805 | void db_init_database( |
| 806 | const char *zFileName, /* Name of database file to create */ |
| 807 | const char *zSchema, /* First part of schema */ |
| 808 | ... /* Additional SQL to run. Terminate with NULL. */ |
| @@ -810,11 +814,11 @@ | |
| 810 | sqlite3 *db; |
| 811 | int rc; |
| 812 | const char *zSql; |
| 813 | va_list ap; |
| 814 | |
| 815 | db = db_open(zFileName); |
| 816 | sqlite3_exec(db, "BEGIN EXCLUSIVE", 0, 0, 0); |
| 817 | rc = sqlite3_exec(db, zSchema, 0, 0, 0); |
| 818 | if( rc!=SQLITE_OK ){ |
| 819 | db_err("%s", sqlite3_errmsg(db)); |
| 820 | } |
| @@ -825,11 +829,15 @@ | |
| 825 | db_err("%s", sqlite3_errmsg(db)); |
| 826 | } |
| 827 | } |
| 828 | va_end(ap); |
| 829 | sqlite3_exec(db, "COMMIT", 0, 0, 0); |
| 830 | sqlite3_close(db); |
| 831 | } |
| 832 | |
| 833 | /* |
| 834 | ** Function to return the number of seconds since 1970. This is |
| 835 | ** the same as strftime('%s','now') but is more compact. |
| @@ -1768,12 +1776,13 @@ | |
| 1768 | |
| 1769 | /* |
| 1770 | ** Flags for the db_find_and_open_repository() function. |
| 1771 | */ |
| 1772 | #if INTERFACE |
| 1773 | #define OPEN_OK_NOT_FOUND 0x001 /* Do not error out if not found */ |
| 1774 | #define OPEN_ANY_SCHEMA 0x002 /* Do not error if schema is wrong */ |
| 1775 | #endif |
| 1776 | |
| 1777 | /* |
| 1778 | ** Try to find the repository and open it. Use the -R or --repository |
| 1779 | ** option to locate the repository. If no such option is available, then |
| @@ -1802,11 +1811,16 @@ | |
| 1802 | if( g.repositoryOpen ){ |
| 1803 | if( (bFlags & OPEN_ANY_SCHEMA)==0 ) db_verify_schema(); |
| 1804 | return; |
| 1805 | } |
| 1806 | rep_not_found: |
| 1807 | if( (bFlags & OPEN_OK_NOT_FOUND)==0 ){ |
| 1808 | #ifdef FOSSIL_ENABLE_JSON |
| 1809 | g.json.resultCode = FSL_JSON_E_DB_NOT_FOUND; |
| 1810 | #endif |
| 1811 | if( nArgUsed==0 ){ |
| 1812 | fossil_fatal("use --repository or -R to specify the repository database"); |
| @@ -2032,12 +2046,12 @@ | |
| 2032 | } |
| 2033 | db_multi_exec( |
| 2034 | "INSERT OR IGNORE INTO user(login, info) VALUES(%Q,'')", zUser |
| 2035 | ); |
| 2036 | db_multi_exec( |
| 2037 | "UPDATE user SET cap='s', pw=lower(hex(randomblob(3)))" |
| 2038 | " WHERE login=%Q", zUser |
| 2039 | ); |
| 2040 | if( !setupUserOnly ){ |
| 2041 | db_multi_exec( |
| 2042 | "INSERT OR IGNORE INTO user(login,pw,cap,info)" |
| 2043 | " VALUES('anonymous',hex(randomblob(8)),'hmnc','Anon');" |
| 2044 |
| --- src/db.c | |
| +++ src/db.c | |
| @@ -117,10 +117,11 @@ | |
| 117 | /* |
| 118 | ** Arrange for the given file to be deleted on a failure. |
| 119 | */ |
| 120 | void db_delete_on_failure(const char *zFilename){ |
| 121 | assert( db.nDeleteOnFail<count(db.azDeleteOnFail) ); |
| 122 | if( zFilename==0 ) return; |
| 123 | db.azDeleteOnFail[db.nDeleteOnFail++] = fossil_strdup(zFilename); |
| 124 | } |
| 125 | |
| 126 | /* |
| 127 | ** Return the transaction nesting depth. 0 means we are currently |
| @@ -799,10 +800,13 @@ | |
| 800 | } |
| 801 | |
| 802 | /* |
| 803 | ** Initialize a new database file with the given schema. If anything |
| 804 | ** goes wrong, call db_err() to exit. |
| 805 | ** |
| 806 | ** If zFilename is NULL, then create an empty repository in an in-memory |
| 807 | ** database. |
| 808 | */ |
| 809 | void db_init_database( |
| 810 | const char *zFileName, /* Name of database file to create */ |
| 811 | const char *zSchema, /* First part of schema */ |
| 812 | ... /* Additional SQL to run. Terminate with NULL. */ |
| @@ -810,11 +814,11 @@ | |
| 814 | sqlite3 *db; |
| 815 | int rc; |
| 816 | const char *zSql; |
| 817 | va_list ap; |
| 818 | |
| 819 | db = db_open(zFileName ? zFileName : ":memory:"); |
| 820 | sqlite3_exec(db, "BEGIN EXCLUSIVE", 0, 0, 0); |
| 821 | rc = sqlite3_exec(db, zSchema, 0, 0, 0); |
| 822 | if( rc!=SQLITE_OK ){ |
| 823 | db_err("%s", sqlite3_errmsg(db)); |
| 824 | } |
| @@ -825,11 +829,15 @@ | |
| 829 | db_err("%s", sqlite3_errmsg(db)); |
| 830 | } |
| 831 | } |
| 832 | va_end(ap); |
| 833 | sqlite3_exec(db, "COMMIT", 0, 0, 0); |
| 834 | if( zFileName || g.db!=0 ){ |
| 835 | sqlite3_close(db); |
| 836 | }else{ |
| 837 | g.db = db; |
| 838 | } |
| 839 | } |
| 840 | |
| 841 | /* |
| 842 | ** Function to return the number of seconds since 1970. This is |
| 843 | ** the same as strftime('%s','now') but is more compact. |
| @@ -1768,12 +1776,13 @@ | |
| 1776 | |
| 1777 | /* |
| 1778 | ** Flags for the db_find_and_open_repository() function. |
| 1779 | */ |
| 1780 | #if INTERFACE |
| 1781 | #define OPEN_OK_NOT_FOUND 0x001 /* Do not error out if not found */ |
| 1782 | #define OPEN_ANY_SCHEMA 0x002 /* Do not error if schema is wrong */ |
| 1783 | #define OPEN_SUBSTITUTE 0x004 /* Fake in-memory repo if not found */ |
| 1784 | #endif |
| 1785 | |
| 1786 | /* |
| 1787 | ** Try to find the repository and open it. Use the -R or --repository |
| 1788 | ** option to locate the repository. If no such option is available, then |
| @@ -1802,11 +1811,16 @@ | |
| 1811 | if( g.repositoryOpen ){ |
| 1812 | if( (bFlags & OPEN_ANY_SCHEMA)==0 ) db_verify_schema(); |
| 1813 | return; |
| 1814 | } |
| 1815 | rep_not_found: |
| 1816 | if( bFlags & OPEN_OK_NOT_FOUND ){ |
| 1817 | /* No errors if the database is not found */ |
| 1818 | if( bFlags & OPEN_SUBSTITUTE ){ |
| 1819 | db_create_repository(0); |
| 1820 | } |
| 1821 | }else{ |
| 1822 | #ifdef FOSSIL_ENABLE_JSON |
| 1823 | g.json.resultCode = FSL_JSON_E_DB_NOT_FOUND; |
| 1824 | #endif |
| 1825 | if( nArgUsed==0 ){ |
| 1826 | fossil_fatal("use --repository or -R to specify the repository database"); |
| @@ -2032,12 +2046,12 @@ | |
| 2046 | } |
| 2047 | db_multi_exec( |
| 2048 | "INSERT OR IGNORE INTO user(login, info) VALUES(%Q,'')", zUser |
| 2049 | ); |
| 2050 | db_multi_exec( |
| 2051 | "UPDATE user SET cap='s', pw=%Q" |
| 2052 | " WHERE login=%Q", fossil_random_password(10), zUser |
| 2053 | ); |
| 2054 | if( !setupUserOnly ){ |
| 2055 | db_multi_exec( |
| 2056 | "INSERT OR IGNORE INTO user(login,pw,cap,info)" |
| 2057 | " VALUES('anonymous',hex(randomblob(8)),'hmnc','Anon');" |
| 2058 |
+2
-2
| --- src/doc.c | ||
| +++ src/doc.c | ||
| @@ -526,12 +526,12 @@ | ||
| 526 | 526 | for(base=0, i=7; i<n; i++){ |
| 527 | 527 | if( z[i]=='$' |
| 528 | 528 | && strncmp(&z[i],"$ROOT/", 6)==0 |
| 529 | 529 | && (z[i-1]=='\'' || z[i-1]=='"') |
| 530 | 530 | && i-base>=9 |
| 531 | - && (fossil_strnicmp(&z[i-7]," href=", 6)==0 || | |
| 532 | - fossil_strnicmp(&z[i-9]," action=", 8)==0) | |
| 531 | + && ((fossil_strnicmp(&z[i-6],"href=",5)==0 && fossil_isspace(z[i-7])) || | |
| 532 | + (fossil_strnicmp(&z[i-8],"action=",7)==0 && fossil_isspace(z[i-9])) ) | |
| 533 | 533 | ){ |
| 534 | 534 | blob_append(cgi_output_blob(), &z[base], i-base); |
| 535 | 535 | blob_appendf(cgi_output_blob(), "%R"); |
| 536 | 536 | base = i+5; |
| 537 | 537 | } |
| 538 | 538 |
| --- src/doc.c | |
| +++ src/doc.c | |
| @@ -526,12 +526,12 @@ | |
| 526 | for(base=0, i=7; i<n; i++){ |
| 527 | if( z[i]=='$' |
| 528 | && strncmp(&z[i],"$ROOT/", 6)==0 |
| 529 | && (z[i-1]=='\'' || z[i-1]=='"') |
| 530 | && i-base>=9 |
| 531 | && (fossil_strnicmp(&z[i-7]," href=", 6)==0 || |
| 532 | fossil_strnicmp(&z[i-9]," action=", 8)==0) |
| 533 | ){ |
| 534 | blob_append(cgi_output_blob(), &z[base], i-base); |
| 535 | blob_appendf(cgi_output_blob(), "%R"); |
| 536 | base = i+5; |
| 537 | } |
| 538 |
| --- src/doc.c | |
| +++ src/doc.c | |
| @@ -526,12 +526,12 @@ | |
| 526 | for(base=0, i=7; i<n; i++){ |
| 527 | if( z[i]=='$' |
| 528 | && strncmp(&z[i],"$ROOT/", 6)==0 |
| 529 | && (z[i-1]=='\'' || z[i-1]=='"') |
| 530 | && i-base>=9 |
| 531 | && ((fossil_strnicmp(&z[i-6],"href=",5)==0 && fossil_isspace(z[i-7])) || |
| 532 | (fossil_strnicmp(&z[i-8],"action=",7)==0 && fossil_isspace(z[i-9])) ) |
| 533 | ){ |
| 534 | blob_append(cgi_output_blob(), &z[base], i-base); |
| 535 | blob_appendf(cgi_output_blob(), "%R"); |
| 536 | base = i+5; |
| 537 | } |
| 538 |
+1
-1
| --- src/fshell.c | ||
| +++ src/fshell.c | ||
| @@ -109,11 +109,11 @@ | ||
| 109 | 109 | continue; |
| 110 | 110 | } |
| 111 | 111 | if( childPid==0 ){ |
| 112 | 112 | /* This is the child process */ |
| 113 | 113 | int main(int, char**); |
| 114 | - main(nArg, azArg); | |
| 114 | + fossil_main(nArg, azArg); | |
| 115 | 115 | exit(0); |
| 116 | 116 | }else{ |
| 117 | 117 | /* The parent process */ |
| 118 | 118 | int status; |
| 119 | 119 | waitpid(childPid, &status, 0); |
| 120 | 120 |
| --- src/fshell.c | |
| +++ src/fshell.c | |
| @@ -109,11 +109,11 @@ | |
| 109 | continue; |
| 110 | } |
| 111 | if( childPid==0 ){ |
| 112 | /* This is the child process */ |
| 113 | int main(int, char**); |
| 114 | main(nArg, azArg); |
| 115 | exit(0); |
| 116 | }else{ |
| 117 | /* The parent process */ |
| 118 | int status; |
| 119 | waitpid(childPid, &status, 0); |
| 120 |
| --- src/fshell.c | |
| +++ src/fshell.c | |
| @@ -109,11 +109,11 @@ | |
| 109 | continue; |
| 110 | } |
| 111 | if( childPid==0 ){ |
| 112 | /* This is the child process */ |
| 113 | int main(int, char**); |
| 114 | fossil_main(nArg, azArg); |
| 115 | exit(0); |
| 116 | }else{ |
| 117 | /* The parent process */ |
| 118 | int status; |
| 119 | waitpid(childPid, &status, 0); |
| 120 |
+2
-2
| --- src/login.c | ||
| +++ src/login.c | ||
| @@ -2018,11 +2018,11 @@ | ||
| 2018 | 2018 | const char *zNewName = find_option("name",0,1); |
| 2019 | 2019 | const char *zOther; |
| 2020 | 2020 | char *zErr = 0; |
| 2021 | 2021 | verify_all_options(); |
| 2022 | 2022 | if( g.argc!=4 ){ |
| 2023 | - fossil_fatal("unknown extra arguments to \"login-group add\""); | |
| 2023 | + fossil_fatal("unknown extra arguments to \"login-group join\""); | |
| 2024 | 2024 | } |
| 2025 | 2025 | zOther = g.argv[3]; |
| 2026 | 2026 | login_group_leave(&zErr); |
| 2027 | 2027 | sqlite3_free(zErr); |
| 2028 | 2028 | zErr = 0; |
| @@ -2042,11 +2042,11 @@ | ||
| 2042 | 2042 | login_group_leave(&zErr); |
| 2043 | 2043 | if( zErr ) fossil_fatal("Oops: %s", zErr); |
| 2044 | 2044 | return; |
| 2045 | 2045 | } |
| 2046 | 2046 | }else{ |
| 2047 | - fossil_fatal("unknown command \"%s\" - should be \"add\" or \"leave\"", | |
| 2047 | + fossil_fatal("unknown command \"%s\" - should be \"join\" or \"leave\"", | |
| 2048 | 2048 | zCmd); |
| 2049 | 2049 | } |
| 2050 | 2050 | } |
| 2051 | 2051 | /* Show the current login group information */ |
| 2052 | 2052 | zLGName = login_group_name(); |
| 2053 | 2053 |
| --- src/login.c | |
| +++ src/login.c | |
| @@ -2018,11 +2018,11 @@ | |
| 2018 | const char *zNewName = find_option("name",0,1); |
| 2019 | const char *zOther; |
| 2020 | char *zErr = 0; |
| 2021 | verify_all_options(); |
| 2022 | if( g.argc!=4 ){ |
| 2023 | fossil_fatal("unknown extra arguments to \"login-group add\""); |
| 2024 | } |
| 2025 | zOther = g.argv[3]; |
| 2026 | login_group_leave(&zErr); |
| 2027 | sqlite3_free(zErr); |
| 2028 | zErr = 0; |
| @@ -2042,11 +2042,11 @@ | |
| 2042 | login_group_leave(&zErr); |
| 2043 | if( zErr ) fossil_fatal("Oops: %s", zErr); |
| 2044 | return; |
| 2045 | } |
| 2046 | }else{ |
| 2047 | fossil_fatal("unknown command \"%s\" - should be \"add\" or \"leave\"", |
| 2048 | zCmd); |
| 2049 | } |
| 2050 | } |
| 2051 | /* Show the current login group information */ |
| 2052 | zLGName = login_group_name(); |
| 2053 |
| --- src/login.c | |
| +++ src/login.c | |
| @@ -2018,11 +2018,11 @@ | |
| 2018 | const char *zNewName = find_option("name",0,1); |
| 2019 | const char *zOther; |
| 2020 | char *zErr = 0; |
| 2021 | verify_all_options(); |
| 2022 | if( g.argc!=4 ){ |
| 2023 | fossil_fatal("unknown extra arguments to \"login-group join\""); |
| 2024 | } |
| 2025 | zOther = g.argv[3]; |
| 2026 | login_group_leave(&zErr); |
| 2027 | sqlite3_free(zErr); |
| 2028 | zErr = 0; |
| @@ -2042,11 +2042,11 @@ | |
| 2042 | login_group_leave(&zErr); |
| 2043 | if( zErr ) fossil_fatal("Oops: %s", zErr); |
| 2044 | return; |
| 2045 | } |
| 2046 | }else{ |
| 2047 | fossil_fatal("unknown command \"%s\" - should be \"join\" or \"leave\"", |
| 2048 | zCmd); |
| 2049 | } |
| 2050 | } |
| 2051 | /* Show the current login group information */ |
| 2052 | zLGName = login_group_name(); |
| 2053 |
+11
| --- src/main.c | ||
| +++ src/main.c | ||
| @@ -328,10 +328,12 @@ | ||
| 328 | 328 | /* |
| 329 | 329 | ** atexit() handler which frees up "some" of the resources |
| 330 | 330 | ** used by fossil. |
| 331 | 331 | */ |
| 332 | 332 | static void fossil_atexit(void) { |
| 333 | + static int once = 0; | |
| 334 | + if( once++ ) return; /* Ensure that this routine only runs once */ | |
| 333 | 335 | #if USE_SEE |
| 334 | 336 | /* |
| 335 | 337 | ** Zero, unlock, and free the saved database encryption key now. |
| 336 | 338 | */ |
| 337 | 339 | db_unsave_encryption_key(); |
| @@ -630,10 +632,19 @@ | ||
| 630 | 632 | int _CRT_glob = 0x0001; /* See MinGW bug #2062 */ |
| 631 | 633 | #endif |
| 632 | 634 | int main(int argc, char **argv) |
| 633 | 635 | #endif |
| 634 | 636 | { |
| 637 | + return fossil_main(argc, argv); | |
| 638 | +} | |
| 639 | + | |
| 640 | +/* All the work of main() is done by a separate procedure "fossil_main()". | |
| 641 | +** We have to break this out, because fossil_main() is sometimes called | |
| 642 | +** separately (by the "shell" command) but we do not want atwait() handlers | |
| 643 | +** being called by separate invocations of fossil_main(). | |
| 644 | +*/ | |
| 645 | +int fossil_main(int argc, char **argv){ | |
| 635 | 646 | const char *zCmdName = "unknown"; |
| 636 | 647 | const CmdOrPage *pCmd = 0; |
| 637 | 648 | int rc; |
| 638 | 649 | |
| 639 | 650 | #if !defined(_WIN32_WCE) |
| 640 | 651 |
| --- src/main.c | |
| +++ src/main.c | |
| @@ -328,10 +328,12 @@ | |
| 328 | /* |
| 329 | ** atexit() handler which frees up "some" of the resources |
| 330 | ** used by fossil. |
| 331 | */ |
| 332 | static void fossil_atexit(void) { |
| 333 | #if USE_SEE |
| 334 | /* |
| 335 | ** Zero, unlock, and free the saved database encryption key now. |
| 336 | */ |
| 337 | db_unsave_encryption_key(); |
| @@ -630,10 +632,19 @@ | |
| 630 | int _CRT_glob = 0x0001; /* See MinGW bug #2062 */ |
| 631 | #endif |
| 632 | int main(int argc, char **argv) |
| 633 | #endif |
| 634 | { |
| 635 | const char *zCmdName = "unknown"; |
| 636 | const CmdOrPage *pCmd = 0; |
| 637 | int rc; |
| 638 | |
| 639 | #if !defined(_WIN32_WCE) |
| 640 |
| --- src/main.c | |
| +++ src/main.c | |
| @@ -328,10 +328,12 @@ | |
| 328 | /* |
| 329 | ** atexit() handler which frees up "some" of the resources |
| 330 | ** used by fossil. |
| 331 | */ |
| 332 | static void fossil_atexit(void) { |
| 333 | static int once = 0; |
| 334 | if( once++ ) return; /* Ensure that this routine only runs once */ |
| 335 | #if USE_SEE |
| 336 | /* |
| 337 | ** Zero, unlock, and free the saved database encryption key now. |
| 338 | */ |
| 339 | db_unsave_encryption_key(); |
| @@ -630,10 +632,19 @@ | |
| 632 | int _CRT_glob = 0x0001; /* See MinGW bug #2062 */ |
| 633 | #endif |
| 634 | int main(int argc, char **argv) |
| 635 | #endif |
| 636 | { |
| 637 | return fossil_main(argc, argv); |
| 638 | } |
| 639 | |
| 640 | /* All the work of main() is done by a separate procedure "fossil_main()". |
| 641 | ** We have to break this out, because fossil_main() is sometimes called |
| 642 | ** separately (by the "shell" command) but we do not want atwait() handlers |
| 643 | ** being called by separate invocations of fossil_main(). |
| 644 | */ |
| 645 | int fossil_main(int argc, char **argv){ |
| 646 | const char *zCmdName = "unknown"; |
| 647 | const CmdOrPage *pCmd = 0; |
| 648 | int rc; |
| 649 | |
| 650 | #if !defined(_WIN32_WCE) |
| 651 |
+5
-1
| --- src/markdown_html.c | ||
| +++ src/markdown_html.c | ||
| @@ -433,11 +433,15 @@ | ||
| 433 | 433 | char zClose[20]; |
| 434 | 434 | |
| 435 | 435 | if( zLink==0 || zLink[0]==0 ){ |
| 436 | 436 | zClose[0] = 0; |
| 437 | 437 | }else{ |
| 438 | - wiki_resolve_hyperlink(ob, 0, zLink, zClose, sizeof(zClose), 0, zTitle); | |
| 438 | + static const int flags = | |
| 439 | + WIKI_NOBADLINKS | | |
| 440 | + WIKI_MARKDOWNLINKS | |
| 441 | + ; | |
| 442 | + wiki_resolve_hyperlink(ob, flags, zLink, zClose, sizeof(zClose), 0, zTitle); | |
| 439 | 443 | } |
| 440 | 444 | if( blob_size(content)==0 ){ |
| 441 | 445 | if( link ) BLOB_APPEND_BLOB(ob, link); |
| 442 | 446 | }else{ |
| 443 | 447 | BLOB_APPEND_BLOB(ob, content); |
| 444 | 448 |
| --- src/markdown_html.c | |
| +++ src/markdown_html.c | |
| @@ -433,11 +433,15 @@ | |
| 433 | char zClose[20]; |
| 434 | |
| 435 | if( zLink==0 || zLink[0]==0 ){ |
| 436 | zClose[0] = 0; |
| 437 | }else{ |
| 438 | wiki_resolve_hyperlink(ob, 0, zLink, zClose, sizeof(zClose), 0, zTitle); |
| 439 | } |
| 440 | if( blob_size(content)==0 ){ |
| 441 | if( link ) BLOB_APPEND_BLOB(ob, link); |
| 442 | }else{ |
| 443 | BLOB_APPEND_BLOB(ob, content); |
| 444 |
| --- src/markdown_html.c | |
| +++ src/markdown_html.c | |
| @@ -433,11 +433,15 @@ | |
| 433 | char zClose[20]; |
| 434 | |
| 435 | if( zLink==0 || zLink[0]==0 ){ |
| 436 | zClose[0] = 0; |
| 437 | }else{ |
| 438 | static const int flags = |
| 439 | WIKI_NOBADLINKS | |
| 440 | WIKI_MARKDOWNLINKS |
| 441 | ; |
| 442 | wiki_resolve_hyperlink(ob, flags, zLink, zClose, sizeof(zClose), 0, zTitle); |
| 443 | } |
| 444 | if( blob_size(content)==0 ){ |
| 445 | if( link ) BLOB_APPEND_BLOB(ob, link); |
| 446 | }else{ |
| 447 | BLOB_APPEND_BLOB(ob, content); |
| 448 |
+53
| --- src/util.c | ||
| +++ src/util.c | ||
| @@ -525,5 +525,58 @@ | ||
| 525 | 525 | fossil_panic("pledge(\"%s\",NULL) fails with errno=%d", |
| 526 | 526 | promises, (int)errno); |
| 527 | 527 | } |
| 528 | 528 | } |
| 529 | 529 | #endif /* defined(HAVE_PLEDGE) */ |
| 530 | + | |
| 531 | +/* | |
| 532 | +** Construct a random password and return it as a string. N is the | |
| 533 | +** recommended number of characters for the password. | |
| 534 | +** | |
| 535 | +** Space to hold the returned string is obtained from fossil_malloc() | |
| 536 | +** and should be freed by the caller. | |
| 537 | +*/ | |
| 538 | +char *fossil_random_password(int N){ | |
| 539 | + char zSrc[60]; | |
| 540 | + int nSrc; | |
| 541 | + int i; | |
| 542 | + char z[60]; | |
| 543 | + | |
| 544 | + /* Source characters for the password. Omit characters like "0", "O", | |
| 545 | + ** "1" and "I" that might be easily confused */ | |
| 546 | + static const char zAlphabet[] = | |
| 547 | + /* 0 1 2 3 4 5 */ | |
| 548 | + /* 123456789 123456789 123456789 123456789 123456789 123456 */ | |
| 549 | + "23456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ"; | |
| 550 | + | |
| 551 | + if( N<8 ) N = 8; | |
| 552 | + else if( N>sizeof(zAlphabet)-2 ) N = sizeof(zAlphabet)-2; | |
| 553 | + nSrc = sizeof(zAlphabet) - 1; | |
| 554 | + memcpy(zSrc, zAlphabet, nSrc); | |
| 555 | + | |
| 556 | + for(i=0; i<N; i++){ | |
| 557 | + unsigned r; | |
| 558 | + sqlite3_randomness(sizeof(r), &r); | |
| 559 | + r %= nSrc; | |
| 560 | + z[i] = zSrc[r]; | |
| 561 | + zSrc[r] = zSrc[--nSrc]; | |
| 562 | + } | |
| 563 | + z[i] = 0; | |
| 564 | + return fossil_strdup(z); | |
| 565 | +} | |
| 566 | + | |
| 567 | +/* | |
| 568 | +** COMMAND: test-random-password | |
| 569 | +** | |
| 570 | +** Usage: %fossil test-random-password ?N? | |
| 571 | +** | |
| 572 | +** Generate a random password string of approximately N characters in length. | |
| 573 | +** If N is omitted, use 10. Values of N less than 8 are changed to 8 | |
| 574 | +** and greater than 55 and changed to 55. | |
| 575 | +*/ | |
| 576 | +void test_random_password(void){ | |
| 577 | + int N = 10; | |
| 578 | + if( g.argc>=3 ){ | |
| 579 | + N = atoi(g.argv[2]); | |
| 580 | + } | |
| 581 | + fossil_print("%s\n", fossil_random_password(N)); | |
| 582 | +} | |
| 530 | 583 |
| --- src/util.c | |
| +++ src/util.c | |
| @@ -525,5 +525,58 @@ | |
| 525 | fossil_panic("pledge(\"%s\",NULL) fails with errno=%d", |
| 526 | promises, (int)errno); |
| 527 | } |
| 528 | } |
| 529 | #endif /* defined(HAVE_PLEDGE) */ |
| 530 |
| --- src/util.c | |
| +++ src/util.c | |
| @@ -525,5 +525,58 @@ | |
| 525 | fossil_panic("pledge(\"%s\",NULL) fails with errno=%d", |
| 526 | promises, (int)errno); |
| 527 | } |
| 528 | } |
| 529 | #endif /* defined(HAVE_PLEDGE) */ |
| 530 | |
| 531 | /* |
| 532 | ** Construct a random password and return it as a string. N is the |
| 533 | ** recommended number of characters for the password. |
| 534 | ** |
| 535 | ** Space to hold the returned string is obtained from fossil_malloc() |
| 536 | ** and should be freed by the caller. |
| 537 | */ |
| 538 | char *fossil_random_password(int N){ |
| 539 | char zSrc[60]; |
| 540 | int nSrc; |
| 541 | int i; |
| 542 | char z[60]; |
| 543 | |
| 544 | /* Source characters for the password. Omit characters like "0", "O", |
| 545 | ** "1" and "I" that might be easily confused */ |
| 546 | static const char zAlphabet[] = |
| 547 | /* 0 1 2 3 4 5 */ |
| 548 | /* 123456789 123456789 123456789 123456789 123456789 123456 */ |
| 549 | "23456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ"; |
| 550 | |
| 551 | if( N<8 ) N = 8; |
| 552 | else if( N>sizeof(zAlphabet)-2 ) N = sizeof(zAlphabet)-2; |
| 553 | nSrc = sizeof(zAlphabet) - 1; |
| 554 | memcpy(zSrc, zAlphabet, nSrc); |
| 555 | |
| 556 | for(i=0; i<N; i++){ |
| 557 | unsigned r; |
| 558 | sqlite3_randomness(sizeof(r), &r); |
| 559 | r %= nSrc; |
| 560 | z[i] = zSrc[r]; |
| 561 | zSrc[r] = zSrc[--nSrc]; |
| 562 | } |
| 563 | z[i] = 0; |
| 564 | return fossil_strdup(z); |
| 565 | } |
| 566 | |
| 567 | /* |
| 568 | ** COMMAND: test-random-password |
| 569 | ** |
| 570 | ** Usage: %fossil test-random-password ?N? |
| 571 | ** |
| 572 | ** Generate a random password string of approximately N characters in length. |
| 573 | ** If N is omitted, use 10. Values of N less than 8 are changed to 8 |
| 574 | ** and greater than 55 and changed to 55. |
| 575 | */ |
| 576 | void test_random_password(void){ |
| 577 | int N = 10; |
| 578 | if( g.argc>=3 ){ |
| 579 | N = atoi(g.argv[2]); |
| 580 | } |
| 581 | fossil_print("%s\n", fossil_random_password(N)); |
| 582 | } |
| 583 |
+1
| --- src/wiki.c | ||
| +++ src/wiki.c | ||
| @@ -1629,10 +1629,11 @@ | ||
| 1629 | 1629 | ** Render markdown wiki from FILE to stdout. |
| 1630 | 1630 | ** |
| 1631 | 1631 | */ |
| 1632 | 1632 | void test_markdown_render(void){ |
| 1633 | 1633 | Blob in, out; |
| 1634 | + db_find_and_open_repository(OPEN_OK_NOT_FOUND|OPEN_SUBSTITUTE,0); | |
| 1634 | 1635 | verify_all_options(); |
| 1635 | 1636 | if( g.argc!=3 ) usage("FILE"); |
| 1636 | 1637 | blob_zero(&out); |
| 1637 | 1638 | blob_read_from_file(&in, g.argv[2], ExtFILE); |
| 1638 | 1639 | markdown_to_html(&in, 0, &out); |
| 1639 | 1640 |
| --- src/wiki.c | |
| +++ src/wiki.c | |
| @@ -1629,10 +1629,11 @@ | |
| 1629 | ** Render markdown wiki from FILE to stdout. |
| 1630 | ** |
| 1631 | */ |
| 1632 | void test_markdown_render(void){ |
| 1633 | Blob in, out; |
| 1634 | verify_all_options(); |
| 1635 | if( g.argc!=3 ) usage("FILE"); |
| 1636 | blob_zero(&out); |
| 1637 | blob_read_from_file(&in, g.argv[2], ExtFILE); |
| 1638 | markdown_to_html(&in, 0, &out); |
| 1639 |
| --- src/wiki.c | |
| +++ src/wiki.c | |
| @@ -1629,10 +1629,11 @@ | |
| 1629 | ** Render markdown wiki from FILE to stdout. |
| 1630 | ** |
| 1631 | */ |
| 1632 | void test_markdown_render(void){ |
| 1633 | Blob in, out; |
| 1634 | db_find_and_open_repository(OPEN_OK_NOT_FOUND|OPEN_SUBSTITUTE,0); |
| 1635 | verify_all_options(); |
| 1636 | if( g.argc!=3 ) usage("FILE"); |
| 1637 | blob_zero(&out); |
| 1638 | blob_read_from_file(&in, g.argv[2], ExtFILE); |
| 1639 | markdown_to_html(&in, 0, &out); |
| 1640 |
+24
-19
| --- src/wikiformat.c | ||
| +++ src/wikiformat.c | ||
| @@ -30,10 +30,11 @@ | ||
| 30 | 30 | #define WIKI_NOBLOCK 0x004 /* No block markup of any kind */ |
| 31 | 31 | #define WIKI_BUTTONS 0x008 /* Allow sub-menu buttons */ |
| 32 | 32 | #define WIKI_NOBADLINKS 0x010 /* Ignore broken hyperlinks */ |
| 33 | 33 | #define WIKI_LINKSONLY 0x020 /* No markup. Only decorate links */ |
| 34 | 34 | #define WIKI_NEWLINE 0x040 /* Honor \n - break lines at each \n */ |
| 35 | +#define WIKI_MARKDOWNLINKS 0x080 /* Resolve hyperlinks as in markdown */ | |
| 35 | 36 | #endif |
| 36 | 37 | |
| 37 | 38 | |
| 38 | 39 | /* |
| 39 | 40 | ** These are the only markup attributes allowed. |
| @@ -1211,20 +1212,22 @@ | ||
| 1211 | 1212 | ** [http://www.fossil-scm.org/] |
| 1212 | 1213 | ** [https://www.fossil-scm.org/] |
| 1213 | 1214 | ** [ftp://www.fossil-scm.org/] |
| 1214 | 1215 | ** [mailto:[email protected]] |
| 1215 | 1216 | ** |
| 1216 | -** [/path] | |
| 1217 | +** [/path] -> Refers to the root of the Fossil hierarchy, not | |
| 1218 | +** the root of the URI domain | |
| 1217 | 1219 | ** |
| 1218 | 1220 | ** [./relpath] |
| 1221 | +** [../relpath] | |
| 1219 | 1222 | ** |
| 1220 | -** [WikiPageName] | |
| 1221 | -** [wiki:WikiPageName] | |
| 1223 | +** [#fragment] | |
| 1222 | 1224 | ** |
| 1223 | 1225 | ** [0123456789abcdef] |
| 1224 | 1226 | ** |
| 1225 | -** [#fragment] | |
| 1227 | +** [WikiPageName] | |
| 1228 | +** [wiki:WikiPageName] | |
| 1226 | 1229 | ** |
| 1227 | 1230 | ** [2010-02-27 07:13] |
| 1228 | 1231 | */ |
| 1229 | 1232 | void wiki_resolve_hyperlink( |
| 1230 | 1233 | Blob *pOut, /* Write the HTML output here */ |
| @@ -1296,24 +1299,35 @@ | ||
| 1296 | 1299 | blob_appendf(pOut, "%z[",xhref(zExtraNS, "%R/info/%s", zTarget)); |
| 1297 | 1300 | zTerm = "]</a>"; |
| 1298 | 1301 | }else{ |
| 1299 | 1302 | zTerm = ""; |
| 1300 | 1303 | } |
| 1301 | - }else if( strlen(zTarget)>=10 && fossil_isdigit(zTarget[0]) && zTarget[4]=='-' | |
| 1302 | - && db_int(0, "SELECT datetime(%Q) NOT NULL", zTarget) ){ | |
| 1303 | - blob_appendf(pOut, "<a href=\"%R/timeline?c=%T\"%s>", zTarget, zExtra); | |
| 1304 | 1304 | }else if( (z = validWikiPageName(mFlags, zTarget))!=0 ){ |
| 1305 | + /* The link is to a valid wiki page name */ | |
| 1305 | 1306 | const char *zOverride = wiki_is_overridden(zTarget); |
| 1306 | 1307 | if( zOverride ){ |
| 1307 | 1308 | blob_appendf(pOut, "<a href=\"%R/info/%S\"%s>", zOverride, zExtra); |
| 1308 | 1309 | }else{ |
| 1309 | 1310 | blob_appendf(pOut, "<a href=\"%R/wiki?name=%T\"%s>", z, zExtra); |
| 1310 | 1311 | } |
| 1311 | - }else if( zOrig && zTarget>=&zOrig[2] && !fossil_isspace(zTarget[-2]) ){ | |
| 1312 | - /* Probably an array subscript in code */ | |
| 1312 | + }else if( strlen(zTarget)>=10 && fossil_isdigit(zTarget[0]) && zTarget[4]=='-' | |
| 1313 | + && db_int(0, "SELECT datetime(%Q) NOT NULL", zTarget) ){ | |
| 1314 | + /* Dates or date-and-times in ISO8610 resolve to a link to the | |
| 1315 | + ** timeline for that date */ | |
| 1316 | + blob_appendf(pOut, "<a href=\"%R/timeline?c=%T\"%s>", zTarget, zExtra); | |
| 1317 | + }else if( mFlags & WIKI_MARKDOWNLINKS ){ | |
| 1318 | + /* If none of the above, and if rendering links for markdown, then | |
| 1319 | + ** create a link to the literal text of the target */ | |
| 1320 | + blob_appendf(pOut, "<a href=\"%h\"%s>", zTarget, zExtra); | |
| 1321 | + }else if( zOrig && zTarget>=&zOrig[2] | |
| 1322 | + && zTarget[-1]=='[' && !fossil_isspace(zTarget[-2]) ){ | |
| 1323 | + /* If the hyperlink markup is not preceded by whitespace, then it | |
| 1324 | + ** is probably a C-language subscript or similar, not really a | |
| 1325 | + ** hyperlink. Just ignore it. */ | |
| 1313 | 1326 | zTerm = ""; |
| 1314 | 1327 | }else if( (mFlags & (WIKI_NOBADLINKS|WIKI_LINKSONLY))!=0 ){ |
| 1328 | + /* Also ignore the link if various flags are set */ | |
| 1315 | 1329 | zTerm = ""; |
| 1316 | 1330 | }else{ |
| 1317 | 1331 | blob_appendf(pOut, "<span class=\"brokenlink\">[%h]", zTarget); |
| 1318 | 1332 | zTerm = "</span>"; |
| 1319 | 1333 | } |
| @@ -1758,20 +1772,10 @@ | ||
| 1758 | 1772 | } |
| 1759 | 1773 | blob_append(renderer.pOut, "\n", 1); |
| 1760 | 1774 | free(renderer.aStack); |
| 1761 | 1775 | } |
| 1762 | 1776 | |
| 1763 | -/* | |
| 1764 | -** Send a string as wiki to CGI output. | |
| 1765 | -*/ | |
| 1766 | -void wiki_write(const char *zIn, int flags){ | |
| 1767 | - Blob in; | |
| 1768 | - blob_init(&in, zIn, -1); | |
| 1769 | - wiki_convert(&in, 0, flags); | |
| 1770 | - blob_reset(&in); | |
| 1771 | -} | |
| 1772 | - | |
| 1773 | 1777 | /* |
| 1774 | 1778 | ** COMMAND: test-wiki-render |
| 1775 | 1779 | ** |
| 1776 | 1780 | ** Usage: %fossil test-wiki-render FILE [OPTIONS] |
| 1777 | 1781 | ** |
| @@ -1790,10 +1794,11 @@ | ||
| 1790 | 1794 | if( find_option("htmlonly",0,0)!=0 ) flags |= WIKI_HTMLONLY; |
| 1791 | 1795 | if( find_option("linksonly",0,0)!=0 ) flags |= WIKI_LINKSONLY; |
| 1792 | 1796 | if( find_option("nobadlinks",0,0)!=0 ) flags |= WIKI_NOBADLINKS; |
| 1793 | 1797 | if( find_option("inline",0,0)!=0 ) flags |= WIKI_INLINE; |
| 1794 | 1798 | if( find_option("noblock",0,0)!=0 ) flags |= WIKI_NOBLOCK; |
| 1799 | + db_find_and_open_repository(OPEN_OK_NOT_FOUND|OPEN_SUBSTITUTE,0); | |
| 1795 | 1800 | verify_all_options(); |
| 1796 | 1801 | if( g.argc!=3 ) usage("FILE"); |
| 1797 | 1802 | blob_zero(&out); |
| 1798 | 1803 | blob_read_from_file(&in, g.argv[2], ExtFILE); |
| 1799 | 1804 | wiki_convert(&in, &out, flags); |
| 1800 | 1805 |
| --- src/wikiformat.c | |
| +++ src/wikiformat.c | |
| @@ -30,10 +30,11 @@ | |
| 30 | #define WIKI_NOBLOCK 0x004 /* No block markup of any kind */ |
| 31 | #define WIKI_BUTTONS 0x008 /* Allow sub-menu buttons */ |
| 32 | #define WIKI_NOBADLINKS 0x010 /* Ignore broken hyperlinks */ |
| 33 | #define WIKI_LINKSONLY 0x020 /* No markup. Only decorate links */ |
| 34 | #define WIKI_NEWLINE 0x040 /* Honor \n - break lines at each \n */ |
| 35 | #endif |
| 36 | |
| 37 | |
| 38 | /* |
| 39 | ** These are the only markup attributes allowed. |
| @@ -1211,20 +1212,22 @@ | |
| 1211 | ** [http://www.fossil-scm.org/] |
| 1212 | ** [https://www.fossil-scm.org/] |
| 1213 | ** [ftp://www.fossil-scm.org/] |
| 1214 | ** [mailto:[email protected]] |
| 1215 | ** |
| 1216 | ** [/path] |
| 1217 | ** |
| 1218 | ** [./relpath] |
| 1219 | ** |
| 1220 | ** [WikiPageName] |
| 1221 | ** [wiki:WikiPageName] |
| 1222 | ** |
| 1223 | ** [0123456789abcdef] |
| 1224 | ** |
| 1225 | ** [#fragment] |
| 1226 | ** |
| 1227 | ** [2010-02-27 07:13] |
| 1228 | */ |
| 1229 | void wiki_resolve_hyperlink( |
| 1230 | Blob *pOut, /* Write the HTML output here */ |
| @@ -1296,24 +1299,35 @@ | |
| 1296 | blob_appendf(pOut, "%z[",xhref(zExtraNS, "%R/info/%s", zTarget)); |
| 1297 | zTerm = "]</a>"; |
| 1298 | }else{ |
| 1299 | zTerm = ""; |
| 1300 | } |
| 1301 | }else if( strlen(zTarget)>=10 && fossil_isdigit(zTarget[0]) && zTarget[4]=='-' |
| 1302 | && db_int(0, "SELECT datetime(%Q) NOT NULL", zTarget) ){ |
| 1303 | blob_appendf(pOut, "<a href=\"%R/timeline?c=%T\"%s>", zTarget, zExtra); |
| 1304 | }else if( (z = validWikiPageName(mFlags, zTarget))!=0 ){ |
| 1305 | const char *zOverride = wiki_is_overridden(zTarget); |
| 1306 | if( zOverride ){ |
| 1307 | blob_appendf(pOut, "<a href=\"%R/info/%S\"%s>", zOverride, zExtra); |
| 1308 | }else{ |
| 1309 | blob_appendf(pOut, "<a href=\"%R/wiki?name=%T\"%s>", z, zExtra); |
| 1310 | } |
| 1311 | }else if( zOrig && zTarget>=&zOrig[2] && !fossil_isspace(zTarget[-2]) ){ |
| 1312 | /* Probably an array subscript in code */ |
| 1313 | zTerm = ""; |
| 1314 | }else if( (mFlags & (WIKI_NOBADLINKS|WIKI_LINKSONLY))!=0 ){ |
| 1315 | zTerm = ""; |
| 1316 | }else{ |
| 1317 | blob_appendf(pOut, "<span class=\"brokenlink\">[%h]", zTarget); |
| 1318 | zTerm = "</span>"; |
| 1319 | } |
| @@ -1758,20 +1772,10 @@ | |
| 1758 | } |
| 1759 | blob_append(renderer.pOut, "\n", 1); |
| 1760 | free(renderer.aStack); |
| 1761 | } |
| 1762 | |
| 1763 | /* |
| 1764 | ** Send a string as wiki to CGI output. |
| 1765 | */ |
| 1766 | void wiki_write(const char *zIn, int flags){ |
| 1767 | Blob in; |
| 1768 | blob_init(&in, zIn, -1); |
| 1769 | wiki_convert(&in, 0, flags); |
| 1770 | blob_reset(&in); |
| 1771 | } |
| 1772 | |
| 1773 | /* |
| 1774 | ** COMMAND: test-wiki-render |
| 1775 | ** |
| 1776 | ** Usage: %fossil test-wiki-render FILE [OPTIONS] |
| 1777 | ** |
| @@ -1790,10 +1794,11 @@ | |
| 1790 | if( find_option("htmlonly",0,0)!=0 ) flags |= WIKI_HTMLONLY; |
| 1791 | if( find_option("linksonly",0,0)!=0 ) flags |= WIKI_LINKSONLY; |
| 1792 | if( find_option("nobadlinks",0,0)!=0 ) flags |= WIKI_NOBADLINKS; |
| 1793 | if( find_option("inline",0,0)!=0 ) flags |= WIKI_INLINE; |
| 1794 | if( find_option("noblock",0,0)!=0 ) flags |= WIKI_NOBLOCK; |
| 1795 | verify_all_options(); |
| 1796 | if( g.argc!=3 ) usage("FILE"); |
| 1797 | blob_zero(&out); |
| 1798 | blob_read_from_file(&in, g.argv[2], ExtFILE); |
| 1799 | wiki_convert(&in, &out, flags); |
| 1800 |
| --- src/wikiformat.c | |
| +++ src/wikiformat.c | |
| @@ -30,10 +30,11 @@ | |
| 30 | #define WIKI_NOBLOCK 0x004 /* No block markup of any kind */ |
| 31 | #define WIKI_BUTTONS 0x008 /* Allow sub-menu buttons */ |
| 32 | #define WIKI_NOBADLINKS 0x010 /* Ignore broken hyperlinks */ |
| 33 | #define WIKI_LINKSONLY 0x020 /* No markup. Only decorate links */ |
| 34 | #define WIKI_NEWLINE 0x040 /* Honor \n - break lines at each \n */ |
| 35 | #define WIKI_MARKDOWNLINKS 0x080 /* Resolve hyperlinks as in markdown */ |
| 36 | #endif |
| 37 | |
| 38 | |
| 39 | /* |
| 40 | ** These are the only markup attributes allowed. |
| @@ -1211,20 +1212,22 @@ | |
| 1212 | ** [http://www.fossil-scm.org/] |
| 1213 | ** [https://www.fossil-scm.org/] |
| 1214 | ** [ftp://www.fossil-scm.org/] |
| 1215 | ** [mailto:[email protected]] |
| 1216 | ** |
| 1217 | ** [/path] -> Refers to the root of the Fossil hierarchy, not |
| 1218 | ** the root of the URI domain |
| 1219 | ** |
| 1220 | ** [./relpath] |
| 1221 | ** [../relpath] |
| 1222 | ** |
| 1223 | ** [#fragment] |
| 1224 | ** |
| 1225 | ** [0123456789abcdef] |
| 1226 | ** |
| 1227 | ** [WikiPageName] |
| 1228 | ** [wiki:WikiPageName] |
| 1229 | ** |
| 1230 | ** [2010-02-27 07:13] |
| 1231 | */ |
| 1232 | void wiki_resolve_hyperlink( |
| 1233 | Blob *pOut, /* Write the HTML output here */ |
| @@ -1296,24 +1299,35 @@ | |
| 1299 | blob_appendf(pOut, "%z[",xhref(zExtraNS, "%R/info/%s", zTarget)); |
| 1300 | zTerm = "]</a>"; |
| 1301 | }else{ |
| 1302 | zTerm = ""; |
| 1303 | } |
| 1304 | }else if( (z = validWikiPageName(mFlags, zTarget))!=0 ){ |
| 1305 | /* The link is to a valid wiki page name */ |
| 1306 | const char *zOverride = wiki_is_overridden(zTarget); |
| 1307 | if( zOverride ){ |
| 1308 | blob_appendf(pOut, "<a href=\"%R/info/%S\"%s>", zOverride, zExtra); |
| 1309 | }else{ |
| 1310 | blob_appendf(pOut, "<a href=\"%R/wiki?name=%T\"%s>", z, zExtra); |
| 1311 | } |
| 1312 | }else if( strlen(zTarget)>=10 && fossil_isdigit(zTarget[0]) && zTarget[4]=='-' |
| 1313 | && db_int(0, "SELECT datetime(%Q) NOT NULL", zTarget) ){ |
| 1314 | /* Dates or date-and-times in ISO8610 resolve to a link to the |
| 1315 | ** timeline for that date */ |
| 1316 | blob_appendf(pOut, "<a href=\"%R/timeline?c=%T\"%s>", zTarget, zExtra); |
| 1317 | }else if( mFlags & WIKI_MARKDOWNLINKS ){ |
| 1318 | /* If none of the above, and if rendering links for markdown, then |
| 1319 | ** create a link to the literal text of the target */ |
| 1320 | blob_appendf(pOut, "<a href=\"%h\"%s>", zTarget, zExtra); |
| 1321 | }else if( zOrig && zTarget>=&zOrig[2] |
| 1322 | && zTarget[-1]=='[' && !fossil_isspace(zTarget[-2]) ){ |
| 1323 | /* If the hyperlink markup is not preceded by whitespace, then it |
| 1324 | ** is probably a C-language subscript or similar, not really a |
| 1325 | ** hyperlink. Just ignore it. */ |
| 1326 | zTerm = ""; |
| 1327 | }else if( (mFlags & (WIKI_NOBADLINKS|WIKI_LINKSONLY))!=0 ){ |
| 1328 | /* Also ignore the link if various flags are set */ |
| 1329 | zTerm = ""; |
| 1330 | }else{ |
| 1331 | blob_appendf(pOut, "<span class=\"brokenlink\">[%h]", zTarget); |
| 1332 | zTerm = "</span>"; |
| 1333 | } |
| @@ -1758,20 +1772,10 @@ | |
| 1772 | } |
| 1773 | blob_append(renderer.pOut, "\n", 1); |
| 1774 | free(renderer.aStack); |
| 1775 | } |
| 1776 | |
| 1777 | /* |
| 1778 | ** COMMAND: test-wiki-render |
| 1779 | ** |
| 1780 | ** Usage: %fossil test-wiki-render FILE [OPTIONS] |
| 1781 | ** |
| @@ -1790,10 +1794,11 @@ | |
| 1794 | if( find_option("htmlonly",0,0)!=0 ) flags |= WIKI_HTMLONLY; |
| 1795 | if( find_option("linksonly",0,0)!=0 ) flags |= WIKI_LINKSONLY; |
| 1796 | if( find_option("nobadlinks",0,0)!=0 ) flags |= WIKI_NOBADLINKS; |
| 1797 | if( find_option("inline",0,0)!=0 ) flags |= WIKI_INLINE; |
| 1798 | if( find_option("noblock",0,0)!=0 ) flags |= WIKI_NOBLOCK; |
| 1799 | db_find_and_open_repository(OPEN_OK_NOT_FOUND|OPEN_SUBSTITUTE,0); |
| 1800 | verify_all_options(); |
| 1801 | if( g.argc!=3 ) usage("FILE"); |
| 1802 | blob_zero(&out); |
| 1803 | blob_read_from_file(&in, g.argv[2], ExtFILE); |
| 1804 | wiki_convert(&in, &out, flags); |
| 1805 |
+151
-69
| --- www/defcsp.md | ||
| +++ www/defcsp.md | ||
| @@ -1,106 +1,188 @@ | ||
| 1 | 1 | # The Default Content Security Policy (CSP) |
| 2 | 2 | |
| 3 | -When Fossil’s web interface generates an HTML page, it | |
| 4 | -normally includes a [Content Security Policy][csp] (CSP) | |
| 5 | -in the `<head>`. | |
| 6 | -The CSP tells the browser what types of content (HTML, image, CSS, | |
| 7 | -JavaScript...) the document may reference and from where the | |
| 8 | -content may be sourced. | |
| 9 | - | |
| 10 | -CSP is a security measure designed to prevent [cross-site scripting][xss] | |
| 11 | -(XSS) and other similar code injection attacks. | |
| 12 | -The CSP defines a “white list” of content types and origins that | |
| 13 | -are considered safe. Any references to resources that are not | |
| 14 | -on the white list are ignored. | |
| 15 | - | |
| 16 | -If Fossil were perfect and bug-free and never allowed any kind of | |
| 17 | -code injection on the pages it generates, then the CSP would not | |
| 18 | -be useful. The Fossil developers are not aware of any defects | |
| 19 | -in Fossil that allow code injection, and will promptly fix any defects | |
| 20 | -that are brought to their attention. Lots of eyeballs are looking at | |
| 21 | -Fossil to find problems in the code, and the Fossil build process uses | |
| 22 | -custom static analysis techniques to help identify code injection problems | |
| 23 | -at compile-time. Nevertheless, problems do sometimes (rarely) slip | |
| 24 | -through. The CSP serves as a final line of defense, preventing | |
| 25 | -code injection defects in Fossil from turning into actual | |
| 26 | -vulnerabilities. | |
| 3 | +When Fossil’s web interface generates an HTML page, it normally includes | |
| 4 | +a [Content Security Policy][csp] (CSP) in the `<head>`. The CSP defines | |
| 5 | +a “white list” to tell the browser what types of content (HTML, images, | |
| 6 | +CSS, JavaScript...) the document may reference and the sources the | |
| 7 | +browser is allowed to pull such content from. The aim is to prevent | |
| 8 | +certain classes of [cross-site scripting][xss] (XSS) and code injection | |
| 9 | +attacks. The browser will not pull content types disallowed by the CSP. | |
| 10 | + | |
| 11 | +Fossil has built-in server-side content filtering logic. For example, it | |
| 12 | +purposely breaks `<script>` tags when it finds them in Markdown and | |
| 13 | +Fossil Wiki documents. (But not in [HTML-formatted embedded | |
| 14 | +docs][hfed]!) We also back that with multiple levels of analysis and | |
| 15 | +checks to find and fix content security problems: compile-time static | |
| 16 | +analysis, run-time dynamic analysis, and manual code inspection. Fossil | |
| 17 | +is open source software, so it benefits from the “[many | |
| 18 | +eyeballs][llaw],” limited by the size of its developer community. | |
| 19 | + | |
| 20 | +However, there is a practical limit to the power of server-side | |
| 21 | +filtering and code quality practices. | |
| 22 | + | |
| 23 | +First, there is an endless battle between those looking for clever paths | |
| 24 | +around such barriers and those erecting the barriers. The developers of | |
| 25 | +Fossil are committed to holding up our end of that fight, but this is, | |
| 26 | +to some extent, a reactive posture. It is cold comfort if Fossil’s | |
| 27 | +developers react quickly to a report of code injection — as we do! — if | |
| 28 | +the bad guys learn of it and start exploiting it first. | |
| 29 | + | |
| 30 | +Second, Fossil has purposefully powerful features that are inherently | |
| 31 | +difficult to police from the server side: HTML [in wiki](/wiki_rules) | |
| 32 | +and [in Markdown](/md_rules) docs, [TH1 docs](./th1.md), etc. | |
| 33 | + | |
| 34 | +Fossil’s strong default CSP adds client-side filtering to backstop our | |
| 35 | +server-side measures. | |
| 27 | 36 | |
| 28 | 37 | Fossil site administrators can [modify the default CSP](#override), perhaps |
| 29 | 38 | to add trusted external sources for auxiliary content. But for maximum |
| 30 | 39 | safety, site developers are encouraged to work within the restrictions |
| 31 | 40 | imposed by the default CSP and avoid the temptation to relax the CSP |
| 32 | 41 | unless they fully understand the security implications of what they are |
| 33 | 42 | doing. |
| 43 | + | |
| 44 | +[llaw]: https://en.wikipedia.org/wiki/Linus%27s_Law | |
| 45 | + | |
| 34 | 46 | |
| 35 | 47 | ## The Default Restrictions |
| 36 | 48 | |
| 37 | 49 | The Fossil default CSP declares the following content restrictions: |
| 38 | 50 | |
| 39 | 51 | |
| 40 | 52 | ### <a name="base"></a> default-src 'self' data: |
| 41 | 53 | |
| 42 | -This policy means mixed-origin content isn’t allowed, so you can’t refer to | |
| 43 | -resources (images, style-sheets, and scripts) on other web domains. | |
| 44 | -Hence the following Markdown for an inline | |
| 45 | -image hosted on another site will cause a CSP error: | |
| 54 | +This policy means mixed-origin content isn’t allowed, so you can’t refer | |
| 55 | +to resources on other web domains. Browsers will ignore a link like the | |
| 56 | +one in the following Markdown under our default CSP: | |
| 46 | 57 | |
| 47 | 58 |  |
| 59 | + | |
| 60 | +If you look in the browser’s developer console, you should see a CSP | |
| 61 | +error when attempting to render such a page. | |
| 48 | 62 | |
| 49 | 63 | The default policy does allows inline `data:` URIs, which means you could |
| 50 | 64 | [data-encode][de] your image content and put it inline within the |
| 51 | 65 | document: |
| 52 | 66 | |
| 53 | 67 |  |
| 54 | 68 | |
| 55 | 69 | That method is best used for fairly small resources. Large `data:` URIs |
| 56 | -are hard to read and edit. Keep in mind that if you put such a thing | |
| 57 | -into a Fossil forum post, anyone subscribed to email alerts will get a | |
| 58 | -copy of the raw URI text, which is really ugly. | |
| 70 | +are hard to read and edit. There are secondary problems as well: if you | |
| 71 | +put a large image into a Fossil forum post this way, anyone subscribed | |
| 72 | +to email alerts will get a copy of the raw URI text, which can amount to | |
| 73 | +pages and pages of [ugly Base64-encoded text][b64]. | |
| 74 | + | |
| 75 | +Fossil offers several alternatives for serving large content resources | |
| 76 | +from within the repository: | |
| 77 | + | |
| 78 | +* **versioned content** via [`/raw`](/help?cmd=/raw) | |
| 79 | +* **[unversioned content](./unvers.wiki)** via [`/uv`](/help?cmd=/uv) | |
| 80 | +* **relative links** | |
| 59 | 81 | |
| 60 | -For larger images in [embedded documentation](./embeddeddoc.wiki) you | |
| 61 | -store the image as a separate file in the Fossil repository and reference | |
| 62 | -it via a relative URI. | |
| 82 | +Only the first two options work in [wiki articles][wiki], | |
| 83 | +[tickets][tkt], [forum posts][fp], and [tech notes][tn]. The last | |
| 84 | +option is a much simpler alternative, but it only works within [embedded | |
| 85 | +documentation][ed]: | |
| 63 | 86 | |
| 64 | 87 |  |
| 65 | 88 | |
| 66 | -Any content from the same domain as the Fossil repository will work fine. | |
| 67 | -So if the Fossil repository is but one path in a larger website, it will | |
| 68 | -be able reference other static resources within that same website. It | |
| 69 | -can also reference [unversioned content](./unvers.wiki). However, as | |
| 70 | -unversioned content and content outside of the Fossil repository itself | |
| 71 | -will not be transferred by [sync](/help?cmd=sync), the references probably | |
| 72 | -will not work in clones of your repository. | |
| 89 | +Because all of these methods pull content from within the Fossil | |
| 90 | +repository, they all count as “self” for the purposes of the CSP. | |
| 91 | + | |
| 92 | +This rule also works when the Fossil repository is but one path in a | |
| 93 | +larger website. The browser can’t distinguish Fossil-served content from | |
| 94 | +that served by the rest of the same web domain, so your repository can | |
| 95 | +refer to other resources within that same web site, whether they are | |
| 96 | +static files served by [an HTTP proxy in front of Fossil][svr], by | |
| 97 | +another Fossil repository served under that same domain, or dynamic | |
| 98 | +content served by, say, a PHP app on that same site. | |
| 99 | + | |
| 100 | +Beware that there are a number of problems that come up with using such | |
| 101 | +out-of-repository resources, which all stem from the fact that they | |
| 102 | +aren’t included in a [sync](/help?cmd=sync): | |
| 103 | + | |
| 104 | +1. Relative links break in `fossil ui` when run on a clone. | |
| 105 | + | |
| 106 | +2. Absolute links break under certain types of failover and | |
| 107 | + load-balancing schemes. | |
| 108 | + | |
| 109 | +3. Absolute links fail when one’s purpose in using a clone is to | |
| 110 | + recover from the loss of a project web site by standing that clone | |
| 111 | + up [as a server][svr] elsewhere. | |
| 112 | + | |
| 113 | +You can avoid all of these problems by referring to in-repo resources | |
| 114 | +exclusively. | |
| 115 | + | |
| 116 | +[b64]: https://en.wikipedia.org/wiki/Base64 | |
| 117 | +[svr]: ./server/ | |
| 118 | + | |
| 73 | 119 | |
| 74 | 120 | ### <a name="style"></a> style-src 'self' 'unsafe-inline' |
| 75 | 121 | |
| 76 | -This policy allows CSS information to come from separate files in the | |
| 77 | -same domain of the Fossil server, or for CSS to be embedded inline within | |
| 78 | -the document text. | |
| 79 | - | |
| 80 | -The `'unsafe-inline'` element means that an injection vulnerability in | |
| 81 | -Fossil would allow an attacker to modify the CSS for a Fossil-generated | |
| 82 | -page. This is not ideal, but nor is it as dangerous as allowing | |
| 83 | -injected javascript to run, and Fossil uses of in-line CSS | |
| 84 | -for things like setting background colors in timelines and defining | |
| 85 | -line widths in bar graphs on the [Activity Reports](/reports) page, | |
| 86 | -so it seems like in-line CSS is a necessary compromise at this time. | |
| 122 | +This policy allows CSS information to come from separate files hosted | |
| 123 | +under the Fossil repo server’s Internet domain, or for CSS to be | |
| 124 | +embedded within `<style>` tags within the document text. | |
| 125 | + | |
| 126 | +The `'unsafe-inline'` declaration excludes CSS within individual HTML | |
| 127 | +elements: | |
| 128 | + | |
| 129 | + <p style="margin-left: 4em">Indented text.</p> | |
| 130 | + | |
| 131 | +Because this policy is weaker than [our default for script | |
| 132 | +elements](#script), there is the potential for an atacker to modify a | |
| 133 | +Fossil-generated page via CSS. While such page modifications are not as | |
| 134 | +dangerous as injected JavaScript, the real reason we allow it is that | |
| 135 | +Fossil still emits in-page `<style>` blocks in a few places. Over time, | |
| 136 | +we may work out ways to avoid each of these, which will eventually allow | |
| 137 | +us to tighten this CSP rule down to match the `script` rule. We | |
| 138 | +recommend that you do your own CSS modifications [via the skin][cs] | |
| 139 | +rather than depend on the ability to insert `<script>` blocks into | |
| 140 | +individual pages. | |
| 141 | + | |
| 87 | 142 | |
| 88 | 143 | ### <a name="script"></a> script-src 'self' 'nonce-%s' |
| 89 | 144 | |
| 90 | -This policy disables in-line javascript and only allows `<script>` | |
| 91 | -elements if the `<script>` includes a `nonce=` attribute the | |
| 92 | -matches the %s section of the CSP. Fossil provides a different | |
| 93 | -random nonce for every page it generates, and since an attacker has | |
| 94 | -no way of predicting what that nonce will be, the attacker is unable | |
| 95 | -to inject working javascript. | |
| 96 | - | |
| 97 | -For documents generated by the [CGI extensions](./serverext.wiki), the | |
| 98 | -value of the nonce is accessible in the FOSSIL_NONCE environment variable. | |
| 99 | -TH1 scripts that run while generating the header or footer can access | |
| 100 | -the nonce in the $nonce variable. The JavaScript section of a | |
| 101 | -[custom skin][cs] automatically includes the appropriate nonce. | |
| 145 | +This policy disables in-line JavaScript and only allows `<script>` | |
| 146 | +elements if the `<script>` includes a `nonce` attribute that matches the | |
| 147 | +one declared by the CSP. That nonce is a large random number, unique for | |
| 148 | +each HTTP page generated by Fossil, so an attacker cannot guess the | |
| 149 | +value, so the browser will ignore an attacker’s injected JavaScript. | |
| 150 | + | |
| 151 | +That nonce can only come from one of three sources, all of which should | |
| 152 | +be protected at the system administration level on the Fossil server: | |
| 153 | + | |
| 154 | +* **Fossil server C code:** All code paths in Fossil that emit | |
| 155 | + `<script>` elements include the `nonce` attribute. There are several | |
| 156 | + cases, such as the “JavaScript” section of a [custom skin][cs]. | |
| 157 | + That text is currently inserted into each HTML page generated by | |
| 158 | + Fossil,¹ which means it needs to include a `nonce` attribute to | |
| 159 | + allow it to run under this default CSP. We consider JavaScript | |
| 160 | + emitted via these paths to be safe because it’s audited by the | |
| 161 | + Fossil developers. We assume that you got your Fossil server’s code | |
| 162 | + from a trustworthy source and that an attacker cannot replace your | |
| 163 | + Fossil server binary. | |
| 164 | + | |
| 165 | +* **TH1 code:** The Fossil TH1 interpreter pre-defines the [`$nonce` | |
| 166 | + variable](./th1.md#nonce) for use in [custom skins][cs]. For | |
| 167 | + example, some of the stock skins that ship with Fossil include a | |
| 168 | + wall clock feature up in the corner that updates once a minute. | |
| 169 | + These paths are safe in the default Fossil configuration because | |
| 170 | + only the [all-powerful Setup user][su] can write TH1 code that | |
| 171 | + executes in the server’s running context. | |
| 172 | + | |
| 173 | + There is, however, [a default-disabled path](#xss) to beware of, | |
| 174 | + covered in the next section. | |
| 175 | + | |
| 176 | +* **[CGI server extensions][ext]:** Fossil exports the nonce to the | |
| 177 | + CGI in the `FOSSIL_NONCE` environment variable, which it can then | |
| 178 | + use in `<script>` elements it generates. Because these extensions | |
| 179 | + can only be installed by the Fossil server’s system administrator, | |
| 180 | + this path is also considered safe. | |
| 181 | + | |
| 182 | +[su]: ./admin-v-setup.md | |
| 183 | + | |
| 102 | 184 | |
| 103 | 185 | #### <a name="xss"></a>Cross-Site Scripting via Ordinary User Capabilities |
| 104 | 186 | |
| 105 | 187 | We’re so restrictive about how we treat JavaScript because it can lead |
| 106 | 188 | to difficult-to-avoid scripting attacks. If we used the same CSP for |
| @@ -155,10 +237,11 @@ | ||
| 155 | 237 | since the only way to create or modify HTML-formatted embedded docs is |
| 156 | 238 | through check-ins. |
| 157 | 239 | |
| 158 | 240 | [ed]: ./embeddeddoc.wiki |
| 159 | 241 | [edtf]: ./embeddeddoc.wiki#th1 |
| 242 | +[ext]: ./serverext.wiki | |
| 160 | 243 | [fp]: ./forum.wiki |
| 161 | 244 | [hfed]: ./embeddeddoc.wiki#html |
| 162 | 245 | [tkt]: ./tickets.wiki |
| 163 | 246 | [tn]: ./event.wiki |
| 164 | 247 | [wiki]: ./wikitheory.wiki |
| @@ -220,23 +303,23 @@ | ||
| 220 | 303 | |
| 221 | 304 | This then tells you one way to override Fossil’s default CSP: provide |
| 222 | 305 | your own HTML header in a custom skin. |
| 223 | 306 | |
| 224 | 307 | A useful combination is to entirely override the default CSP in the skin |
| 225 | -but then provide a new CSP [in the front-end proxy layer](./server/) | |
| 308 | +but then provide a new CSP [in the front-end proxy layer][svr] | |
| 226 | 309 | using any of the many reverse proxy servers that can define custom HTTP |
| 227 | 310 | headers. |
| 228 | 311 | |
| 229 | 312 | |
| 230 | 313 | ------------ |
| 231 | 314 | |
| 232 | 315 | |
| 233 | 316 | **Asides and Digressions:** |
| 234 | 317 | |
| 235 | -1. There is actually a third context that can correctly insert this | |
| 236 | - nonce attribute: [a CGI server extension](./serverext.wiki), by use of | |
| 237 | - the `FOSSIL_NONCE` variable sent to the CGI by Fossil. | |
| 318 | +1. Fossil might someday switch to serving the “JavaScript” section of a | |
| 319 | + custom skin as a virtual text file, allowing it to be cached by the | |
| 320 | + browser, reducing page load times. | |
| 238 | 321 | |
| 239 | 322 | 2. The stock Bootstrap skin does actually include a `<head>` tag, but |
| 240 | 323 | from Fossil 2.7 through Fossil 2.9, it just repeated the same CSP |
| 241 | 324 | text that Fossil’s C code inserts into the HTML header for all other |
| 242 | 325 | stock skins. With Fossil 2.10, the stock Bootstrap skin uses |
| @@ -245,6 +328,5 @@ | ||
| 245 | 328 | |
| 246 | 329 | [cs]: ./customskin.md |
| 247 | 330 | [csp]: https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP |
| 248 | 331 | [de]: https://dopiaza.org/tools/datauri/index.php |
| 249 | 332 | [xss]: https://en.wikipedia.org/wiki/Cross-site_scripting |
| 250 | -[xssci]: https://fossil-scm.org/forum/forumpost/e7c386b21f | |
| 251 | 333 |
| --- www/defcsp.md | |
| +++ www/defcsp.md | |
| @@ -1,106 +1,188 @@ | |
| 1 | # The Default Content Security Policy (CSP) |
| 2 | |
| 3 | When Fossil’s web interface generates an HTML page, it |
| 4 | normally includes a [Content Security Policy][csp] (CSP) |
| 5 | in the `<head>`. |
| 6 | The CSP tells the browser what types of content (HTML, image, CSS, |
| 7 | JavaScript...) the document may reference and from where the |
| 8 | content may be sourced. |
| 9 | |
| 10 | CSP is a security measure designed to prevent [cross-site scripting][xss] |
| 11 | (XSS) and other similar code injection attacks. |
| 12 | The CSP defines a “white list” of content types and origins that |
| 13 | are considered safe. Any references to resources that are not |
| 14 | on the white list are ignored. |
| 15 | |
| 16 | If Fossil were perfect and bug-free and never allowed any kind of |
| 17 | code injection on the pages it generates, then the CSP would not |
| 18 | be useful. The Fossil developers are not aware of any defects |
| 19 | in Fossil that allow code injection, and will promptly fix any defects |
| 20 | that are brought to their attention. Lots of eyeballs are looking at |
| 21 | Fossil to find problems in the code, and the Fossil build process uses |
| 22 | custom static analysis techniques to help identify code injection problems |
| 23 | at compile-time. Nevertheless, problems do sometimes (rarely) slip |
| 24 | through. The CSP serves as a final line of defense, preventing |
| 25 | code injection defects in Fossil from turning into actual |
| 26 | vulnerabilities. |
| 27 | |
| 28 | Fossil site administrators can [modify the default CSP](#override), perhaps |
| 29 | to add trusted external sources for auxiliary content. But for maximum |
| 30 | safety, site developers are encouraged to work within the restrictions |
| 31 | imposed by the default CSP and avoid the temptation to relax the CSP |
| 32 | unless they fully understand the security implications of what they are |
| 33 | doing. |
| 34 | |
| 35 | ## The Default Restrictions |
| 36 | |
| 37 | The Fossil default CSP declares the following content restrictions: |
| 38 | |
| 39 | |
| 40 | ### <a name="base"></a> default-src 'self' data: |
| 41 | |
| 42 | This policy means mixed-origin content isn’t allowed, so you can’t refer to |
| 43 | resources (images, style-sheets, and scripts) on other web domains. |
| 44 | Hence the following Markdown for an inline |
| 45 | image hosted on another site will cause a CSP error: |
| 46 | |
| 47 |  |
| 48 | |
| 49 | The default policy does allows inline `data:` URIs, which means you could |
| 50 | [data-encode][de] your image content and put it inline within the |
| 51 | document: |
| 52 | |
| 53 |  |
| 54 | |
| 55 | That method is best used for fairly small resources. Large `data:` URIs |
| 56 | are hard to read and edit. Keep in mind that if you put such a thing |
| 57 | into a Fossil forum post, anyone subscribed to email alerts will get a |
| 58 | copy of the raw URI text, which is really ugly. |
| 59 | |
| 60 | For larger images in [embedded documentation](./embeddeddoc.wiki) you |
| 61 | store the image as a separate file in the Fossil repository and reference |
| 62 | it via a relative URI. |
| 63 | |
| 64 |  |
| 65 | |
| 66 | Any content from the same domain as the Fossil repository will work fine. |
| 67 | So if the Fossil repository is but one path in a larger website, it will |
| 68 | be able reference other static resources within that same website. It |
| 69 | can also reference [unversioned content](./unvers.wiki). However, as |
| 70 | unversioned content and content outside of the Fossil repository itself |
| 71 | will not be transferred by [sync](/help?cmd=sync), the references probably |
| 72 | will not work in clones of your repository. |
| 73 | |
| 74 | ### <a name="style"></a> style-src 'self' 'unsafe-inline' |
| 75 | |
| 76 | This policy allows CSS information to come from separate files in the |
| 77 | same domain of the Fossil server, or for CSS to be embedded inline within |
| 78 | the document text. |
| 79 | |
| 80 | The `'unsafe-inline'` element means that an injection vulnerability in |
| 81 | Fossil would allow an attacker to modify the CSS for a Fossil-generated |
| 82 | page. This is not ideal, but nor is it as dangerous as allowing |
| 83 | injected javascript to run, and Fossil uses of in-line CSS |
| 84 | for things like setting background colors in timelines and defining |
| 85 | line widths in bar graphs on the [Activity Reports](/reports) page, |
| 86 | so it seems like in-line CSS is a necessary compromise at this time. |
| 87 | |
| 88 | ### <a name="script"></a> script-src 'self' 'nonce-%s' |
| 89 | |
| 90 | This policy disables in-line javascript and only allows `<script>` |
| 91 | elements if the `<script>` includes a `nonce=` attribute the |
| 92 | matches the %s section of the CSP. Fossil provides a different |
| 93 | random nonce for every page it generates, and since an attacker has |
| 94 | no way of predicting what that nonce will be, the attacker is unable |
| 95 | to inject working javascript. |
| 96 | |
| 97 | For documents generated by the [CGI extensions](./serverext.wiki), the |
| 98 | value of the nonce is accessible in the FOSSIL_NONCE environment variable. |
| 99 | TH1 scripts that run while generating the header or footer can access |
| 100 | the nonce in the $nonce variable. The JavaScript section of a |
| 101 | [custom skin][cs] automatically includes the appropriate nonce. |
| 102 | |
| 103 | #### <a name="xss"></a>Cross-Site Scripting via Ordinary User Capabilities |
| 104 | |
| 105 | We’re so restrictive about how we treat JavaScript because it can lead |
| 106 | to difficult-to-avoid scripting attacks. If we used the same CSP for |
| @@ -155,10 +237,11 @@ | |
| 155 | since the only way to create or modify HTML-formatted embedded docs is |
| 156 | through check-ins. |
| 157 | |
| 158 | [ed]: ./embeddeddoc.wiki |
| 159 | [edtf]: ./embeddeddoc.wiki#th1 |
| 160 | [fp]: ./forum.wiki |
| 161 | [hfed]: ./embeddeddoc.wiki#html |
| 162 | [tkt]: ./tickets.wiki |
| 163 | [tn]: ./event.wiki |
| 164 | [wiki]: ./wikitheory.wiki |
| @@ -220,23 +303,23 @@ | |
| 220 | |
| 221 | This then tells you one way to override Fossil’s default CSP: provide |
| 222 | your own HTML header in a custom skin. |
| 223 | |
| 224 | A useful combination is to entirely override the default CSP in the skin |
| 225 | but then provide a new CSP [in the front-end proxy layer](./server/) |
| 226 | using any of the many reverse proxy servers that can define custom HTTP |
| 227 | headers. |
| 228 | |
| 229 | |
| 230 | ------------ |
| 231 | |
| 232 | |
| 233 | **Asides and Digressions:** |
| 234 | |
| 235 | 1. There is actually a third context that can correctly insert this |
| 236 | nonce attribute: [a CGI server extension](./serverext.wiki), by use of |
| 237 | the `FOSSIL_NONCE` variable sent to the CGI by Fossil. |
| 238 | |
| 239 | 2. The stock Bootstrap skin does actually include a `<head>` tag, but |
| 240 | from Fossil 2.7 through Fossil 2.9, it just repeated the same CSP |
| 241 | text that Fossil’s C code inserts into the HTML header for all other |
| 242 | stock skins. With Fossil 2.10, the stock Bootstrap skin uses |
| @@ -245,6 +328,5 @@ | |
| 245 | |
| 246 | [cs]: ./customskin.md |
| 247 | [csp]: https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP |
| 248 | [de]: https://dopiaza.org/tools/datauri/index.php |
| 249 | [xss]: https://en.wikipedia.org/wiki/Cross-site_scripting |
| 250 | [xssci]: https://fossil-scm.org/forum/forumpost/e7c386b21f |
| 251 |
| --- www/defcsp.md | |
| +++ www/defcsp.md | |
| @@ -1,106 +1,188 @@ | |
| 1 | # The Default Content Security Policy (CSP) |
| 2 | |
| 3 | When Fossil’s web interface generates an HTML page, it normally includes |
| 4 | a [Content Security Policy][csp] (CSP) in the `<head>`. The CSP defines |
| 5 | a “white list” to tell the browser what types of content (HTML, images, |
| 6 | CSS, JavaScript...) the document may reference and the sources the |
| 7 | browser is allowed to pull such content from. The aim is to prevent |
| 8 | certain classes of [cross-site scripting][xss] (XSS) and code injection |
| 9 | attacks. The browser will not pull content types disallowed by the CSP. |
| 10 | |
| 11 | Fossil has built-in server-side content filtering logic. For example, it |
| 12 | purposely breaks `<script>` tags when it finds them in Markdown and |
| 13 | Fossil Wiki documents. (But not in [HTML-formatted embedded |
| 14 | docs][hfed]!) We also back that with multiple levels of analysis and |
| 15 | checks to find and fix content security problems: compile-time static |
| 16 | analysis, run-time dynamic analysis, and manual code inspection. Fossil |
| 17 | is open source software, so it benefits from the “[many |
| 18 | eyeballs][llaw],” limited by the size of its developer community. |
| 19 | |
| 20 | However, there is a practical limit to the power of server-side |
| 21 | filtering and code quality practices. |
| 22 | |
| 23 | First, there is an endless battle between those looking for clever paths |
| 24 | around such barriers and those erecting the barriers. The developers of |
| 25 | Fossil are committed to holding up our end of that fight, but this is, |
| 26 | to some extent, a reactive posture. It is cold comfort if Fossil’s |
| 27 | developers react quickly to a report of code injection — as we do! — if |
| 28 | the bad guys learn of it and start exploiting it first. |
| 29 | |
| 30 | Second, Fossil has purposefully powerful features that are inherently |
| 31 | difficult to police from the server side: HTML [in wiki](/wiki_rules) |
| 32 | and [in Markdown](/md_rules) docs, [TH1 docs](./th1.md), etc. |
| 33 | |
| 34 | Fossil’s strong default CSP adds client-side filtering to backstop our |
| 35 | server-side measures. |
| 36 | |
| 37 | Fossil site administrators can [modify the default CSP](#override), perhaps |
| 38 | to add trusted external sources for auxiliary content. But for maximum |
| 39 | safety, site developers are encouraged to work within the restrictions |
| 40 | imposed by the default CSP and avoid the temptation to relax the CSP |
| 41 | unless they fully understand the security implications of what they are |
| 42 | doing. |
| 43 | |
| 44 | [llaw]: https://en.wikipedia.org/wiki/Linus%27s_Law |
| 45 | |
| 46 | |
| 47 | ## The Default Restrictions |
| 48 | |
| 49 | The Fossil default CSP declares the following content restrictions: |
| 50 | |
| 51 | |
| 52 | ### <a name="base"></a> default-src 'self' data: |
| 53 | |
| 54 | This policy means mixed-origin content isn’t allowed, so you can’t refer |
| 55 | to resources on other web domains. Browsers will ignore a link like the |
| 56 | one in the following Markdown under our default CSP: |
| 57 | |
| 58 |  |
| 59 | |
| 60 | If you look in the browser’s developer console, you should see a CSP |
| 61 | error when attempting to render such a page. |
| 62 | |
| 63 | The default policy does allows inline `data:` URIs, which means you could |
| 64 | [data-encode][de] your image content and put it inline within the |
| 65 | document: |
| 66 | |
| 67 |  |
| 68 | |
| 69 | That method is best used for fairly small resources. Large `data:` URIs |
| 70 | are hard to read and edit. There are secondary problems as well: if you |
| 71 | put a large image into a Fossil forum post this way, anyone subscribed |
| 72 | to email alerts will get a copy of the raw URI text, which can amount to |
| 73 | pages and pages of [ugly Base64-encoded text][b64]. |
| 74 | |
| 75 | Fossil offers several alternatives for serving large content resources |
| 76 | from within the repository: |
| 77 | |
| 78 | * **versioned content** via [`/raw`](/help?cmd=/raw) |
| 79 | * **[unversioned content](./unvers.wiki)** via [`/uv`](/help?cmd=/uv) |
| 80 | * **relative links** |
| 81 | |
| 82 | Only the first two options work in [wiki articles][wiki], |
| 83 | [tickets][tkt], [forum posts][fp], and [tech notes][tn]. The last |
| 84 | option is a much simpler alternative, but it only works within [embedded |
| 85 | documentation][ed]: |
| 86 | |
| 87 |  |
| 88 | |
| 89 | Because all of these methods pull content from within the Fossil |
| 90 | repository, they all count as “self” for the purposes of the CSP. |
| 91 | |
| 92 | This rule also works when the Fossil repository is but one path in a |
| 93 | larger website. The browser can’t distinguish Fossil-served content from |
| 94 | that served by the rest of the same web domain, so your repository can |
| 95 | refer to other resources within that same web site, whether they are |
| 96 | static files served by [an HTTP proxy in front of Fossil][svr], by |
| 97 | another Fossil repository served under that same domain, or dynamic |
| 98 | content served by, say, a PHP app on that same site. |
| 99 | |
| 100 | Beware that there are a number of problems that come up with using such |
| 101 | out-of-repository resources, which all stem from the fact that they |
| 102 | aren’t included in a [sync](/help?cmd=sync): |
| 103 | |
| 104 | 1. Relative links break in `fossil ui` when run on a clone. |
| 105 | |
| 106 | 2. Absolute links break under certain types of failover and |
| 107 | load-balancing schemes. |
| 108 | |
| 109 | 3. Absolute links fail when one’s purpose in using a clone is to |
| 110 | recover from the loss of a project web site by standing that clone |
| 111 | up [as a server][svr] elsewhere. |
| 112 | |
| 113 | You can avoid all of these problems by referring to in-repo resources |
| 114 | exclusively. |
| 115 | |
| 116 | [b64]: https://en.wikipedia.org/wiki/Base64 |
| 117 | [svr]: ./server/ |
| 118 | |
| 119 | |
| 120 | ### <a name="style"></a> style-src 'self' 'unsafe-inline' |
| 121 | |
| 122 | This policy allows CSS information to come from separate files hosted |
| 123 | under the Fossil repo server’s Internet domain, or for CSS to be |
| 124 | embedded within `<style>` tags within the document text. |
| 125 | |
| 126 | The `'unsafe-inline'` declaration excludes CSS within individual HTML |
| 127 | elements: |
| 128 | |
| 129 | <p style="margin-left: 4em">Indented text.</p> |
| 130 | |
| 131 | Because this policy is weaker than [our default for script |
| 132 | elements](#script), there is the potential for an atacker to modify a |
| 133 | Fossil-generated page via CSS. While such page modifications are not as |
| 134 | dangerous as injected JavaScript, the real reason we allow it is that |
| 135 | Fossil still emits in-page `<style>` blocks in a few places. Over time, |
| 136 | we may work out ways to avoid each of these, which will eventually allow |
| 137 | us to tighten this CSP rule down to match the `script` rule. We |
| 138 | recommend that you do your own CSS modifications [via the skin][cs] |
| 139 | rather than depend on the ability to insert `<script>` blocks into |
| 140 | individual pages. |
| 141 | |
| 142 | |
| 143 | ### <a name="script"></a> script-src 'self' 'nonce-%s' |
| 144 | |
| 145 | This policy disables in-line JavaScript and only allows `<script>` |
| 146 | elements if the `<script>` includes a `nonce` attribute that matches the |
| 147 | one declared by the CSP. That nonce is a large random number, unique for |
| 148 | each HTTP page generated by Fossil, so an attacker cannot guess the |
| 149 | value, so the browser will ignore an attacker’s injected JavaScript. |
| 150 | |
| 151 | That nonce can only come from one of three sources, all of which should |
| 152 | be protected at the system administration level on the Fossil server: |
| 153 | |
| 154 | * **Fossil server C code:** All code paths in Fossil that emit |
| 155 | `<script>` elements include the `nonce` attribute. There are several |
| 156 | cases, such as the “JavaScript” section of a [custom skin][cs]. |
| 157 | That text is currently inserted into each HTML page generated by |
| 158 | Fossil,¹ which means it needs to include a `nonce` attribute to |
| 159 | allow it to run under this default CSP. We consider JavaScript |
| 160 | emitted via these paths to be safe because it’s audited by the |
| 161 | Fossil developers. We assume that you got your Fossil server’s code |
| 162 | from a trustworthy source and that an attacker cannot replace your |
| 163 | Fossil server binary. |
| 164 | |
| 165 | * **TH1 code:** The Fossil TH1 interpreter pre-defines the [`$nonce` |
| 166 | variable](./th1.md#nonce) for use in [custom skins][cs]. For |
| 167 | example, some of the stock skins that ship with Fossil include a |
| 168 | wall clock feature up in the corner that updates once a minute. |
| 169 | These paths are safe in the default Fossil configuration because |
| 170 | only the [all-powerful Setup user][su] can write TH1 code that |
| 171 | executes in the server’s running context. |
| 172 | |
| 173 | There is, however, [a default-disabled path](#xss) to beware of, |
| 174 | covered in the next section. |
| 175 | |
| 176 | * **[CGI server extensions][ext]:** Fossil exports the nonce to the |
| 177 | CGI in the `FOSSIL_NONCE` environment variable, which it can then |
| 178 | use in `<script>` elements it generates. Because these extensions |
| 179 | can only be installed by the Fossil server’s system administrator, |
| 180 | this path is also considered safe. |
| 181 | |
| 182 | [su]: ./admin-v-setup.md |
| 183 | |
| 184 | |
| 185 | #### <a name="xss"></a>Cross-Site Scripting via Ordinary User Capabilities |
| 186 | |
| 187 | We’re so restrictive about how we treat JavaScript because it can lead |
| 188 | to difficult-to-avoid scripting attacks. If we used the same CSP for |
| @@ -155,10 +237,11 @@ | |
| 237 | since the only way to create or modify HTML-formatted embedded docs is |
| 238 | through check-ins. |
| 239 | |
| 240 | [ed]: ./embeddeddoc.wiki |
| 241 | [edtf]: ./embeddeddoc.wiki#th1 |
| 242 | [ext]: ./serverext.wiki |
| 243 | [fp]: ./forum.wiki |
| 244 | [hfed]: ./embeddeddoc.wiki#html |
| 245 | [tkt]: ./tickets.wiki |
| 246 | [tn]: ./event.wiki |
| 247 | [wiki]: ./wikitheory.wiki |
| @@ -220,23 +303,23 @@ | |
| 303 | |
| 304 | This then tells you one way to override Fossil’s default CSP: provide |
| 305 | your own HTML header in a custom skin. |
| 306 | |
| 307 | A useful combination is to entirely override the default CSP in the skin |
| 308 | but then provide a new CSP [in the front-end proxy layer][svr] |
| 309 | using any of the many reverse proxy servers that can define custom HTTP |
| 310 | headers. |
| 311 | |
| 312 | |
| 313 | ------------ |
| 314 | |
| 315 | |
| 316 | **Asides and Digressions:** |
| 317 | |
| 318 | 1. Fossil might someday switch to serving the “JavaScript” section of a |
| 319 | custom skin as a virtual text file, allowing it to be cached by the |
| 320 | browser, reducing page load times. |
| 321 | |
| 322 | 2. The stock Bootstrap skin does actually include a `<head>` tag, but |
| 323 | from Fossil 2.7 through Fossil 2.9, it just repeated the same CSP |
| 324 | text that Fossil’s C code inserts into the HTML header for all other |
| 325 | stock skins. With Fossil 2.10, the stock Bootstrap skin uses |
| @@ -245,6 +328,5 @@ | |
| 328 | |
| 329 | [cs]: ./customskin.md |
| 330 | [csp]: https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP |
| 331 | [de]: https://dopiaza.org/tools/datauri/index.php |
| 332 | [xss]: https://en.wikipedia.org/wiki/Cross-site_scripting |
| 333 |
+36
-31
| --- www/server/any/althttpd.md | ||
| +++ www/server/any/althttpd.md | ||
| @@ -1,37 +1,42 @@ | ||
| 1 | 1 | # Serving via althttpd |
| 2 | 2 | |
| 3 | -The public SQLite and Fossil web sites are not purely served by Fossil | |
| 4 | -for two reasons: | |
| 5 | - | |
| 6 | -1. We want access to these sites to be secured with TLS, which we do | |
| 7 | - [via `stunnel`](./stunnel.md). | |
| 8 | - | |
| 9 | -2. Parts of these web sites are static, stored as plain files on disk, | |
| 10 | - not as Fossil artifacts. We serve such files using a separate web | |
| 11 | - server called [`althttpd`][ah], written by the primary author of | |
| 12 | - both SQLite and Fossil, D. Richard Hipp. `althttpd` is a lightweight | |
| 13 | - HTTP-only web server. It handles the static HTTP hits on | |
| 14 | - <tt>sqlite.org</tt> and <tt>fossil-scm.org</tt>, delegating HTTPS | |
| 15 | - hits to `stunnel` and dynamic content hits to Fossil [via | |
| 16 | - CGI][cgi]. | |
| 17 | - | |
| 18 | -The largest single chunk of static content served directly by `althttpd` | |
| 19 | -rather than via Fossil is the [SQLite documentation][sd], which is built | |
| 20 | -[from source files][ds]. We don’t want those output files stored in | |
| 21 | -Fossil; we already keep that process’s *input* files in Fossil. Thus the | |
| 22 | -choice to serve the output statically. | |
| 23 | - | |
| 24 | -In addition to the [server’s documentation page][ah], there is a large, | |
| 25 | -helpful header comment in the server’s [single-file C | |
| 26 | -implementation][ac]. Between that and the generic [Serving via CGI][cgi] | |
| 27 | -docs, you should be able to figure out how to serve Fossil via | |
| 28 | -`althttpd`. | |
| 3 | +[Althttpd][althttpd] | |
| 4 | +is a light-weight web server that has been used to implement the SQLite and | |
| 5 | +Fossil websites for well over a decade. Althttpd strives for simplicity, | |
| 6 | +security, ease of configuration, and low resource usage. | |
| 7 | + | |
| 8 | +To set up a Fossil server as CGI on a host running the althttpd web | |
| 9 | +server, follow these steps. | |
| 10 | +<ol> | |
| 11 | +<li<p>Get the althttpd webserver running on the host. This is easily | |
| 12 | +done by following the [althttpd documentation][althttpd]. | |
| 13 | + | |
| 14 | +<li><p>Create a CGI script for your Fossil respository. The script will | |
| 15 | +be typically be two lines of code that look something like this: | |
| 16 | + | |
| 17 | +~~~ | |
| 18 | + #!/usr/bin/fossil | |
| 19 | + repository: /home/yourlogin/fossils/project.fossil | |
| 20 | +~~~ | |
| 21 | + | |
| 22 | +Modify the filenames to conform to your system, of course. The | |
| 23 | +CGI script accepts [other options][cgi] besides the | |
| 24 | +repository:" line. You can add in other options as you desire, | |
| 25 | +but the single "repository:" line is normally all that is needed | |
| 26 | +to get started. | |
| 27 | + | |
| 28 | +<li><p>Make the CGI script executable. | |
| 29 | + | |
| 30 | +<li><p>Verify that the fossil repository file and the directory that contains | |
| 31 | +the repository are both writable by whatever user the web server is | |
| 32 | +running and. | |
| 33 | +</ol> | |
| 34 | + | |
| 35 | +And you are done. Visit the URL that corresponds to the CGI script | |
| 36 | +you created to start using your Fossil server. | |
| 29 | 37 | |
| 30 | 38 | *[Return to the top-level Fossil server article.](../)* |
| 31 | 39 | |
| 32 | 40 | |
| 33 | -[ac]: https://sqlite.org/docsrc/file/misc/althttpd.c | |
| 34 | -[ah]: https://sqlite.org/docsrc/doc/trunk/misc/althttpd.md | |
| 35 | -[cgi]: ./cgi.md | |
| 36 | -[ds]: https://sqlite.org/docsrc/ | |
| 37 | -[sd]: https://sqlite.org/docs.html | |
| 41 | +[althttpd]: https://sqlite.org/docsrc/doc/trunk/misc/althttpd.md | |
| 42 | +[cgi]: ../../cgi.wiki | |
| 38 | 43 |
| --- www/server/any/althttpd.md | |
| +++ www/server/any/althttpd.md | |
| @@ -1,37 +1,42 @@ | |
| 1 | # Serving via althttpd |
| 2 | |
| 3 | The public SQLite and Fossil web sites are not purely served by Fossil |
| 4 | for two reasons: |
| 5 | |
| 6 | 1. We want access to these sites to be secured with TLS, which we do |
| 7 | [via `stunnel`](./stunnel.md). |
| 8 | |
| 9 | 2. Parts of these web sites are static, stored as plain files on disk, |
| 10 | not as Fossil artifacts. We serve such files using a separate web |
| 11 | server called [`althttpd`][ah], written by the primary author of |
| 12 | both SQLite and Fossil, D. Richard Hipp. `althttpd` is a lightweight |
| 13 | HTTP-only web server. It handles the static HTTP hits on |
| 14 | <tt>sqlite.org</tt> and <tt>fossil-scm.org</tt>, delegating HTTPS |
| 15 | hits to `stunnel` and dynamic content hits to Fossil [via |
| 16 | CGI][cgi]. |
| 17 | |
| 18 | The largest single chunk of static content served directly by `althttpd` |
| 19 | rather than via Fossil is the [SQLite documentation][sd], which is built |
| 20 | [from source files][ds]. We don’t want those output files stored in |
| 21 | Fossil; we already keep that process’s *input* files in Fossil. Thus the |
| 22 | choice to serve the output statically. |
| 23 | |
| 24 | In addition to the [server’s documentation page][ah], there is a large, |
| 25 | helpful header comment in the server’s [single-file C |
| 26 | implementation][ac]. Between that and the generic [Serving via CGI][cgi] |
| 27 | docs, you should be able to figure out how to serve Fossil via |
| 28 | `althttpd`. |
| 29 | |
| 30 | *[Return to the top-level Fossil server article.](../)* |
| 31 | |
| 32 | |
| 33 | [ac]: https://sqlite.org/docsrc/file/misc/althttpd.c |
| 34 | [ah]: https://sqlite.org/docsrc/doc/trunk/misc/althttpd.md |
| 35 | [cgi]: ./cgi.md |
| 36 | [ds]: https://sqlite.org/docsrc/ |
| 37 | [sd]: https://sqlite.org/docs.html |
| 38 |
| --- www/server/any/althttpd.md | |
| +++ www/server/any/althttpd.md | |
| @@ -1,37 +1,42 @@ | |
| 1 | # Serving via althttpd |
| 2 | |
| 3 | [Althttpd][althttpd] |
| 4 | is a light-weight web server that has been used to implement the SQLite and |
| 5 | Fossil websites for well over a decade. Althttpd strives for simplicity, |
| 6 | security, ease of configuration, and low resource usage. |
| 7 | |
| 8 | To set up a Fossil server as CGI on a host running the althttpd web |
| 9 | server, follow these steps. |
| 10 | <ol> |
| 11 | <li<p>Get the althttpd webserver running on the host. This is easily |
| 12 | done by following the [althttpd documentation][althttpd]. |
| 13 | |
| 14 | <li><p>Create a CGI script for your Fossil respository. The script will |
| 15 | be typically be two lines of code that look something like this: |
| 16 | |
| 17 | ~~~ |
| 18 | #!/usr/bin/fossil |
| 19 | repository: /home/yourlogin/fossils/project.fossil |
| 20 | ~~~ |
| 21 | |
| 22 | Modify the filenames to conform to your system, of course. The |
| 23 | CGI script accepts [other options][cgi] besides the |
| 24 | repository:" line. You can add in other options as you desire, |
| 25 | but the single "repository:" line is normally all that is needed |
| 26 | to get started. |
| 27 | |
| 28 | <li><p>Make the CGI script executable. |
| 29 | |
| 30 | <li><p>Verify that the fossil repository file and the directory that contains |
| 31 | the repository are both writable by whatever user the web server is |
| 32 | running and. |
| 33 | </ol> |
| 34 | |
| 35 | And you are done. Visit the URL that corresponds to the CGI script |
| 36 | you created to start using your Fossil server. |
| 37 | |
| 38 | *[Return to the top-level Fossil server article.](../)* |
| 39 | |
| 40 | |
| 41 | [althttpd]: https://sqlite.org/docsrc/doc/trunk/misc/althttpd.md |
| 42 | [cgi]: ../../cgi.wiki |
| 43 |
+35
-21
| --- www/server/any/scgi.md | ||
| +++ www/server/any/scgi.md | ||
| @@ -9,20 +9,30 @@ | ||
| 9 | 9 | This can be used with a web server such as [nginx](http://nginx.org) |
| 10 | 10 | which does not support [Fossil’s CGI mode](./cgi.md). |
| 11 | 11 | |
| 12 | 12 | A basic nginx configuration to support SCGI with Fossil looks like this: |
| 13 | 13 | |
| 14 | - location /example/ { | |
| 14 | + location /code/ { | |
| 15 | 15 | include scgi_params; |
| 16 | + scgi_param SCRIPT_NAME "/code"; | |
| 16 | 17 | scgi_pass localhost:9000; |
| 17 | - scgi_param SCRIPT_NAME "/example"; | |
| 18 | - scgi_param HTTPS "on"; | |
| 19 | 18 | } |
| 20 | 19 | |
| 21 | -Start Fossil so that it will respond to nginx’s SCGI calls like this: | |
| 20 | +The `scgi_params` file comes with nginx, and it simply translates nginx | |
| 21 | +internal variables to `scgi_param` directives to create SCGI environment | |
| 22 | +variables for the proxied program; in this case, Fossil. Our explicit | |
| 23 | +`scgi_param` call to define `SCRIPT_NAME` adds one more variable to this | |
| 24 | +set, which is necessary for this configuration to work properly, because | |
| 25 | +our repo isn’t at the root of the URL hierarchy. Without it, when Fossil | |
| 26 | +generates absolute URLs, they’ll be missing the `/code` part at the | |
| 27 | +start, which will typically cause [404 errors][404]. | |
| 28 | + | |
| 29 | +The final directive simply tells nginx to proxy all calls to URLs under | |
| 30 | +`/code` down to an SCGI program on TCP port 9000. We can temporarily | |
| 31 | +set Fossil up as a server on that port like so: | |
| 22 | 32 | |
| 23 | - fossil server /path/to/repo.fossil --scgi --localhost --port 9000 | |
| 33 | + $ fossil server /path/to/repo.fossil --scgi --localhost --port 9000 & | |
| 24 | 34 | |
| 25 | 35 | The `--scgi` option switches Fossil into SCGI mode from its default, |
| 26 | 36 | which is [stand-alone HTTP server mode](./none.md). All of the other |
| 27 | 37 | options discussed in that linked document — such as the ability to serve |
| 28 | 38 | a directory full of Fossil repositories rather than just a single |
| @@ -34,23 +44,27 @@ | ||
| 34 | 44 | |
| 35 | 45 | Giving an explicit non-default TCP port number via `--port` is a good |
| 36 | 46 | idea to avoid conflicts with use of Fossil’s default TCP service port, |
| 37 | 47 | 8080, which may conflict with local uses of `fossil ui` and such. |
| 38 | 48 | |
| 39 | -Fossil requires the `SCRIPT_NAME` environment variable in order to | |
| 40 | -function properly, but nginx does not provide this variable by default, | |
| 41 | -so it is necessary to provide it in the configuration. Failure to do | |
| 42 | -this will cause Fossil to return an error. | |
| 43 | - | |
| 44 | -The [example `fslsrv` script](/file/tools/fslsrv) shows off these same | |
| 45 | -concepts in a more complicated setting. You might want to mine that | |
| 46 | -script for ideas. | |
| 47 | - | |
| 48 | -You might want to next read one of the platform-specific versions of this | |
| 49 | -document, which goes into more detail: | |
| 50 | - | |
| 51 | -* [Debian/Ubuntu](../debian/nginx.md) | |
| 52 | - | |
| 53 | -There is a [separate article](../../tls-nginx.md) showing how to add TLS | |
| 54 | -encryption to this basic SCGI + nginx setup. | |
| 49 | +We characterized the SCGI service start command above as “temporary” | |
| 50 | +because running Fossil in the background like that means it won’t start | |
| 51 | +back up on a reboot of the server. A simple solution to that is to add | |
| 52 | +that command to `/etc/rc.local` on systems that have it. However, you | |
| 53 | +might want to consider setting Fossil up as an OS service instead, so | |
| 54 | +that you get the benefits of the platform’s service management | |
| 55 | +framework: | |
| 56 | + | |
| 57 | +* [Linux (systemd)](../debian/service.md) | |
| 58 | +* [Windows service](../windows/service.md) | |
| 59 | +* [macOS (launchd)](../macos/service.md) | |
| 60 | +* [xinetd](../any/xinetd.md) | |
| 61 | +* [inetd](../any/inetd.md) | |
| 62 | + | |
| 63 | +We go into more detail on nginx service setup with Fossil in our | |
| 64 | +[Debian/Ubuntu specific guide](../debian/nginx.md). Then in [a later | |
| 65 | +article](../../tls-nginx.md) that builds upon that, we show how to add | |
| 66 | +TLS encryption to this basic SCGI + nginx setup on Debian type OSes. | |
| 55 | 67 | |
| 56 | 68 | *[Return to the top-level Fossil server article.](../)* |
| 69 | + | |
| 70 | +[404]: https://en.wikipedia.org/wiki/HTTP_404 | |
| 57 | 71 |
| --- www/server/any/scgi.md | |
| +++ www/server/any/scgi.md | |
| @@ -9,20 +9,30 @@ | |
| 9 | This can be used with a web server such as [nginx](http://nginx.org) |
| 10 | which does not support [Fossil’s CGI mode](./cgi.md). |
| 11 | |
| 12 | A basic nginx configuration to support SCGI with Fossil looks like this: |
| 13 | |
| 14 | location /example/ { |
| 15 | include scgi_params; |
| 16 | scgi_pass localhost:9000; |
| 17 | scgi_param SCRIPT_NAME "/example"; |
| 18 | scgi_param HTTPS "on"; |
| 19 | } |
| 20 | |
| 21 | Start Fossil so that it will respond to nginx’s SCGI calls like this: |
| 22 | |
| 23 | fossil server /path/to/repo.fossil --scgi --localhost --port 9000 |
| 24 | |
| 25 | The `--scgi` option switches Fossil into SCGI mode from its default, |
| 26 | which is [stand-alone HTTP server mode](./none.md). All of the other |
| 27 | options discussed in that linked document — such as the ability to serve |
| 28 | a directory full of Fossil repositories rather than just a single |
| @@ -34,23 +44,27 @@ | |
| 34 | |
| 35 | Giving an explicit non-default TCP port number via `--port` is a good |
| 36 | idea to avoid conflicts with use of Fossil’s default TCP service port, |
| 37 | 8080, which may conflict with local uses of `fossil ui` and such. |
| 38 | |
| 39 | Fossil requires the `SCRIPT_NAME` environment variable in order to |
| 40 | function properly, but nginx does not provide this variable by default, |
| 41 | so it is necessary to provide it in the configuration. Failure to do |
| 42 | this will cause Fossil to return an error. |
| 43 | |
| 44 | The [example `fslsrv` script](/file/tools/fslsrv) shows off these same |
| 45 | concepts in a more complicated setting. You might want to mine that |
| 46 | script for ideas. |
| 47 | |
| 48 | You might want to next read one of the platform-specific versions of this |
| 49 | document, which goes into more detail: |
| 50 | |
| 51 | * [Debian/Ubuntu](../debian/nginx.md) |
| 52 | |
| 53 | There is a [separate article](../../tls-nginx.md) showing how to add TLS |
| 54 | encryption to this basic SCGI + nginx setup. |
| 55 | |
| 56 | *[Return to the top-level Fossil server article.](../)* |
| 57 |
| --- www/server/any/scgi.md | |
| +++ www/server/any/scgi.md | |
| @@ -9,20 +9,30 @@ | |
| 9 | This can be used with a web server such as [nginx](http://nginx.org) |
| 10 | which does not support [Fossil’s CGI mode](./cgi.md). |
| 11 | |
| 12 | A basic nginx configuration to support SCGI with Fossil looks like this: |
| 13 | |
| 14 | location /code/ { |
| 15 | include scgi_params; |
| 16 | scgi_param SCRIPT_NAME "/code"; |
| 17 | scgi_pass localhost:9000; |
| 18 | } |
| 19 | |
| 20 | The `scgi_params` file comes with nginx, and it simply translates nginx |
| 21 | internal variables to `scgi_param` directives to create SCGI environment |
| 22 | variables for the proxied program; in this case, Fossil. Our explicit |
| 23 | `scgi_param` call to define `SCRIPT_NAME` adds one more variable to this |
| 24 | set, which is necessary for this configuration to work properly, because |
| 25 | our repo isn’t at the root of the URL hierarchy. Without it, when Fossil |
| 26 | generates absolute URLs, they’ll be missing the `/code` part at the |
| 27 | start, which will typically cause [404 errors][404]. |
| 28 | |
| 29 | The final directive simply tells nginx to proxy all calls to URLs under |
| 30 | `/code` down to an SCGI program on TCP port 9000. We can temporarily |
| 31 | set Fossil up as a server on that port like so: |
| 32 | |
| 33 | $ fossil server /path/to/repo.fossil --scgi --localhost --port 9000 & |
| 34 | |
| 35 | The `--scgi` option switches Fossil into SCGI mode from its default, |
| 36 | which is [stand-alone HTTP server mode](./none.md). All of the other |
| 37 | options discussed in that linked document — such as the ability to serve |
| 38 | a directory full of Fossil repositories rather than just a single |
| @@ -34,23 +44,27 @@ | |
| 44 | |
| 45 | Giving an explicit non-default TCP port number via `--port` is a good |
| 46 | idea to avoid conflicts with use of Fossil’s default TCP service port, |
| 47 | 8080, which may conflict with local uses of `fossil ui` and such. |
| 48 | |
| 49 | We characterized the SCGI service start command above as “temporary” |
| 50 | because running Fossil in the background like that means it won’t start |
| 51 | back up on a reboot of the server. A simple solution to that is to add |
| 52 | that command to `/etc/rc.local` on systems that have it. However, you |
| 53 | might want to consider setting Fossil up as an OS service instead, so |
| 54 | that you get the benefits of the platform’s service management |
| 55 | framework: |
| 56 | |
| 57 | * [Linux (systemd)](../debian/service.md) |
| 58 | * [Windows service](../windows/service.md) |
| 59 | * [macOS (launchd)](../macos/service.md) |
| 60 | * [xinetd](../any/xinetd.md) |
| 61 | * [inetd](../any/inetd.md) |
| 62 | |
| 63 | We go into more detail on nginx service setup with Fossil in our |
| 64 | [Debian/Ubuntu specific guide](../debian/nginx.md). Then in [a later |
| 65 | article](../../tls-nginx.md) that builds upon that, we show how to add |
| 66 | TLS encryption to this basic SCGI + nginx setup on Debian type OSes. |
| 67 | |
| 68 | *[Return to the top-level Fossil server article.](../)* |
| 69 | |
| 70 | [404]: https://en.wikipedia.org/wiki/HTTP_404 |
| 71 |
+63
-68
| --- www/server/debian/nginx.md | ||
| +++ www/server/debian/nginx.md | ||
| @@ -66,15 +66,15 @@ | ||
| 66 | 66 | |
| 67 | 67 | Fossil provides four major ways to access a repository it’s serving |
| 68 | 68 | remotely, three of which are straightforward to use with nginx: |
| 69 | 69 | |
| 70 | 70 | * **HTTP** — Fossil has a built-in HTTP server: [`fossil |
| 71 | - server`](/help/server). While this method is efficient and it’s | |
| 72 | - possible to use nginx to proxy access to another HTTP server, this | |
| 73 | - option is overkill for our purposes. nginx is itself a fully | |
| 74 | - featured HTTP server, so we will choose in this guide not to make | |
| 75 | - nginx reinterpret Fossil’s implementation of HTTP. | |
| 71 | + server`](../any/none.md). While this method is efficient and it’s | |
| 72 | + possible to use nginx to proxy access to another HTTP server, we | |
| 73 | + don’t see any particularly good reason to make nginx reinterpret | |
| 74 | + Fossil’s own implementation of HTTP when we have a better option. | |
| 75 | + (But see [below](#http).) | |
| 76 | 76 | |
| 77 | 77 | * **CGI** — This method is simple but inefficient, because it launches |
| 78 | 78 | a separate Fossil instance on every HTTP hit. |
| 79 | 79 | |
| 80 | 80 | Since Fossil is a relatively small self-contained program, and it’s |
| @@ -107,103 +107,74 @@ | ||
| 107 | 107 | $ sudo apt install fossil nginx |
| 108 | 108 | |
| 109 | 109 | |
| 110 | 110 | ## <a name="scgi"></a>Running Fossil in SCGI Mode |
| 111 | 111 | |
| 112 | -I run my Fossil SCGI server instances with a variant of [the `fslsrv` | |
| 113 | -shell script](/file/tools/fslsrv) currently hosted in the Fossil source | |
| 114 | -code repository. You’ll want to download that and make a copy of it, so | |
| 115 | -you can customize it to your particular needs. | |
| 116 | - | |
| 117 | -This script allows running multiple Fossil SCGI servers, one per | |
| 118 | -repository, each bound to a different high-numbered `localhost` port, so | |
| 119 | -that only nginx can see and proxy them out to the public. The | |
| 120 | -“`example`” repo is on TCP port localhost:12345, and the “`foo`” repo is | |
| 121 | -on localhost:12346. | |
| 122 | - | |
| 123 | -As written, the `fslsrv` script expects repositories to be stored in the | |
| 124 | -calling user’s home directory under `~/museum`, because where else do | |
| 125 | -you keep Fossils? | |
| 126 | - | |
| 127 | -That home directory also needs to have a directory to hold log files, | |
| 128 | -`~/log/fossil/*.log`. Fossil doesn’t put out much logging, but when it | |
| 129 | -does, it’s better to have it captured than to need to re-create the | |
| 130 | -problem after the fact. | |
| 131 | - | |
| 132 | -The use of `--baseurl` in this script lets us have each Fossil | |
| 133 | -repository mounted in a different location in the URL scheme. Here, for | |
| 134 | -example, we’re saying that the “`example`” repository is hosted under | |
| 135 | -the `/code` URI on its domains, but that the “`foo`” repo is hosted at | |
| 136 | -the top level of its domain. You’ll want to do something like the | |
| 137 | -former for a Fossil repo that’s just one piece of a larger site, but the | |
| 138 | -latter for a repo that is basically the whole point of the site. | |
| 139 | - | |
| 140 | -You might also want another script to automate the update, build, and | |
| 141 | -deployment steps for new Fossil versions: | |
| 142 | - | |
| 143 | - #!/bin/sh | |
| 144 | - cd $HOME/src/fossil/trunk | |
| 145 | - fossil up | |
| 146 | - make -j11 | |
| 147 | - killall fossil | |
| 148 | - sudo make install | |
| 149 | - fslsrv | |
| 150 | - | |
| 151 | -The `killall fossil` step is needed only on OSes that refuse to let you | |
| 152 | -replace a running binary on disk. | |
| 153 | - | |
| 154 | -As written, the `fslsrv` script assumes a Linux environment. It expects | |
| 155 | -`/bin/bash` to exist, and it depends on non-POSIX tools like `pgrep`. | |
| 156 | -It should not be difficult to port to systems like macOS or the BSDs. | |
| 112 | +For the following nginx configuration to work, it needs to contact a | |
| 113 | +Fossil instance speaking the SCGI protocol. There are [many ways](../) | |
| 114 | +to set that up. For Debian type systems, we primarily recommend | |
| 115 | +following [our systemd user service guide](service.md). | |
| 116 | + | |
| 117 | +Another option would be to customize [the `fslsrv` shell | |
| 118 | +script](/file/tools/fslsrv) that ships with Fossil as an example of | |
| 119 | +launching multiple Fossil instances in the background to serve multiple | |
| 120 | +URLs. | |
| 121 | + | |
| 122 | +However you do it, you need to match up the TCP port numbers between it | |
| 123 | +and those in the nginx configuration below. | |
| 157 | 124 | |
| 158 | 125 | |
| 159 | 126 | ## <a name="config"></a>Configuration |
| 160 | 127 | |
| 161 | 128 | On Debian and Ubuntu systems the primary user-level configuration file |
| 162 | 129 | for nginx is `/etc/nginx/sites-enabled/default`. I recommend that this |
| 163 | 130 | file contain only a list of include statements, one for each site that |
| 164 | 131 | server hosts: |
| 165 | 132 | |
| 166 | - include local/example | |
| 167 | - include local/foo | |
| 133 | + include local/example.com | |
| 134 | + include local/foo.net | |
| 168 | 135 | |
| 169 | 136 | Those files then each define one domain’s configuration. Here, |
| 170 | -`/etc/nginx/local/example` contains the configuration for | |
| 171 | -`*.example.com` and `*.example.net`; and `local/foo` contains the | |
| 172 | -configuration for `*.foo.net`. | |
| 137 | +`/etc/nginx/local/example.com` contains the configuration for | |
| 138 | +`*.example.com` and its alias `*.example.net`; and `local/foo.net` | |
| 139 | +contains the configuration for `*.foo.net`. | |
| 173 | 140 | |
| 174 | -The configuration for our `foo.net` web site, stored in | |
| 175 | -`/etc/nginx/sites-enabled/local/foo` is: | |
| 141 | +The configuration for our `example.com` web site, stored in | |
| 142 | +`/etc/nginx/sites-enabled/local/example.com` is: | |
| 176 | 143 | |
| 177 | 144 | server { |
| 178 | - server_name .foo.net; | |
| 145 | + server_name .example.com .example.net ""; | |
| 179 | 146 | include local/generic; |
| 180 | 147 | |
| 181 | - access_log /var/log/nginx/foo.net-https-access.log; | |
| 182 | - error_log /var/log/nginx/foo.net-https-error.log; | |
| 148 | + access_log /var/log/nginx/example.com-https-access.log; | |
| 149 | + error_log /var/log/nginx/example.com-https-error.log; | |
| 183 | 150 | |
| 184 | - # Bypass Fossil for the static Doxygen docs | |
| 185 | - location /doc/html { | |
| 186 | - root /var/www/foo.net; | |
| 151 | + # Bypass Fossil for the static documentation generated from | |
| 152 | + # our source code by Doxygen, so it merges into the embedded | |
| 153 | + # doc URL hierarchy at Fossil’s $ROOT/doc without requiring that | |
| 154 | + # these generated files actually be stored in the repo. This | |
| 155 | + # also lets us set aggressive caching on these docs, since | |
| 156 | + # they rarely change. | |
| 157 | + location /code/doc/html { | |
| 158 | + root /var/www/example.com/code/doc/html; | |
| 187 | 159 | |
| 188 | 160 | location ~* \.(html|ico|css|js|gif|jpg|png)$ { |
| 189 | 161 | expires 7d; |
| 190 | 162 | add_header Vary Accept-Encoding; |
| 191 | 163 | access_log off; |
| 192 | 164 | } |
| 193 | 165 | } |
| 194 | 166 | |
| 195 | 167 | # Redirect everything else to the Fossil instance |
| 196 | - location / { | |
| 168 | + location /code { | |
| 197 | 169 | include scgi_params; |
| 170 | + scgi_param SCRIPT_NAME "/code"; | |
| 198 | 171 | scgi_pass 127.0.0.1:12345; |
| 199 | - scgi_param HTTPS "on"; | |
| 200 | - scgi_param SCRIPT_NAME ""; | |
| 201 | 172 | } |
| 202 | 173 | } |
| 203 | 174 | |
| 204 | -As you can see, this is a simple extension of [the basic nginx service | |
| 175 | +As you can see, this is a pure extension of [the basic nginx service | |
| 205 | 176 | configuration for SCGI][scgii], showing off a few ideas you might want to |
| 206 | 177 | try on your own site, such as static asset proxying. |
| 207 | 178 | |
| 208 | 179 | The `local/generic` file referenced above helps us reduce unnecessary |
| 209 | 180 | repetition among the multiple sites this configuration hosts: |
| @@ -221,10 +192,34 @@ | ||
| 221 | 192 | the `access_log` and `error_log` directives, which follow an obvious |
| 222 | 193 | pattern from one host to the next. Sadly, you must tolerate some |
| 223 | 194 | repetition across `server { }` blocks when setting up multiple domains |
| 224 | 195 | on a single server. |
| 225 | 196 | |
| 226 | -The configuration for `example.com` and `example.net` is similar. | |
| 197 | +The configuration for `foo.net` is similar. | |
| 227 | 198 | |
| 228 | 199 | See [the nginx docs](http://nginx.org/en/docs/) for more ideas. |
| 229 | 200 | |
| 201 | + | |
| 202 | +## <a name="http"></a>Proxying HTTP Anyway | |
| 203 | + | |
| 204 | +[Above](#modes), we argued that proxying SCGI is a better option than | |
| 205 | +making nginx reinterpret Fossil’s own implementation of HTTP. If you | |
| 206 | +want Fossil to speak HTTP, just [set Fossil up as a standalone | |
| 207 | +server](../any/none.md). And if you want nginx to [provide TLS | |
| 208 | +encryption for Fossil][tls], proxying HTTP instead of SCGI provides no | |
| 209 | +benefit. | |
| 210 | + | |
| 211 | +However, it is still worth showing the proper method of proxying | |
| 212 | +Fossil’s HTTP server through nginx if only to make reading nginx | |
| 213 | +documentation on other sites easier: | |
| 214 | + | |
| 215 | + location /code { | |
| 216 | + rewrite ^/code(/.*) $1 break; | |
| 217 | + proxy_pass http://127.0.0.1:12345; | |
| 218 | + } | |
| 219 | + | |
| 220 | +The most common thing people get wrong when hand-rolling a configuration | |
| 221 | +like this is to get the slashes wrong. Fossil is senstitive to this. For | |
| 222 | +instance, Fossil will not collapse double slashes down to a single | |
| 223 | +slash, as some other HTTP servers will. | |
| 224 | + | |
| 230 | 225 | *[Return to the top-level Fossil server article.](../)* |
| 231 | 226 |
| --- www/server/debian/nginx.md | |
| +++ www/server/debian/nginx.md | |
| @@ -66,15 +66,15 @@ | |
| 66 | |
| 67 | Fossil provides four major ways to access a repository it’s serving |
| 68 | remotely, three of which are straightforward to use with nginx: |
| 69 | |
| 70 | * **HTTP** — Fossil has a built-in HTTP server: [`fossil |
| 71 | server`](/help/server). While this method is efficient and it’s |
| 72 | possible to use nginx to proxy access to another HTTP server, this |
| 73 | option is overkill for our purposes. nginx is itself a fully |
| 74 | featured HTTP server, so we will choose in this guide not to make |
| 75 | nginx reinterpret Fossil’s implementation of HTTP. |
| 76 | |
| 77 | * **CGI** — This method is simple but inefficient, because it launches |
| 78 | a separate Fossil instance on every HTTP hit. |
| 79 | |
| 80 | Since Fossil is a relatively small self-contained program, and it’s |
| @@ -107,103 +107,74 @@ | |
| 107 | $ sudo apt install fossil nginx |
| 108 | |
| 109 | |
| 110 | ## <a name="scgi"></a>Running Fossil in SCGI Mode |
| 111 | |
| 112 | I run my Fossil SCGI server instances with a variant of [the `fslsrv` |
| 113 | shell script](/file/tools/fslsrv) currently hosted in the Fossil source |
| 114 | code repository. You’ll want to download that and make a copy of it, so |
| 115 | you can customize it to your particular needs. |
| 116 | |
| 117 | This script allows running multiple Fossil SCGI servers, one per |
| 118 | repository, each bound to a different high-numbered `localhost` port, so |
| 119 | that only nginx can see and proxy them out to the public. The |
| 120 | “`example`” repo is on TCP port localhost:12345, and the “`foo`” repo is |
| 121 | on localhost:12346. |
| 122 | |
| 123 | As written, the `fslsrv` script expects repositories to be stored in the |
| 124 | calling user’s home directory under `~/museum`, because where else do |
| 125 | you keep Fossils? |
| 126 | |
| 127 | That home directory also needs to have a directory to hold log files, |
| 128 | `~/log/fossil/*.log`. Fossil doesn’t put out much logging, but when it |
| 129 | does, it’s better to have it captured than to need to re-create the |
| 130 | problem after the fact. |
| 131 | |
| 132 | The use of `--baseurl` in this script lets us have each Fossil |
| 133 | repository mounted in a different location in the URL scheme. Here, for |
| 134 | example, we’re saying that the “`example`” repository is hosted under |
| 135 | the `/code` URI on its domains, but that the “`foo`” repo is hosted at |
| 136 | the top level of its domain. You’ll want to do something like the |
| 137 | former for a Fossil repo that’s just one piece of a larger site, but the |
| 138 | latter for a repo that is basically the whole point of the site. |
| 139 | |
| 140 | You might also want another script to automate the update, build, and |
| 141 | deployment steps for new Fossil versions: |
| 142 | |
| 143 | #!/bin/sh |
| 144 | cd $HOME/src/fossil/trunk |
| 145 | fossil up |
| 146 | make -j11 |
| 147 | killall fossil |
| 148 | sudo make install |
| 149 | fslsrv |
| 150 | |
| 151 | The `killall fossil` step is needed only on OSes that refuse to let you |
| 152 | replace a running binary on disk. |
| 153 | |
| 154 | As written, the `fslsrv` script assumes a Linux environment. It expects |
| 155 | `/bin/bash` to exist, and it depends on non-POSIX tools like `pgrep`. |
| 156 | It should not be difficult to port to systems like macOS or the BSDs. |
| 157 | |
| 158 | |
| 159 | ## <a name="config"></a>Configuration |
| 160 | |
| 161 | On Debian and Ubuntu systems the primary user-level configuration file |
| 162 | for nginx is `/etc/nginx/sites-enabled/default`. I recommend that this |
| 163 | file contain only a list of include statements, one for each site that |
| 164 | server hosts: |
| 165 | |
| 166 | include local/example |
| 167 | include local/foo |
| 168 | |
| 169 | Those files then each define one domain’s configuration. Here, |
| 170 | `/etc/nginx/local/example` contains the configuration for |
| 171 | `*.example.com` and `*.example.net`; and `local/foo` contains the |
| 172 | configuration for `*.foo.net`. |
| 173 | |
| 174 | The configuration for our `foo.net` web site, stored in |
| 175 | `/etc/nginx/sites-enabled/local/foo` is: |
| 176 | |
| 177 | server { |
| 178 | server_name .foo.net; |
| 179 | include local/generic; |
| 180 | |
| 181 | access_log /var/log/nginx/foo.net-https-access.log; |
| 182 | error_log /var/log/nginx/foo.net-https-error.log; |
| 183 | |
| 184 | # Bypass Fossil for the static Doxygen docs |
| 185 | location /doc/html { |
| 186 | root /var/www/foo.net; |
| 187 | |
| 188 | location ~* \.(html|ico|css|js|gif|jpg|png)$ { |
| 189 | expires 7d; |
| 190 | add_header Vary Accept-Encoding; |
| 191 | access_log off; |
| 192 | } |
| 193 | } |
| 194 | |
| 195 | # Redirect everything else to the Fossil instance |
| 196 | location / { |
| 197 | include scgi_params; |
| 198 | scgi_pass 127.0.0.1:12345; |
| 199 | scgi_param HTTPS "on"; |
| 200 | scgi_param SCRIPT_NAME ""; |
| 201 | } |
| 202 | } |
| 203 | |
| 204 | As you can see, this is a simple extension of [the basic nginx service |
| 205 | configuration for SCGI][scgii], showing off a few ideas you might want to |
| 206 | try on your own site, such as static asset proxying. |
| 207 | |
| 208 | The `local/generic` file referenced above helps us reduce unnecessary |
| 209 | repetition among the multiple sites this configuration hosts: |
| @@ -221,10 +192,34 @@ | |
| 221 | the `access_log` and `error_log` directives, which follow an obvious |
| 222 | pattern from one host to the next. Sadly, you must tolerate some |
| 223 | repetition across `server { }` blocks when setting up multiple domains |
| 224 | on a single server. |
| 225 | |
| 226 | The configuration for `example.com` and `example.net` is similar. |
| 227 | |
| 228 | See [the nginx docs](http://nginx.org/en/docs/) for more ideas. |
| 229 | |
| 230 | *[Return to the top-level Fossil server article.](../)* |
| 231 |
| --- www/server/debian/nginx.md | |
| +++ www/server/debian/nginx.md | |
| @@ -66,15 +66,15 @@ | |
| 66 | |
| 67 | Fossil provides four major ways to access a repository it’s serving |
| 68 | remotely, three of which are straightforward to use with nginx: |
| 69 | |
| 70 | * **HTTP** — Fossil has a built-in HTTP server: [`fossil |
| 71 | server`](../any/none.md). While this method is efficient and it’s |
| 72 | possible to use nginx to proxy access to another HTTP server, we |
| 73 | don’t see any particularly good reason to make nginx reinterpret |
| 74 | Fossil’s own implementation of HTTP when we have a better option. |
| 75 | (But see [below](#http).) |
| 76 | |
| 77 | * **CGI** — This method is simple but inefficient, because it launches |
| 78 | a separate Fossil instance on every HTTP hit. |
| 79 | |
| 80 | Since Fossil is a relatively small self-contained program, and it’s |
| @@ -107,103 +107,74 @@ | |
| 107 | $ sudo apt install fossil nginx |
| 108 | |
| 109 | |
| 110 | ## <a name="scgi"></a>Running Fossil in SCGI Mode |
| 111 | |
| 112 | For the following nginx configuration to work, it needs to contact a |
| 113 | Fossil instance speaking the SCGI protocol. There are [many ways](../) |
| 114 | to set that up. For Debian type systems, we primarily recommend |
| 115 | following [our systemd user service guide](service.md). |
| 116 | |
| 117 | Another option would be to customize [the `fslsrv` shell |
| 118 | script](/file/tools/fslsrv) that ships with Fossil as an example of |
| 119 | launching multiple Fossil instances in the background to serve multiple |
| 120 | URLs. |
| 121 | |
| 122 | However you do it, you need to match up the TCP port numbers between it |
| 123 | and those in the nginx configuration below. |
| 124 | |
| 125 | |
| 126 | ## <a name="config"></a>Configuration |
| 127 | |
| 128 | On Debian and Ubuntu systems the primary user-level configuration file |
| 129 | for nginx is `/etc/nginx/sites-enabled/default`. I recommend that this |
| 130 | file contain only a list of include statements, one for each site that |
| 131 | server hosts: |
| 132 | |
| 133 | include local/example.com |
| 134 | include local/foo.net |
| 135 | |
| 136 | Those files then each define one domain’s configuration. Here, |
| 137 | `/etc/nginx/local/example.com` contains the configuration for |
| 138 | `*.example.com` and its alias `*.example.net`; and `local/foo.net` |
| 139 | contains the configuration for `*.foo.net`. |
| 140 | |
| 141 | The configuration for our `example.com` web site, stored in |
| 142 | `/etc/nginx/sites-enabled/local/example.com` is: |
| 143 | |
| 144 | server { |
| 145 | server_name .example.com .example.net ""; |
| 146 | include local/generic; |
| 147 | |
| 148 | access_log /var/log/nginx/example.com-https-access.log; |
| 149 | error_log /var/log/nginx/example.com-https-error.log; |
| 150 | |
| 151 | # Bypass Fossil for the static documentation generated from |
| 152 | # our source code by Doxygen, so it merges into the embedded |
| 153 | # doc URL hierarchy at Fossil’s $ROOT/doc without requiring that |
| 154 | # these generated files actually be stored in the repo. This |
| 155 | # also lets us set aggressive caching on these docs, since |
| 156 | # they rarely change. |
| 157 | location /code/doc/html { |
| 158 | root /var/www/example.com/code/doc/html; |
| 159 | |
| 160 | location ~* \.(html|ico|css|js|gif|jpg|png)$ { |
| 161 | expires 7d; |
| 162 | add_header Vary Accept-Encoding; |
| 163 | access_log off; |
| 164 | } |
| 165 | } |
| 166 | |
| 167 | # Redirect everything else to the Fossil instance |
| 168 | location /code { |
| 169 | include scgi_params; |
| 170 | scgi_param SCRIPT_NAME "/code"; |
| 171 | scgi_pass 127.0.0.1:12345; |
| 172 | } |
| 173 | } |
| 174 | |
| 175 | As you can see, this is a pure extension of [the basic nginx service |
| 176 | configuration for SCGI][scgii], showing off a few ideas you might want to |
| 177 | try on your own site, such as static asset proxying. |
| 178 | |
| 179 | The `local/generic` file referenced above helps us reduce unnecessary |
| 180 | repetition among the multiple sites this configuration hosts: |
| @@ -221,10 +192,34 @@ | |
| 192 | the `access_log` and `error_log` directives, which follow an obvious |
| 193 | pattern from one host to the next. Sadly, you must tolerate some |
| 194 | repetition across `server { }` blocks when setting up multiple domains |
| 195 | on a single server. |
| 196 | |
| 197 | The configuration for `foo.net` is similar. |
| 198 | |
| 199 | See [the nginx docs](http://nginx.org/en/docs/) for more ideas. |
| 200 | |
| 201 | |
| 202 | ## <a name="http"></a>Proxying HTTP Anyway |
| 203 | |
| 204 | [Above](#modes), we argued that proxying SCGI is a better option than |
| 205 | making nginx reinterpret Fossil’s own implementation of HTTP. If you |
| 206 | want Fossil to speak HTTP, just [set Fossil up as a standalone |
| 207 | server](../any/none.md). And if you want nginx to [provide TLS |
| 208 | encryption for Fossil][tls], proxying HTTP instead of SCGI provides no |
| 209 | benefit. |
| 210 | |
| 211 | However, it is still worth showing the proper method of proxying |
| 212 | Fossil’s HTTP server through nginx if only to make reading nginx |
| 213 | documentation on other sites easier: |
| 214 | |
| 215 | location /code { |
| 216 | rewrite ^/code(/.*) $1 break; |
| 217 | proxy_pass http://127.0.0.1:12345; |
| 218 | } |
| 219 | |
| 220 | The most common thing people get wrong when hand-rolling a configuration |
| 221 | like this is to get the slashes wrong. Fossil is senstitive to this. For |
| 222 | instance, Fossil will not collapse double slashes down to a single |
| 223 | slash, as some other HTTP servers will. |
| 224 | |
| 225 | *[Return to the top-level Fossil server article.](../)* |
| 226 |
+121
-35
| --- www/server/index.html | ||
| +++ www/server/index.html | ||
| @@ -3,10 +3,14 @@ | ||
| 3 | 3 | <style type="text/css"> |
| 4 | 4 | p { |
| 5 | 5 | margin-left: 4em; |
| 6 | 6 | margin-right: 3em; |
| 7 | 7 | } |
| 8 | + | |
| 9 | + li p { | |
| 10 | + margin-left: 0; | |
| 11 | + } | |
| 8 | 12 | |
| 9 | 13 | h2 { |
| 10 | 14 | margin-left: 1em; |
| 11 | 15 | } |
| 12 | 16 | |
| @@ -52,95 +56,136 @@ | ||
| 52 | 56 | |
| 53 | 57 | |
| 54 | 58 | <h2>No Server Required</h2> |
| 55 | 59 | |
| 56 | 60 | <p>Fossil does not require a central server, but <a |
| 57 | -href="whyuseaserver.wiki">a server can be very useful</a>.</p> | |
| 61 | +href="whyuseaserver.wiki">a server can be useful</a>.</p> | |
| 62 | + | |
| 63 | +<p>A Fossil server does not require much memory, CPU, or disk space | |
| 64 | +and can run comfortably on a generic $5/month virtual host | |
| 65 | +or on a small device like a Raspberry Pi, or it can co-exist | |
| 66 | +on a host running other services without getting in the way. | |
| 58 | 67 | |
| 59 | 68 | <p>This article is a quick-reference guide for setting up your own |
| 60 | 69 | Fossil server, with links to more detailed instructions specific to |
| 61 | 70 | particular systems, should you want extra help.</p> |
| 62 | 71 | |
| 63 | 72 | |
| 64 | -<h2 id="methods">Methods</h2> | |
| 73 | +<h2 id="prep">Repository Prep</h2> | |
| 74 | + | |
| 75 | +<p>Prior to serving a Fossil repository to others, consider running <a | |
| 76 | +href="$ROOT/help?cmd=ui"><tt>fossil ui</tt></a> locally and taking these | |
| 77 | +minimum recommended preparation steps:</p> | |
| 78 | + | |
| 79 | +<ol> | |
| 80 | + <li><p>Fossil creates only one user in a <a | |
| 81 | + href="$ROOT/help?cmd=new">new repository</a> and gives it the <a | |
| 82 | + href="../admin-v-setup.md">all-powerful Setup capability</a>. (“s”) | |
| 83 | + The 10-digit random password generated for that user is fairly strong | |
| 84 | + against remote attack, even without explicit password guess rate | |
| 85 | + limiting, but because that user has so much power, you may want to | |
| 86 | + give it a much stronger password under Admin → Users.</a></li> | |
| 87 | + | |
| 88 | + <li><p>Run the Admin → Security-Audit tool to verify that other | |
| 89 | + security-related permissions and settings are as you want them. | |
| 90 | + Consider clicking the “Take it private” link on that page to lock down | |
| 91 | + the security on that site to a level appropriate to a private | |
| 92 | + repository, even if you will eventually want some public service. It's | |
| 93 | + better to start from a secure position and open up service | |
| 94 | + feature-by-feature as necessary than it is to start from a fully open | |
| 95 | + position and lock down features one by one to achieve a secure | |
| 96 | + stance.</p></li> | |
| 97 | +</ol> | |
| 98 | + | |
| 99 | +<p>With the repository secured, it is safe to upload a copy of the | |
| 100 | +repository file to your server and proceed with server setup, below. | |
| 101 | +Further configuration steps can wait until <a href="#postsetup">after | |
| 102 | +the server is running</a>.</p> | |
| 103 | + | |
| 104 | + | |
| 105 | +<h2 id="methods">Activation Methods</h2> | |
| 65 | 106 | |
| 66 | -<p>There are basically four ways to set up a Fossil server:</p> | |
| 107 | +<p>There are basically four ways to run a Fossil server:</p> | |
| 67 | 108 | |
| 68 | 109 | <ol> |
| 69 | 110 | <li><a id="cgi" href="any/cgi.md">CGI</a> |
| 70 | - <li><a id="standalone" href="any/none.md">Stand-alone HTTP server</a> | |
| 71 | 111 | <li>Socket listener |
| 112 | + <li><a id="standalone" href="any/none.md">Stand-alone HTTP server</a> | |
| 72 | 113 | <li><a id="scgi" href="any/scgi.md">SCGI</a> |
| 73 | 114 | </ol> |
| 74 | 115 | |
| 75 | 116 | <p>All of these methods can serve either a single repository or a |
| 76 | -directory containing repositories named "<tt>*.fossil</tt>".</p> | |
| 117 | +directory hierarchy containing mulitiple repositories.</p> | |
| 77 | 118 | |
| 78 | -<p>You are not restricted to using a single method. The same Fossil | |
| 119 | +<p>You are not restricted to a single server setup. The same Fossil | |
| 79 | 120 | repository can be served using two or more of the above techniques at |
| 80 | 121 | the same time. These methods use clean, well-defined, standard |
| 81 | 122 | interfaces (CGI, SCGI, and HTTP) which allow you to easily migrate from |
| 82 | -one method to another to accommodate changes in hosting providers or | |
| 123 | +one method to another in response to changes in hosting providers or | |
| 83 | 124 | administrator preferences.</p> |
| 84 | 125 | |
| 85 | 126 | <h3>CGI</h3> |
| 86 | 127 | |
| 87 | 128 | <p>Most ordinary web servers can <a href="any/cgi.md">run Fossil as a |
| 88 | 129 | CGI script</a>. This method is known to work with Apache, |
| 89 | 130 | <tt>lighttpd</tt>, and <a |
| 90 | 131 | href="any/althttpd.md"><tt>althttpd</tt></a>. The Fossil server |
| 91 | -administrator places a <a href="/help?cmd=cgi">short CGI script</a> in | |
| 92 | -the web server's document hierarchy, and when a client requests the | |
| 93 | -appropriate URL, that script runs Fossil to generate the response.</p> | |
| 132 | +administrator places a <a href="$ROOT/help?cmd=cgi">short CGI script</a> in | |
| 133 | +the web server's document hierarchy and when a client requests the URL | |
| 134 | +that corresponds to that script, Fossil runs and generates the | |
| 135 | +response.</p> | |
| 94 | 136 | |
| 95 | 137 | <p>CGI is a good choice for merging Fossil into an existing web site, |
| 96 | -particularly on hosts that have CGI set up for you already and won't let | |
| 97 | -you modify the web server configuration further. The Fossil <a | |
| 98 | -href="../selfhost.wiki">self-hosting repositories</a> are implemented | |
| 99 | -with CGI underneath <tt>althttpd</tt>.</p> | |
| 138 | +particularly on hosts that have CGI set up and working. | |
| 139 | +The Fossil <a href="../selfhost.wiki">self-hosting repositories</a> are | |
| 140 | +implemented with CGI underneath <tt>althttpd</tt>.</p> | |
| 141 | + | |
| 142 | +<h3>Socket Listener</h3> | |
| 143 | + | |
| 144 | +<p>Socket listener daemons such as | |
| 145 | +<a id="inetd" href="any/inetd.md"><tt>inetd</tt></a>, <a id="xinetd" | |
| 146 | +href="any/xinetd.md"><tt>xinetd</tt></a>, <a id="stunnel" | |
| 147 | +href="any/stunnel.md"><tt>stunnel</tt></a>, <a | |
| 148 | +href="macos/service.md"><tt>launchd</tt></a>, and <a | |
| 149 | +href="debian/service.md"><tt>systemd</tt></a> | |
| 150 | +can be configured to invoke the the | |
| 151 | +<a href="$ROOT/help?cmd=http"><tt>fossil http</tt></a> command to handle | |
| 152 | +each incoming HTTP request. The "<tt>fossil http</tt>" command reads | |
| 153 | +the HTTP request off of standard input, computes an appropriate | |
| 154 | +reply, and writes the reply on standard output. There is a separate | |
| 155 | +invocation of the "<tt>fossil http</tt>" command for each HTTP request. | |
| 156 | +The socket listener daemon takes care of relaying content to and from | |
| 157 | +the client, and (in the case of <a href="any/stunnel.md">stunnel</a>) | |
| 158 | +handling TLS decryption and encryption. | |
| 100 | 159 | |
| 101 | 160 | <h3>Stand-alone HTTP Server</h3> |
| 102 | 161 | |
| 103 | 162 | <p>This is the <a href="any/none.md">easiest method</a>. |
| 104 | -A stand-alone server uses the <a | |
| 105 | -href="/help?cmd=server"><tt>fossil server</tt></a> command to run a | |
| 163 | +A stand-alone server uses the | |
| 164 | +<a href="$ROOT/help?cmd=server"><tt>fossil server</tt></a> command to run a | |
| 106 | 165 | process that listens for incoming HTTP requests on a socket and then |
| 107 | 166 | dispatches a copy of itself to deal with each incoming request. You can |
| 108 | 167 | expose Fossil directly to the clients in this way or you can interpose a |
| 109 | 168 | <a href="https://en.wikipedia.org/wiki/Reverse_proxy">reverse proxy</a> |
| 110 | 169 | layer between the clients and Fossil.</p> |
| 111 | 170 | |
| 112 | -<h3>Socket Listener</h3> | |
| 113 | - | |
| 114 | -<p>Only slightly more complicated is the socket listener method. | |
| 115 | -Instead of letting Fossil run in the background continuously to handle | |
| 116 | -HTTP requests from clients, you configure a socket listener daemon to | |
| 117 | -run a <a href="/help?cmd=http"><tt>fossil http</tt></a> command on each | |
| 118 | -HTTP hit. That Fossil instance handles only that one hit and then shuts | |
| 119 | -back down, letting the socket listener go back to waiting for the next | |
| 120 | -hit. This scheme is known to work with <a id="inetd" | |
| 121 | -href="any/inetd.md"><tt>inetd</tt></a>, <a id="xinetd" | |
| 122 | -href="any/xinetd.md"><tt>xinetd</tt></a>, <a id="stunnel" | |
| 123 | -href="any/stunnel.md"><tt>stunnel</tt></a>, <a | |
| 124 | -href="macos/service.md"><tt>launchd</tt></a>, and <a | |
| 125 | -href="debian/service.md"><tt>systemd</tt></a>.</p> | |
| 126 | - | |
| 127 | 171 | <h3>SCGI</h3> |
| 128 | 172 | |
| 129 | -<p>The Fossil standalone server can also run <a href="any/scgi.md">in | |
| 130 | -SCGI mode</a> — <a href="/help/server"><tt>fossil server --scgi</tt></a> | |
| 131 | -— instead of <a href="any/none.md">HTTP mode</a>, which allows it to | |
| 173 | +<p>The Fossil standalone server can also handle <a href="any/scgi.md">SCGI</a>. | |
| 174 | +When the <a href="$ROOT/help?cmd=server"><tt>fossil server</tt></a> command is | |
| 175 | +run with the extra <tt>--scgi</tt> option, it listens for incoming | |
| 176 | +SCGI requests rather than HTTP requests. This allows Fossil to | |
| 132 | 177 | respond to requests from web servers <a href="debian/nginx.md">such as |
| 133 | 178 | nginx</a> that don't support CGI. SCGI is a simpler protocol to proxy |
| 134 | 179 | than HTTP, since the HTTP doesn't have to be re-interpreted in terms of |
| 135 | 180 | the proxy's existing HTTP implementation, but it's more complex to set |
| 136 | 181 | up because you also have to set up an SCGI-to-HTTP proxy for it. It is |
| 137 | 182 | worth taking on this difficulty only when you need to integrate Fossil |
| 138 | 183 | into an existing web site already being served by an SCGI-capable web |
| 139 | 184 | server.</p> |
| 140 | 185 | |
| 141 | -<h2 id="matrix">Setup Tutorials</h2> | |
| 186 | +<h2 id="matrix">Activation Tutorials</h2> | |
| 142 | 187 | |
| 143 | 188 | <p>We've broken the configuration for each method out into a series of |
| 144 | 189 | sub-articles. Some of these are generic, while others depend on |
| 145 | 190 | particular operating systems or front-end software:</p> |
| 146 | 191 | |
| @@ -221,18 +266,59 @@ | ||
| 221 | 266 | |
| 222 | 267 | <p>We welcome <a href="../contribute.wiki">contributions</a> to fill gaps |
| 223 | 268 | (<font size="-2">❌</font>) in the table above.</p> |
| 224 | 269 | </noscript> |
| 225 | 270 | |
| 271 | + | |
| 272 | +<h2 id="postsetup">Post-Activation Configuration</h2> | |
| 273 | + | |
| 274 | +<p>After the server is up and running, log into it as the Setup user and | |
| 275 | +visit the Admin menu to finish configuring that repository for | |
| 276 | +service:</p> | |
| 277 | + | |
| 278 | +<ol> | |
| 279 | + <li><p>Add user accounts for your other team members. Use the | |
| 280 | + pre-defined user capabilities to define access policies rather than | |
| 281 | + give out those same set of capabilities redundantly to each | |
| 282 | + user.</p></li> | |
| 283 | + | |
| 284 | + <li><p>Test access to the repository from each category of non-Setup | |
| 285 | + user that you created. You may have to give your user categories some | |
| 286 | + overlooked capabilities, particularly if you followed <a | |
| 287 | + href="#prep">our earlier advice</a> to take the repository private | |
| 288 | + prior to setting up the server.</p></li> | |
| 289 | + | |
| 290 | + <li><p>Modify the repository's look and feel by <a | |
| 291 | + href="../customskin.md">customizing the skin</a>.</p></li> | |
| 292 | + | |
| 293 | + <li><p>If the repository includes <a | |
| 294 | + href="../embeddeddoc.wiki">embedded documentation</a>, consider | |
| 295 | + activating the search feature (Admin → Search) so that visitors can do | |
| 296 | + full-text search on your documentation.</p></li> | |
| 297 | + | |
| 298 | + <li><p>Now that others can be making changes to the repository, | |
| 299 | + consider monitoring them via <a href="../alerts.md">email alerts</a> | |
| 300 | + or the <a href="$ROOT/help?cmd=/timeline.rss">timeline RSS | |
| 301 | + feed</a>.</p></li> | |
| 302 | + | |
| 303 | + <li><p>Turn on the various logging features.</p></li> | |
| 304 | +</ol> | |
| 305 | + | |
| 306 | +<p>Reload the Admin → Security-Audit page occasionally during this | |
| 307 | +process to double check that you have not mistakenly configured the | |
| 308 | +server in a way that might expose information that you want to keep | |
| 309 | +private.</p> | |
| 310 | + | |
| 226 | 311 | |
| 227 | 312 | <h2 id="more">Further Details</h2> |
| 228 | 313 | |
| 229 | 314 | <ul> |
| 230 | 315 | <li><a id="chroot" href="../chroot.md" >The Server Chroot Jail</a> |
| 231 | 316 | <li><a id="loadmgmt" href="../loadmgmt.md" >Managing Server Load</a> |
| 317 | + <li><a id="bkofc" href="../backoffice.md" >The Backoffice</a> | |
| 232 | 318 | <li><a id="tls" href="../ssl.wiki" >Securing a Repository with TLS</a> |
| 233 | 319 | <li><a id="ext" href="../serverext.wiki">CGI Server Extensions</a> |
| 234 | 320 | <li><a id="about" href="../aboutcgi.wiki" >How CGI Works In Fossil</a> |
| 235 | 321 | <li><a id="sync" href="../sync.wiki" >The Fossil Sync Protocol</a> |
| 236 | 322 | </ul> |
| 237 | 323 | |
| 238 | 324 | </div> |
| 239 | 325 |
| --- www/server/index.html | |
| +++ www/server/index.html | |
| @@ -3,10 +3,14 @@ | |
| 3 | <style type="text/css"> |
| 4 | p { |
| 5 | margin-left: 4em; |
| 6 | margin-right: 3em; |
| 7 | } |
| 8 | |
| 9 | h2 { |
| 10 | margin-left: 1em; |
| 11 | } |
| 12 | |
| @@ -52,95 +56,136 @@ | |
| 52 | |
| 53 | |
| 54 | <h2>No Server Required</h2> |
| 55 | |
| 56 | <p>Fossil does not require a central server, but <a |
| 57 | href="whyuseaserver.wiki">a server can be very useful</a>.</p> |
| 58 | |
| 59 | <p>This article is a quick-reference guide for setting up your own |
| 60 | Fossil server, with links to more detailed instructions specific to |
| 61 | particular systems, should you want extra help.</p> |
| 62 | |
| 63 | |
| 64 | <h2 id="methods">Methods</h2> |
| 65 | |
| 66 | <p>There are basically four ways to set up a Fossil server:</p> |
| 67 | |
| 68 | <ol> |
| 69 | <li><a id="cgi" href="any/cgi.md">CGI</a> |
| 70 | <li><a id="standalone" href="any/none.md">Stand-alone HTTP server</a> |
| 71 | <li>Socket listener |
| 72 | <li><a id="scgi" href="any/scgi.md">SCGI</a> |
| 73 | </ol> |
| 74 | |
| 75 | <p>All of these methods can serve either a single repository or a |
| 76 | directory containing repositories named "<tt>*.fossil</tt>".</p> |
| 77 | |
| 78 | <p>You are not restricted to using a single method. The same Fossil |
| 79 | repository can be served using two or more of the above techniques at |
| 80 | the same time. These methods use clean, well-defined, standard |
| 81 | interfaces (CGI, SCGI, and HTTP) which allow you to easily migrate from |
| 82 | one method to another to accommodate changes in hosting providers or |
| 83 | administrator preferences.</p> |
| 84 | |
| 85 | <h3>CGI</h3> |
| 86 | |
| 87 | <p>Most ordinary web servers can <a href="any/cgi.md">run Fossil as a |
| 88 | CGI script</a>. This method is known to work with Apache, |
| 89 | <tt>lighttpd</tt>, and <a |
| 90 | href="any/althttpd.md"><tt>althttpd</tt></a>. The Fossil server |
| 91 | administrator places a <a href="/help?cmd=cgi">short CGI script</a> in |
| 92 | the web server's document hierarchy, and when a client requests the |
| 93 | appropriate URL, that script runs Fossil to generate the response.</p> |
| 94 | |
| 95 | <p>CGI is a good choice for merging Fossil into an existing web site, |
| 96 | particularly on hosts that have CGI set up for you already and won't let |
| 97 | you modify the web server configuration further. The Fossil <a |
| 98 | href="../selfhost.wiki">self-hosting repositories</a> are implemented |
| 99 | with CGI underneath <tt>althttpd</tt>.</p> |
| 100 | |
| 101 | <h3>Stand-alone HTTP Server</h3> |
| 102 | |
| 103 | <p>This is the <a href="any/none.md">easiest method</a>. |
| 104 | A stand-alone server uses the <a |
| 105 | href="/help?cmd=server"><tt>fossil server</tt></a> command to run a |
| 106 | process that listens for incoming HTTP requests on a socket and then |
| 107 | dispatches a copy of itself to deal with each incoming request. You can |
| 108 | expose Fossil directly to the clients in this way or you can interpose a |
| 109 | <a href="https://en.wikipedia.org/wiki/Reverse_proxy">reverse proxy</a> |
| 110 | layer between the clients and Fossil.</p> |
| 111 | |
| 112 | <h3>Socket Listener</h3> |
| 113 | |
| 114 | <p>Only slightly more complicated is the socket listener method. |
| 115 | Instead of letting Fossil run in the background continuously to handle |
| 116 | HTTP requests from clients, you configure a socket listener daemon to |
| 117 | run a <a href="/help?cmd=http"><tt>fossil http</tt></a> command on each |
| 118 | HTTP hit. That Fossil instance handles only that one hit and then shuts |
| 119 | back down, letting the socket listener go back to waiting for the next |
| 120 | hit. This scheme is known to work with <a id="inetd" |
| 121 | href="any/inetd.md"><tt>inetd</tt></a>, <a id="xinetd" |
| 122 | href="any/xinetd.md"><tt>xinetd</tt></a>, <a id="stunnel" |
| 123 | href="any/stunnel.md"><tt>stunnel</tt></a>, <a |
| 124 | href="macos/service.md"><tt>launchd</tt></a>, and <a |
| 125 | href="debian/service.md"><tt>systemd</tt></a>.</p> |
| 126 | |
| 127 | <h3>SCGI</h3> |
| 128 | |
| 129 | <p>The Fossil standalone server can also run <a href="any/scgi.md">in |
| 130 | SCGI mode</a> — <a href="/help/server"><tt>fossil server --scgi</tt></a> |
| 131 | — instead of <a href="any/none.md">HTTP mode</a>, which allows it to |
| 132 | respond to requests from web servers <a href="debian/nginx.md">such as |
| 133 | nginx</a> that don't support CGI. SCGI is a simpler protocol to proxy |
| 134 | than HTTP, since the HTTP doesn't have to be re-interpreted in terms of |
| 135 | the proxy's existing HTTP implementation, but it's more complex to set |
| 136 | up because you also have to set up an SCGI-to-HTTP proxy for it. It is |
| 137 | worth taking on this difficulty only when you need to integrate Fossil |
| 138 | into an existing web site already being served by an SCGI-capable web |
| 139 | server.</p> |
| 140 | |
| 141 | <h2 id="matrix">Setup Tutorials</h2> |
| 142 | |
| 143 | <p>We've broken the configuration for each method out into a series of |
| 144 | sub-articles. Some of these are generic, while others depend on |
| 145 | particular operating systems or front-end software:</p> |
| 146 | |
| @@ -221,18 +266,59 @@ | |
| 221 | |
| 222 | <p>We welcome <a href="../contribute.wiki">contributions</a> to fill gaps |
| 223 | (<font size="-2">❌</font>) in the table above.</p> |
| 224 | </noscript> |
| 225 | |
| 226 | |
| 227 | <h2 id="more">Further Details</h2> |
| 228 | |
| 229 | <ul> |
| 230 | <li><a id="chroot" href="../chroot.md" >The Server Chroot Jail</a> |
| 231 | <li><a id="loadmgmt" href="../loadmgmt.md" >Managing Server Load</a> |
| 232 | <li><a id="tls" href="../ssl.wiki" >Securing a Repository with TLS</a> |
| 233 | <li><a id="ext" href="../serverext.wiki">CGI Server Extensions</a> |
| 234 | <li><a id="about" href="../aboutcgi.wiki" >How CGI Works In Fossil</a> |
| 235 | <li><a id="sync" href="../sync.wiki" >The Fossil Sync Protocol</a> |
| 236 | </ul> |
| 237 | |
| 238 | </div> |
| 239 |
| --- www/server/index.html | |
| +++ www/server/index.html | |
| @@ -3,10 +3,14 @@ | |
| 3 | <style type="text/css"> |
| 4 | p { |
| 5 | margin-left: 4em; |
| 6 | margin-right: 3em; |
| 7 | } |
| 8 | |
| 9 | li p { |
| 10 | margin-left: 0; |
| 11 | } |
| 12 | |
| 13 | h2 { |
| 14 | margin-left: 1em; |
| 15 | } |
| 16 | |
| @@ -52,95 +56,136 @@ | |
| 56 | |
| 57 | |
| 58 | <h2>No Server Required</h2> |
| 59 | |
| 60 | <p>Fossil does not require a central server, but <a |
| 61 | href="whyuseaserver.wiki">a server can be useful</a>.</p> |
| 62 | |
| 63 | <p>A Fossil server does not require much memory, CPU, or disk space |
| 64 | and can run comfortably on a generic $5/month virtual host |
| 65 | or on a small device like a Raspberry Pi, or it can co-exist |
| 66 | on a host running other services without getting in the way. |
| 67 | |
| 68 | <p>This article is a quick-reference guide for setting up your own |
| 69 | Fossil server, with links to more detailed instructions specific to |
| 70 | particular systems, should you want extra help.</p> |
| 71 | |
| 72 | |
| 73 | <h2 id="prep">Repository Prep</h2> |
| 74 | |
| 75 | <p>Prior to serving a Fossil repository to others, consider running <a |
| 76 | href="$ROOT/help?cmd=ui"><tt>fossil ui</tt></a> locally and taking these |
| 77 | minimum recommended preparation steps:</p> |
| 78 | |
| 79 | <ol> |
| 80 | <li><p>Fossil creates only one user in a <a |
| 81 | href="$ROOT/help?cmd=new">new repository</a> and gives it the <a |
| 82 | href="../admin-v-setup.md">all-powerful Setup capability</a>. (“s”) |
| 83 | The 10-digit random password generated for that user is fairly strong |
| 84 | against remote attack, even without explicit password guess rate |
| 85 | limiting, but because that user has so much power, you may want to |
| 86 | give it a much stronger password under Admin → Users.</a></li> |
| 87 | |
| 88 | <li><p>Run the Admin → Security-Audit tool to verify that other |
| 89 | security-related permissions and settings are as you want them. |
| 90 | Consider clicking the “Take it private” link on that page to lock down |
| 91 | the security on that site to a level appropriate to a private |
| 92 | repository, even if you will eventually want some public service. It's |
| 93 | better to start from a secure position and open up service |
| 94 | feature-by-feature as necessary than it is to start from a fully open |
| 95 | position and lock down features one by one to achieve a secure |
| 96 | stance.</p></li> |
| 97 | </ol> |
| 98 | |
| 99 | <p>With the repository secured, it is safe to upload a copy of the |
| 100 | repository file to your server and proceed with server setup, below. |
| 101 | Further configuration steps can wait until <a href="#postsetup">after |
| 102 | the server is running</a>.</p> |
| 103 | |
| 104 | |
| 105 | <h2 id="methods">Activation Methods</h2> |
| 106 | |
| 107 | <p>There are basically four ways to run a Fossil server:</p> |
| 108 | |
| 109 | <ol> |
| 110 | <li><a id="cgi" href="any/cgi.md">CGI</a> |
| 111 | <li>Socket listener |
| 112 | <li><a id="standalone" href="any/none.md">Stand-alone HTTP server</a> |
| 113 | <li><a id="scgi" href="any/scgi.md">SCGI</a> |
| 114 | </ol> |
| 115 | |
| 116 | <p>All of these methods can serve either a single repository or a |
| 117 | directory hierarchy containing mulitiple repositories.</p> |
| 118 | |
| 119 | <p>You are not restricted to a single server setup. The same Fossil |
| 120 | repository can be served using two or more of the above techniques at |
| 121 | the same time. These methods use clean, well-defined, standard |
| 122 | interfaces (CGI, SCGI, and HTTP) which allow you to easily migrate from |
| 123 | one method to another in response to changes in hosting providers or |
| 124 | administrator preferences.</p> |
| 125 | |
| 126 | <h3>CGI</h3> |
| 127 | |
| 128 | <p>Most ordinary web servers can <a href="any/cgi.md">run Fossil as a |
| 129 | CGI script</a>. This method is known to work with Apache, |
| 130 | <tt>lighttpd</tt>, and <a |
| 131 | href="any/althttpd.md"><tt>althttpd</tt></a>. The Fossil server |
| 132 | administrator places a <a href="$ROOT/help?cmd=cgi">short CGI script</a> in |
| 133 | the web server's document hierarchy and when a client requests the URL |
| 134 | that corresponds to that script, Fossil runs and generates the |
| 135 | response.</p> |
| 136 | |
| 137 | <p>CGI is a good choice for merging Fossil into an existing web site, |
| 138 | particularly on hosts that have CGI set up and working. |
| 139 | The Fossil <a href="../selfhost.wiki">self-hosting repositories</a> are |
| 140 | implemented with CGI underneath <tt>althttpd</tt>.</p> |
| 141 | |
| 142 | <h3>Socket Listener</h3> |
| 143 | |
| 144 | <p>Socket listener daemons such as |
| 145 | <a id="inetd" href="any/inetd.md"><tt>inetd</tt></a>, <a id="xinetd" |
| 146 | href="any/xinetd.md"><tt>xinetd</tt></a>, <a id="stunnel" |
| 147 | href="any/stunnel.md"><tt>stunnel</tt></a>, <a |
| 148 | href="macos/service.md"><tt>launchd</tt></a>, and <a |
| 149 | href="debian/service.md"><tt>systemd</tt></a> |
| 150 | can be configured to invoke the the |
| 151 | <a href="$ROOT/help?cmd=http"><tt>fossil http</tt></a> command to handle |
| 152 | each incoming HTTP request. The "<tt>fossil http</tt>" command reads |
| 153 | the HTTP request off of standard input, computes an appropriate |
| 154 | reply, and writes the reply on standard output. There is a separate |
| 155 | invocation of the "<tt>fossil http</tt>" command for each HTTP request. |
| 156 | The socket listener daemon takes care of relaying content to and from |
| 157 | the client, and (in the case of <a href="any/stunnel.md">stunnel</a>) |
| 158 | handling TLS decryption and encryption. |
| 159 | |
| 160 | <h3>Stand-alone HTTP Server</h3> |
| 161 | |
| 162 | <p>This is the <a href="any/none.md">easiest method</a>. |
| 163 | A stand-alone server uses the |
| 164 | <a href="$ROOT/help?cmd=server"><tt>fossil server</tt></a> command to run a |
| 165 | process that listens for incoming HTTP requests on a socket and then |
| 166 | dispatches a copy of itself to deal with each incoming request. You can |
| 167 | expose Fossil directly to the clients in this way or you can interpose a |
| 168 | <a href="https://en.wikipedia.org/wiki/Reverse_proxy">reverse proxy</a> |
| 169 | layer between the clients and Fossil.</p> |
| 170 | |
| 171 | <h3>SCGI</h3> |
| 172 | |
| 173 | <p>The Fossil standalone server can also handle <a href="any/scgi.md">SCGI</a>. |
| 174 | When the <a href="$ROOT/help?cmd=server"><tt>fossil server</tt></a> command is |
| 175 | run with the extra <tt>--scgi</tt> option, it listens for incoming |
| 176 | SCGI requests rather than HTTP requests. This allows Fossil to |
| 177 | respond to requests from web servers <a href="debian/nginx.md">such as |
| 178 | nginx</a> that don't support CGI. SCGI is a simpler protocol to proxy |
| 179 | than HTTP, since the HTTP doesn't have to be re-interpreted in terms of |
| 180 | the proxy's existing HTTP implementation, but it's more complex to set |
| 181 | up because you also have to set up an SCGI-to-HTTP proxy for it. It is |
| 182 | worth taking on this difficulty only when you need to integrate Fossil |
| 183 | into an existing web site already being served by an SCGI-capable web |
| 184 | server.</p> |
| 185 | |
| 186 | <h2 id="matrix">Activation Tutorials</h2> |
| 187 | |
| 188 | <p>We've broken the configuration for each method out into a series of |
| 189 | sub-articles. Some of these are generic, while others depend on |
| 190 | particular operating systems or front-end software:</p> |
| 191 | |
| @@ -221,18 +266,59 @@ | |
| 266 | |
| 267 | <p>We welcome <a href="../contribute.wiki">contributions</a> to fill gaps |
| 268 | (<font size="-2">❌</font>) in the table above.</p> |
| 269 | </noscript> |
| 270 | |
| 271 | |
| 272 | <h2 id="postsetup">Post-Activation Configuration</h2> |
| 273 | |
| 274 | <p>After the server is up and running, log into it as the Setup user and |
| 275 | visit the Admin menu to finish configuring that repository for |
| 276 | service:</p> |
| 277 | |
| 278 | <ol> |
| 279 | <li><p>Add user accounts for your other team members. Use the |
| 280 | pre-defined user capabilities to define access policies rather than |
| 281 | give out those same set of capabilities redundantly to each |
| 282 | user.</p></li> |
| 283 | |
| 284 | <li><p>Test access to the repository from each category of non-Setup |
| 285 | user that you created. You may have to give your user categories some |
| 286 | overlooked capabilities, particularly if you followed <a |
| 287 | href="#prep">our earlier advice</a> to take the repository private |
| 288 | prior to setting up the server.</p></li> |
| 289 | |
| 290 | <li><p>Modify the repository's look and feel by <a |
| 291 | href="../customskin.md">customizing the skin</a>.</p></li> |
| 292 | |
| 293 | <li><p>If the repository includes <a |
| 294 | href="../embeddeddoc.wiki">embedded documentation</a>, consider |
| 295 | activating the search feature (Admin → Search) so that visitors can do |
| 296 | full-text search on your documentation.</p></li> |
| 297 | |
| 298 | <li><p>Now that others can be making changes to the repository, |
| 299 | consider monitoring them via <a href="../alerts.md">email alerts</a> |
| 300 | or the <a href="$ROOT/help?cmd=/timeline.rss">timeline RSS |
| 301 | feed</a>.</p></li> |
| 302 | |
| 303 | <li><p>Turn on the various logging features.</p></li> |
| 304 | </ol> |
| 305 | |
| 306 | <p>Reload the Admin → Security-Audit page occasionally during this |
| 307 | process to double check that you have not mistakenly configured the |
| 308 | server in a way that might expose information that you want to keep |
| 309 | private.</p> |
| 310 | |
| 311 | |
| 312 | <h2 id="more">Further Details</h2> |
| 313 | |
| 314 | <ul> |
| 315 | <li><a id="chroot" href="../chroot.md" >The Server Chroot Jail</a> |
| 316 | <li><a id="loadmgmt" href="../loadmgmt.md" >Managing Server Load</a> |
| 317 | <li><a id="bkofc" href="../backoffice.md" >The Backoffice</a> |
| 318 | <li><a id="tls" href="../ssl.wiki" >Securing a Repository with TLS</a> |
| 319 | <li><a id="ext" href="../serverext.wiki">CGI Server Extensions</a> |
| 320 | <li><a id="about" href="../aboutcgi.wiki" >How CGI Works In Fossil</a> |
| 321 | <li><a id="sync" href="../sync.wiki" >The Fossil Sync Protocol</a> |
| 322 | </ul> |
| 323 | |
| 324 | </div> |
| 325 |
+13
-10
| --- www/server/whyuseaserver.wiki | ||
| +++ www/server/whyuseaserver.wiki | ||
| @@ -1,10 +1,10 @@ | ||
| 1 | 1 | <title>Benefits Of A Fossil Server</title> |
| 2 | 2 | |
| 3 | 3 | <h2>No Server Required</h2> |
| 4 | 4 | |
| 5 | -Fossil does <em>not</em> require a central server. | |
| 5 | +Fossil does not require a central server. | |
| 6 | 6 | Data sharing and synchronization can be entirely peer-to-peer. |
| 7 | 7 | Fossil uses |
| 8 | 8 | [https://en.wikipedia.org/wiki/Conflict-free_replicated_data_type|conflict-free replicated data types] |
| 9 | 9 | to ensure that (in the limit) all participating peers see the same content. |
| 10 | 10 | |
| @@ -11,27 +11,30 @@ | ||
| 11 | 11 | <h2>But, A Server Can Be Useful</h2> |
| 12 | 12 | |
| 13 | 13 | Fossil does not require a server, but a server can be very useful. |
| 14 | 14 | Here are a few reasons to set up a Fossil server for your project: |
| 15 | 15 | |
| 16 | - 1. <b>A server gives developers a common point of rendezvous for | |
| 16 | + 1. <b>A server works as a complete project website.</b><p> | |
| 17 | + Fossil does more than just version control. It also supports | |
| 18 | + [../tickets.wiki|trouble-tickets], | |
| 19 | + [../wikitheory.wiki|wiki], and a [../forum.wiki|forum]. | |
| 20 | + The [../embeddeddoc.wiki|embedded documentation] | |
| 21 | + feature provides a great mechanism for providing project documentation. | |
| 22 | + The [../unvers.wiki|unversioned files] feature is a convenient way | |
| 23 | + to host builds and downloads on the project website. | |
| 24 | + | |
| 25 | + 2. <b>A server gives developers a common point of rendezvous for | |
| 17 | 26 | syncing their work.</b><p> |
| 18 | - It is possible for developers to synchronous peer-to-peer but | |
| 27 | + It is possible for developers to synchronize peer-to-peer but | |
| 19 | 28 | that requires the developers coordinate the sync, which in turn |
| 20 | 29 | requires that the developers both want to sync at the same moment. |
| 21 | 30 | A server aleviates this time dependency by allowing each developer |
| 22 | 31 | to sync whenever it is convenient (for example, automatically syncing |
| 23 | 32 | after each commit and before each update). Developers all stay |
| 24 | 33 | in sync with each other, without having to interrupt each other |
| 25 | 34 | constantly to set up a peer-to-peer sync. |
| 26 | 35 | |
| 27 | - 2. <b>A server works as a project website for non-developers.</b><p> | |
| 28 | - Fossil does more than just version control. It also supports | |
| 29 | - trouble-tickets, and wiki, and a forum. It shows the status | |
| 30 | - of the project. And the embedded documentation feature provides | |
| 31 | - a great mechanism for providing only instructions. | |
| 32 | - | |
| 33 | 36 | 3. <b>A server provides project leaders with up-to-date status.</b><p> |
| 34 | 37 | Project coordinators and BDFLs can click on a link or two at the |
| 35 | 38 | central Fossil server for a project, and quickly tell what is |
| 36 | 39 | going on. They can do this from anywhere, even from their phones, |
| 37 | 40 | without needing to actually sync to the device they are using. |
| @@ -39,6 +42,6 @@ | ||
| 39 | 42 | 4. <b>A server provides automatic off-site backups.</b><p> |
| 40 | 43 | A Fossil server is an automatic remote backup for all the work |
| 41 | 44 | going into a project. You can even set up multiple servers, at |
| 42 | 45 | multiple sites, with automatic synchronization between them, for |
| 43 | 46 | added redundancy. Such a set up means that no work is lost due |
| 44 | - to a single machine failure. | |
| 47 | + to a single machine failur | |
| 45 | 48 |
| --- www/server/whyuseaserver.wiki | |
| +++ www/server/whyuseaserver.wiki | |
| @@ -1,10 +1,10 @@ | |
| 1 | <title>Benefits Of A Fossil Server</title> |
| 2 | |
| 3 | <h2>No Server Required</h2> |
| 4 | |
| 5 | Fossil does <em>not</em> require a central server. |
| 6 | Data sharing and synchronization can be entirely peer-to-peer. |
| 7 | Fossil uses |
| 8 | [https://en.wikipedia.org/wiki/Conflict-free_replicated_data_type|conflict-free replicated data types] |
| 9 | to ensure that (in the limit) all participating peers see the same content. |
| 10 | |
| @@ -11,27 +11,30 @@ | |
| 11 | <h2>But, A Server Can Be Useful</h2> |
| 12 | |
| 13 | Fossil does not require a server, but a server can be very useful. |
| 14 | Here are a few reasons to set up a Fossil server for your project: |
| 15 | |
| 16 | 1. <b>A server gives developers a common point of rendezvous for |
| 17 | syncing their work.</b><p> |
| 18 | It is possible for developers to synchronous peer-to-peer but |
| 19 | that requires the developers coordinate the sync, which in turn |
| 20 | requires that the developers both want to sync at the same moment. |
| 21 | A server aleviates this time dependency by allowing each developer |
| 22 | to sync whenever it is convenient (for example, automatically syncing |
| 23 | after each commit and before each update). Developers all stay |
| 24 | in sync with each other, without having to interrupt each other |
| 25 | constantly to set up a peer-to-peer sync. |
| 26 | |
| 27 | 2. <b>A server works as a project website for non-developers.</b><p> |
| 28 | Fossil does more than just version control. It also supports |
| 29 | trouble-tickets, and wiki, and a forum. It shows the status |
| 30 | of the project. And the embedded documentation feature provides |
| 31 | a great mechanism for providing only instructions. |
| 32 | |
| 33 | 3. <b>A server provides project leaders with up-to-date status.</b><p> |
| 34 | Project coordinators and BDFLs can click on a link or two at the |
| 35 | central Fossil server for a project, and quickly tell what is |
| 36 | going on. They can do this from anywhere, even from their phones, |
| 37 | without needing to actually sync to the device they are using. |
| @@ -39,6 +42,6 @@ | |
| 39 | 4. <b>A server provides automatic off-site backups.</b><p> |
| 40 | A Fossil server is an automatic remote backup for all the work |
| 41 | going into a project. You can even set up multiple servers, at |
| 42 | multiple sites, with automatic synchronization between them, for |
| 43 | added redundancy. Such a set up means that no work is lost due |
| 44 | to a single machine failure. |
| 45 |
| --- www/server/whyuseaserver.wiki | |
| +++ www/server/whyuseaserver.wiki | |
| @@ -1,10 +1,10 @@ | |
| 1 | <title>Benefits Of A Fossil Server</title> |
| 2 | |
| 3 | <h2>No Server Required</h2> |
| 4 | |
| 5 | Fossil does not require a central server. |
| 6 | Data sharing and synchronization can be entirely peer-to-peer. |
| 7 | Fossil uses |
| 8 | [https://en.wikipedia.org/wiki/Conflict-free_replicated_data_type|conflict-free replicated data types] |
| 9 | to ensure that (in the limit) all participating peers see the same content. |
| 10 | |
| @@ -11,27 +11,30 @@ | |
| 11 | <h2>But, A Server Can Be Useful</h2> |
| 12 | |
| 13 | Fossil does not require a server, but a server can be very useful. |
| 14 | Here are a few reasons to set up a Fossil server for your project: |
| 15 | |
| 16 | 1. <b>A server works as a complete project website.</b><p> |
| 17 | Fossil does more than just version control. It also supports |
| 18 | [../tickets.wiki|trouble-tickets], |
| 19 | [../wikitheory.wiki|wiki], and a [../forum.wiki|forum]. |
| 20 | The [../embeddeddoc.wiki|embedded documentation] |
| 21 | feature provides a great mechanism for providing project documentation. |
| 22 | The [../unvers.wiki|unversioned files] feature is a convenient way |
| 23 | to host builds and downloads on the project website. |
| 24 | |
| 25 | 2. <b>A server gives developers a common point of rendezvous for |
| 26 | syncing their work.</b><p> |
| 27 | It is possible for developers to synchronize peer-to-peer but |
| 28 | that requires the developers coordinate the sync, which in turn |
| 29 | requires that the developers both want to sync at the same moment. |
| 30 | A server aleviates this time dependency by allowing each developer |
| 31 | to sync whenever it is convenient (for example, automatically syncing |
| 32 | after each commit and before each update). Developers all stay |
| 33 | in sync with each other, without having to interrupt each other |
| 34 | constantly to set up a peer-to-peer sync. |
| 35 | |
| 36 | 3. <b>A server provides project leaders with up-to-date status.</b><p> |
| 37 | Project coordinators and BDFLs can click on a link or two at the |
| 38 | central Fossil server for a project, and quickly tell what is |
| 39 | going on. They can do this from anywhere, even from their phones, |
| 40 | without needing to actually sync to the device they are using. |
| @@ -39,6 +42,6 @@ | |
| 42 | 4. <b>A server provides automatic off-site backups.</b><p> |
| 43 | A Fossil server is an automatic remote backup for all the work |
| 44 | going into a project. You can even set up multiple servers, at |
| 45 | multiple sites, with automatic synchronization between them, for |
| 46 | added redundancy. Such a set up means that no work is lost due |
| 47 | to a single machine failur |
| 48 |